1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
#!/usr/bin/env python3
"""
run this in a colab cell to stand up main.py + a public wss:// tunnel to it.
session is ephemeral — restart the notebook, get a new url, re-paste it
into your bot.py-side files/config/connection.txt (or rerun setup_wizard.py).
"""
import os
import re
import secrets
import subprocess
import time
from pathlib import Path
SCRIPT_DIR = Path(__file__).resolve().parent
CONFIG_DIR = SCRIPT_DIR / "config"
def model_from_main(name):
# read the model names straight out of main.py so they can't drift apart
text = (SCRIPT_DIR / "main.py").read_text(encoding="utf-8")
return re.search(rf'^{name}\s*=\s*["\'](.+?)["\']', text, re.M).group(1)
CHATMODEL = model_from_main("chatmodel")
EMBEDMODEL = model_from_main("embedmodel")
def run(cmd, **kwargs):
print(f"$ {cmd}")
return subprocess.run(cmd, shell=True, check=True, **kwargs)
def install_ollama():
print("\n-- installing ollama --")
run("curl -fsSL https://ollama.com/install.sh | sh")
subprocess.Popen("ollama serve", shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
time.sleep(5) # give the server a sec to come up before we start pulling models
def pull_models():
print("\n-- pulling models (this'll take a while) --")
run(f"ollama pull {CHATMODEL}")
run(f"ollama pull {EMBEDMODEL}")
def install_python_deps():
print("\n-- installing python deps --")
run("pip install -q ollama websockets")
def ensure_auth_token() -> str:
CONFIG_DIR.mkdir(parents=True, exist_ok=True)
token_file = CONFIG_DIR / "auth_token.txt"
if token_file.exists():
token = token_file.read_text(encoding="utf-8").strip()
print(f"\nusing existing auth token from {token_file}")
else:
token = secrets.token_urlsafe(32)
token_file.write_text(f"{token}\n", encoding="utf-8")
print(f"\ngenerated new auth token, wrote {token_file}")
return token
def ensure_params():
# main.py is stateless — system_prompt comes over the wire in every payload from bot.py.
# params.json is the one thing it actually reads off its own disk (ollama.chat options
# aren't sent in the payload), so that's the only file that has to exist here.
params_file = CONFIG_DIR / "params.json"
if not params_file.exists():
raise SystemExit(f"missing params.json in {CONFIG_DIR} — upload it before running this")
def start_main():
print("\n-- starting main.py --")
# same deal as the tunnel below, main.py prints a lot and raises BrokenPipe once this cell's stdout is gone
log_file = open(SCRIPT_DIR / "main.log", "w")
return subprocess.Popen(
f"python3 {SCRIPT_DIR / 'main.py'}",
shell=True,
stdout=log_file,
stderr=subprocess.STDOUT,
)
def start_tunnel() -> str:
print("\n-- installing cloudflared --")
run("curl -fsSL -o cloudflared.deb https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb")
run("dpkg -i cloudflared.deb")
print("\n-- opening tunnel to localhost:8765 --")
# logging to a real file instead of a PIPE — a pipe's read end lives in this python
# process, so once this script exits the pipe's reader disappears and cloudflared
# gets SIGPIPE on its next log write and dies. a file has no reader to lose.
log_path = SCRIPT_DIR / "cloudflared.log"
log_file = open(log_path, "w")
subprocess.Popen(
"cloudflared tunnel --url http://localhost:8765",
shell=True,
stdout=log_file,
stderr=subprocess.STDOUT,
)
url = None
deadline = time.time() + 30
while time.time() < deadline:
text = log_path.read_text(encoding="utf-8", errors="ignore")
match = re.search(r"https://[a-zA-Z0-9\-]+\.trycloudflare\.com", text)
if match:
url = match.group(0)
break
time.sleep(1)
if not url:
raise SystemExit(f"couldn't find the tunnel url, check {log_path}")
return url.replace("https://", "wss://")
def main():
install_ollama()
pull_models()
install_python_deps()
ensure_params()
token = ensure_auth_token()
start_main()
time.sleep(3) # let main.py bind its port before the tunnel tries to reach it
wss_url = start_tunnel()
print("\n" + "=" * 60)
print("paste these into setup_wizard.py on the bot.py side:")
print(f" address: {wss_url}")
print(f" token: {token}")
print("=" * 60)
if __name__ == "__main__":
main()
|