Add Deck dashboard with Athena telemetry history
This commit is contained in:
+2
-2
@@ -14,8 +14,8 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-ins
|
||||
WORKDIR /app
|
||||
COPY deploy/image-requirements.lock /app/deploy/image-requirements.lock
|
||||
COPY deploy/tts-requirements.lock /app/deploy/tts-requirements.lock
|
||||
COPY audio_policy.py prompt_enhancer.py prompt_enhancer_worker.py api_compat.py stt.py execution_setup.py tts_runtime.py tts_test.py tts_worker.py auto_test.py chat_test.py endpoint.py inference.py docker_support.py image_encoder_node.py image_runtime.py image_test.py image_upload.py profiles.py capacity.py server.py runtime.py video.py video_proxy.py catalog.py hub_auth.py auth.py collect_hardware.py /app/
|
||||
COPY video-ui.js stt-ui.js tts-ui.js auto-test-ui.js chat-test-ui.js endpoint-ui.js docker-ui.js image-test-ui.js profiles-ui.js index.html app.js studio.js runtime-ui.js catalog-ui.js style.css login.html login.js access-ui.js network-ui.js /app/
|
||||
COPY audio_policy.py prompt_enhancer.py prompt_enhancer_worker.py api_compat.py stt.py execution_setup.py tts_runtime.py tts_test.py tts_worker.py auto_test.py chat_test.py endpoint.py inference.py docker_support.py image_encoder_node.py image_runtime.py image_test.py image_upload.py profiles.py capacity.py server.py runtime.py video.py video_proxy.py catalog.py hub_auth.py auth.py collect_hardware.py dashboard_data.py dashboard_history.py /app/
|
||||
COPY video-ui.js stt-ui.js tts-ui.js auto-test-ui.js chat-test-ui.js endpoint-ui.js docker-ui.js image-test-ui.js profiles-ui.js dashboard-ui.js index.html app.js studio.js runtime-ui.js catalog-ui.js style.css dashboard.css login.html login.js access-ui.js network-ui.js /app/
|
||||
COPY network/__init__.py network/client.py network/config.py network/rpc.py /app/network/
|
||||
ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1 HOME=/tmp \
|
||||
DECK_BIND_HOST=0.0.0.0 DECK_STATE_DIR=/var/lib/deck \
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Copy old Athena dashboard telemetry once, without reading chats or logs.
|
||||
|
||||
Run before the first Deck dashboard start. SQLite's backup API safely includes
|
||||
the source WAL while the old dashboard is still collecting samples.
|
||||
"""
|
||||
import argparse
|
||||
import os
|
||||
import sqlite3
|
||||
from pathlib import Path
|
||||
|
||||
REQUIRED = {'meta','samples_raw','samples_hourly','slot_samples_raw',
|
||||
'slot_samples_hourly','token_totals','token_hourly','model_events'}
|
||||
|
||||
|
||||
def import_history(source, target):
|
||||
source=Path(source)
|
||||
target=Path(target)
|
||||
if not source.is_file() or target.exists():
|
||||
raise ValueError('Quelldatenbank fehlt oder Deck-Ziel existiert bereits; nichts überschrieben.')
|
||||
target.parent.mkdir(parents=True,exist_ok=True)
|
||||
old=sqlite3.connect('file:'+str(source)+'?mode=ro',uri=True)
|
||||
try:
|
||||
tables={row[0] for row in old.execute("SELECT name FROM sqlite_master WHERE type='table'")}
|
||||
if not REQUIRED<=tables:raise ValueError('Unbekanntes Dashboard-History-Schema.')
|
||||
new=sqlite3.connect(target)
|
||||
try:
|
||||
old.backup(new)
|
||||
if new.execute('PRAGMA integrity_check').fetchone()[0]!='ok':
|
||||
raise ValueError('Kopierte Datenbank ist beschädigt.')
|
||||
counts={table:new.execute('SELECT COUNT(*) FROM '+table).fetchone()[0]
|
||||
for table in ('samples_raw','slot_samples_raw','token_hourly','model_events')}
|
||||
except Exception:
|
||||
new.close()
|
||||
target.unlink(missing_ok=True)
|
||||
raise
|
||||
finally:
|
||||
if new: new.close()
|
||||
target.chmod(0o600)
|
||||
if os.geteuid()==0:
|
||||
owner=target.parent.stat()
|
||||
os.chown(target,owner.st_uid,owner.st_gid)
|
||||
return counts
|
||||
finally:
|
||||
old.close()
|
||||
|
||||
|
||||
if __name__=='__main__':
|
||||
parser=argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('source',type=Path)
|
||||
parser.add_argument('target',type=Path)
|
||||
args=parser.parse_args()
|
||||
print(import_history(args.source,args.target))
|
||||
+6
-2
@@ -14,7 +14,7 @@ import urllib.request
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
LABEL = 'de.casaderoll.athena-deck.standalone'
|
||||
FILES = ['prompt_enhancer.py','prompt_enhancer_worker.py','image_upload.py','audio_policy.py','deploy/tts-requirements.lock','stt.py','stt-ui.js','api_compat.py','execution_setup.py','tts_runtime.py','tts_test.py','tts_worker.py','tts-ui.js','auto_test.py','auto-test-ui.js','chat_test.py','chat-test-ui.js','endpoint.py','inference.py','endpoint-ui.js','docker_support.py','docker-ui.js','deploy/docker_helper.py','deploy/setup_docker_helper.py','image_encoder_node.py','image_runtime.py','image_test.py','image-test-ui.js','profiles.py','profiles-ui.js','capacity.py','runtime.py','runtime-ui.js','video.py','video_proxy.py','video-ui.js','catalog.py','hub_auth.py','catalog-ui.js','server.py','auth.py','collect_hardware.py','index.html','app.js','studio.js','style.css','login.html','login.js','access-ui.js','network-ui.js','network/__init__.py','network/client.py','network/config.py','network/rpc.py','deploy/Dockerfile','deploy/image-requirements.lock']
|
||||
FILES = ['prompt_enhancer.py','prompt_enhancer_worker.py','image_upload.py','audio_policy.py','deploy/tts-requirements.lock','stt.py','stt-ui.js','api_compat.py','execution_setup.py','tts_runtime.py','tts_test.py','tts_worker.py','tts-ui.js','auto_test.py','auto-test-ui.js','chat_test.py','chat-test-ui.js','endpoint.py','inference.py','endpoint-ui.js','docker_support.py','docker-ui.js','deploy/docker_helper.py','deploy/setup_docker_helper.py','image_encoder_node.py','image_runtime.py','image_test.py','image-test-ui.js','profiles.py','profiles-ui.js','capacity.py','runtime.py','runtime-ui.js','video.py','video_proxy.py','video-ui.js','catalog.py','hub_auth.py','catalog-ui.js','server.py','auth.py','collect_hardware.py','dashboard_data.py','dashboard_history.py','dashboard-ui.js','dashboard.css','deploy/import_dashboard_history.py','index.html','app.js','studio.js','style.css','login.html','login.js','access-ui.js','network-ui.js','network/__init__.py','network/client.py','network/config.py','network/rpc.py','deploy/Dockerfile','deploy/image-requirements.lock']
|
||||
|
||||
|
||||
def run(*args, check=True, interactive=False):
|
||||
@@ -94,7 +94,7 @@ def launch(config):
|
||||
args=['docker','run','-d','--name',config['name'],'--label',LABEL+'='+str(base),
|
||||
'--restart','unless-stopped','--read-only','--cap-drop','ALL','--security-opt','no-new-privileges:true',
|
||||
'--pids-limit','256' if config.get('image_runtime') else '128','--memory','32g' if config.get('image_runtime') else '8g','--cpus','2', '--tmpfs','/tmp:rw,nosuid,nodev,size=256m',
|
||||
'-v',str(base/'state')+':/var/lib/deck:rw','-e','DECK_ALLOWED_HOSTS=127.0.0.1:'+str(config['port'])+',localhost:'+str(config['port']),
|
||||
'-v',str(base/'state')+':/var/lib/deck:rw','--mount','type=bind,src=/proc,dst=/host/proc,readonly','-e','DECK_HOST_PROC=/host/proc','-e','DECK_ALLOWED_HOSTS=127.0.0.1:'+str(config['port'])+',localhost:'+str(config['port']),
|
||||
'-p','127.0.0.1:'+str(config['port'])+':8108',
|
||||
'--health-cmd', 'python3 -c "import urllib.request,json; assert json.load(urllib.request.urlopen(\'http://127.0.0.1:8108/api/v1/auth/status\',timeout=3))[\'initialized\']"',
|
||||
'--health-interval','30s','--health-timeout','5s','--health-retries','3']
|
||||
@@ -109,6 +109,10 @@ def launch(config):
|
||||
args += ['--mount','type=bind,src=/run/athena-deck-docker,dst=/run/athena-deck-docker,readonly','-e','DECK_DOCKER_HELPER_SOCKET=/run/athena-deck-docker/control.sock']
|
||||
if config['gpu_telemetry']:
|
||||
args += ['--gpus','all','-e','NVIDIA_DRIVER_CAPABILITIES=compute,utility']
|
||||
if Path('/data/models').is_dir():
|
||||
args+=['--mount','type=bind,src=/data/models,dst=/host/models,readonly','-e','DECK_HOST_DATA_DISK=/host/models']
|
||||
if Path('/data/emergency-backups').is_dir():
|
||||
args+=['--mount','type=bind,src=/data/emergency-backups,dst=/host/backups,readonly']
|
||||
if config.get('reference_models'):
|
||||
for folder,filename in [('qwen3.8-27b-iq4-mix','Qwen3.8-27B-IQ4-MIX.gguf'),('qwen3.8-27b-iq4-xs-pure','qwen3.8-27b-IQ4_XS-pure.gguf'),('qwen3.8-27b-abliterated','Qwen3.8-27B-ABLITERATED-Q4_K_M.gguf')]:
|
||||
source=Path('/data/models')/folder/filename
|
||||
|
||||
Reference in New Issue
Block a user