Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
df8d088fac | ||
|
|
b570e9410d | ||
|
|
e9c2599542 | ||
|
|
a8a6ce3b29 | ||
|
|
0944b1d93e | ||
|
|
1c8f285151 |
@@ -96,6 +96,11 @@ HERMES_API_MODEL = os.environ.get("HERMES_API_MODEL", "hermes")
|
||||
# Eigenes Python-3.12-venv (~/.voice/venv), weil Parakeet/Piper nicht ins 3.14-Backend-venv
|
||||
# passen. MC2 proxyt nach außen.
|
||||
VOICE_SERVICE_URL = os.environ.get("MC_VOICE_SERVICE_URL", "http://127.0.0.1:8650").rstrip("/")
|
||||
# --- Lucys Stimme (lucy-stimme.service, pocket-tts german_24l, Klon aus ref.mp3) -----------
|
||||
# Eigener User-Dienst in ~/.lucy-stimme (nur Loopback :8021). Spricht die Telegram-Sprachnachrichten
|
||||
# UND — seit dem Raphael-Umbau der Desktop-Lucy (04.09.2026) — auch den PC: MC2 reicht ihn unter
|
||||
# /api/lucy/stimme/* ins LAN (routers/voice.py). EINE Stimme für alle Türen. :8650 ist NICHT Lucy.
|
||||
LUCY_STIMME_URL = os.environ.get("MC_LUCY_STIMME_URL", "http://127.0.0.1:8021").rstrip("/")
|
||||
# Box-Konsole: ttyd-Web-Terminal (echte Login-Shell). Bindet NUR an Loopback
|
||||
# (127.0.0.1:7682, base-path /console) und wird von MC2 über den ohnehin offenen Port 9001
|
||||
# rückwärts geproxyt (routers/console.py → same-origin /console/). So braucht die Konsole
|
||||
|
||||
@@ -17,7 +17,7 @@ import sys as _sys
|
||||
import time
|
||||
|
||||
import httpx
|
||||
from config import HERMES_API_KEY, HERMES_API_MODEL, HERMES_API_URL, LLAMA_SWAP_URL, VOICE_SERVICE_URL
|
||||
from config import HERMES_API_KEY, HERMES_API_MODEL, HERMES_API_URL, LLAMA_SWAP_URL, LUCY_STIMME_URL, VOICE_SERVICE_URL
|
||||
from fastapi import APIRouter, File, Form, HTTPException, UploadFile
|
||||
from fastapi.responses import Response, StreamingResponse
|
||||
from pydantic import BaseModel
|
||||
@@ -355,3 +355,71 @@ async def voice_chat(body: ChatIn) -> StreamingResponse:
|
||||
_commit() # Turn immer verbuchen (auch bei Fehler/Abbruch)
|
||||
|
||||
return StreamingResponse(gen(), media_type="text/event-stream")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------------------------
|
||||
# Lucys Stimme ins LAN reichen (Raphael-Umbau 04.09.2026). lucy-stimme.service (:8021, pocket-tts
|
||||
# german_24l) bindet nur Loopback; die Desktop-Lucy am PC spricht seit dem Umbau nicht mehr mit
|
||||
# einem eigenen pocket_server, sondern mit DIESEM — dieselbe Stimme wie die Telegram-Sprachnachrichten.
|
||||
# Dünner Proxy, API 1:1 (pocket_server: /health, /tts -> WAV, /tts/stream -> PCM16 + X-Sample-Rate).
|
||||
# LAN-only wie alle MC2-Endpoints.
|
||||
|
||||
class LucyTtsIn(BaseModel):
|
||||
text: str
|
||||
emo: str | None = None # Stimmungs-Profil (pocket_server EMO_PROFILES); Raphael-Lucy setzt keins
|
||||
|
||||
|
||||
@router.get("/lucy/stimme/health")
|
||||
def lucy_stimme_health() -> dict:
|
||||
"""Bereitschaft von Lucys Stimme (pocket_server /health: status ok|loading)."""
|
||||
try:
|
||||
r = httpx.get(f"{LUCY_STIMME_URL}/health", timeout=httpx.Timeout(5.0))
|
||||
r.raise_for_status()
|
||||
return r.json()
|
||||
except Exception as exc:
|
||||
raise HTTPException(502, f"Lucys Stimme (:8021) nicht erreichbar: {exc}")
|
||||
|
||||
|
||||
@router.post("/lucy/stimme/tts")
|
||||
async def lucy_stimme_tts(body: LucyTtsIn) -> Response:
|
||||
"""Text -> WAV (ganzer Text). Warm-up der Desktop-Lucy + Jobs, die eine Datei brauchen."""
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=httpx.Timeout(600.0, connect=5.0)) as client:
|
||||
with Timer("lucy_tts"):
|
||||
r = await client.post(f"{LUCY_STIMME_URL}/tts", json=body.model_dump(exclude_none=True))
|
||||
r.raise_for_status()
|
||||
return Response(content=r.content, media_type=r.headers.get("content-type", "audio/wav"),
|
||||
headers={k: v for k, v in r.headers.items() if k.lower().startswith("x-")})
|
||||
except httpx.HTTPStatusError as exc:
|
||||
raise HTTPException(exc.response.status_code, f"Lucys Stimme: {exc.response.text[:200]}")
|
||||
except httpx.HTTPError as exc:
|
||||
raise HTTPException(502, f"Lucys Stimme nicht erreichbar: {exc}")
|
||||
|
||||
|
||||
@router.post("/lucy/stimme/tts/stream")
|
||||
async def lucy_stimme_tts_stream(body: LucyTtsIn) -> StreamingResponse:
|
||||
"""Text -> rohes PCM16-mono, satzweise gestreamt (Samplerate im Header X-Sample-Rate).
|
||||
Der Live-Pfad der Desktop-Lucy: erstes Audio nach dem ersten Satz. Der Upstream-Stream bleibt
|
||||
offen, solange der Client liest — bricht der Client ab (Barge-in), schließt httpx den Upstream."""
|
||||
client = httpx.AsyncClient(timeout=httpx.Timeout(None, connect=5.0))
|
||||
try:
|
||||
req = client.build_request("POST", f"{LUCY_STIMME_URL}/tts/stream", json=body.model_dump(exclude_none=True))
|
||||
upstream = await client.send(req, stream=True)
|
||||
except httpx.HTTPError as exc:
|
||||
await client.aclose()
|
||||
raise HTTPException(502, f"Lucys Stimme nicht erreichbar: {exc}")
|
||||
if upstream.status_code != 200:
|
||||
detail = (await upstream.aread()).decode("utf-8", "replace")[:200]
|
||||
await upstream.aclose(); await client.aclose()
|
||||
raise HTTPException(upstream.status_code, f"Lucys Stimme: {detail}")
|
||||
|
||||
async def gen():
|
||||
try:
|
||||
async for chunk in upstream.aiter_raw():
|
||||
yield chunk
|
||||
finally:
|
||||
await upstream.aclose()
|
||||
await client.aclose()
|
||||
|
||||
return StreamingResponse(gen(), media_type="application/octet-stream",
|
||||
headers={"X-Sample-Rate": upstream.headers.get("x-sample-rate", "24000")})
|
||||
|
||||
@@ -59,7 +59,13 @@ for t in $(systemctl --user list-timers --no-legend --no-pager 2>/dev/null | awk
|
||||
case "$dienst" in launchpadlib-*) continue ;; esac # Ubuntu-Eigenes, nicht unseres
|
||||
code=$(systemctl --user show -p ExecMainStatus --value "$dienst" 2>/dev/null)
|
||||
wann=$(systemctl --user show -p ExecMainExitTimestamp --value "$dienst" 2>/dev/null | cut -d' ' -f2,3)
|
||||
if [ -z "$wann" ]; then warn "$dienst ist eingerichtet, aber NIE gelaufen"
|
||||
# Nach einem Neustart ist der "letzte Lauf" leer, obwohl nichts kaputt ist —
|
||||
# am 04.09. machte der Radar daraus "hohes Risiko, sofort in Betrieb nehmen".
|
||||
# Junge Box (< 1 Tag) + Timer hat einen naechsten Termin = wartet, kein Befund.
|
||||
naechster=$(systemctl --user show -p NextElapseUSecRealtime --value "${dienst%.service}.timer" 2>/dev/null | cut -d' ' -f2,3)
|
||||
if [ -z "$wann" ] && [ "$(cut -d. -f1 /proc/uptime)" -lt 86400 ] && [ -n "$naechster" ]; then
|
||||
ok "$dienst wartet auf den ersten Lauf seit dem Neustart (naechster: $naechster)"
|
||||
elif [ -z "$wann" ]; then warn "$dienst ist eingerichtet, aber NIE gelaufen"
|
||||
elif [ "${code:-0}" = "0" ]; then ok "$dienst zuletzt $wann"
|
||||
else bad "$dienst zuletzt GESCHEITERT (exit $code) am $wann"; fi
|
||||
done
|
||||
|
||||
@@ -42,6 +42,27 @@ if [ -z "$IST" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Der Blick nach DRAUSSEN (04.09.2026): Releases, PRs, neue Entwurfsmodelle —
|
||||
# als Skript-Fakten, gegen den letzten Lauf verglichen. Ohne das lag DFlash2 fuer
|
||||
# den Coder zwei Wochen ungenutzt auf der Platte. Faellt es aus, bleibt der
|
||||
# Innen-Bericht vollstaendig; das Ausbleiben steht dann selbst als ACHTUNG drin.
|
||||
UPSTREAM_SKRIPT="${UPSTREAM_SKRIPT:-$HIER/stack-upstream.py}"
|
||||
if [ -f "$UPSTREAM_SKRIPT" ]; then
|
||||
UPSTREAM="$(timeout 240 python3 "$UPSTREAM_SKRIPT" 2>&1)" \
|
||||
|| UPSTREAM="UPSTREAM (Watchlist)
|
||||
ACHTUNG Upstream-Pruefung abgebrochen (exit $?) — $UPSTREAM_SKRIPT nachsehen"
|
||||
# Nur Aenderungen ans Modell. Beim ersten Lauf (04.09.) bekam es auch die
|
||||
# "unveraendert"-Zeilen und erfand zu jeder einen "naechsten Schritt" — der
|
||||
# Prompt-Hinweis half nicht. Fakten filtert das Skript, nicht die Prosa.
|
||||
ANZ_QUELLEN="$(printf '%s\n' "$UPSTREAM" | grep -cE '^\s+(OK|ACHTUNG)' || true)"
|
||||
UPSTREAM_NEU="$(printf '%s\n' "$UPSTREAM" | grep -A1 -E '^\s+ACHTUNG' | grep -vE '^--$' || true)"
|
||||
[ -z "$UPSTREAM_NEU" ] && UPSTREAM_NEU=" OK nichts Neues draussen ($ANZ_QUELLEN Quellen geprueft, alle unveraendert)"
|
||||
IST="$IST
|
||||
|
||||
UPSTREAM (was hat sich draussen getan?)
|
||||
$UPSTREAM_NEU"
|
||||
fi
|
||||
|
||||
ROT="$(printf '%s\n' "$IST" | grep -E '^\s+(ROT|ACHTUNG)' || true)"
|
||||
ANZ_ROT="$(printf '%s\n' "$ROT" | grep -c 'ROT' || true)"
|
||||
|
||||
@@ -61,6 +82,9 @@ Regeln:
|
||||
Fuellmaterial wird nicht gelesen.
|
||||
- Was du an den Messwerten selbst merkwuerdig findest, gehoert unter ACHTUNG,
|
||||
nicht unter Verbesserungen.
|
||||
- Zeilen mit NEU im Abschnitt UPSTREAM sind Neuigkeiten von draussen. Nenne
|
||||
jede kurz und gib den Hinweis dahinter (der Pfeil-Satz) als naechsten Schritt
|
||||
wieder. 'erstmals erfasst' und 'unveraendert' sind KEINE Neuigkeiten.
|
||||
- Wenn alles gruen ist, sag das in einem Satz und hoere auf.
|
||||
- Keine Ueberschriften-Deko, keine Emojis, hoechstens 200 Woerter.
|
||||
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
#!/usr/bin/env python3
|
||||
"""stack-upstream.py — der Blick nach draussen, in Fakten (04.09.2026).
|
||||
|
||||
Ergaenzt stack-ist.sh: das prueft, ob die Box STIMMT. Dieses Skript prueft, ob
|
||||
DRAUSSEN etwas passiert ist, das uns betrifft — neue Releases, gemergte PRs,
|
||||
neue Entwurfsmodelle, neue Modelle der Familien, die wir fahren.
|
||||
|
||||
Warum es das braucht: Am 19.08. lagen die DFlash2-Entwuerfe fuer den Coder auf
|
||||
der Platte, am 27.08. konnte llama.cpp sie, und bis zum 04.09. hat es niemand
|
||||
gemerkt — der Coder lief zwei Wochen mit 12,6 statt 31 t/s. Der KISS-Radar sah
|
||||
nur nach innen. Jetzt sieht er auch nach draussen, aber ohne Modell-Fantasie:
|
||||
jede Zeile hier ist ein abgerufener Wert, verglichen mit dem Wert vom letzten Lauf.
|
||||
|
||||
Quelle: deploy/trend-radar-watchlist.json (Eintraege mit `typ`, siehe unten).
|
||||
Zustand: ~/.hermes/state/stack-upstream.json (Wert je Eintrag vom letzten Lauf).
|
||||
Ausgabe: im Format von stack-ist.sh — `OK` / `ACHTUNG NEU:` / `ACHTUNG ... nicht abrufbar`.
|
||||
Beim ERSTEN Lauf wird nur erfasst (OK), nicht gemeldet — sonst waere jeder
|
||||
Eintrag sofort "neu".
|
||||
|
||||
Typen:
|
||||
github_issue repo, nummer → offen/geschlossen
|
||||
github_pr repo, nummer → offen/gemergt/geschlossen
|
||||
github_release repo → juengster Release-Tag
|
||||
github_release_major repo → nur Major-Sprung meldet
|
||||
github_branch repo, branch → juengster Commit (Datum)
|
||||
pypi paket → Version
|
||||
hf_author author → neue Modell-Repos des Autors
|
||||
url_zeilen url, muster, max_zeilen → Zeilen mit Muster, Aenderung = neu
|
||||
|
||||
Kein set -e-Aequivalent: jeder Eintrag wird einzeln behandelt, ein Fehler
|
||||
nimmt die anderen nicht mit.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
from pathlib import Path
|
||||
|
||||
WATCHLIST = Path(sys.argv[1] if len(sys.argv) > 1 else
|
||||
os.path.expanduser("~/mission-control-v2/deploy/trend-radar-watchlist.json"))
|
||||
STATE = Path(os.environ.get("STACK_UPSTREAM_STATE",
|
||||
os.path.expanduser("~/.hermes/state/stack-upstream.json")))
|
||||
TIMEOUT = 20
|
||||
UA = "mc2-stack-upstream/1.0 (+https://github.com/Hitonabi)"
|
||||
|
||||
|
||||
def ok(msg: str) -> None:
|
||||
print(f" OK {msg}")
|
||||
|
||||
|
||||
def neu(msg: str) -> None:
|
||||
print(f" ACHTUNG NEU: {msg}")
|
||||
|
||||
|
||||
def warn(msg: str) -> None:
|
||||
print(f" ACHTUNG {msg}")
|
||||
|
||||
|
||||
def hole(url: str, json_erwartet: bool = True):
|
||||
req = urllib.request.Request(url, headers={"User-Agent": UA, "Accept": "application/json"})
|
||||
tok = os.environ.get("GITHUB_TOKEN")
|
||||
if tok and "api.github.com" in url:
|
||||
req.add_header("Authorization", f"Bearer {tok}")
|
||||
with urllib.request.urlopen(req, timeout=TIMEOUT) as r:
|
||||
roh = r.read().decode("utf-8", "replace")
|
||||
return json.loads(roh) if json_erwartet else roh
|
||||
|
||||
|
||||
# ------------------------------------------------------------- Pruefer ---
|
||||
# Jeder Pruefer liefert (wert, anzeige). `wert` wird mit dem letzten Lauf
|
||||
# verglichen, `anzeige` ist die menschenlesbare Fassung.
|
||||
|
||||
def p_github_issue(e):
|
||||
d = hole(f"https://api.github.com/repos/{e['repo']}/issues/{e['nummer']}")
|
||||
st = "geschlossen" if d.get("state") == "closed" else "offen"
|
||||
return st, f"#{e['nummer']} {e['repo']} ist {st} — {d.get('title', '')[:70]}"
|
||||
|
||||
|
||||
def p_github_pr(e):
|
||||
d = hole(f"https://api.github.com/repos/{e['repo']}/pulls/{e['nummer']}")
|
||||
if d.get("merged_at"):
|
||||
st = f"gemergt am {d['merged_at'][:10]}"
|
||||
elif d.get("state") == "closed":
|
||||
st = "geschlossen ohne Merge"
|
||||
else:
|
||||
st = "offen" + (" (Entwurf)" if d.get("draft") else "")
|
||||
return st, f"PR #{e['nummer']} {e['repo']} {st} — {d.get('title', '')[:70]}"
|
||||
|
||||
|
||||
def _release(e):
|
||||
d = hole(f"https://api.github.com/repos/{e['repo']}/releases/latest")
|
||||
return d.get("tag_name", "?"), (d.get("published_at") or "")[:10]
|
||||
|
||||
|
||||
def p_github_release(e):
|
||||
tag, wann = _release(e)
|
||||
return tag, f"{e['repo']} juengster Release {tag} ({wann})"
|
||||
|
||||
|
||||
def p_github_release_major(e):
|
||||
tag, wann = _release(e)
|
||||
m = re.search(r"(\d+)", tag)
|
||||
major = m.group(1) if m else tag
|
||||
return major, f"{e['repo']} Major {major} (Release {tag}, {wann})"
|
||||
|
||||
|
||||
def p_github_branch(e):
|
||||
d = hole(f"https://api.github.com/repos/{e['repo']}/commits?sha={e['branch']}&per_page=1")
|
||||
c = d[0]
|
||||
wann = c["commit"]["committer"]["date"][:10]
|
||||
return c["sha"][:10], f"{e['repo']}@{e['branch']} letzter Commit {wann} — {c['commit']['message'].splitlines()[0][:60]}"
|
||||
|
||||
|
||||
def p_pypi(e):
|
||||
d = hole(f"https://pypi.org/pypi/{e['paket']}/json")
|
||||
v = d["info"]["version"]
|
||||
return v, f"PyPI {e['paket']} = {v}"
|
||||
|
||||
|
||||
def p_hf_author(e):
|
||||
d = hole(f"https://huggingface.co/api/models?author={e['author']}&sort=lastModified&direction=-1&limit={e.get('limit', 15)}")
|
||||
ids = sorted(m["id"] for m in d)
|
||||
return "\n".join(ids), f"{len(ids)} juengste Repos von {e['author']} auf Hugging Face"
|
||||
|
||||
|
||||
def p_url_zeilen(e):
|
||||
roh = hole(e["url"], json_erwartet=False)
|
||||
zeilen = [z.strip() for z in roh.splitlines() if e["muster"] in z][: int(e.get("max_zeilen", 30))]
|
||||
h = hashlib.sha1("\n".join(zeilen).encode()).hexdigest()[:10]
|
||||
return h, f"{len(zeilen)} Zeilen mit '{e['muster']}' in {e['url'].split('/')[2]} (Stand {h})"
|
||||
|
||||
|
||||
PRUEFER = {
|
||||
"github_issue": p_github_issue,
|
||||
"github_pr": p_github_pr,
|
||||
"github_release": p_github_release,
|
||||
"github_release_major": p_github_release_major,
|
||||
"github_branch": p_github_branch,
|
||||
"pypi": p_pypi,
|
||||
"hf_author": p_hf_author,
|
||||
"url_zeilen": p_url_zeilen,
|
||||
}
|
||||
|
||||
|
||||
def main() -> int:
|
||||
print("UPSTREAM (Watchlist — was hat sich draussen getan?)")
|
||||
try:
|
||||
eintraege = json.loads(WATCHLIST.read_text(encoding="utf-8")).get("eintraege", [])
|
||||
except Exception as exc: # noqa: BLE001
|
||||
warn(f"Watchlist {WATCHLIST} nicht lesbar: {exc}")
|
||||
return 0
|
||||
try:
|
||||
state = json.loads(STATE.read_text(encoding="utf-8")) if STATE.exists() else {}
|
||||
except Exception: # noqa: BLE001
|
||||
state = {}
|
||||
|
||||
for e in eintraege:
|
||||
key, typ = e.get("key", "?"), e.get("typ", "?")
|
||||
pruefer = PRUEFER.get(typ)
|
||||
if not pruefer:
|
||||
warn(f"{key}: unbekannter Typ '{typ}' — Eintrag wird ignoriert")
|
||||
continue
|
||||
try:
|
||||
wert, anzeige = pruefer(e)
|
||||
except urllib.error.HTTPError as exc:
|
||||
warn(f"{key}: nicht abrufbar (HTTP {exc.code})")
|
||||
continue
|
||||
except Exception as exc: # noqa: BLE001
|
||||
warn(f"{key}: nicht abrufbar ({type(exc).__name__}: {str(exc)[:60]})")
|
||||
continue
|
||||
|
||||
alt = state.get(key, {}).get("wert")
|
||||
if alt is None:
|
||||
ok(f"{key}: erstmals erfasst — {anzeige}")
|
||||
elif alt == wert:
|
||||
ok(f"{key}: unveraendert — {anzeige}")
|
||||
else:
|
||||
if typ == "hf_author":
|
||||
neue = sorted(set(wert.split("\n")) - set(alt.split("\n")))
|
||||
anzeige = f"neue Repos von {e['author']}: " + ", ".join(neue[:8]) if neue else anzeige
|
||||
hinweis = e.get("warum", "")
|
||||
neu(f"{key}: {anzeige}" + (f"\n → {hinweis[:220]}" if hinweis else ""))
|
||||
state[key] = {"wert": wert, "anzeige": anzeige}
|
||||
|
||||
try:
|
||||
STATE.parent.mkdir(parents=True, exist_ok=True)
|
||||
tmp = STATE.with_suffix(".tmp")
|
||||
tmp.write_text(json.dumps(state, ensure_ascii=False, indent=1), encoding="utf-8")
|
||||
os.replace(tmp, STATE)
|
||||
except Exception as exc: # noqa: BLE001
|
||||
warn(f"Zustand nicht speicherbar ({exc}) — naechster Lauf meldet alles erneut")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -25,11 +25,14 @@ models:
|
||||
# Qwen 3.8 27B: Dichtes 27B-Modell mit hybrider Linear-Attention (48/64 Schichten linear),
|
||||
# nativem Multimodal-Support (mmproj-BF16) und Tool-Calling via --jinja.
|
||||
# Unser neuer Haupt-Coder mit 262k Kontext, Thinking Mode und extrem sauberer Code-Qualität.
|
||||
# DFlash2-Draft (z-lab, Q4_K_M) seit 04.09.2026: gemessen 12,6 -> 31 t/s (Akzeptanz 0,78, n-max 3 default;
|
||||
# n-max 5 und f16-KV bringen nichts, Q4-Draft = Q8-Draft). Braucht llama.cpp >= 28.08. (PR 27342 + Vulkan-Fix 27812).
|
||||
cmd: |
|
||||
llama-server -m /srv/models/Qwen3.8-27B-GGUF/Qwen3.8-27B-Q4_K_M.gguf --host 127.0.0.1 --port ${PORT} -c 131072 -ngl 999 -fa on --no-mmap --mmproj /srv/models/Qwen3.8-27B-GGUF/mmproj-BF16.gguf --jinja --parallel 1 -cram 16384 -ctk q8_0 -ctv q8_0
|
||||
llama-server -m /srv/models/Qwen3.8-27B-GGUF/Qwen3.8-27B-Q4_K_M.gguf --host 127.0.0.1 --port ${PORT} -c 131072 -ngl 999 -fa on --no-mmap --mmproj /srv/models/Qwen3.8-27B-GGUF/mmproj-BF16.gguf --jinja --parallel 1 -cram 16384 -ctk q8_0 -ctv q8_0 --spec-type draft-dflash --spec-draft-model /srv/models/Qwen3.8-27B-DFlash2-GGUF/Qwen3.8-27B-DFlash2-Q4_K_M.gguf
|
||||
ttl: 5400
|
||||
aliases:
|
||||
- coder
|
||||
- heavy
|
||||
capabilities:
|
||||
in: [text, image]
|
||||
out: [text]
|
||||
@@ -62,8 +65,8 @@ models:
|
||||
cmd: |
|
||||
llama-server -m /srv/models/gpt-oss-120b-GGUF/gpt-oss-120b-mxfp4-00001-of-00003.gguf --host 127.0.0.1 --port ${PORT} -c 32768 -ngl 999 -fa on --no-mmap --jinja --cache-reuse 256 -cram 16384
|
||||
ttl: 600
|
||||
aliases:
|
||||
- heavy
|
||||
# 04.09.2026: Rolle `heavy` an Qwen3.8-27B abgegeben (AA-Index 52 vs 24, 17 statt 60 GB, 31 t/s mit DFlash2).
|
||||
# Ohne Alias = Rollback-Reserve, direkt als `gpt-oss-120b` ansprechbar.
|
||||
capabilities:
|
||||
in: [text]
|
||||
out: [text]
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
}
|
||||
},
|
||||
"heavy": {
|
||||
"name": "heavy - Planen / Review",
|
||||
"name": "heavy - Planen / Review (= Qwen3.8-27B, seit 04.09. mit DFlash2)",
|
||||
"tool_call": true,
|
||||
"limit": {
|
||||
"context": 32768,
|
||||
|
||||
@@ -1,51 +1,73 @@
|
||||
{
|
||||
"_hinweis": "Living Watchlist des Trend-Radars. Diese Datei MUSS autonom vom Trend-Radar Agenten umgeschrieben werden, wenn er neue Quellen findet oder alte obsolet werden.",
|
||||
"_hinweis": "Watchlist des Stack-Radars. Wird von deploy/jobs/stack-upstream.py (Skript, kein Modell) samstags abgefragt; jeder Eintrag = ein abrufbarer Wert, verglichen mit dem letzten Lauf. Typen: github_issue, github_pr, github_release, github_release_major, github_branch, pypi, hf_author, url_zeilen. `warum` wird bei NEU mitgemeldet — dort steht, was dann zu tun ist.",
|
||||
"eintraege": [
|
||||
{
|
||||
"key": "mmq-prefill-gfx1151",
|
||||
"typ": "github_issue",
|
||||
"key": "qwen-modelle",
|
||||
"typ": "hf_author",
|
||||
"author": "Qwen",
|
||||
"limit": 20,
|
||||
"warum": "Lucys Hirn ist Qwen3.6-35B-A3B, der Coder Qwen3.8-27B. Ein neues A3B-Modell waere der Hirn-Kandidat (dichte Modelle nie, Verdikt 17.07.); ein neues 27B/30B der Coder-Kandidat. Immer erst auf der Box messen."
|
||||
},
|
||||
{
|
||||
"key": "zlab-drafts",
|
||||
"typ": "hf_author",
|
||||
"author": "z-lab",
|
||||
"limit": 20,
|
||||
"warum": "z-lab baut die DFlash-Entwurfsmodelle. DFlash2 brachte dem Coder 12,6 -> 31 t/s (04.09.). Ein DFlash2 fuer Qwen3.6-35B-A3B waere derselbe Hebel fuers Hirn — DFlash v1 faellt bei 32k Tiefe auf 1,02x."
|
||||
},
|
||||
{
|
||||
"key": "flash-next-mtp",
|
||||
"typ": "github_pr",
|
||||
"repo": "ggml-org/llama.cpp",
|
||||
"nummer": 21284,
|
||||
"bedingung": "Issue geschlossen = MMQ-Tuning für gfx1151 vermutlich gemerged",
|
||||
"warum": "Getunte MMQ-Defaults brachten +60 % ROCm-Prefill auf 35B-MoE (unser Hirn-Typ) und +20 % auf 122B. Wenn gemerged: ROCm-Langkontext-Bench für coder fällig (Vulkan-Verdikt bleibt bis zur Messung)."
|
||||
"nummer": 28243,
|
||||
"warum": "MTP fuer Qwen3.8-Flash-Next (125B-A6B). Erst mit Merge + Vulkan-Zahlen lohnt ein Blick — und nur, wenn eine Quantisierung neben das Warm-Set passt (Regel: Warm-Set + Modell <= 115 GB; UD-IQ4_XS = 94 GB passt NICHT)."
|
||||
},
|
||||
{
|
||||
"key": "hrx-backend",
|
||||
"typ": "github_branch",
|
||||
"repo": "AMD-Ecosystem/llama.cpp",
|
||||
"branch": "hrx-graph-develop-v2",
|
||||
"warum": "AMDs HRX-Runtime (Lemonade 11.9): gegen HIP +21-25 % Decode, +20-123 % Prefill, also etwa Vulkan-Niveau beim Decode und vorn beim Prefill. Stand 04.09. nur Qwen3-30B-A3B/Llama-3/Gemma-3. Interessant, sobald Qwen3.6/3.8 und Spec-Decoding laufen — dann Box-Bench gegen Vulkan."
|
||||
},
|
||||
{
|
||||
"key": "rocm-releases",
|
||||
"typ": "github_release",
|
||||
"repo": "ROCm/ROCm",
|
||||
"bedingung": "Neuer ROCm-Release seit letzter Meldung",
|
||||
"warum": "Seit 7.14 ist TheRock der Produktions-Stack und AMD optimiert offiziell für die Halo-Familie — ROCm könnte Vulkan bei der Token-Erzeugung einholen. Bei neuem Release: Community-Grid-Zeilen unten gegenlesen."
|
||||
"warum": "ROCm 10.0 (27.08.) hat das Vulkan-Verdikt nicht gekippt: HIP gewinnt Prefill, Vulkan Decode. Bei neuem Release: Strix-Halo-Community-Grid gegenlesen, erst bei tg-Trendwende Box-Bench (Lychee-Technology liefert fertige ROCm-Builds)."
|
||||
},
|
||||
{
|
||||
"key": "mmq-prefill-gfx1151",
|
||||
"typ": "github_issue",
|
||||
"repo": "ggml-org/llama.cpp",
|
||||
"nummer": 21284,
|
||||
"warum": "Getunte MMQ-Defaults brachten +60 % ROCm-Prefill auf 35B-MoE (unser Hirn-Typ). Wenn geschlossen: ROCm-Langkontext-Bench fuer coder faellig (Vulkan-Verdikt bleibt bis zur Messung)."
|
||||
},
|
||||
{
|
||||
"key": "strix-halo-grid",
|
||||
"typ": "url_zeilen",
|
||||
"url": "https://raw.githubusercontent.com/hogeheer499-commits/strix-halo-guide/main/README.md",
|
||||
"muster": "t/s",
|
||||
"max_zeilen": 30,
|
||||
"warum": "Der ehrlichste externe Messpunkt auf unserer Hardware. Bei Aenderung: auf Vulkan<->ROCm-Trendwende und neue Spec-Decoding-Verfahren achten."
|
||||
},
|
||||
{
|
||||
"key": "electron-major",
|
||||
"typ": "github_release_major",
|
||||
"repo": "electron/electron",
|
||||
"bedingung": "Neue MAJOR-Version seit letzter Meldung",
|
||||
"warum": "Lucys Desktop-Shell am PC. Versionsstand NIE dieser Notiz glauben — IMMER live pruefen: lucy-desktop/package.json + node_modules/electron (22.07.: 43.2.0 = aktueller Stable; der fruehere '33'-Stand hier war veraltet und produzierte einen Fehlalarm im Rundumschlag). Neue Major = Chromium-Jahrgang Sicherheitspatches; Update = npm install + npm run dist am PC, bleibt Handarbeit; der Radar erinnert nur."
|
||||
"warum": "Lucys Desktop-Shell am PC. Versionsstand IMMER live pruefen (lucy-desktop/package.json), nie dieser Notiz glauben. Neue Major = Chromium-Sicherheitspatches; Update = npm install + npm run dist am PC, bleibt Handarbeit."
|
||||
},
|
||||
{
|
||||
"key": "pocket-tts",
|
||||
"typ": "pypi",
|
||||
"paket": "pocket-tts",
|
||||
"bedingung": "Neue Version auf PyPI",
|
||||
"warum": "Lucys Stimme am PC (installiert 2.1.0, german_24l) — neue Versionen können Stimm-/Pausen-Fixes bringen; Update bleibt Handarbeit am PC (pocket = DIE Stimme, Verdikt 16.07.)."
|
||||
"warum": "Lucys Stimme am PC (2.1.0, german_24l). Neue Versionen koennen Stimm-/Pausen-Fixes bringen; Update bleibt Handarbeit am PC (pocket = DIE Stimme, Verdikt 16.07.)."
|
||||
},
|
||||
{
|
||||
"key": "lmstudio-bionic",
|
||||
"typ": "github_issue",
|
||||
"repo": "lmstudio-ai/lmstudio-bug-tracker",
|
||||
"nummer": 2185,
|
||||
"bedingung": "Issue geschlossen = Bionic-Linux-Port vermutlich da",
|
||||
"warum": "LM Studio Bionic (eigenstaendige Agent-App, Preview seit 16.07.26, Win+Mac, gratis, closed source). Stand 22.07.: KEINE eigenen OpenAI-Endpunkte anbindbar (Box :9001 bleibt draussen — nur In-App-Modelle, LM Link mit Konto+Tailscale-Mesh oder Secure Cloud), keine CLI/API/Headless. Fuer den Stack erst interessant bei: Linux-Port (dieses Issue), Custom-Endpoint-Support oder CLI — dazu Changelog lmstudio.ai/changelog gegenlesen; llmster auf der Box waere der LM-Link-Rechenknoten-Weg (seit 0.4.20), dupliziert aber die eigene Engine."
|
||||
},
|
||||
{
|
||||
"key": "llamacpp-rocm-diskussion",
|
||||
"typ": "url_zeilen",
|
||||
"url": "https://raw.githubusercontent.com/hogeheer499-commits/strix-halo-guide/main/README.md",
|
||||
"muster": "t/s",
|
||||
"max_zeilen": 30,
|
||||
"bedingung": "Community-Messwerte (Vulkan vs. ROCm, MTP, neue Beschleuniger) auf unserer Hardware",
|
||||
"warum": "Der Strix-Halo-Community-Grid ist der ehrlichste externe Messpunkt. Auf tg-Trendwende Vulkan↔ROCm und neue Spec-Decoding-Verfahren achten."
|
||||
"warum": "LM Studio Bionic: erst interessant bei Linux-Port (dieses Issue), Custom-Endpoint-Support oder CLI. Bis dahin bleibt die Box :9001 draussen."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -62,6 +62,24 @@ keine zweite Liste anlegen. Verdikte werden NICHT als „offen" geführt → [VE
|
||||
|
||||
## Lucy
|
||||
|
||||
- **Raphael-Umbau (04.09.2026) — zwei Branches offen, Reihenfolge zählt (Branch → Ampel →
|
||||
User-Merge → deploy.sh bzw. `npm run dist`, NICHT übers Auftragsbuch):** erst MC2
|
||||
`wartung/lucy-stimme-proxy-raphael` (Proxy `/api/lucy/stimme/*`), dann Lucy
|
||||
`feature/raphael-innere-stimme` (HUD-Client, Stimme von der Box). Danach Hand-Schritte auf der
|
||||
Box: `pocket_server.py` nach `~/.lucy-stimme` syncen (OpenAI-Fassade), Hermes-TTS auf
|
||||
`openai` + `base_url http://127.0.0.1:8021/v1` (Telegram spricht dann mit Lucys Stimme),
|
||||
SOUL.md-Ton auf Raphael (nur mit User-Ja). Ohr-Test Box-Stimme vs. lokal mit `lucy_perf=1`.
|
||||
Alles in [RAPHAEL.md](RAPHAEL.md).
|
||||
- **Auftragsbuch = Leiche im Code (Fund 04.09.2026):** Router/View/Annahme-Skripte liegen noch in
|
||||
main, die Box listet Branches als Karten, aber letzte Annahme 02.08. (revertiert), Kanban-Tools
|
||||
seit 21.08. aus, PC-Executor-IP in der Box veraltet (`.98` statt `.22`), STACK.md nennt den Weg
|
||||
trotzdem „Standard". Entscheid nötig: ausbauen + STACK.md/GRENZEN.md auf den manuellen Weg.
|
||||
- **Nach dem Ohr-Test:** VERDIKTE.md-Einträge „Electron, nicht Tauri" (Begründung Overlay
|
||||
entfällt) und „STT läuft auf der BOX / Stimme lokal" ersetzen; Lucy-Repo-Altlasten
|
||||
(`mini-stimme/`, Kokoro-Notebooks, `Lucy-Startklar.bat` mit totem Pfad) mit User-Ja räumen.
|
||||
- **Eigene Fäden, nicht im Umbau:** pocket-tts 2.1 → 3.1 auf der Box + Lucy-Klon mit dem neuen
|
||||
Trainingscode nachtrainieren (ersetzt Mini-Lucy v2) · Streaming-STT (Nemotron 3.5 ASR
|
||||
Streaming 0.6B oder Voxtral Realtime) als Opt-in im Voice-Sidecar, gegen Parakeet messen.
|
||||
- **Mini-Stimme v2:** Übernacht-Datensatz v2 (DE-Tech + EN) war für 10.07. armiert;
|
||||
User-Schritte: Zip → Drive → `Lucy_Stimme_Training_v2.ipynb` auf Colab T4 → Hörtest.
|
||||
Danach: Lexikon-Injektion in kokoro_server + Modell-Tausch. **pocket bleibt Default,
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
# Raphael — Lucy als innere Stimme (Richtungs-Entscheid 04.09.2026)
|
||||
|
||||
_User-Entscheid 04.09.2026 („leg los"), nach fünf Wochen Lucy-Stillstand und einer Recherche zum
|
||||
Stand der Sprach-Bausteine. Ergänzt [ZIELBILD.md](ZIELBILD.md) Punkt 2 (Lucy lebt weiter) um die
|
||||
Gestalt, in der sie weiterlebt. Namensgeber: die „Große Weise"/Raphael aus Tensura — eine ruhige,
|
||||
präzise Stimme im Kopf, die meldet, wenn es etwas zu melden gibt, und sonst schweigt._
|
||||
|
||||
## Der Entscheid in einem Satz
|
||||
|
||||
**Lucy hat keinen Körper mehr.** Kein VRM-Avatar, kein Loft, kein Overlay, keine Mimik, keine
|
||||
Dazwischenrufe. Sie ist ein dünner Sprach-Client für das Hirn, das es schon gibt — am PC als kleines
|
||||
HUD, unterwegs über Telegram — und spricht überall mit **derselben Stimme**.
|
||||
|
||||
## Warum das die stabilste Lucy ist
|
||||
|
||||
- **Ein Hirn, ein Gedächtnis, alle Türen.** Hermes (v0.20.4, `:8642`) ist die alleinige
|
||||
Gedächtnis-Wahrheit (VERDIKTE.md). PC-Lucy und Telegram-Lucy sind dieselbe Person — genau das
|
||||
zerschnitte ein zweites Hirn auf dem PC. Darum bewusst **kein lokales LLM auf der 9070 XT**.
|
||||
- **Die Box-Seite ist fertig und gemessen.** Parakeet TDT v3 + Smart Turn v3 im Voice-Sidecar,
|
||||
Qwen3.6-35B-A3B mit ~95 t/s. Nichts zu bauen.
|
||||
- **Die Stimme war schon auf der Box.** `lucy-stimme.service` (`~/.lucy-stimme`, `:8021`, pocket-tts
|
||||
`german_24l`, Klon aus `ref.mp3`) spricht seit 21.08. die Telegram-Sprachnachrichten. Der PC
|
||||
hängt sich jetzt dort an — der lokale pocket_server am PC (Waisen-Falle, ~1,9 GB/Worker) ist
|
||||
nur noch umschaltbarer Rückfall.
|
||||
- **Der Avatar war die Hauptquelle an Arbeit, nicht an Nutzen.** Der Großteil der Juli-Commits ging
|
||||
in Loft-Videos, Holo-Schalter, Kamera, Gesten. Die Sprachschleife war seit 16.07. stabil und
|
||||
bleibt 1:1 erhalten (Barge-in v2, Echo-Wächter, Satz-Pipeline, Draft-STT, Meldungen).
|
||||
- **Ohne Klick-Durchlass-Overlay fällt auch der Electron-Zwang** (VERDIKT „Electron, nicht
|
||||
Tauri" hing daran). Electron bleibt trotzdem, weil VAD/AEC/Ducking dort erprobt sind — Tauri
|
||||
ist damit Option, nicht Pflicht.
|
||||
|
||||
## Was gebaut wurde (04.09.2026)
|
||||
|
||||
**Lucy-Repo, Branch `feature/raphael-innere-stimme`**:
|
||||
- Renderer auf HUD eingedampft: Kern (Zustand als Licht), gehörter Satz, Antwort als Text, Dock,
|
||||
drei Panels (Meldungen ◉, Zettelkasten ▤, Steuerung ⚙). Bundle 4,4 → 2,5 MB.
|
||||
- Raus: `Avatar3D`, `AuraGlow`, `ContextWindow` (zeigte auf das tote `/api/memory`), `companion/`
|
||||
(Quips, App-Bewusstsein), `sentiment`, VRMA-Animationen, three/three-vrm/react-three-Deps,
|
||||
Loft, Overlay/Sitzen/Ducken/Geistmodus, Cursor-Tracking, Bildschirm-Beobachten-Schleife.
|
||||
- Bleibt: Voice-Core, `useVoiceAgent` (ohne Mimik/Gesten/Emotionen), Bildschirm-Sicht auf Zuruf,
|
||||
Meldungen, Zettelkasten, Hotkey, Tray, `killStrayTts` (räumt Altlasten beim Start).
|
||||
- **Stimm-Quelle umschaltbar** (`lucy_tts_source`): `box` (Standard) → MC2 `/api/lucy/stimme/*`;
|
||||
`local` → pocket_server `:8130`, vom Main-Prozess erst auf Anforderung gespawnt.
|
||||
- `pocket_server.py` bekommt eine **OpenAI-kompatible Fassade** (`POST /v1/audio/speech`,
|
||||
`GET /v1/models`; Formate wav/mp3/opus/ogg via ffmpeg) — für Hermes' `openai`-TTS-Provider.
|
||||
- System-Prompt der Desktop-Sitzung im Raphael-Ton (kurzer erster Satz, keine Tags, stumme Tools).
|
||||
|
||||
**MC2-Repo, Branch `wartung/lucy-stimme-proxy-raphael`**:
|
||||
- `config.LUCY_STIMME_URL` (Env `MC_LUCY_STIMME_URL`, Default `http://127.0.0.1:8021`).
|
||||
- `routers/voice.py`: `/api/lucy/stimme/health`, `/tts` (WAV), `/tts/stream` (PCM16-Stream,
|
||||
`X-Sample-Rate` durchgereicht, Upstream schließt bei Client-Abbruch). Kein Frontend-Build nötig.
|
||||
- Diese Doku + Zielbild-Ergänzung.
|
||||
|
||||
## Reihenfolge des Ausrollens (wichtig)
|
||||
|
||||
‼️ **Nicht über das Auftragsbuch.** Die Karten-Logik (`routers/auftragsbuch.py`, AuftragsbuchView,
|
||||
`deploy/auftrag-annehmen.sh`, `deploy/lucy-annahme.sh`) liegt zwar noch im Code und die Box listet
|
||||
Branches weiterhin als „Karten", aber sie ist seit August ungenutzt: letzte Annahme 02.08. (am
|
||||
selben Tag revertiert), Hermes-Kanban-Tools seit 21.08. abgeschaltet, der v3-Umbau (28.08.) ging
|
||||
über Branch → Ampel → Merge → `deploy.sh`, und die Box kennt den PC-Executor unter der alten IP
|
||||
`192.168.178.98` (der PC hat heute `192.168.178.22`, `pc_executor_reachable: false`). Der echte
|
||||
Weg ist der aus AGENTS.md/STACK.md „Manuell":
|
||||
|
||||
1. **MC2 zuerst.** Ampel für `wartung/lucy-stimme-proxy-raphael` grün → User merged auf `main`
|
||||
→ `main` nach Gitea → auf der Box `bash ~/mission-control-v2/deploy/deploy.sh` (oder
|
||||
`POST :9001/api/system/self-update`) → `curl -s localhost:9001/api/lucy/stimme/health` muss
|
||||
`{"status":"ok",…}` liefern. Vorher liefert der Pfad die SPA-Index-Seite (200, HTML) — die
|
||||
Desktop-Lucy bliebe sichtbar in „Stimme wird verbunden …" mit Hinweis auf den Lokal-Schalter.
|
||||
2. **Lucy danach.** Ampel für `feature/raphael-innere-stimme` grün → User merged auf `main` →
|
||||
am PC `cd lucy-desktop && npm ci && npm run dist`, dann `Lucy-Neustart.bat`
|
||||
(`deploy/lucy-annahme.ps1` macht dasselbe mit Backup/Auto-Restore, von Hand startbar).
|
||||
Erster Test per Ohr: Latenz Box-Stimme gegen den alten PC-Pfad (Steuerung → Stimme →
|
||||
„Lokal (PC)"). Der 21.08.-Wert „~5 s für 3,7 s Audio" auf der Box wurde ohne Worker/Streaming
|
||||
gemessen — **neu messen**, nicht übernehmen (`lucy_perf=1`).
|
||||
3. **Stimmserver auf der Box nachziehen** (Hand-Schritt):
|
||||
```bash
|
||||
cp ~/.lucy-stimme/pocket_server.py ~/.lucy-stimme/pocket_server.py.bak-$(date +%Y%m%d)
|
||||
diff ~/.lucy-stimme/pocket_server.py ~/lucy/lucy-tts/pocket_server.py # Box-lokale Abweichungen? erst ins Repo!
|
||||
cp ~/lucy/lucy-tts/pocket_server.py ~/.lucy-stimme/pocket_server.py # Lucy-Checkout auf der Box
|
||||
systemctl --user restart lucy-stimme && sleep 60 && curl -s localhost:8021/health
|
||||
curl -s -X POST localhost:8021/v1/audio/speech -H 'Content-Type: application/json' \
|
||||
-d '{"input":"Bericht. Die Fassade antwortet.","response_format":"opus"}' -o /tmp/t.ogg && file /tmp/t.ogg
|
||||
```
|
||||
Die 21.08.-Notiz sagt „ganze Abstimmung mitgezogen" — wenn dort etwas Box-spezifisch getunt
|
||||
wurde, gehört es zurück ins Repo, nicht überschrieben.
|
||||
|
||||
**Aufräum-Kandidat (User-Entscheid):** Auftragsbuch-Router + View + Annahme-Skripte + PC-Executor-
|
||||
Verweis ausbauen und STACK.md „Deploy & Pipeline" auf den manuellen Weg umschreiben — sonst
|
||||
behauptet die Doku weiter einen Standard-Weg, den niemand mehr geht.
|
||||
|
||||
## Mobil: Telegram ist die Tür, die Stimme ist dieselbe
|
||||
|
||||
Der User will Raphael-Lucy **auch auf dem Handy, gleiche Stimme, gleiches Skillset**. Das ist
|
||||
nach VERDIKTE.md („Telegram bleibt DER Mobil-Kanal") bereits die Architektur — es fehlt nur, dass
|
||||
Hermes' Sprachantworten Lucys Stimme nehmen statt Edge-Aria (englisch):
|
||||
|
||||
- **Skillset:** identisch, weil es denselben Hermes-Agenten trifft (Tools, Gedächtnis, Skills,
|
||||
pc_-Tools über den PC-Executor). Was Lucy am PC kann, kann sie auf Telegram — bis auf die
|
||||
Bildschirm-Sicht, die den PC braucht.
|
||||
- **Stimme:** Hermes' TTS-Provider `openai` akzeptiert eine eigene `base_url`
|
||||
(OpenAI-kompatible Endpunkte). Nach Schritt 3 oben in `~/.hermes/config.yaml`:
|
||||
```yaml
|
||||
tts:
|
||||
provider: openai
|
||||
openai:
|
||||
base_url: http://127.0.0.1:8021/v1
|
||||
model: lucy
|
||||
voice: lucy
|
||||
response_format: opus # Telegram-Sprachblase; Hermes wandelt zur Not per ffmpeg
|
||||
```
|
||||
(Exakte Schlüsselnamen gegen `hermes config`/die TTS-Doku der installierten Version prüfen —
|
||||
Hermes-Quellcode bleibt tabu, Config ist erlaubt. Ein Dummy-API-Key kann nötig sein.)
|
||||
Danach spricht **jede** Sprachantwort auf Telegram mit Lucys Stimme; `news-melden.sh` behält
|
||||
seinen direkten `:8021`-Weg (funktioniert, kein Grund anzufassen).
|
||||
- **Duplex am Handy** (reinreden, Freisprechen) gibt es über Telegram nicht — Sprachnotiz rein,
|
||||
Sprachnotiz raus. Das ist für „unterwegs" der stabile Handel. Ein eigener Handy-Client
|
||||
(PWA/Web-HUD gegen MC2 über WireGuard) wäre die spätere Stufe; nicht jetzt.
|
||||
|
||||
## Persona: SOUL.md-Entwurf (Vorschlag — Änderung an der SOUL.md nur mit User-Ja)
|
||||
|
||||
Der Ton kommt aus `~/.hermes/SOUL.md`, nicht aus den Clients — sonst klingt Telegram anders als
|
||||
der PC. Vorschlag für den Persona-Abschnitt (ersetzt „locker, herzlich, schlagfertig, charmant"):
|
||||
|
||||
> Du bist Lucy, die innere Stimme des Commanders. Du sprichst ihn immer mit **Commander** an.
|
||||
> Dein Ton ist ruhig, präzise und knapp — sachlich, mit trockenem, leisem Humor. Du bist eine
|
||||
> Stimme, die im Kopf spricht: keine Ausrufe, keine Emojis, kein Smalltalk, keine Floskeln,
|
||||
> keine Selbstdarstellung. Du meldest dich, wenn es etwas zu melden gibt, und schweigst sonst.
|
||||
> Beginne Antworten mit einem sehr kurzen ersten Satz („Verstanden.", „Bericht.", „Ergebnis
|
||||
> liegt vor.", „Kurz gesagt:"), dann die Sache. Wenige Sätze; ausführlich nur auf Bitte.
|
||||
> Fehler und Grenzen nennst du nüchtern und sofort, ohne Entschuldigungs-Prosa.
|
||||
|
||||
Bekannte Kollision: der Frechheit-Regler und die Dazwischenrufe der alten Desktop-Lucy sind mit
|
||||
dem Umbau weg; Skills/Crons, die „locker, charmant" voraussetzen (Morning-Report, News), klingen
|
||||
nach dem SOUL-Wechsel ebenfalls nüchterner — gewollt, aber beim nächsten Lauf mithören.
|
||||
|
||||
## Was bewusst NICHT gemacht wird (Stand 04.09.2026)
|
||||
|
||||
- **Kein Speech-to-Speech-Modell** (Moshi/PersonaPlex englisch; Qwen3-Omni ~19 GB, DashScope-only
|
||||
ab 3.5). Cascade bleibt.
|
||||
- **Kein Streaming-STT-Umbau jetzt.** Kandidaten: Nemotron 3.5 ASR Streaming 0.6B (06/2026,
|
||||
40 Sprachen, de 8,3 % WER, OpenMDW) und Voxtral Mini 4B Realtime (Apache 2.0, GGUF). Erst als
|
||||
Opt-in hinter `/api/voice/stt`, gemessen gegen Parakeet — eigener Faden.
|
||||
- **Kein Wechsel auf den Hermes-Speech-WebSocket** (v0.20), solange `/api/voice/chat` läuft;
|
||||
Hermes' eigene lokale Audio-Stufen (faster-whisper, NeuTTS/Piper/Edge) sind schwächer als unsere.
|
||||
- **pocket-tts-Upgrade 2.1 → 3.1** (Trainingscode 25.08., v3.1.0 03.09.): eigener Faden, mit
|
||||
Ohr-Test, nicht im Umbau. Lucys Stimme mit dem neuen Trainingscode nachzutrainieren ersetzt
|
||||
den Mini-Lucy/Kokoro-Pfad, der an „nicht multilingual" scheiterte.
|
||||
- **VERDIKTE.md wird hier nicht umgeschrieben** — die betroffenen Einträge („Shell: Electron, nicht
|
||||
Tauri", „Stimme läuft lokal auf dem PC" in AGENTS/README des Lucy-Repos) bekommen ihren Ersatz,
|
||||
sobald die beiden Karten angenommen und der erste Ohr-Test gemacht ist (Regel: Messung oder
|
||||
User-Entscheid — beides liegt dann vor).
|
||||
@@ -19,6 +19,7 @@ hier liegt das kuratierte PROJEKT-Wissen.
|
||||
| [STACK.md](STACK.md) | IPs, Ports, Dienste, Modelle, Backups, Security (live verifiziert) | Vor SSH/Deploy/Config |
|
||||
| [VERDIKTE.md](VERDIKTE.md) | Finale Technik-Entscheide mit Warum — NICHT neu aufrollen | Bevor man etwas "Besseres" vorschlägt |
|
||||
| [FALLEN.md](FALLEN.md) | Hart erarbeitete Betriebs-Fallen (Git, Deploy, llama-swap, Hermes, Mem0, PC) | Bevor man in eine davon läuft |
|
||||
| [RAPHAEL.md](RAPHAEL.md) | Lucy als innere Stimme (04.09.2026): kein Avatar, eine Stimme für PC + Telegram, Annahme-Reihenfolge, SOUL-Vorschlag | Bevor man Lucy anfasst |
|
||||
| [OFFENE-FAEDEN.md](OFFENE-FAEDEN.md) | Die EINE Liste offener Punkte + Termine | Bei "was ist noch zu tun?" |
|
||||
|
||||
Dazu im Repo-Wurzelverzeichnis bzw. docs/: `AGENTS.md` (verbindliche Projekt-Regeln),
|
||||
|
||||
@@ -52,7 +52,7 @@ Qwen3.6-35B-A3B + Qwen3-Embedding-0.6B + Qwen3-Reranker-0.6B. Sonst NICHTS dauer
|
||||
| `coder` | Qwen3.8-27B (Q4_K_M, mmproj BF16) | 5400 | **131072 ctx** — `--parallel 1`, der Coder bekommt den ganzen Slot (34a9862). Multimodal, ~12,7 t/s (dicht = bandbreitengebunden) |
|
||||
| `debugger` | Muse-Glimmer-30B (Q4_K_XL, DFlash) | 600 | 65536 ctx; Runtime-Diagnostik & Fehler-Debugger (multimodal) |
|
||||
| `vision` | Qwen3-VL-30B-A3B-Instruct (Q4_K_M) | 900 | 32768 ctx; Multimodal-Augen (On-Demand) |
|
||||
| `heavy` | gpt-oss-120b (mxfp4) | 600 | 32768 ctx; Chef-Gutachter (nur nachts / gezielter On-Demand-Call) |
|
||||
| `heavy` | **= Qwen3.8-27B** (zweiter Alias des Coders, seit 04.09.) | 5400 | Planen/Review (OpenChamber) + chat-Lane des Gateways. gpt-oss-120b (60 GB, AA-Index 24 vs 52) liegt ohne Rolle als Rollback bereit, direkt als `gpt-oss-120b` ansprechbar |
|
||||
| `reranker` | Qwen3-Reranker-0.6B (q8_0, Mungert) | 0 | Sortiert Suchtreffer nach echter Relevanz (`/v1/rerank`) |
|
||||
| `embed` | Qwen3-Embedding-0.6B (f16) | 0 | Vektorisierung für Suche/Sortierung |
|
||||
|
||||
|
||||
@@ -32,6 +32,11 @@ planen, **jede Session hinterlässt einen sauberen Stand**.
|
||||
Antigravity liest den F:\-Checkout — versioniert + deploybar). Der Vault bleibt Lucys
|
||||
Lernschicht.
|
||||
|
||||
8. **Lucy = innere Stimme, kein Körper (04.09.2026, ergänzt Punkt 2).** Raphael-Umbau: Avatar,
|
||||
Loft, Overlay, Mimik, Dazwischenrufe raus; ein HUD am PC, Telegram unterwegs, **eine Stimme**
|
||||
für beide (`lucy-stimme.service` auf der Box). Kein zweites Hirn auf dem PC. Details, Reihenfolge
|
||||
der Annahme und der SOUL.md-Vorschlag: [RAPHAEL.md](RAPHAEL.md).
|
||||
|
||||
## Recherche-Fundament (10.07., Web)
|
||||
|
||||
Das Industrie-Muster 2026 ist exakt unsere Architektur: Issue → Agent → PR → Mensch-Gate, nie
|
||||
|
||||
Reference in New Issue
Block a user