Enable llama.cpp builds, release management and reference model auto-fit

This commit is contained in:
Mikei386
2026-09-28 16:45:24 +02:00
parent 5fb732469a
commit ba524b0a70
13 changed files with 411 additions and 20 deletions
+21 -2
View File
@@ -7,6 +7,7 @@ import secrets
from http.cookies import SimpleCookie, CookieError
from auth import CredentialStore, verify_password
from catalog import Catalog
from runtime import Runtime
from urllib.parse import urlsplit, parse_qs
from network.client import NetworkClient
from network.config import parse_config, ConfigError
@@ -97,6 +98,7 @@ class Server(ThreadingHTTPServer):
def __init__(self, port, state_dir=None):
super().__init__((os.environ.get('DECK_BIND_HOST','127.0.0.1'), port), Handler)
self.catalog = Catalog(Path(state_dir or os.environ.get("DECK_STATE_DIR", ROOT/".state"))/"models")
self.runtime = Runtime(Path(state_dir or os.environ.get("DECK_STATE_DIR", ROOT/".state"))/"runtime")
self.demo = DemoService()
self.hardware = HardwareProvider()
self.started = time.time()
@@ -260,14 +262,19 @@ class Handler(BaseHTTPRequestHandler):
return self.respond({'error':'Anmeldung erforderlich.'},401)
if not self.authenticated() and self.path == '/':
return self.respond((ROOT/'login.html').read_bytes(), mime='text/html; charset=utf-8')
routes = {'/': ('index.html', 'text/html; charset=utf-8'), '/app.js': ('app.js', 'text/javascript'), '/style.css': ('style.css', 'text/css'), '/network-ui.js': ('network-ui.js', 'text/javascript'), '/access-ui.js': ('access-ui.js', 'text/javascript'), '/studio.js': ('studio.js', 'text/javascript'), '/catalog-ui.js': ('catalog-ui.js','text/javascript')}
routes = {'/': ('index.html', 'text/html; charset=utf-8'), '/app.js': ('app.js', 'text/javascript'), '/style.css': ('style.css', 'text/css'), '/network-ui.js': ('network-ui.js', 'text/javascript'), '/access-ui.js': ('access-ui.js', 'text/javascript'), '/studio.js': ('studio.js', 'text/javascript'), '/catalog-ui.js': ('catalog-ui.js','text/javascript'), '/runtime-ui.js': ('runtime-ui.js','text/javascript')}
if self.path in routes:
name, mime = routes[self.path]
return self.respond((ROOT/name).read_bytes(), mime=mime)
if self.path == '/api/v1/status':
return self.respond(dict(name='Athena Deck', version='0.5.0', state='ready', uptime_seconds=round(time.time()-self.server.started), mode='isolated', location=os.environ.get('DECK_LOCATION', 'Athena · Debian-Server'), demo=self.server.demo.status()))
return self.respond(dict(name='Athena Deck', version='0.6.0', state='ready', uptime_seconds=round(time.time()-self.server.started), mode='isolated', location=os.environ.get('DECK_LOCATION', 'Athena · Debian-Server'), demo=self.server.demo.status()))
if self.path == '/api/v1/hardware':
return self.respond(self.server.hardware.snapshot())
if self.path.startswith('/api/v1/runtime'):
actions={'/api/v1/runtime':self.server.runtime.status,'/api/v1/runtime/prerequisites':self.server.runtime.prerequisites,'/api/v1/runtime/releases':self.server.runtime.releases,'/api/v1/runtime/log':self.server.runtime.log,'/api/v1/runtime/references':self.server.runtime.references}
if self.path in actions:
try:return self.respond(actions[self.path]())
except Exception:return self.respond({'error':'Laufzeitabfrage fehlgeschlagen; Verbindung oder Werkzeuge prüfen.'},503)
if self.path.startswith('/api/v1/catalog'):
try:
path=urlsplit(self.path);q=parse_qs(path.query)
@@ -311,6 +318,17 @@ class Handler(BaseHTTPRequestHandler):
with self.server.auth_lock:
self.server.sessions.pop(self.session_token(),None)
return self.respond({'logged_out':True})
if self.path.startswith('/api/v1/runtime/'):
try:
data=self.read_json();action=self.path.rsplit('/',1)[1]
if action=='build' and set(data)=={'revision','backend','jobs'}:return self.respond(self.server.runtime.start(**data))
if action=='fit' and set(data)=={'profile','context','slots'}:return self.respond(self.server.runtime.fit(**data))
if action=='cancel' and not data:return self.respond(self.server.runtime.stop())
if action=='activate' and set(data)=={'build_id'}:return self.respond(self.server.runtime.activate(**data))
if action=='rollback' and not data:return self.respond(self.server.runtime.rollback())
raise ValueError('Ungültige Laufzeitaktion.')
except ValueError as exc:return self.respond({'error':str(exc)},400)
except (OSError, subprocess.SubprocessError):return self.respond({'error':'Laufzeitaktion fehlgeschlagen; Speicher und Werkzeuge prüfen.'},503)
if self.path in ('/api/v1/catalog/download','/api/v1/catalog/cancel'):
try:
data=self.read_json()
@@ -359,6 +377,7 @@ def main():
try:
server.serve_forever()
finally:
server.runtime.stop()
server.catalog.stop()
server.demo.stop()
server.server_close()