Update TOOLS.md, cron jobs, KB index; add discord file sender + pocket-tts plan
Pre-existing work committed before starting Ralph self-improvement run on ralph/echo-improve branch, so that branch's diff stays isolated to the pocket-tts integration. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
70
tools/discord_send_file.py
Normal file
70
tools/discord_send_file.py
Normal file
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Trimite un fișier (audio, imagine, etc.) direct într-un canal Discord.
|
||||
|
||||
De ce există: `__AUDIO__:<path>` (folosit de fast_commands.py) e interceptat
|
||||
de discord_bot.py DOAR când niciun bloc de text n-a fost deja streamat pe
|
||||
canal în turul curent. Într-un răspuns conversațional normal (acest proces,
|
||||
`claude_session.py`), fiecare bloc de text pe care Claude îl produce e
|
||||
trimis live prin `on_text` înainte ca răspunsul final să fie evaluat —
|
||||
deci prefixul `__AUDIO__:` ajunge mereu trimis ca text brut, nu convertit
|
||||
în attachment. Singura cale de a atașa un fișier dintr-un răspuns Claude
|
||||
obișnuit e apelul direct la REST API-ul Discord, cu tokenul botului.
|
||||
|
||||
CLI:
|
||||
python3 tools/discord_send_file.py --channel <id> --file /path/audio.wav [--text "mesaj"]
|
||||
|
||||
Modul:
|
||||
from tools.discord_send_file import send_file
|
||||
send_file(channel_id, "/path/audio.wav", content="mesaj opțional")
|
||||
|
||||
Channel ID: dacă nu-l știi din conversație, citește `sessions/active.json`
|
||||
(cheia e channel_id-ul; de obicei există o singură sesiune activă).
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import mimetypes
|
||||
import sys
|
||||
|
||||
import httpx
|
||||
|
||||
sys.path.insert(0, "/home/moltbot/echo-core")
|
||||
from src.credential_store import get_secret
|
||||
|
||||
|
||||
def send_file(channel_id: str, path: str, content: str | None = None, filename: str | None = None) -> dict:
|
||||
"""Trimite un fișier direct pe canalul Discord dat, via REST API.
|
||||
|
||||
Returns: {"ok": True, "message_id": "..."} sau {"ok": False, "error": "..."}
|
||||
"""
|
||||
token = get_secret("discord_token")
|
||||
if not token:
|
||||
return {"ok": False, "error": "discord_token lipsește din keyring (echo-core)."}
|
||||
|
||||
filename = filename or path.rsplit("/", 1)[-1]
|
||||
mime = mimetypes.guess_type(filename)[0] or "application/octet-stream"
|
||||
|
||||
try:
|
||||
with httpx.Client(timeout=30) as client, open(path, "rb") as f:
|
||||
resp = client.post(
|
||||
f"https://discord.com/api/v10/channels/{channel_id}/messages",
|
||||
headers={"Authorization": f"Bot {token}"},
|
||||
files={"file": (filename, f, mime)},
|
||||
data={"content": content} if content else {},
|
||||
)
|
||||
if resp.status_code not in (200, 201):
|
||||
return {"ok": False, "error": f"HTTP {resp.status_code}: {resp.text[:300]}"}
|
||||
return {"ok": True, "message_id": resp.json().get("id")}
|
||||
except Exception as e:
|
||||
return {"ok": False, "error": str(e)}
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="Trimite un fișier direct pe un canal Discord")
|
||||
parser.add_argument("--channel", required=True, help="Channel ID Discord")
|
||||
parser.add_argument("--file", required=True, help="Cale către fișierul de trimis")
|
||||
parser.add_argument("--text", default=None, help="Text opțional care însoțește fișierul")
|
||||
args = parser.parse_args()
|
||||
|
||||
result = send_file(args.channel, args.file, content=args.text)
|
||||
print(result)
|
||||
sys.exit(0 if result.get("ok") else 1)
|
||||
Reference in New Issue
Block a user