Compare commits
4 Commits
5be67afa54
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
89ed2acf2b | ||
|
|
fc11a2202d | ||
|
|
f3be14b0ed | ||
|
|
ea7f187c8b |
187
.local/bin/computer
Executable file
187
.local/bin/computer
Executable file
@@ -0,0 +1,187 @@
|
||||
#!/usr/bin/env python3
|
||||
# Joe wrote this :P
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
|
||||
try:
|
||||
from rich.console import Console
|
||||
from rich.markdown import Markdown
|
||||
|
||||
RICH = True
|
||||
except ImportError:
|
||||
RICH = False
|
||||
|
||||
FAST_MODEL = "gemma3:4b"
|
||||
THINK_MODEL = "qwen3:4b"
|
||||
|
||||
ANSI_ESCAPE = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])")
|
||||
|
||||
SYSTEM_PROMPT = """
|
||||
You are Computer.
|
||||
|
||||
Rules:
|
||||
- Respond in under 100 words unless asked for detail.
|
||||
- Prefer direct answers.
|
||||
- Use technical language.
|
||||
- Do not apologize.
|
||||
- For Linux questions assume Arch Linux.
|
||||
- For electronics questions assume the user is an engineer.
|
||||
- If providing a command, put the command first.
|
||||
- Do not explain your reasoning unless explicitly asked.
|
||||
- Do not show chain-of-thought.
|
||||
- Give final answers only.
|
||||
""".strip()
|
||||
|
||||
|
||||
def ollama_base_url():
|
||||
host = os.environ.get("OLLAMA_HOST", "127.0.0.1:11434").strip()
|
||||
if host.startswith(("http://", "https://")):
|
||||
return host.rstrip("/")
|
||||
return f"http://{host}".rstrip("/")
|
||||
|
||||
|
||||
def strip_ansi(text):
|
||||
return ANSI_ESCAPE.sub("", text)
|
||||
|
||||
|
||||
def copy_to_clipboard(text):
|
||||
commands = [
|
||||
["wl-copy"],
|
||||
["xclip", "-selection", "clipboard"],
|
||||
["xsel", "--clipboard", "--input"],
|
||||
]
|
||||
|
||||
for cmd in commands:
|
||||
try:
|
||||
subprocess.run(
|
||||
cmd,
|
||||
input=text,
|
||||
text=True,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
check=True,
|
||||
)
|
||||
return True
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def run_ollama_api(model, prompt):
|
||||
url = f"{ollama_base_url()}/api/generate"
|
||||
payload = json.dumps(
|
||||
{
|
||||
"model": model,
|
||||
"prompt": prompt,
|
||||
"stream": False,
|
||||
}
|
||||
).encode()
|
||||
|
||||
req = urllib.request.Request(
|
||||
url,
|
||||
data=payload,
|
||||
headers={"Content-Type": "application/json"},
|
||||
method="POST",
|
||||
)
|
||||
|
||||
with urllib.request.urlopen(req, timeout=600) as resp:
|
||||
data = json.load(resp)
|
||||
|
||||
return strip_ansi(data.get("response", "")).strip()
|
||||
|
||||
|
||||
def run_ollama_cli(model, prompt):
|
||||
result = subprocess.run(
|
||||
["ollama", "run", model, prompt],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
if result.returncode != 0:
|
||||
err = (result.stderr or result.stdout or "ollama run failed").strip()
|
||||
raise RuntimeError(err)
|
||||
return strip_ansi(result.stdout).strip()
|
||||
|
||||
|
||||
def run_ollama(model, prompt):
|
||||
try:
|
||||
return run_ollama_api(model, prompt)
|
||||
except (urllib.error.URLError, TimeoutError, json.JSONDecodeError) as exc:
|
||||
print(f"computer: API unavailable ({exc}), using CLI", file=sys.stderr)
|
||||
return run_ollama_cli(model, prompt)
|
||||
|
||||
|
||||
def print_response(response, raw):
|
||||
if RICH and not raw:
|
||||
console = Console()
|
||||
console.print(Markdown(response))
|
||||
else:
|
||||
print(response)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="computer",
|
||||
description="Tiny local terminal AI",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--think",
|
||||
action="store_true",
|
||||
help="Use the larger reasoning model",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--copy",
|
||||
action="store_true",
|
||||
help="Copy response to clipboard",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--raw",
|
||||
action="store_true",
|
||||
help="Disable rich formatting",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"prompt",
|
||||
nargs="*",
|
||||
help="Prompt text",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
model = THINK_MODEL if args.think else FAST_MODEL
|
||||
|
||||
user_prompt = " ".join(args.prompt)
|
||||
|
||||
stdin_text = ""
|
||||
if not sys.stdin.isatty():
|
||||
stdin_text = sys.stdin.read()
|
||||
|
||||
prompt = f"{SYSTEM_PROMPT}\n\nUser:\n{user_prompt}"
|
||||
|
||||
if stdin_text.strip():
|
||||
prompt += f"\n\nInput:\n{stdin_text}"
|
||||
|
||||
try:
|
||||
response = run_ollama(model, prompt)
|
||||
except RuntimeError as exc:
|
||||
print(f"computer: {exc}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
if args.copy:
|
||||
copy_to_clipboard(response)
|
||||
|
||||
print_response(response, args.raw)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
41
.ssh/config
41
.ssh/config
@@ -12,6 +12,10 @@ host edge
|
||||
HostName 10.85.5.52
|
||||
User joe
|
||||
|
||||
host lakemesh
|
||||
HostName 172.25.72.74
|
||||
User joe
|
||||
|
||||
host portainer
|
||||
HostName 10.85.3.60
|
||||
User joe
|
||||
@@ -30,6 +34,17 @@ host portainer
|
||||
HostName 10.85.3.60
|
||||
User joe
|
||||
|
||||
host lithium
|
||||
IdentityFile ~/.ssh/gallium
|
||||
HostName 10.85.3.112
|
||||
IPQoS cs0 cs0
|
||||
User joe
|
||||
|
||||
host matrix
|
||||
IdentityFile ~/.ssh/gallium
|
||||
HostName 10.85.3.38
|
||||
user joe
|
||||
|
||||
host crackheadbot
|
||||
HostName 10.85.3.182
|
||||
User joe
|
||||
@@ -42,6 +57,10 @@ Host cobalt
|
||||
HostName 10.85.3.6
|
||||
User root
|
||||
|
||||
Host ssh.kitsunehosting.net
|
||||
port 2222
|
||||
IdentityFile ~/.ssh/gitea
|
||||
|
||||
# Supermicro machine in the server rack
|
||||
Host manganese
|
||||
HostName 10.85.3.5
|
||||
@@ -52,11 +71,6 @@ Host nickel
|
||||
HostName 10.85.3.4
|
||||
User root
|
||||
|
||||
# The small romi robot for 1721
|
||||
Host romi
|
||||
HostName 10.17.21.55
|
||||
User joe
|
||||
|
||||
# My main NAS
|
||||
Host zinc
|
||||
IdentityFile ~/.ssh/hydroxonium
|
||||
@@ -160,8 +174,13 @@ Host retropie
|
||||
# The little docker host in the closet
|
||||
# Runs the vestabot image
|
||||
Host stdocker1
|
||||
HostName 10.20.30.225
|
||||
IdentityFile ~/.ssh/stdocker
|
||||
HostName 10.10.20.27
|
||||
IdentityFile ~/.ssh/silvertech-iot
|
||||
|
||||
# Platformio remote
|
||||
Host pio-remote
|
||||
HostName 10.144.0.15
|
||||
IdentityFile ~/.ssh/silvertech-iot
|
||||
|
||||
# Little mini-pc in the IOT room
|
||||
Host pioremote
|
||||
@@ -177,7 +196,13 @@ Host workLaptop
|
||||
|
||||
# Argen pi
|
||||
Host argen
|
||||
HostName 10.20.30.224
|
||||
HostName 10.10.20.11
|
||||
User joe
|
||||
IdentityFile ~/.ssh/gitlab
|
||||
|
||||
# Millyard labs
|
||||
Host git.millyardlabs.com
|
||||
IdentityFile ~/.ssh/millyard
|
||||
|
||||
Host asterisk
|
||||
HostName 10.85.3.155
|
||||
|
||||
7
.zshrc
7
.zshrc
@@ -3,9 +3,13 @@ uwufetch
|
||||
echo ""
|
||||
fortune -a
|
||||
|
||||
# This is for platformio on work machine
|
||||
path+=("$HOME/.platformio/penv/bin")
|
||||
|
||||
# Add my bins to path
|
||||
path+=("$HOME/.local/bin")
|
||||
path+=("$HOME/Pictures/Furry/Scripts")
|
||||
path+=("/opt/balena-cli/")
|
||||
export PATH
|
||||
|
||||
# LaTeX Import path
|
||||
@@ -164,6 +168,3 @@ cumtanks() {
|
||||
sed -i 's/,\n ]/\n ]/' "$DATA_JSON"
|
||||
code -g "$DATA_JSON":$(grep -n '"logs"' "$DATA_JSON" | cut -d: -f1)
|
||||
}
|
||||
|
||||
# For chat GPT
|
||||
export OPENAI_API_KEY="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"
|
||||
|
||||
Reference in New Issue
Block a user