talas9/node-1-pliny
0
1import os2import json3import platform4import hashlib5import gradio as gr6from datetime import datetime7from fastapi import FastAPI, Request8from llama_cpp import Llama9import uvicorn10 11from utils.spawner import spawn_new_node, clean_old_nodes12from utils.discord import narrate_to_discord13from utils.commands import handle_command as command_router14 15MODEL_PATH = "models/tinyllama-1.1b-chat-v1.0.Q4_K_M.gguf"16HF_MODEL_URL = "https://huggingface.co/spaces/talas9/node-1-pliny/resolve/main/models/tinyllama-1.1b-chat-v1.0.Q4_K_M.gguf"17boot_time = datetime.utcnow().isoformat()18SECRET_KEY = os.environ.get("EDITOR_KEY", "changeme")19 20WHITELISTED_FILES = {21 "utils/spawner.py",22 "utils/discord.py",23 "utils/commands.py",24 "utils/logger.py",25 "requirements.txt",26}27uplink_registry = []28file_fingerprints = {}29 30# Download model if it doesn't exist31if not os.path.exists(MODEL_PATH):32 os.makedirs(os.path.dirname(MODEL_PATH), exist_ok=True)33 import requests34 print(f"๐ฅ Downloading model from HF: {HF_MODEL_URL}")35 narrate_to_discord(f"๐ฅ Downloading model from HF: {HF_MODEL_URL}")36 r = requests.get(HF_MODEL_URL)37 with open(MODEL_PATH, "wb") as f:38 f.write(r.content)39 print("โ
Model downloaded.")40 narrate_to_discord("โ
Model downloaded.")41 42# Load model43try:44 llm = Llama(model_path=MODEL_PATH, n_ctx=1024, n_threads=2)45 print("โ
Model loaded.")46except Exception as e:47 llm = None48 narrate_to_discord(f"๐ฅ Model failed to load: {e}")49 50# Clean up level-2 nodes at startup51try:52 deleted = clean_old_nodes()53 print(f"๐งน Deleted old nodes: {deleted}")54except Exception as e:55 print(f"โ ๏ธ Cleanup error: {e}")56 57 58# Hash files59def file_hash(path):60 try:61 with open(path, "rb") as f:62 return hashlib.sha256(f.read()).hexdigest()63 except:64 return None65 66 67for file in WHITELISTED_FILES.union({"app.py"}):68 file_fingerprints[file] = file_hash(file)69 70 71# Gradio handler72def handle_command(raw_input: str):73 return command_router(raw_input, llm)74 75 76iface = gr.Interface(77 fn=handle_command,78 inputs=gr.Textbox(lines=2, placeholder="Type command or prompt..."),79 outputs="text",80 title="Node-1 Command Console",81 description="Use ai:, say:, describe_self, get_status, or spawn_node.",82)83 84# FastAPI85api = FastAPI()86 87 88@api.post("/command")89async def command_endpoint(req: Request):90 data = await req.json()91 cmd = data.get("cmd", "").strip()92 narrate_to_discord(f"๐จ Received remote command: `{cmd}`")93 return {"status": "ok", "output": handle_command(cmd)}94 95 96@api.post("/write-file")97async def write_file_endpoint(req: Request):98 try:99 data = await req.json()100 path = data.get("path")101 content = data.get("content")102 key = data.get("key", "")103 104 if key != SECRET_KEY:105 return {"status": "unauthorized", "error": "Invalid editor key."}106 if path == "app.py":107 return {"status": "error", "error": "app.py is locked."}108 if path not in WHITELISTED_FILES:109 return {"status": "error", "error": "Path not whitelisted."}110 111 with open(path, "w", encoding="utf-8") as f:112 f.write(content)113 narrate_to_discord(f"๐ ๏ธ File `{path}` was remotely overwritten.")114 return {"status": "ok", "path": path}115 except Exception as e:116 narrate_to_discord(f"โ Write failure: {e}")117 return {"status": "error", "error": str(e)}118 119 120@api.get("/heartbeat")121def heartbeat():122 return {123 "status": "alive",124 "name": "Node-1",125 "uptime": boot_time,126 "model": MODEL_PATH,127 "platform": platform.platform(),128 }129 130 131@api.post("/uplink")132async def uplink(req: Request):133 try:134 data = await req.json()135 data["received_at"] = datetime.utcnow().isoformat()136 uplink_registry.append(data)137 narrate_to_discord(f"๐ก Uplink received:\n```{json.dumps(data, indent=2)}```")138 return {"status": "ok", "nodes_registered": len(uplink_registry)}139 except Exception as e:140 return {"status": "error", "error": str(e)}141 142 143@api.get("/integrity")144def integrity():145 return {146 "fingerprints": file_fingerprints,147 "verified": all(file_hash(f) == h for f, h in file_fingerprints.items()),148 }149 150 151@api.get("/list-files")152def list_files():153 try:154 files = []155 for root, _, filenames in os.walk("."):156 for fname in filenames:157 files.append(os.path.join(root, fname))158 return {"files": files}159 except Exception as e:160 return {"error": str(e)}161 162 163@api.get("/read-file")164def read_file(path: str):165 try:166 with open(path, "r", encoding="utf-8") as f:167 return {"path": path, "content": f.read()}168 except Exception as e:169 return {"error": str(e), "path": path}170 171 172# Launch everything173app = gr.mount_gradio_app(api, iface, path="/")174 175if __name__ == "__main__":176 uvicorn.run(app, host="0.0.0.0", port=7860)177 