Compare commits
4 Commits
3dd2ddbd6a
...
44cf0001bb
| Author | SHA1 | Date | |
|---|---|---|---|
| 44cf0001bb | |||
| 574f9be5ea | |||
| 0d2d5b860d | |||
| 8fe39adc01 |
@@ -269,9 +269,9 @@
|
|||||||
"prompt": "Heartbeat check. Rulează src/heartbeat.py printr-un scurt raport de status.\nDacă nu e nimic de raportat (email=0, calendar nu are evenimente <2h, kb ok), răspunde doar cu HEARTBEAT_OK și oprește-te — nu trimite mesaj.\nDacă e ceva: raport scurt pe Discord #echo-work.",
|
"prompt": "Heartbeat check. Rulează src/heartbeat.py printr-un scurt raport de status.\nDacă nu e nimic de raportat (email=0, calendar nu are evenimente <2h, kb ok), răspunde doar cu HEARTBEAT_OK și oprește-te — nu trimite mesaj.\nDacă e ceva: raport scurt pe Discord #echo-work.",
|
||||||
"allowed_tools": [],
|
"allowed_tools": [],
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"last_run": "2026-05-26T18:00:00.002989+00:00",
|
"last_run": "2026-05-27T06:00:00.002154+00:00",
|
||||||
"last_status": "error",
|
"last_status": "ok",
|
||||||
"next_run": "2026-05-27T06:00:00+00:00"
|
"next_run": "2026-05-27T08:00:00+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "night-execute",
|
"name": "night-execute",
|
||||||
|
|||||||
BIN
image copy.png
BIN
image copy.png
Binary file not shown.
|
Before Width: | Height: | Size: 63 KiB |
@@ -909,6 +909,55 @@ def create_bot(config: Config) -> discord.Client:
|
|||||||
f"Error reading logs: {e}", ephemeral=True
|
f"Error reading logs: {e}", ephemeral=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@tree.command(name="audio", description="TTS: convertește text sau URL în voice note")
|
||||||
|
@app_commands.describe(
|
||||||
|
voce="Voce (M1-M5 masculin, F1-F5 feminin; default M2)",
|
||||||
|
text_sau_url="Text direct, URL articol, sau gol pentru ultimul răspuns Echo",
|
||||||
|
rezumat="Dacă să facă Claude rezumat înainte de TTS (doar pentru URL)",
|
||||||
|
)
|
||||||
|
@app_commands.choices(
|
||||||
|
voce=[
|
||||||
|
app_commands.Choice(name="M1 — Masculin 1", value="M1"),
|
||||||
|
app_commands.Choice(name="M2 — Masculin 2 (default)", value="M2"),
|
||||||
|
app_commands.Choice(name="M3 — Masculin 3", value="M3"),
|
||||||
|
app_commands.Choice(name="M4 — Masculin 4", value="M4"),
|
||||||
|
app_commands.Choice(name="M5 — Masculin 5", value="M5"),
|
||||||
|
app_commands.Choice(name="F1 — Feminin 1", value="F1"),
|
||||||
|
app_commands.Choice(name="F2 — Feminin 2", value="F2"),
|
||||||
|
app_commands.Choice(name="F3 — Feminin 3", value="F3"),
|
||||||
|
app_commands.Choice(name="F4 — Feminin 4", value="F4"),
|
||||||
|
app_commands.Choice(name="F5 — Feminin 5", value="F5"),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
async def audio_cmd(
|
||||||
|
interaction: discord.Interaction,
|
||||||
|
voce: str | None = None,
|
||||||
|
text_sau_url: str | None = None,
|
||||||
|
rezumat: bool = False,
|
||||||
|
) -> None:
|
||||||
|
await interaction.response.defer()
|
||||||
|
args: list[str] = []
|
||||||
|
if voce:
|
||||||
|
args.append(voce)
|
||||||
|
if text_sau_url:
|
||||||
|
args.extend(text_sau_url.split())
|
||||||
|
if rezumat:
|
||||||
|
args.append("rezumat")
|
||||||
|
result = await asyncio.to_thread(fast_dispatch, "audio", args)
|
||||||
|
if result and result.startswith("__AUDIO__:"):
|
||||||
|
wav_path = result[len("__AUDIO__:"):]
|
||||||
|
try:
|
||||||
|
await interaction.followup.send(
|
||||||
|
file=discord.File(wav_path, filename="echo-audio.wav")
|
||||||
|
)
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
os.unlink(wav_path)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
await interaction.followup.send(result or "Eroare TTS.")
|
||||||
|
|
||||||
# --- Ralph commands (autonomous project execution) ---
|
# --- Ralph commands (autonomous project execution) ---
|
||||||
|
|
||||||
async def _autocomplete_by_status(
|
async def _autocomplete_by_status(
|
||||||
|
|||||||
@@ -1135,7 +1135,7 @@ def create_telegram_bot(config: Config, token: str) -> Application:
|
|||||||
BotCommand("logs", "Show log lines"),
|
BotCommand("logs", "Show log lines"),
|
||||||
BotCommand("doctor", "Diagnostics"),
|
BotCommand("doctor", "Diagnostics"),
|
||||||
BotCommand("heartbeat", "Health checks"),
|
BotCommand("heartbeat", "Health checks"),
|
||||||
BotCommand("audio", "TTS: text → voice note"),
|
BotCommand("audio", "TTS: text/url → voice note [voce] [rezumat]"),
|
||||||
BotCommand("p", "Ralph: propose new project"),
|
BotCommand("p", "Ralph: propose new project"),
|
||||||
BotCommand("a", "Ralph: approve project for tonight"),
|
BotCommand("a", "Ralph: approve project for tonight"),
|
||||||
BotCommand("l", "Ralph: list projects status"),
|
BotCommand("l", "Ralph: list projects status"),
|
||||||
|
|||||||
@@ -691,9 +691,9 @@ Reminders:
|
|||||||
Audio:
|
Audio:
|
||||||
/audio <text> — TTS pe text
|
/audio <text> — TTS pe text
|
||||||
/audio <url> — Extrage articol → audio
|
/audio <url> — Extrage articol → audio
|
||||||
/audio rezumat <url> — Rezumat Claude → audio
|
/audio <url> rezumat — Rezumat Claude → audio (flag oriunde)
|
||||||
/audio — Ultimul răspuns Echo → audio
|
/audio — Ultimul răspuns Echo → audio
|
||||||
/audio M2 [text|url|gol] — Voce specificată (M1-M5, F1-F5)
|
/audio M2 [text|url] [rezumat] — Voce specificată (M1-M5, F1-F5)
|
||||||
/audio ajutor — Ajutor detaliat
|
/audio ajutor — Ajutor detaliat
|
||||||
|
|
||||||
Ops:
|
Ops:
|
||||||
@@ -728,7 +728,7 @@ def cmd_audio(args: list[str]) -> str:
|
|||||||
/audio M2 [text|url|gol] → voce specificată (M1-M5, F1-F5)
|
/audio M2 [text|url|gol] → voce specificată (M1-M5, F1-F5)
|
||||||
/audio ajutor → ajutor
|
/audio ajutor → ajutor
|
||||||
"""
|
"""
|
||||||
voice = "M1"
|
voice = "M2"
|
||||||
remaining = list(args)
|
remaining = list(args)
|
||||||
|
|
||||||
# Detectare voce ca prim token
|
# Detectare voce ca prim token
|
||||||
@@ -736,6 +736,12 @@ def cmd_audio(args: list[str]) -> str:
|
|||||||
voice = remaining[0].upper()
|
voice = remaining[0].upper()
|
||||||
remaining = remaining[1:]
|
remaining = remaining[1:]
|
||||||
|
|
||||||
|
# Detectare flag "rezumat" oriunde în args (indiferent de ordine)
|
||||||
|
do_summarize = False
|
||||||
|
if any(t.lower() == "rezumat" for t in remaining):
|
||||||
|
do_summarize = True
|
||||||
|
remaining = [t for t in remaining if t.lower() != "rezumat"]
|
||||||
|
|
||||||
channel_id = _get_ctx_channel()
|
channel_id = _get_ctx_channel()
|
||||||
|
|
||||||
# Determinare text sursă
|
# Determinare text sursă
|
||||||
@@ -752,25 +758,24 @@ def cmd_audio(args: list[str]) -> str:
|
|||||||
"🎙️ /audio — Text-to-Speech local (Supertonic)\n\n"
|
"🎙️ /audio — Text-to-Speech local (Supertonic)\n\n"
|
||||||
" /audio <text> — TTS pe text dat\n"
|
" /audio <text> — TTS pe text dat\n"
|
||||||
" /audio <url> — extrage articol → audio\n"
|
" /audio <url> — extrage articol → audio\n"
|
||||||
" /audio rezumat <url> — rezumat Claude → audio\n"
|
" /audio <url> rezumat — rezumat Claude → audio\n"
|
||||||
" /audio — ultimul răspuns Echo → audio\n"
|
" /audio — ultimul răspuns Echo → audio\n"
|
||||||
" /audio M2 <...> — voce specifică (M1-M5, F1-F5)\n\n"
|
" /audio M2 [text|url] [rezumat] — voce specifică (M1-M5, F1-F5)\n\n"
|
||||||
|
"Flag rezumat: poate fi pus oriunde în comandă\n"
|
||||||
|
" /audio rezumat <url> ≡ /audio <url> rezumat ≡ /audio M2 <url> rezumat\n\n"
|
||||||
"Voci: M1 M2 M3 M4 M5 (masculin) · F1 F2 F3 F4 F5 (feminin)"
|
"Voci: M1 M2 M3 M4 M5 (masculin) · F1 F2 F3 F4 F5 (feminin)"
|
||||||
)
|
)
|
||||||
|
|
||||||
elif (len(remaining) >= 2
|
elif len(remaining) == 1 and remaining[0].startswith("http"):
|
||||||
and remaining[0].lower() == "rezumat"
|
url = remaining[0]
|
||||||
and remaining[1].startswith("http")):
|
if do_summarize:
|
||||||
url = remaining[1]
|
|
||||||
extracted = _extract_url_text(url)
|
extracted = _extract_url_text(url)
|
||||||
if not extracted:
|
if not extracted:
|
||||||
return f"Nu am putut extrage text din URL: {url}"
|
return f"Nu am putut extrage text din URL: {url}"
|
||||||
text = _claude_summarize(extracted)
|
text = _claude_summarize(extracted)
|
||||||
if not text:
|
if not text:
|
||||||
return "Rezumatul a eșuat. Încearcă /audio <url> pentru extragere directă."
|
return "Rezumatul a eșuat. Încearcă /audio <url> pentru extragere directă."
|
||||||
|
else:
|
||||||
elif len(remaining) == 1 and remaining[0].startswith("http"):
|
|
||||||
url = remaining[0]
|
|
||||||
text = _extract_url_text(url)
|
text = _extract_url_text(url)
|
||||||
if not text:
|
if not text:
|
||||||
return f"Nu am putut extrage text din URL: {url}"
|
return f"Nu am putut extrage text din URL: {url}"
|
||||||
@@ -800,7 +805,7 @@ def _tts_synthesize(text: str, voice: str) -> dict:
|
|||||||
import tts as _tts_mod
|
import tts as _tts_mod
|
||||||
# Re-import pentru a prinde modificări la hot-reload
|
# Re-import pentru a prinde modificări la hot-reload
|
||||||
importlib.reload(_tts_mod)
|
importlib.reload(_tts_mod)
|
||||||
return _tts_mod.synthesize(text, voice=voice)
|
return _tts_mod.synthesize(text, voice=voice, lang="ro")
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
return {"ok": False, "error": f"tools/tts.py nu poate fi importat: {e}"}
|
return {"ok": False, "error": f"tools/tts.py nu poate fi importat: {e}"}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import httpx
|
|||||||
|
|
||||||
SUPERTONIC_URL = "http://127.0.0.1:7788"
|
SUPERTONIC_URL = "http://127.0.0.1:7788"
|
||||||
VOICES = {"M1", "M2", "M3", "M4", "M5", "F1", "F2", "F3", "F4", "F5"}
|
VOICES = {"M1", "M2", "M3", "M4", "M5", "F1", "F2", "F3", "F4", "F5"}
|
||||||
DEFAULT_VOICE = "M1"
|
DEFAULT_VOICE = "M2"
|
||||||
DEFAULT_LANG = "ro"
|
DEFAULT_LANG = "ro"
|
||||||
|
|
||||||
|
|
||||||
@@ -46,6 +46,7 @@ def synthesize(text: str, voice: str = DEFAULT_VOICE, lang: str = DEFAULT_LANG)
|
|||||||
"input": text,
|
"input": text,
|
||||||
"voice": voice,
|
"voice": voice,
|
||||||
"response_format": "wav",
|
"response_format": "wav",
|
||||||
|
"lang": lang,
|
||||||
},
|
},
|
||||||
timeout=60.0,
|
timeout=60.0,
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user