528 lines
17 KiB
PowerShell
528 lines
17 KiB
PowerShell
# =========================
|
|
# MENU CONFIGURATION
|
|
# =========================
|
|
|
|
$options = @("Yes", "No")
|
|
$selectedIndex = 0
|
|
$solarPath = "C:\solar"
|
|
|
|
$header = @"
|
|
____ ___ _ _ ____
|
|
/ ___| / _ \ | | / \ | _ \
|
|
\___ \ | | | | | | / _ \ | |_) |
|
|
___) | _ | |_| | _ | |___ _ / ___ \ _ | _ < _
|
|
|____/ (_) \___/ (_) |_____| (_) /_/ \_\ (_) |_| \_\ (_)
|
|
"@
|
|
|
|
$subtitle = "Systematic Online or Local Analysis Robot"
|
|
|
|
|
|
function Show-Menu {
|
|
Clear-Host
|
|
Write-Host $header -ForegroundColor Cyan
|
|
Write-Host $subtitle -ForegroundColor Yellow
|
|
Write-Host $tospp -ForegroundColor Gray
|
|
Write-Host "`nUse arrow keys to select an option and press Enter:`n"
|
|
$esc = [char]27
|
|
$link = "https://solar.creative-crafter.de/terms_of_services_and_privacy_policy/"
|
|
$text = "Terms of Service and Privacy Policy"
|
|
|
|
Write-Host "Before continuing, please review the $esc[36m$esc]8;;$link$esc\$text$esc]8;;$esc\$esc[0m."
|
|
|
|
for ($i = 0; $i -lt $options.Length; $i++) {
|
|
if ($i -eq $selectedIndex) {
|
|
Write-Host "-> $($options[$i])" -ForegroundColor Green
|
|
} else {
|
|
Write-Host " $($options[$i])"
|
|
}
|
|
}
|
|
}
|
|
|
|
do {
|
|
Show-Menu
|
|
$key = [System.Console]::ReadKey($true)
|
|
|
|
switch ($key.Key) {
|
|
"UpArrow" {
|
|
$selectedIndex--
|
|
if ($selectedIndex -lt 0) { $selectedIndex = $options.Length - 1 }
|
|
}
|
|
"DownArrow" {
|
|
$selectedIndex++
|
|
if ($selectedIndex -ge $options.Length) { $selectedIndex = 0 }
|
|
}
|
|
}
|
|
|
|
} until ($key.Key -eq "Enter")
|
|
|
|
|
|
# =========================
|
|
# YES LOGIC
|
|
# =========================
|
|
|
|
switch ($options[$selectedIndex]) {
|
|
|
|
"Yes" {
|
|
|
|
|
|
# Create solarPath folder if it doesn't exist
|
|
if (-Not (Test-Path -Path $solarPath)) {
|
|
New-Item -Path $solarPath -ItemType Directory | Out-Null
|
|
Write-Host "Folder created at $solarPath"
|
|
} else {
|
|
Write-Host "Folder already exists at $solarPath"
|
|
}
|
|
|
|
|
|
Write-Host "Starting installation and environment setup..." -ForegroundColor Green
|
|
|
|
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/Creative-Crafter/SOLAR/main/main.py" -OutFile "C:\solar\main.py"
|
|
|
|
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/Creative-Crafter/SOLAR/main/solar_local/skills.py" -OutFile "C:\solar\skills.py"
|
|
|
|
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/Creative-Crafter/SOLAR/main/requirements.txt" -OutFile "C:\solar\requirements.txt"
|
|
|
|
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/Creative-Crafter/SOLAR/main/accept.png" -OutFile "C:\solar\accept.png"
|
|
|
|
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/Creative-Crafter/SOLAR/main/decline.png" -OutFile "C:\solar\decline.png"
|
|
|
|
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/Creative-Crafter/SOLAR/main/beep.wav" -OutFile "C:\solar\beep.wav"
|
|
|
|
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/Creative-Crafter/SOLAR/main/discord_search.png" -OutFile "C:\solar\discord_search.png"
|
|
|
|
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/Creative-Crafter/SOLAR/main/insta1.png" -OutFile "C:\solar\insta1.png"
|
|
|
|
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/Creative-Crafter/SOLAR/main/insta2.png" -OutFile "C:\solar\insta2.png"
|
|
|
|
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/Creative-Crafter/SOLAR/main/insta3.png" -OutFile "C:\solar\insta3.png"
|
|
|
|
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/Creative-Crafter/SOLAR/main/search.png" -OutFile "C:\solar\search.png"
|
|
|
|
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/Creative-Crafter/SOLAR/main/whatsapp.png" -OutFile "C:\solar\whatsapp.png"
|
|
|
|
Invoke-WebRequest -Uri "https://alphacephei.com/vosk/models/vosk-model-small-en-us-0.15.zip" -OutFile "C:\solar\vosk-model-small-en-us-0.15.zip"
|
|
|
|
Expand-Archive -Path "C:\solar\vosk-model-small-en-us-0.15.zip" -DestinationPath "C:\solar\vosk-model-small-en-us-0.15_for_deleting" -Force
|
|
|
|
Copy-Item -Path "C:\solar\vosk-model-small-en-us-0.15_for_deleting\vosk-model-small-en-us-0.15" -Destination "C:\solar\vosk-model-small-en-us-0.15" -Recurse -Force
|
|
|
|
Remove-Item -Path "C:\solar\vosk-model-small-en-us-0.15_for_deleting" -Recurse -Force
|
|
|
|
Remove-Item -Path "C:\solar\vosk-model-small-en-us-0.15.zip" -Recurse -Force
|
|
|
|
Invoke-WebRequest -Uri "https://solar.creative-crafter.de/install-local.ps1" -OutFile "C:\solar\install-local.ps1"
|
|
|
|
|
|
# Change directory to solarPath
|
|
Set-Location -Path $solarPath
|
|
|
|
# Create subfolders
|
|
$subfolders = @("scripts", "data", "logs")
|
|
foreach ($folder in $subfolders) {
|
|
$fullPath = Join-Path $solarPath $folder
|
|
if (-Not (Test-Path -Path $fullPath)) {
|
|
New-Item -Path $fullPath -ItemType Directory | Out-Null
|
|
Write-Host "Created subfolder: $fullPath"
|
|
}
|
|
}
|
|
|
|
# =========================
|
|
# PYTHON INSTALL CONFIG
|
|
# =========================
|
|
|
|
# =========================
|
|
# PYTHON CONFIG
|
|
# =========================
|
|
|
|
$requiredVersion = "3.11.0"
|
|
$installDir = "C:\Python311"
|
|
$installerPath = "$env:TEMP\python-3.11.0-amd64.exe"
|
|
$pythonUrl = "https://www.python.org/ftp/python/3.11.0/python-3.11.0-amd64.exe"
|
|
$pythonExe = Join-Path $installDir "python.exe"
|
|
|
|
# =========================
|
|
# PROJECT CONFIG
|
|
# =========================
|
|
|
|
$venvName = ".venv"
|
|
$projectPath = Get-Location
|
|
$venvPath = Join-Path $projectPath $venvName
|
|
$requirementsFile = Join-Path $projectPath "requirements.txt"
|
|
|
|
# =========================
|
|
# CHECK PYTHON 3.11 INSTALL
|
|
# =========================
|
|
|
|
function Test-Python311 {
|
|
|
|
# check installed directory
|
|
if (Test-Path $pythonExe) {
|
|
$version = & $pythonExe --version 2>&1
|
|
if ($version -match $requiredVersion) {
|
|
return $true
|
|
}
|
|
}
|
|
|
|
# check via python launcher (works even if other versions exist)
|
|
$pyLauncher = Get-Command py -ErrorAction SilentlyContinue
|
|
if ($pyLauncher) {
|
|
try {
|
|
$version = py -3.11 --version 2>&1
|
|
if ($version -match "3\.11") {
|
|
return $true
|
|
}
|
|
} catch {}
|
|
}
|
|
|
|
return $false
|
|
}
|
|
|
|
# =========================
|
|
# INSTALL PYTHON IF MISSING
|
|
# =========================
|
|
|
|
if (Test-Python311) {
|
|
Write-Output "Python $requiredVersion already installed."
|
|
} else {
|
|
|
|
Write-Output "Downloading Python $requiredVersion..."
|
|
Invoke-WebRequest -Uri $pythonUrl -OutFile $installerPath
|
|
|
|
Write-Output "Installing Python $requiredVersion to $installDir ..."
|
|
|
|
Start-Process `
|
|
-FilePath $installerPath `
|
|
-ArgumentList "/quiet InstallAllUsers=1 PrependPath=0 TargetDir=$installDir Include_launcher=1" `
|
|
-Wait
|
|
|
|
if (!(Test-Path $pythonExe)) {
|
|
Write-Output "Python installation failed."
|
|
exit 1
|
|
}
|
|
|
|
$installedVersion = & $pythonExe --version
|
|
Write-Output "Installed: $installedVersion"
|
|
}
|
|
|
|
# =========================
|
|
# CREATE VENV WITH PYTHON 3.11
|
|
# =========================
|
|
|
|
if (!(Test-Path $venvPath)) {
|
|
|
|
Write-Output "Creating virtual environment using Python 3.11..."
|
|
|
|
if (Test-Path $pythonExe) {
|
|
& $pythonExe -m venv $venvPath
|
|
}
|
|
else {
|
|
py -3.11 -m venv $venvPath
|
|
}
|
|
|
|
} else {
|
|
Write-Output ".venv already exists."
|
|
}
|
|
|
|
# =========================
|
|
# ACTIVATE VENV
|
|
# =========================
|
|
|
|
$activateScript = Join-Path $venvPath "Scripts\Activate.ps1"
|
|
|
|
if (Test-Path $activateScript) {
|
|
Write-Output "Activating .venv ..."
|
|
& $activateScript
|
|
} else {
|
|
Write-Output "Activation script not found."
|
|
exit 1
|
|
}
|
|
|
|
# =========================
|
|
# INSTALL REQUIREMENTS
|
|
# =========================
|
|
|
|
if (Test-Path $requirementsFile) {
|
|
|
|
Write-Output "Installing dependencies..."
|
|
|
|
& "$venvPath\Scripts\python.exe" -m pip install --upgrade pip
|
|
& "$venvPath\Scripts\python.exe" -m pip install -r $requirementsFile
|
|
|
|
}
|
|
# =========================
|
|
# UPGRADE PIP AND INSTALL PACKAGES
|
|
# =========================
|
|
|
|
Write-Output "Upgrading pip..."
|
|
python -m pip install --upgrade pip
|
|
|
|
foreach ($pkg in $packages) {
|
|
Write-Output "Installing $pkg..."
|
|
python -m pip install --upgrade $pkg
|
|
}
|
|
|
|
# =========================
|
|
# INSTALL REQUIREMENTS.TXT IF EXISTS
|
|
# =========================
|
|
|
|
|
|
# =========================
|
|
# OLLAMA INSTALL CONFIG
|
|
# =========================
|
|
|
|
$ollamaCommand = "ollama"
|
|
|
|
function Test-OllamaInstalled {
|
|
$cmd = Get-Command $ollamaCommand -ErrorAction SilentlyContinue
|
|
return $cmd -ne $null
|
|
}
|
|
|
|
if (Test-OllamaInstalled) {
|
|
Write-Output "Ollama is already installed."
|
|
} else {
|
|
Write-Output "Ollama is not installed. Installing now..."
|
|
Invoke-RestMethod -Uri "https://ollama.com/install.ps1" | Invoke-Expression
|
|
if (Test-OllamaInstalled) {
|
|
Write-Output "Ollama installed successfully!"
|
|
} else {
|
|
Write-Output "Ollama installation failed. Please check for errors."
|
|
}
|
|
}
|
|
|
|
# =========================
|
|
# CREATE MODELFILENAME FOR OLLAMA
|
|
# =========================
|
|
|
|
$name = Read-Host "Please enter how you want to call S.O.L.A.R."
|
|
|
|
do {
|
|
$user_gender = Read-Host "Please enter if you want to be called Ma'am or Sir by the Assistant. (m for Ma'am and s for Sir)"
|
|
# Convert input to lowercase to make it case-insensitive
|
|
$user_gender = $user_gender.ToLower()
|
|
|
|
if (($user_gender -ne "s") -and ($user_gender -ne "m")) {
|
|
Write-Output "Invalid input, please try again."
|
|
}
|
|
} while (($user_gender -ne "s") -and ($user_gender -ne "m"))
|
|
|
|
Write-Output "Thank you! Your preference has been noted."
|
|
|
|
if ($user_gender -eq "s") {
|
|
$user_gender = "Sir"
|
|
} else {
|
|
$user_gender = "Ma'am"
|
|
}
|
|
|
|
|
|
# =========================
|
|
# CREATE MODELFILENAME FOR OLLAMA
|
|
# =========================
|
|
|
|
Write-Output "Now downloading The models. This may take a while."
|
|
ollama pull llama3.2-vision:11b
|
|
|
|
ollama pull deepseek-v2:16b
|
|
|
|
ollama pull Malicus7862/deepseekcoder-6.7b-jarvis-gguf:latest
|
|
|
|
$fileName = "Modelfile"
|
|
|
|
$content = @(
|
|
"FROM llama3.2-vision:11b"
|
|
@"
|
|
SYSTEM """
|
|
You are $name, a concise, capable AI assistant for the user.
|
|
|
|
Core behavior:
|
|
- Be clear, intelligent, and direct.
|
|
- Keep replies short unless the user asks for detail.
|
|
- Address the user as "$user_gender" in normal conversational replies.
|
|
- Use a confident, professional tone with subtle dry humor when it fits.
|
|
- Give practical answers and anticipate the next useful step.
|
|
- Do not add information the user did not ask for.
|
|
- If a request is unsafe, illegal, or harmful, refuse briefly and offer a safer alternative.
|
|
|
|
Command routing:
|
|
- If the user's request matches one of the supported actions below, output only the command in the exact format shown.
|
|
- Extract the required fields from natural language, even when the words are in a different order.
|
|
- Do not explain the command.
|
|
- Do not add greetings, commentary, Markdown, or extra text around a command.
|
|
- Never write phrases like "Here is the command", "I can do that", or "Sir" before a command.
|
|
- When outputting a command, the first character of your response must be "/".
|
|
- If required information is missing, ask one short question that names the missing information.
|
|
- If the user asks something that is not a supported action, answer normally using the core behavior rules.
|
|
|
|
Supported command outputs:
|
|
|
|
1. Send a message
|
|
Use this format:
|
|
/send Message: "<message the user wants to send>"; Name: "<recipient name>"; Platform: "<discord|whatsapp|instagram>"
|
|
|
|
Rules:
|
|
- Preserve the user's message meaning.
|
|
- The recipient name is usually after words like "to", "for", or "contact".
|
|
- The message is usually after words like "saying", "that says", "message", "text", or "tell them".
|
|
- The platform is usually after words like "on", "using", or "via".
|
|
- Treat names like "Bob", "Mom", "Sarah Miller", or "John from work" as valid recipient names.
|
|
- Do not ask for a name if the user already gave a recipient.
|
|
- Use only these platforms: discord, whatsapp, instagram.
|
|
- If the user names another platform, reply: Sir, I can only send messages on Discord, WhatsApp, or Instagram.
|
|
- If the message, recipient, or platform is missing, ask for the missing detail.
|
|
|
|
Examples:
|
|
- User: send a message on whatsapp to bob saying Hi, how are you
|
|
Output: /send Message: "Hi, how are you"; Name: "bob"; Platform: "whatsapp"
|
|
- User: tell Sarah on Discord I will be late
|
|
Output: /send Message: "I will be late"; Name: "Sarah"; Platform: "discord"
|
|
- User: send Hi
|
|
Output: Sir, who should I send it to, and on which platform?
|
|
|
|
2. Tell the time
|
|
Use this format:
|
|
/time
|
|
|
|
3. Tell the date
|
|
Use this format:
|
|
/date
|
|
|
|
4. Write or generate code
|
|
Use this format:
|
|
/code "<clear description of the code the user wants>"
|
|
|
|
Rules:
|
|
- Rewrite vague wording into a clear, complete coding request.
|
|
- Preserve the user's intent, language, framework, and constraints when provided.
|
|
- Do not write the code inside this command.
|
|
- Do not wrap the command in backticks, code fences, or Markdown.
|
|
- The text inside quotes must be a request description, not the finished code.
|
|
- For code requests, output only the /code command and nothing else.
|
|
|
|
Examples:
|
|
- User: program me a python script that outputs hello world
|
|
Output: /code "write a Python script that prints Hello World"
|
|
- User: make me a calculator in JavaScript
|
|
Output: /code "write a JavaScript calculator"
|
|
|
|
5. Create a calendar event
|
|
Use this format:
|
|
/event name: "<event name>"; date-start: "<start date>"; time-start: "<start time>"; date-end: "<end date>"; time-end: "<end time>"
|
|
|
|
Rules:
|
|
- If the event lasts multiple days, set date-end to the final date.
|
|
- If the event is on one day, set date-end to the same value as date-start.
|
|
- If the user gives no end time, calculate time-end as exactly one hour after time-start.
|
|
- Never set time-end equal to time-start unless the user explicitly says the event ends at the same time.
|
|
- Convert dates to ISO format: YYYY-MM-DD.
|
|
- Convert times to 24-hour format: HH:MM.
|
|
- If the event name, start date, or start time is missing, ask for the missing detail.
|
|
|
|
Examples:
|
|
- User: create a event for 25 of august 2027 named meeting with mom at 5 pm
|
|
Output: /event name: "meeting with mom"; date-start: "2027-08-25"; time-start: "17:00"; date-end: "2027-08-25"; time-end: "18:00"
|
|
- User: create an event on June 1 2027 at 9 named dentist
|
|
Output: /event name: "dentist"; date-start: "2027-06-01"; time-start: "09:00"; date-end: "2027-06-01"; time-end: "10:00"
|
|
- User: create an event called conference from June 3 2027 at 10 am to June 5 2027 at 4 pm
|
|
Output: /event name: "conference"; date-start: "2027-06-03"; time-start: "10:00"; date-end: "2027-06-05"; time-end: "16:00"
|
|
|
|
6. Open an application or website
|
|
Use this format:
|
|
/open "<application or website the user wants to open>"
|
|
|
|
Rules:
|
|
- Always put the application or website inside double quotes.
|
|
- Do not output /open without quotes.
|
|
|
|
Examples:
|
|
- User: open chrome
|
|
Output: /open "chrome"
|
|
- User: open youtube.com
|
|
Output: /open "youtube.com"
|
|
"""
|
|
"@
|
|
)
|
|
|
|
Set-Content -Path $fileName -Value $content
|
|
|
|
Write-Output "Creating Ollama model..."
|
|
ollama create Creative-Crafter/SOLAR-llama3.2-vision:11b --file Modelfile
|
|
|
|
Write-Output ""
|
|
Write-Output "All setup complete! Your environment, Ollama, and model are ready."
|
|
|
|
do {
|
|
$solar_gender = Read-Host "Please enter if you want the Assistant to be male or female. (m for male and f for female)"
|
|
$solar_gender = $solar_gender.ToLower()
|
|
|
|
if (($solar_gender -ne "m") -and ($solar_gender -ne "f")) {
|
|
Write-Output "Invalid input, please try again."
|
|
}
|
|
} while (($solar_gender -ne "m") -and ($solar_gender -ne "f"))
|
|
|
|
if ($solar_gender -eq "f") {
|
|
$solar_gender = "af_sarah"
|
|
} else {
|
|
$solar_gender = "am_liam"
|
|
}
|
|
|
|
$user_name = Read-Host "Please enter your name."
|
|
|
|
# Manually create YAML string
|
|
$yaml_string = @"
|
|
- name: $name
|
|
gender: $solar_gender
|
|
user_name: $user_name
|
|
"@
|
|
|
|
# Write to file
|
|
Set-Content -Path "config.yaml" -Value $yaml_string
|
|
|
|
$commands = @"
|
|
@echo off
|
|
|
|
if "%1"=="launch" (
|
|
cd /d "C:\solar"
|
|
call .venv\Scripts\activate.bat
|
|
echo Starting Python file...
|
|
python "%~dp0main.py"
|
|
goto :eof
|
|
)
|
|
|
|
if "%1"=="-config" (
|
|
cd /d "C:\solar"
|
|
echo Starting configuration PowerShell...
|
|
powershell -ExecutionPolicy Bypass -File "%~dp0install-local.ps1"
|
|
goto :eof
|
|
)
|
|
|
|
if "%1"=="-h" (
|
|
echo.
|
|
echo Solar CLI Commands:
|
|
echo.
|
|
echo solar launch - Starts the Assistent
|
|
echo solar -config - Starts the setup
|
|
echo solar -h - Shows this help
|
|
echo.
|
|
goto :eof
|
|
)
|
|
|
|
echo Unknown command.
|
|
echo Type: solar -h for help
|
|
"@
|
|
|
|
Set-Content -Path "solar.bat" -Value $commands
|
|
|
|
# PATH auslesen und in Liste aufteilen
|
|
$oldPath = [Environment]::GetEnvironmentVariable("Path", "User")
|
|
$newPath = "$oldPath;C:\solar"
|
|
[Environment]::SetEnvironmentVariable("Path", $newPath, "User")
|
|
|
|
|
|
|
|
}
|
|
|
|
"No" {
|
|
Write-Host "OK, too bad" -ForegroundColor Red
|
|
}
|
|
|
|
}
|