| import os |
| import time |
| import json |
| import base64 |
| import requests |
| import tempfile |
| import threading |
| import queue |
| import winsound |
|
|
| TRANSCRIPT_PATH = r"C:\Users\nasko\.gemini\antigravity\brain\695897cf-1c58-4886-a686-e9d8c406ebef\.system_generated\logs\transcript.jsonl" |
| API_URL = "http://localhost:8000/api/v1/synthesize/stream" |
|
|
| audio_queue = queue.Queue() |
|
|
| def player_worker(): |
| """ |
| Взима готови WAV файлове от опашката и ги пуска. |
| """ |
| while True: |
| file_path = audio_queue.get() |
| if file_path is None: break |
| |
| print(f"🔊 Възпроизвеждам от API...") |
| winsound.PlaySound(file_path, winsound.SND_FILENAME) |
| |
| try: |
| os.remove(file_path) |
| except OSError: |
| pass |
| |
| audio_queue.task_done() |
|
|
| def process_text(text: str): |
| """ |
| Изпраща текста към API-то и чака за стрийминг на аудио парчета. |
| """ |
| print(f"📡 Изпращане към API: {text[:50]}...") |
| try: |
| response = requests.post(API_URL, json={ |
| "text": text, |
| "voice_style": "F5", |
| "speed": 1.6 |
| }, stream=True) |
| |
| if response.status_code != 200: |
| print(f"Грешка от API: {response.status_code} - {response.text}") |
| return |
| |
| for line in response.iter_lines(): |
| if line: |
| data = json.loads(line) |
| if "error" in data: |
| print(f"API Грешка: {data['error']}") |
| continue |
| |
| chunk_index = data.get("chunk_index") |
| audio_base64 = data.get("audio_base64") |
| |
| if audio_base64: |
| audio_bytes = base64.b64decode(audio_base64) |
| |
| |
| fd, file_path = tempfile.mkstemp(suffix=f"_chunk_{chunk_index}.wav") |
| os.close(fd) |
| |
| with open(file_path, "wb") as f: |
| f.write(audio_bytes) |
| |
| audio_queue.put(file_path) |
| except requests.exceptions.ConnectionError: |
| print("Не мога да се свържа с API-то! Увери се, че `api.py` работи на порт 8000.") |
| except Exception as e: |
| print(f"Грешка при комуникация с API: {e}") |
|
|
| def tail_file(): |
| """ |
| Следи чата (transcript.jsonl) за нови съобщения от модела. |
| """ |
| if not os.path.exists(TRANSCRIPT_PATH): |
| print(f"Файлът не съществува: {TRANSCRIPT_PATH}") |
| return |
| |
| with open(TRANSCRIPT_PATH, "r", encoding="utf-8") as f: |
| f.seek(0, 2) |
| |
| while True: |
| line = f.readline() |
| if not line: |
| time.sleep(0.5) |
| continue |
| |
| try: |
| data = json.loads(line) |
| if data.get("source") == "MODEL" and data.get("type") in ["PLANNER_RESPONSE", "GENERIC"]: |
| full_text = data.get("content", "") |
| if full_text and not full_text.startswith("Created At:"): |
| print("\n📝 Получен нов текст от чата.") |
| process_text(full_text) |
| except Exception as e: |
| pass |
|
|
| if __name__ == "__main__": |
| t_play = threading.Thread(target=player_worker, daemon=True) |
| t_play.start() |
| |
| print("Ani Voice Client слуша за съобщения и чака API-то...") |
| tail_file() |
|
|