Immagini: avanzamento sul volto e nel registro, elenco modelli scaricati; impostazioni con etichette a capo e larghezza contenuta
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
3e9ecd487d
commit
a078dff608
5 files changed
+107
-30
No files matched your search
+1
-1
@@ -84,7 +84,7 @@ class Avatar3DView(QWebEngineView):
|
|||||||
|
|
||||||
# ── API thread-safe (valori semplici, letti dal timer sul thread Qt) ──
|
# ── API thread-safe (valori semplici, letti dal timer sul thread Qt) ──
|
||||||
def set_state(self, state: str) -> None:
|
def set_state(self, state: str) -> None:
|
||||||
self._state = str(state or "LISTENING")
|
self._state = str(state or "LISTENING").replace("'", "’")
|
||||||
|
|
||||||
def set_audio_level(self, level: float) -> None:
|
def set_audio_level(self, level: float) -> None:
|
||||||
try:
|
try:
|
||||||
|
|||||||
+31
-13
@@ -45,9 +45,16 @@ def _combo(items, current) -> QComboBox:
|
|||||||
c.addItem(label, value)
|
c.addItem(label, value)
|
||||||
idx = c.findData(current)
|
idx = c.findData(current)
|
||||||
c.setCurrentIndex(idx if idx >= 0 else 0)
|
c.setCurrentIndex(idx if idx >= 0 else 0)
|
||||||
|
# le etichette lunghe non allargano la finestra: il menu si apre comunque a larghezza piena
|
||||||
|
c.setSizeAdjustPolicy(QComboBox.SizeAdjustPolicy.AdjustToMinimumContentsLengthWithIcon); c.setMinimumContentsLength(22)
|
||||||
return c
|
return c
|
||||||
|
|
||||||
|
|
||||||
|
def _note(text: str) -> QLabel:
|
||||||
|
"""Etichetta descrittiva che va a capo invece di allargare la finestra."""
|
||||||
|
lbl = QLabel(text); lbl.setWordWrap(True); return lbl
|
||||||
|
|
||||||
|
|
||||||
class SettingsDialog(QDialog):
|
class SettingsDialog(QDialog):
|
||||||
_async = pyqtSignal(str, object)
|
_async = pyqtSignal(str, object)
|
||||||
|
|
||||||
@@ -88,7 +95,7 @@ class SettingsDialog(QDialog):
|
|||||||
self.api_key = QLineEdit(); self.api_key.setEchoMode(QLineEdit.EchoMode.Password)
|
self.api_key = QLineEdit(); self.api_key.setEchoMode(QLineEdit.EchoMode.Password)
|
||||||
self.api_key.setPlaceholderText("•••••• (salvata, lascia vuoto per non cambiarla)" if s.get_secret("anthropic_api_key") else "sk-ant-…")
|
self.api_key.setPlaceholderText("•••••• (salvata, lascia vuoto per non cambiarla)" if s.get_secret("anthropic_api_key") else "sk-ant-…")
|
||||||
f.addRow("Chiave API Anthropic", self.api_key)
|
f.addRow("Chiave API Anthropic", self.api_key)
|
||||||
f.addRow("", QLabel("Creala su console.anthropic.com. Viene salvata nel portachiavi di macOS."))
|
f.addRow("", _note("Creala su console.anthropic.com. Viene salvata nel portachiavi di macOS."))
|
||||||
self.stack.addWidget(w)
|
self.stack.addWidget(w)
|
||||||
# Locale
|
# Locale
|
||||||
w = QWidget(); f = QFormLayout(w)
|
w = QWidget(); f = QFormLayout(w)
|
||||||
@@ -183,7 +190,7 @@ class SettingsDialog(QDialog):
|
|||||||
|
|
||||||
# ── Telegram ──────────────────────────────────────────────────────
|
# ── Telegram ──────────────────────────────────────────────────────
|
||||||
form3 = QFormLayout()
|
form3 = QFormLayout()
|
||||||
form3.addRow(QLabel("Telegram (account personale): credenziali da my.telegram.org > API development tools"))
|
form3.addRow(_note("Telegram (account personale): credenziali da my.telegram.org > API development tools"))
|
||||||
row = QHBoxLayout()
|
row = QHBoxLayout()
|
||||||
self.tg_id = QLineEdit(str(s.get("telegram_api_id") or "")); self.tg_id.setPlaceholderText("api id"); row.addWidget(self.tg_id)
|
self.tg_id = QLineEdit(str(s.get("telegram_api_id") or "")); self.tg_id.setPlaceholderText("api id"); row.addWidget(self.tg_id)
|
||||||
self.tg_hash = QLineEdit(); self.tg_hash.setEchoMode(QLineEdit.EchoMode.Password)
|
self.tg_hash = QLineEdit(); self.tg_hash.setEchoMode(QLineEdit.EchoMode.Password)
|
||||||
@@ -207,7 +214,7 @@ class SettingsDialog(QDialog):
|
|||||||
|
|
||||||
# ── WhatsApp (dispositivo collegato, Baileys) ─────────────────────
|
# ── WhatsApp (dispositivo collegato, Baileys) ─────────────────────
|
||||||
form4 = QFormLayout()
|
form4 = QFormLayout()
|
||||||
form4.addRow(QLabel("WhatsApp in tempo reale (client non ufficiale: possibile blocco del numero, a tuo rischio)"))
|
form4.addRow(_note("WhatsApp in tempo reale (client non ufficiale: possibile blocco del numero, a tuo rischio)"))
|
||||||
row = QHBoxLayout()
|
row = QHBoxLayout()
|
||||||
self.wa_live = QCheckBox("Attivo all'avvio"); self.wa_live.setChecked(bool(s.get("whatsapp_live"))); row.addWidget(self.wa_live)
|
self.wa_live = QCheckBox("Attivo all'avvio"); self.wa_live.setChecked(bool(s.get("whatsapp_live"))); row.addWidget(self.wa_live)
|
||||||
self.wa_annuncia = QCheckBox("Annuncia a voce i messaggi in arrivo"); self.wa_annuncia.setChecked(bool(s.get("whatsapp_annuncia"))); row.addWidget(self.wa_annuncia)
|
self.wa_annuncia = QCheckBox("Annuncia a voce i messaggi in arrivo"); self.wa_annuncia.setChecked(bool(s.get("whatsapp_annuncia"))); row.addWidget(self.wa_annuncia)
|
||||||
@@ -224,7 +231,7 @@ class SettingsDialog(QDialog):
|
|||||||
|
|
||||||
# ── Assistenza server (bot sysadmin + monitoraggio Sentinella) ────
|
# ── Assistenza server (bot sysadmin + monitoraggio Sentinella) ────
|
||||||
form_srv = QFormLayout()
|
form_srv = QFormLayout()
|
||||||
form_srv.addRow(QLabel("Assistenza server: bot Telegram sysadmin e monitoraggio Sentinella sul server ponte (accesso SSH con chiave)"))
|
form_srv.addRow(_note("Assistenza server: bot Telegram sysadmin e monitoraggio Sentinella sul server ponte (accesso SSH con chiave)"))
|
||||||
self.srv_ssh = QLineEdit(str(s.get("server_assist_ssh") or "")); self.srv_ssh.setPlaceholderText("root@host del server ponte")
|
self.srv_ssh = QLineEdit(str(s.get("server_assist_ssh") or "")); self.srv_ssh.setPlaceholderText("root@host del server ponte")
|
||||||
form_srv.addRow("SSH server ponte", self.srv_ssh)
|
form_srv.addRow("SSH server ponte", self.srv_ssh)
|
||||||
self.srv_dir = QLineEdit(str(s.get("server_assist_dir") or "")); self.srv_dir.setPlaceholderText("/opt/aiserverassistance")
|
self.srv_dir = QLineEdit(str(s.get("server_assist_dir") or "")); self.srv_dir.setPlaceholderText("/opt/aiserverassistance")
|
||||||
@@ -250,7 +257,7 @@ class SettingsDialog(QDialog):
|
|||||||
|
|
||||||
# ── Casa (Home Assistant) ─────────────────────────────────────────
|
# ── Casa (Home Assistant) ─────────────────────────────────────────
|
||||||
form_ha = QFormLayout()
|
form_ha = QFormLayout()
|
||||||
form_ha.addRow(QLabel("Home Assistant: crea un token di accesso a lunga durata dal tuo profilo (Sicurezza) e incollalo qui. Viene salvato nel portachiavi."))
|
form_ha.addRow(_note("Home Assistant: crea un token di accesso a lunga durata dal tuo profilo (Sicurezza) e incollalo qui. Viene salvato nel portachiavi."))
|
||||||
self.ha_url = QLineEdit(str(s.get("homeassistant_url") or "")); self.ha_url.setPlaceholderText("http://homeassistant.local:8123")
|
self.ha_url = QLineEdit(str(s.get("homeassistant_url") or "")); self.ha_url.setPlaceholderText("http://homeassistant.local:8123")
|
||||||
form_ha.addRow("Indirizzo", self.ha_url)
|
form_ha.addRow("Indirizzo", self.ha_url)
|
||||||
row = QHBoxLayout()
|
row = QHBoxLayout()
|
||||||
@@ -265,30 +272,40 @@ class SettingsDialog(QDialog):
|
|||||||
from PyQt6.QtWidgets import QPlainTextEdit
|
from PyQt6.QtWidgets import QPlainTextEdit
|
||||||
from .mcp_client import CONFIG_FILE as MCP_FILE, manager as mcp_manager
|
from .mcp_client import CONFIG_FILE as MCP_FILE, manager as mcp_manager
|
||||||
form_mcp = QFormLayout()
|
form_mcp = QFormLayout()
|
||||||
form_mcp.addRow(QLabel("Server MCP esterni: stesso formato di Claude Desktop (mcpServers con command/args/env, oppure url/headers). "
|
form_mcp.addRow(_note("Server MCP esterni: stesso formato di Claude Desktop (mcpServers con command/args/env, oppure url/headers). "
|
||||||
"Gli strumenti diventano disponibili a tutti i motori; con Claude Code i server vengono passati direttamente a claude."))
|
"Gli strumenti diventano disponibili a tutti i motori; con Claude Code i server vengono passati direttamente a claude."))
|
||||||
self.mcp_text = QPlainTextEdit()
|
self.mcp_text = QPlainTextEdit()
|
||||||
try:
|
try:
|
||||||
self.mcp_text.setPlainText(MCP_FILE.read_text(encoding="utf-8"))
|
self.mcp_text.setPlainText(MCP_FILE.read_text(encoding="utf-8"))
|
||||||
except Exception:
|
except Exception:
|
||||||
self.mcp_text.setPlainText('{\n "mcpServers": {\n }\n}\n')
|
self.mcp_text.setPlainText('{\n "mcpServers": {\n }\n}\n')
|
||||||
self.mcp_text.setMinimumHeight(220)
|
self.mcp_text.setMinimumHeight(180); self.mcp_text.setMaximumHeight(260)
|
||||||
|
self.mcp_text.setLineWrapMode(QPlainTextEdit.LineWrapMode.WidgetWidth)
|
||||||
form_mcp.addRow(self.mcp_text)
|
form_mcp.addRow(self.mcp_text)
|
||||||
row = QHBoxLayout()
|
row = QHBoxLayout()
|
||||||
b = QPushButton("Applica e ricollega"); b.clicked.connect(self._mcp_apply); row.addWidget(b)
|
b = QPushButton("Applica e ricollega"); b.clicked.connect(self._mcp_apply); row.addWidget(b)
|
||||||
b = QPushButton("Esempio"); b.clicked.connect(self._mcp_example); row.addWidget(b)
|
b = QPushButton("Esempio"); b.clicked.connect(self._mcp_example); row.addWidget(b)
|
||||||
row.addStretch()
|
row.addStretch()
|
||||||
form_mcp.addRow(row)
|
form_mcp.addRow(row)
|
||||||
self.mcp_hint = QLabel(mcp_manager.status()); self.mcp_hint.setWordWrap(True); form_mcp.addRow(self.mcp_hint)
|
self.mcp_hint = QLabel(mcp_manager.status()); self.mcp_hint.setWordWrap(True); self.mcp_hint.setMinimumWidth(200); form_mcp.addRow(self.mcp_hint)
|
||||||
add(pg_tool, form_mcp)
|
add(pg_tool, form_mcp)
|
||||||
|
|
||||||
# ── Immagini (mflux) ──────────────────────────────────────────────
|
# ── Immagini (mflux) ──────────────────────────────────────────────
|
||||||
form_img = QFormLayout()
|
form_img = QFormLayout()
|
||||||
form_img.addRow(QLabel("Generazione immagini in locale (mflux, MLX). Il primo uso scarica il modello da Hugging Face."))
|
form_img.addRow(_note("Generazione immagini in locale (mflux, MLX). Il primo uso scarica il modello da Hugging Face."))
|
||||||
self.img_fam = _combo([("z-image-turbo", "Z-Image Turbo (veloce, 8 passi, consigliato)"), ("schnell", "FLUX.1 schnell (4 passi)"), ("dev", "FLUX.1 dev (lento, licenza non commerciale)"), ("qwen", "Qwen-Image (pesante, ottimo col testo)")], s.get("immagini_famiglia") or "z-image-turbo")
|
self.img_fam = _combo([("z-image-turbo", "Z-Image Turbo (veloce, 8 passi, consigliato)"), ("schnell", "FLUX.1 schnell (4 passi)"), ("dev", "FLUX.1 dev (lento, licenza non commerciale)"), ("qwen", "Qwen-Image (pesante, ottimo col testo)")], s.get("immagini_famiglia") or "z-image-turbo")
|
||||||
form_img.addRow("Famiglia", self.img_fam)
|
form_img.addRow("Famiglia", self.img_fam)
|
||||||
self.img_model = QLineEdit(str(s.get("immagini_modello") or "")); self.img_model.setPlaceholderText("vuoto = predefinito (es. mflux-community/z-image-turbo-mflux-q4)")
|
self.img_model = QComboBox(); self.img_model.setEditable(True)
|
||||||
form_img.addRow("Modello (repo Hugging Face)", self.img_model)
|
try:
|
||||||
|
sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "plugins"))
|
||||||
|
import importlib
|
||||||
|
self.img_model.addItems([""] + importlib.import_module("immagini").cached_image_models())
|
||||||
|
except Exception:
|
||||||
|
self.img_model.addItem("")
|
||||||
|
self.img_model.setEditText(str(s.get("immagini_modello") or ""))
|
||||||
|
self.img_model.setSizeAdjustPolicy(QComboBox.SizeAdjustPolicy.AdjustToMinimumContentsLengthWithIcon); self.img_model.setMinimumContentsLength(30)
|
||||||
|
self.img_model.lineEdit().setPlaceholderText("vuoto = predefinito della famiglia; un nome nuovo viene scaricato al primo uso")
|
||||||
|
form_img.addRow("Modello (elenco: già scaricati)", self.img_model)
|
||||||
add(pg_tool, form_img)
|
add(pg_tool, form_img)
|
||||||
|
|
||||||
btns = QHBoxLayout(); btns.addStretch()
|
btns = QHBoxLayout(); btns.addStretch()
|
||||||
@@ -299,7 +316,8 @@ class SettingsDialog(QDialog):
|
|||||||
outer.addLayout(btns)
|
outer.addLayout(btns)
|
||||||
screen = QApplication.primaryScreen().availableGeometry() if QApplication.primaryScreen() else None
|
screen = QApplication.primaryScreen().availableGeometry() if QApplication.primaryScreen() else None
|
||||||
h = int(screen.height() * 0.85) if screen else 800
|
h = int(screen.height() * 0.85) if screen else 800
|
||||||
self.resize(820, min(900, h))
|
w = min(1000, int(screen.width() * 0.9)) if screen else 1000
|
||||||
|
self.resize(w, min(900, h))
|
||||||
self._async.connect(self._on_async)
|
self._async.connect(self._on_async)
|
||||||
self._check_cc()
|
self._check_cc()
|
||||||
|
|
||||||
@@ -569,7 +587,7 @@ class SettingsDialog(QDialog):
|
|||||||
"server_assist_dir": self.srv_dir.text().strip() or "/opt/aiserverassistance",
|
"server_assist_dir": self.srv_dir.text().strip() or "/opt/aiserverassistance",
|
||||||
"server_assist_bot": self.srv_bot.text().strip().lstrip("@") or "luzaserver_bot",
|
"server_assist_bot": self.srv_bot.text().strip().lstrip("@") or "luzaserver_bot",
|
||||||
"homeassistant_url": self.ha_url.text().strip().rstrip("/"),
|
"homeassistant_url": self.ha_url.text().strip().rstrip("/"),
|
||||||
"immagini_famiglia": self.img_fam.currentData() or "z-image-turbo", "immagini_modello": self.img_model.text().strip(),
|
"immagini_famiglia": self.img_fam.currentData() or "z-image-turbo", "immagini_modello": self.img_model.currentText().strip(),
|
||||||
}
|
}
|
||||||
if self.ha_token.text().strip():
|
if self.ha_token.text().strip():
|
||||||
values["homeassistant_token"] = self.ha_token.text().strip()
|
values["homeassistant_token"] = self.ha_token.text().strip()
|
||||||
|
|||||||
+3
-3
@@ -194,7 +194,7 @@ function drawOverlay() {
|
|||||||
levels.push(dispLevel); levels.shift();
|
levels.push(dispLevel); levels.shift();
|
||||||
const col = COLORS[state.name] || '#00d4ff';
|
const col = COLORS[state.name] || '#00d4ff';
|
||||||
stateEl.style.color = col; stateEl.style.textShadow = `0 0 8px ${col}88`;
|
stateEl.style.color = col; stateEl.style.textShadow = `0 0 8px ${col}88`;
|
||||||
stateEl.textContent = '● ' + state.name;
|
stateEl.textContent = '● ' + (state.label || state.name);
|
||||||
wctx.clearRect(0, 0, wave.width, wave.height);
|
wctx.clearRect(0, 0, wave.width, wave.height);
|
||||||
const n = levels.length, bw = wave.width / n;
|
const n = levels.length, bw = wave.width / n;
|
||||||
for (let i = 0; i < n; i++) {
|
for (let i = 0; i < n; i++) {
|
||||||
@@ -206,8 +206,8 @@ function drawOverlay() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
window.avatar3d = {
|
window.avatar3d = {
|
||||||
update(level, open, width, name) { state.level = level; state.open = open; state.width = width; if (name) state.name = name; },
|
update(level, open, width, name) { state.level = level; state.open = open; state.width = width; if (name) { state.label = name; state.name = name.split(' ')[0]; } },
|
||||||
setState(name) { state.name = name; },
|
setState(name) { state.label = name; state.name = name.split(' ')[0]; },
|
||||||
glance(dx, dy, hold) { smooth.glanceX = dx * 0.3; smooth.glanceY = -dy * 0.2; smooth.glanceUntil = clock.elapsedTime + (hold || 1.1); },
|
glance(dx, dy, hold) { smooth.glanceX = dx * 0.3; smooth.glanceY = -dy * 0.2; smooth.glanceUntil = clock.elapsedTime + (hold || 1.1); },
|
||||||
setFraming(f) { state.framing = f; frame(); },
|
setFraming(f) { state.framing = f; frame(); },
|
||||||
status() { return { loaded: Boolean(model), animation: Boolean(mixer), head: Boolean(head), blendShapes: mouth.hasShapes, morphs: morphMeshes.length, eyes: eyes.length }; },
|
status() { return { loaded: Boolean(model), animation: Boolean(mixer), head: Boolean(head), blendShapes: mouth.hasShapes, morphs: morphMeshes.length, eyes: eyes.length }; },
|
||||||
|
|||||||
+65
-6
@@ -27,6 +27,19 @@ FORMATI = {"quadrata": (1024, 1024), "orizzontale": (1280, 768), "verticale": (7
|
|||||||
_last: dict = {"path": ""}
|
_last: dict = {"path": ""}
|
||||||
|
|
||||||
|
|
||||||
|
def cached_image_models() -> list[str]:
|
||||||
|
"""Modelli per immagini già presenti nella cache di Hugging Face (mflux, FLUX, Z-Image, Qwen-Image)."""
|
||||||
|
hub = Path.home() / ".cache" / "huggingface" / "hub"
|
||||||
|
out = []
|
||||||
|
if hub.exists():
|
||||||
|
for d in sorted(hub.glob("models--*")):
|
||||||
|
name = d.name[len("models--"):].replace("--", "/")
|
||||||
|
low = name.lower()
|
||||||
|
if any(k in low for k in ("mflux", "flux", "z-image", "qwen-image")) and (d / "snapshots").exists():
|
||||||
|
out.append(name)
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
def _cfg() -> tuple[str, str]:
|
def _cfg() -> tuple[str, str]:
|
||||||
s = Settings()
|
s = Settings()
|
||||||
fam = str(s.get("immagini_famiglia") or "z-image-turbo")
|
fam = str(s.get("immagini_famiglia") or "z-image-turbo")
|
||||||
@@ -34,6 +47,55 @@ def _cfg() -> tuple[str, str]:
|
|||||||
return fam, repo
|
return fam, repo
|
||||||
|
|
||||||
|
|
||||||
|
def _progress(ctx: dict, text: str) -> None:
|
||||||
|
"""Mostra l'avanzamento sul volto (stato del HUD) e nel registro."""
|
||||||
|
player = ctx.get("player")
|
||||||
|
if player is not None and hasattr(player, "set_state"):
|
||||||
|
try:
|
||||||
|
player.set_state(f"PROCESSING · {text}")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
if ctx.get("log"):
|
||||||
|
ctx["log"](f"[immagini] {text}")
|
||||||
|
|
||||||
|
|
||||||
|
def _run_with_progress(cmd: list[str], steps: int, ctx: dict, timeout: int = 1800):
|
||||||
|
"""Esegue mflux leggendo la barra di avanzamento (download dei pesi e passi di diffusione)."""
|
||||||
|
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, bufsize=0)
|
||||||
|
buf, lines, last, t0 = "", [], "", time.time()
|
||||||
|
_progress(ctx, "immagine: avvio")
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
ch = proc.stdout.read(1)
|
||||||
|
if not ch:
|
||||||
|
break
|
||||||
|
if time.time() - t0 > timeout:
|
||||||
|
proc.kill()
|
||||||
|
return None, "", ""
|
||||||
|
if ch in ("\r", "\n"):
|
||||||
|
line = buf.strip(); buf = ""
|
||||||
|
if not line:
|
||||||
|
continue
|
||||||
|
lines.append(line)
|
||||||
|
m = re.search(r"Fetching (\d+) files:\s*(\d+)%", line)
|
||||||
|
if m:
|
||||||
|
msg = f"download modello {m.group(2)}%"
|
||||||
|
elif (m := re.search(r"(\d+)/(\d+)\s*\[", line)):
|
||||||
|
k, n = int(m.group(1)), int(m.group(2))
|
||||||
|
msg = f"immagine {k}/{n}" if k < n else "immagine: salvataggio"
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
if msg != last:
|
||||||
|
last = msg
|
||||||
|
_progress(ctx, msg)
|
||||||
|
else:
|
||||||
|
buf += ch
|
||||||
|
finally:
|
||||||
|
proc.wait()
|
||||||
|
tail = " | ".join(l for l in lines[-3:] if "it/s" not in l and "s/it" not in l)
|
||||||
|
return proc, tail, ""
|
||||||
|
|
||||||
|
|
||||||
def genera(params: dict, ctx: dict) -> str:
|
def genera(params: dict, ctx: dict) -> str:
|
||||||
prompt = str(params.get("descrizione", "")).strip()
|
prompt = str(params.get("descrizione", "")).strip()
|
||||||
if not prompt:
|
if not prompt:
|
||||||
@@ -61,16 +123,13 @@ def genera(params: dict, ctx: dict) -> str:
|
|||||||
if ctx.get("log"):
|
if ctx.get("log"):
|
||||||
ctx["log"](f"[immagini] {fam} {w}x{h} {steps} passi: {prompt[:80]}")
|
ctx["log"](f"[immagini] {fam} {w}x{h} {steps} passi: {prompt[:80]}")
|
||||||
t = time.time()
|
t = time.time()
|
||||||
try:
|
proc, tail, err = _run_with_progress(cmd, steps, ctx)
|
||||||
proc = subprocess.run(cmd, capture_output=True, text=True, timeout=1800)
|
if proc is None:
|
||||||
except subprocess.TimeoutExpired:
|
|
||||||
return "Generazione interrotta: troppo lenta (oltre 30 minuti)."
|
return "Generazione interrotta: troppo lenta (oltre 30 minuti)."
|
||||||
if proc.returncode != 0 or not out.exists():
|
if proc.returncode != 0 or not out.exists():
|
||||||
err = (proc.stderr or proc.stdout).strip().splitlines()
|
|
||||||
tail = " | ".join(err[-3:]) if err else f"codice {proc.returncode}"
|
|
||||||
if "not found" in tail.lower() or "401" in tail or "403" in tail:
|
if "not found" in tail.lower() or "401" in tail or "403" in tail:
|
||||||
tail += " (controlla il nome del modello nelle impostazioni, o accetta la licenza su Hugging Face)"
|
tail += " (controlla il nome del modello nelle impostazioni, o accetta la licenza su Hugging Face)"
|
||||||
return f"Generazione fallita: {tail[:400]}"
|
return f"Generazione fallita: {tail[:400] or f'codice {proc.returncode}'}"
|
||||||
_last["path"] = str(out)
|
_last["path"] = str(out)
|
||||||
secs = time.time() - t
|
secs = time.time() - t
|
||||||
if params.get("mostra", True) not in (False, "false", "no"):
|
if params.get("mostra", True) not in (False, "false", "no"):
|
||||||
|
|||||||
@@ -632,7 +632,7 @@ class HudCanvas(QWidget):
|
|||||||
# either way because the animation state keeps stepping at 60 Hz.
|
# either way because the animation state keeps stepping at 60 Hz.
|
||||||
self._paint_tick = (self._paint_tick + 1) % 6
|
self._paint_tick = (self._paint_tick + 1) % 6
|
||||||
active = (self.speaking or amp > 0.02
|
active = (self.speaking or amp > 0.02
|
||||||
or self.state in ("THINKING", "PROCESSING"))
|
or self.state.split(" ")[0] in ("THINKING", "PROCESSING"))
|
||||||
if _blinked or (self._paint_tick % 2 == 0 if active
|
if _blinked or (self._paint_tick % 2 == 0 if active
|
||||||
else self._paint_tick % 3 == 0):
|
else self._paint_tick % 3 == 0):
|
||||||
# Nothing is on screen when the window is hidden or minimised, so
|
# Nothing is on screen when the window is hidden or minimised, so
|
||||||
@@ -665,9 +665,9 @@ class HudCanvas(QWidget):
|
|||||||
return qcol(C.MUTED_C), qcol(C.MUTED_C)
|
return qcol(C.MUTED_C), qcol(C.MUTED_C)
|
||||||
if self.speaking:
|
if self.speaking:
|
||||||
return qcol(C.PRI), qcol(C.ACC)
|
return qcol(C.PRI), qcol(C.ACC)
|
||||||
if self.state in ("THINKING", "PROCESSING"):
|
if self.state.split(" ")[0] in ("THINKING", "PROCESSING"):
|
||||||
return qcol(C.PRI), qcol(C.ACC2)
|
return qcol(C.PRI), qcol(C.ACC2)
|
||||||
if self.state == "LISTENING":
|
if self.state.split(" ")[0] == "LISTENING":
|
||||||
return qcol(C.PRI), qcol(C.GREEN)
|
return qcol(C.PRI), qcol(C.GREEN)
|
||||||
return qcol(C.PRI), qcol(C.PRI_DIM)
|
return qcol(C.PRI), qcol(C.PRI_DIM)
|
||||||
|
|
||||||
@@ -763,7 +763,7 @@ class HudCanvas(QWidget):
|
|||||||
# 6. Sweeping arcs. Long spans, not dashes — the original's grandeur
|
# 6. Sweeping arcs. Long spans, not dashes — the original's grandeur
|
||||||
# came from a few big strokes. Speed is the state: idle drifts,
|
# came from a few big strokes. Speed is the state: idle drifts,
|
||||||
# thinking hurries, speaking runs.
|
# thinking hurries, speaking runs.
|
||||||
rate = 1.0 + (1.9 if self.state in ("THINKING", "PROCESSING") else 0.0) \
|
rate = 1.0 + (1.9 if self.state.split(" ")[0] in ("THINKING", "PROCESSING") else 0.0) \
|
||||||
+ (1.2 if self.speaking else 0.0)
|
+ (1.2 if self.speaking else 0.0)
|
||||||
for k, (rr, span, count, dirn, col, a, wid) in enumerate((
|
for k, (rr, span, count, dirn, col, a, wid) in enumerate((
|
||||||
(0.955, 118, 2, +1, acc, 0.75, 2.0),
|
(0.955, 118, 2, +1, acc, 0.75, 2.0),
|
||||||
@@ -852,9 +852,9 @@ class HudCanvas(QWidget):
|
|||||||
_main = qcol(C.PRI)
|
_main = qcol(C.PRI)
|
||||||
if self.speaking:
|
if self.speaking:
|
||||||
_acc = qcol(C.ACC)
|
_acc = qcol(C.ACC)
|
||||||
elif self.state in ("THINKING", "PROCESSING"):
|
elif self.state.split(" ")[0] in ("THINKING", "PROCESSING"):
|
||||||
_acc = qcol(C.ACC2)
|
_acc = qcol(C.ACC2)
|
||||||
elif self.state == "LISTENING":
|
elif self.state.split(" ")[0] == "LISTENING":
|
||||||
_acc = qcol(C.GREEN)
|
_acc = qcol(C.GREEN)
|
||||||
else:
|
else:
|
||||||
_acc = qcol(C.PRI)
|
_acc = qcol(C.PRI)
|
||||||
@@ -882,7 +882,7 @@ class HudCanvas(QWidget):
|
|||||||
elif self.state == "PROCESSING":
|
elif self.state == "PROCESSING":
|
||||||
sym = "▷" if self._blink else "▶"
|
sym = "▷" if self._blink else "▶"
|
||||||
txt, col = f"{sym} PROCESSING", qcol(C.ACC2)
|
txt, col = f"{sym} PROCESSING", qcol(C.ACC2)
|
||||||
elif self.state == "LISTENING":
|
elif self.state.split(" ")[0] == "LISTENING":
|
||||||
sym = "●" if self._blink else "○"
|
sym = "●" if self._blink else "○"
|
||||||
txt, col = f"{sym} LISTENING", qcol(C.GREEN)
|
txt, col = f"{sym} LISTENING", qcol(C.GREEN)
|
||||||
else:
|
else:
|
||||||
|
|||||||
Reference in new issue
Block a user