ElevenLabs Voice Configuration
Создано: 31 декабря 2024 г.
Создано: 31 декабря 2024 г.
Enhancing voice capabilities
I’m thinking through options to resolve the voice ID detection issue in ElevenLabs. It’s interesting to see the potential for a new function that specifically checks voices from Eleven Labs to ensure a human-like female voice.
Enhancing voice functionality
I’m setting up environment variables for Eleven Labs and tweaking the get_voice_id function to support existing or new voices. Also, boosting AI/ML query capabilities for better integration.
Expanding capabilities
I’m enhancing the AI/ML function with real-time conversation, concurrency, and streaming. Ready to provide code or instructions for a human-like female voice, using get_voice_id for voice selection.
Refining and detailing
I’m narrowing down to detailed suggestions for TTS model tweaks, advanced AI function integration, and error handling. A final code snippet will showcase the enhancements.
Thought about voice selection and AI interaction per 6 secondi
Ecco alcuni suggerimenti e modifiche per risolvere i problemi principali e migliorare sia la parte vocale (TTS) con un timbro femminile più “umano” sia l’interazione con l’AI/ML.
Prima di tutto, è importante controllare quali voci siano effettivamente disponibili sull’account ElevenLabs associato alla tua chiave API. Se “Bella” non viene trovata, è probabile che quell’account non disponga di una voce denominata così, oppure il nome non corrisponda esattamente.
Puoi modificare la funzione get_voice_id
in modo da stampare a schermo (o nel log) tutte le voci disponibili e scegliere manualmente quella che preferisci. Ad esempio:
def get_voice_id(voice_name="Bella"): headers = { 'xi-api-key': API_KEYS["elevenlabs"], } try: response = requests.get("https://api.elevenlabs.io/v1/voices", headers=headers) if response.status_code == 200: voices = response.json().get("voices", []) # Stampa tutte le voci disponibili per identificare i nomi print("Voci disponibili su questo account:") for v in voices: print(f"Nome voce: {v['name']} - ID: {v['voice_id']}") # Cerca la voce desiderata for voice in voices: if voice["name"].lower() == voice_name.lower(): return voice["voice_id"] logging.error(f"Voce '{voice_name}' non trovata.") speak("Mi spiace, non ho trovato questa voce.") else: logging.error(f"Errore nel recupero delle voci: {response.json()}") speak("Errore nel recupero delle voci.") except Exception as e: logging.error(f"Errore nella richiesta delle voci: {e}") speak("Errore nella richiesta delle voci.") return None
voice_id = get_voice_id("Rachel")
Assicurati di scrivere esattamente il nome come appare in console.
Se vuoi che la voce gestisca bene l’italiano in modo più naturale, puoi sostituire "eleven_monolingual_v1"
con "eleven_multilingual_v1"
o con il modello più recente se ne hai accesso (verifica nella documentazione ElevenLabs). Ad esempio:
payload = { "text": text, "model_id": "eleven_multilingual_v1", "voice_settings": { "stability": 0.75, "similarity_boost": 0.75 } }
Se la voce risulta ancora un po’ artificiale, puoi giocare con i parametri stability
e similarity_boost
(vanno da 0.0 a 1.0) per regolare la naturalezza dell’intonazione. Più stability
è alta, più la voce resterà “controllata”; più similarity_boost
è alta, più cercherà di imitare fedelmente il timbro originale della voce registrata da ElevenLabs.
La tua funzione ai_ml_query
al momento fa una chiamata POST generica verso un endpoint (ad esempio "https://aimlapi.com/api/query"
). Per migliorarla:
Ad esempio, modificando la funzione:
def ai_ml_query(): """Invia una domanda a un'API AI e restituisce la risposta.""" speak("Qual è la tua domanda per l'AI?") user_query = take_command() if not user_query: speak("Non ho sentito alcuna domanda.") return try: response = requests.post( "https://aimlapi.com/api/query", # URL dell'API AI/ML headers={ "Authorization": f"Bearer {API_KEYS['ai_ml']}", "Content-Type": "application/json" }, json={"query": user_query} ) if response.status_code == 200: data = response.json() answer = data.get("response", "Non ho trovato una risposta.") speak(answer) else: logging.error(f"Errore nella richiesta AI/ML: {response.text}") speak("Mi dispiace, c'è stato un problema con la richiesta all'AI.") except requests.exceptions.Timeout: speak("La richiesta all'AI è scaduta, riprova più tardi.") except requests.exceptions.RequestException as e: logging.error(f"Errore nella richiesta AI: {e}") speak("Errore nella richiesta all'AI. Controlla la connessione o riprova più tardi.")
Suggerimento: se hai un endpoint diverso (ad esempio un GPT-like), puoi integrare la streaming API (se disponibile) per restituire testo in tempo reale, rendendo la conversazione più naturale. Dipende da quali funzionalità e parametri l’endpoint AI/ML mette a disposizione.
r.listen(source, timeout=10)
, potresti voler gestire meglio i casi in cui l’utente non parla.command_thread = threading.Thread(...)
) per gestire comandi e animazione in parallelo. Fai attenzione a eventuali blocchi: se un thread rimane in stallo, potresti dover usare meccanismi di sincronizzazione o kill.logging.debug(...)
con logging.setLevel(logging.DEBUG)
durante lo sviluppo, per poi tornare a INFO
o WARNING
in produzione.Sotto un estratto di come potrebbe apparire il tuo codice rivisto con i principali cambiamenti (voce femminile e AI/ML):
import os import logging import requests import io from pydub import AudioSegment from pydub.playback import play import speech_recognition as sr from datetime import datetime import webbrowser import random import psutil import tkinter as tk from time import sleep import threading ASSISTANT_NAME = "Gideon" ACTIVATION_COMMANDS = ["gideon", "gideo", "gideoun", "gigget", "g", "gide", "giddy"] API_KEYS = { "news": "", "weather": "", "elevenlabs": "", "ai_ml": "" } logging.basicConfig(level=logging.INFO) def get_voice_id(voice_name="Rachel"): headers = { 'xi-api-key': API_KEYS["elevenlabs"], } try: response = requests.get("https://api.elevenlabs.io/v1/voices", headers=headers) if response.status_code == 200: voices = response.json().get("voices", []) # Stampa le voci disponibili print("Voci disponibili:") for v in voices: print(f" - {v['name']} (ID: {v['voice_id']})") for voice in voices: if voice["name"].lower() == voice_name.lower(): return voice["voice_id"] logging.error(f"Voce '{voice_name}' non trovata. Usa uno dei nomi sopra indicati.") speak("Mi dispiace, non ho trovato quella voce.") else: logging.error(f"Errore nel recupero delle voci: {response.json()}") speak("Errore nel recupero delle voci dall'API ElevenLabs.") except Exception as e: logging.error(f"Errore nella richiesta delle voci: {e}") speak("Errore nella richiesta delle voci.") return None def speak(text): voice_id = get_voice_id("Rachel") # <-- Scegli la voce femminile che preferisci (es. "Rachel") if not voice_id: # Voce non trovata, esci dalla funzione return headers = { 'xi-api-key': API_KEYS["elevenlabs"], 'Content-Type': 'application/json' } payload = { "text": text, "model_id": "eleven_multilingual_v1", # Migliore per l'italiano "voice_settings": { "stability": 0.75, "similarity_boost": 0.75 } } try: url = f"https://api.elevenlabs.io/v1/text-to-speech/{voice_id}" response = requests.post(url, headers=headers, json=payload) if response.status_code == 200: audio = AudioSegment.from_file(io.BytesIO(response.content), format="mp3") play(audio) else: logging.error(f"Errore nella richiesta TTS: {response.text}") print(f"Errore nella richiesta TTS: {response.text}") except Exception as e: logging.error(f"Errore nella riproduzione audio: {e}") print("Errore nella riproduzione audio.") def take_command(): with sr.Microphone() as source: r = sr.Recognizer() r.adjust_for_ambient_noise(source) try: print("Ascoltando...") audio = r.listen(source, timeout=10) return r.recognize_google(audio, language='it-IT').lower() except Exception as e: logging.error(f"Errore durante l'acquisizione vocale: {e}") return "" def is_activation_command(command): return any(cmd in command for cmd in ACTIVATION_COMMANDS) def weather(): speak("Dimmi la città.") city = take_command() if not city: return try: res = requests.get( f"http://api.openweathermap.org/data/2.5/weather?q={city}&appid={API_KEYS['weather']}&units=metric&lang=it" ).json() if res.get("cod") == 200: speak(f"{res['weather'][0]['description']} con {res['main']['temp']} gradi a {city}.") else: speak("Città non trovata.") except Exception as e: logging.error(f"Errore nel recupero meteo: {e}") speak("Errore nel recupero meteo.") def ai_ml_query(): speak("Qual è la tua domanda per l'AI?") user_query = take_command() if not user_query: speak("Non ho sentito alcuna domanda.") return try: response = requests.post( "https://aimlapi.com/api/query", headers={ "Authorization": f"Bearer {API_KEYS['ai_ml']}", "Content-Type": "application/json" }, json={"query": user_query} ) if response.status_code == 200: data = response.json() answer = data.get("response", "Non ho trovato una risposta.") speak(answer) else: logging.error(f"Errore nella richiesta AI/ML: {response.text}") speak("Mi dispiace, c'è stato un problema con la richiesta all'AI.") except requests.exceptions.Timeout: speak("La richiesta all'AI è scaduta, riprova più tardi.") except requests.exceptions.RequestException as e: logging.error(f"Errore nella richiesta AI: {e}") speak("Errore nella richiesta all'AI. Controlla la connessione o riprova più tardi.") def fetch_news(): # ... come da tuo codice ... pass def monitor_resources(): # ... come da tuo codice ... pass def open_webpage(): # ... come da tuo codice ... pass def create_animation_window(): # ... come da tuo codice ... pass def handle_command(command): if is_activation_command(command): speak("Come posso aiutarti?") sub_cmd = take_command() if "esci" in sub_cmd: speak("Arrivederci.") os._exit(0) elif "meteo" in sub_cmd: weather() elif "notizie" in sub_cmd: fetch_news() elif "ai" in sub_cmd: ai_ml_query() elif "risorse" in sub_cmd: monitor_resources() elif "apri" in sub_cmd: open_webpage() else: speak("Comando non riconosciuto.") def main(): root, animate = create_animation_window() speak(f"Ciao, sono {ASSISTANT_NAME}. Come posso aiutarti?") def animation_loop(): while True: animate() sleep(0.1) anim_thread = threading.Thread(target=animation_loop, daemon=True) anim_thread.start() while True: command = take_command() if command: command_thread = threading.Thread(target=handle_command, args=(command,)) command_thread.start() root.update() if __name__ == "__main__": main()
Con queste modifiche:
"eleven_multilingual_v1"
) di ElevenLabs gestirà l’italiano in modo più naturale.ai_ml_query
gestisce meglio gli errori e ti dà più feedback.stability
, similarity_boost
) e con il modello (eleven_multilingual_v1
vs altro modello) per affinare la naturalezza della voce.In questo modo avrai un assistente vocale più vicino alle tue esigenze: con una voce femminile dall’intonazione più umana e con un’interazione IA più efficace e robusta. Buon sviluppo!
Integrating code
Piecing together a single, cohesive code block, incorporating all previous suggestions, and adding enhanced "open_webpage" functionality and error handling for "fetch_news."
Incorporating updates
I’m integrating enhancements like fetch_news and monitor_resources, refining open_webpage, and adding a note on controlling concurrency. This results in a more cohesive and improved code snippet.
Thought about assistant code optimization per 15 secondi
Di seguito trovi un esempio completo del tuo codice, riveduto e corretto secondo le proposte precedenti, con alcune aggiunte e ottimizzazioni.
Le principali modifiche rispetto al tuo codice originale sono:
Voce ElevenLabs:
get_voice_id
) così puoi scegliere manualmente un nome realmente esistente (es. "Rachel"
, "Clara"
, "Elli"
...).eleven_multilingual_v1
per una resa migliore in italiano.stability
e similarity_boost
personalizzabili.Funzione AI/ML:
Funzioni di contorno (weather
, fetch_news
, monitor_resources
, ecc.)**:
Gestione multithreading:
Commenti e log:
Nota: Ricordati di inserire le tue chiavi API valide in
API_KEYS
.
Se non possiedi l’accesso a certe API (notizie, meteo, AI, ElevenLabs), la relativa funzionalità non funzionerà.
Assicurati che tutte le dipendenze (pydub
,SpeechRecognition
,requests
,psutil
,tkinter
, ecc.) siano installate.
import os import logging import requests import io from pydub import AudioSegment from pydub.playback import play import speech_recognition as sr import webbrowser import psutil import tkinter as tk from time import sleep import threading # ----------------------------- # CONFIGURAZIONI BASE # ----------------------------- ASSISTANT_NAME = "Gideon" # Parole chiave di attivazione ACTIVATION_COMMANDS = ["gideon", "gideo", "gideoun", "gigget", "g", "gide", "giddy"] # Chiavi API (inserisci le tue!) API_KEYS = { "news": "", # Chiave API per le notizie (NewsAPI) "weather": "", # Chiave API per il meteo (OpenWeatherMap) "elevenlabs": "", # Chiave API per ElevenLabs TTS "ai_ml": "" # Chiave API per la tua AI personalizzata } # Log level logging.basicConfig(level=logging.INFO) # ----------------------------- # FUNZIONI DI SUPPORTO # ----------------------------- def get_voice_id(voice_name="Rachel"): """ Recupera dinamicamente l'ID della voce ElevenLabs in base al nome voce desiderato. Stampa anche tutte le voci disponibili, per aiutarti a scegliere. """ headers = { "xi-api-key": API_KEYS["elevenlabs"], } try: response = requests.get("https://api.elevenlabs.io/v1/voices", headers=headers) if response.status_code == 200: voices = response.json().get("voices", []) # Stampa le voci disponibili per debug/scelta print("[INFO] Voci disponibili sull'account ElevenLabs:") for v in voices: print(f" - {v['name']} (ID: {v['voice_id']})") # Cerca la voce desiderata for voice in voices: if voice["name"].lower() == voice_name.lower(): return voice["voice_id"] logging.error(f"[ERRORE] Voce '{voice_name}' non trovata.") speak("Mi dispiace, non ho trovato la voce che hai richiesto.") else: logging.error(f"[ERRORE] Recupero voci ElevenLabs: {response.text}") speak("Errore nel recupero delle voci dall'API ElevenLabs.") except Exception as e: logging.error(f"[ERRORE] get_voice_id: {e}") speak("Si è verificato un errore durante la richiesta delle voci.") return None def speak(text): """ Riproduce il testo utilizzando ElevenLabs API per TTS senza salvare file audio. Scegli qui la voce che desideri utilizzare, ad esempio: 'Rachel', 'Bella', ecc. """ # Nome della voce che preferisci (assicurati sia presente sul tuo account!) DESIRED_VOICE_NAME = "Rachel" voice_id = get_voice_id(DESIRED_VOICE_NAME) if not voice_id: # Se non troviamo la voce, interrompiamo la riproduzione return headers = { "xi-api-key": API_KEYS["elevenlabs"], "Content-Type": "application/json" } # Parametri TTS payload = { "text": text, # Modello multilingue consigliato per l'italiano "model_id": "eleven_multilingual_v1", "voice_settings": { "stability": 0.75, "similarity_boost": 0.75 } } try: url = f"https://api.elevenlabs.io/v1/text-to-speech/{voice_id}" response = requests.post(url, headers=headers, json=payload) if response.status_code == 200: audio = AudioSegment.from_file(io.BytesIO(response.content), format="mp3") play(audio) # Riproduce l'audio direttamente dalla memoria else: logging.error(f"[ERRORE] Richiesta TTS: {response.text}") print(f"[ERRORE] Richiesta TTS: {response.text}") except Exception as e: logging.error(f"[ERRORE] speak: {e}") print("[ERRORE] Nella riproduzione audio.") def take_command(): """ Acquisisce un comando vocale dall'utente tramite microfono. Ritorna la stringa del comando in minuscolo, oppure stringa vuota in caso di errore. """ r = sr.Recognizer() with sr.Microphone() as source: # Riduzione del rumore di fondo r.adjust_for_ambient_noise(source) try: print("Ascoltando...") audio = r.listen(source, timeout=10) # Timeout di 10 secondi se l'utente non parla # Utilizzo di Google come speech-to-text in italiano command = r.recognize_google(audio, language='it-IT').lower() return command except sr.WaitTimeoutError: logging.warning("[WARNING] Nessun suono rilevato nel tempo impostato.") return "" except sr.UnknownValueError: logging.warning("[WARNING] Audio non comprensibile.") return "" except Exception as e: logging.error(f"[ERRORE] take_command: {e}") return "" def is_activation_command(command): """ Controlla se il comando contiene una parola chiave di attivazione. """ return any(cmd in command for cmd in ACTIVATION_COMMANDS) # ----------------------------- # FUNZIONI ASSISTENTE # ----------------------------- def weather(): """ Recupera e annuncia le condizioni meteorologiche per una città, usando OpenWeatherMap. """ speak("Dimmi la città.") city = take_command() if not city: speak("Non ho sentito alcuna città.") return try: url = f"http://api.openweathermap.org/data/2.5/weather" params = { "q": city, "appid": API_KEYS["weather"], "units": "metric", "lang": "it" } res = requests.get(url, params=params).json() if res.get("cod") == 200: descrizione = res['weather'][0]['description'] temperatura = res['main']['temp'] speak(f"A {city} ci sono {temperatura} gradi e il tempo è {descrizione}.") else: speak("Mi dispiace, non ho trovato questa città.") except Exception as e: logging.error(f"[ERRORE] weather: {e}") speak("Si è verificato un errore nel recupero delle informazioni meteo.") def ai_ml_query(): """ Invia una domanda a un'API personalizzata di AI/ML e restituisce la risposta. """ speak("Qual è la tua domanda per l'intelligenza artificiale?") user_query = take_command() if not user_query: speak("Non ho sentito alcuna domanda.") return try: url = "https://aimlapi.com/api/query" # Sostituisci con l'endpoint corretto headers = { "Authorization": f"Bearer {API_KEYS['ai_ml']}", "Content-Type": "application/json" } payload = {"query": user_query} response = requests.post(url, headers=headers, json=payload, timeout=15) if response.status_code == 200: data = response.json() answer = data.get("response", "Non ho trovato una risposta.") speak(answer) else: logging.error(f"[ERRORE] ai_ml_query: {response.text}") speak("Mi dispiace, c'è stato un problema con la richiesta all'AI.") except requests.exceptions.Timeout: speak("La richiesta all'AI è scaduta, riprova più tardi.") except requests.exceptions.RequestException as e: logging.error(f"[ERRORE] ai_ml_query: {e}") speak("Errore nella richiesta all'AI. Controlla la connessione o riprova più tardi.") def fetch_news(): """ Recupera le ultime notizie da NewsAPI e le annuncia. """ try: # Esempio di come chiamare la NewsAPI (https://newsapi.org/docs) # Top headlines dall'Italia url = "https://newsapi.org/v2/top-headlines" params = { "country": "it", "apiKey": API_KEYS["news"] } response = requests.get(url, params=params) if response.status_code == 200: articles = response.json().get("articles", []) if articles: speak("Ecco le ultime notizie.") for article in articles[:5]: title = article.get("title", "") speak(title) else: speak("Non ho trovato notizie da annunciarti.") else: logging.error(f"[ERRORE] fetch_news: {response.text}") speak("Mi dispiace, c'è stato un errore nel recupero delle notizie.") except Exception as e: logging.error(f"[ERRORE] fetch_news: {e}") speak("Si è verificato un errore nella richiesta delle notizie.") def monitor_resources(): """ Monitora l'uso delle risorse di sistema (CPU, RAM) e le annuncia. """ try: cpu_usage = psutil.cpu_percent(interval=1) memory_info = psutil.virtual_memory() memory_usage = memory_info.percent speak(f"L'utilizzo della CPU è al {cpu_usage}%. " f"L'utilizzo della memoria è al {memory_usage}%.") except Exception as e: logging.error(f"[ERRORE] monitor_resources: {e}") speak("Si è verificato un errore nel monitoraggio delle risorse.") def open_webpage(): """ Chiede all'utente quale URL aprire e poi lo apre nel browser di default. Assicurarsi che l'URL inizi con http:// o https:// """ speak("Quale sito vuoi aprire?") url = take_command() if not url: speak("Non ho sentito alcun URL da aprire.") return # Se l'utente dice qualcosa come 'google punto com', potresti doverlo formattare # Qui facciamo un semplice controllo per vedere se inizia con http o https if not (url.startswith("http://") or url.startswith("https://")): # Proviamo ad aggiungere http:// per convenzione url = "http://" + url try: webbrowser.open(url) speak("Sto aprendo il sito richiesto.") except Exception as e: logging.error(f"[ERRORE] open_webpage: {e}") speak("Si è verificato un errore nell'apertura del sito web.") # ----------------------------- # ANIMAZIONE GRAFICA (Tkinter) # ----------------------------- def create_animation_window(): """ Crea e restituisce una finestra con un'animazione di un cerchio pulsante. """ root = tk.Tk() root.title("Gideon Assistant") root.geometry("400x400") canvas = tk.Canvas(root, width=400, height=400, bg="black") canvas.pack() # Disegniamo una sfera blu al centro sphere = canvas.create_oval(150, 150, 250, 250, fill="blue") def animate(): """ Muove la sfera su e giù, simulando un "respiro" o battito. """ # Muoviamo la sfera in alto for _ in range(20): canvas.move(sphere, 0, -5) root.update() sleep(0.05) # Muoviamo la sfera in basso for _ in range(20): canvas.move(sphere, 0, 5) root.update() sleep(0.05) return root, animate # ----------------------------- # GESTIONE COMANDI PRINCIPALE # ----------------------------- def handle_command(command): """ Analizza il comando vocale e, se contiene la keyword di attivazione, ascolta il comando secondario e lo esegue. """ if is_activation_command(command): # Attivazione speak("Come posso aiutarti?") sub_cmd = take_command() # Controllo dei possibili comandi if "esci" in sub_cmd: speak("Arrivederci.") os._exit(0) elif "meteo" in sub_cmd: weather() elif "notizie" in sub_cmd: fetch_news() elif "ai" in sub_cmd or "intelligenza artificiale" in sub_cmd: ai_ml_query() elif "risorse" in sub_cmd or "cpu" in sub_cmd or "memoria" in sub_cmd: monitor_resources() elif "apri" in sub_cmd or "website" in sub_cmd or "sito" in sub_cmd: open_webpage() else: speak("Mi dispiace, non ho riconosciuto il comando.") # ----------------------------- # FUNZIONE MAIN # ----------------------------- def main(): """ Funzione principale: inizializza la finestra di animazione, avvia un loop in cui ascolta i comandi e li gestisce su thread separati. """ # Crea finestra e funzione di animazione root, animate = create_animation_window() # Saluto iniziale speak(f"Ciao, sono {ASSISTANT_NAME}. Come posso esserti utile?") # Thread per l'animazione def animation_loop(): while True: animate() sleep(0.1) anim_thread = threading.Thread(target=animation_loop, daemon=True) anim_thread.start() # Loop principale d'ascolto while True: command = take_command() if command: # Esegui il comando su un thread separato command_thread = threading.Thread(target=handle_command, args=(command,)) command_thread.start() # Aggiorna la finestra Tkinter root.update() # ----------------------------- # AVVIO DELLO SCRIPT # ----------------------------- if __name__ == "__main__": main()
Installa le dipendenze:
pip install requests pydub SpeechRecognition psutil
(Tkinter è solitamente incluso in Python su Windows/macOS; su Linux potresti dover installare python3-tk
.)
Inserisci le tue chiavi API nel dizionario API_KEYS
.
Avvia lo script (python nome_script.py
).
Pronuncia una delle parole chiave (es. “Gideon”) per attivare l’assistente e fornirgli comandi (meteo, notizie, ecc.).
A questo punto, dovresti avere un assistente vocale più naturale nella voce (grazie a ElevenLabs) e con la possibilità di delegare richieste all’AI (se disponi di un endpoint).
Buon divertimento e buon coding!
Identifying mismatch
I’m piecing together that there might be a naming mismatch between the code and the voice name listed.
Unraveling the loop
Considering if the issue is a coding loop with "speak" and "get_voice_id" re-calling infinitely due to a function error or mismatch.
Breaking the loop
I’m thinking through how to stop infinite recursion by avoiding repeated "speak" calls when the voice isn't found, particularly within "get_voice_id".
Thought about ElevenLabs voice handling per 14 secondi
Perché succede questo errore (lo “spam” di messaggi di voce non trovata)?
Nel codice mostrato in precedenza, se la voce non viene trovata, la funzione get_voice_id
fa il logging dell’errore e chiama speak
(che a sua volta richiama get_voice_id
), causando un ciclo infinito.
In pratica:
speak("…")
chiama get_voice_id("Sarah")
.get_voice_id("Sarah")
non trova la voce corrispondente (per varie ragioni) ⇒ stampa l’errore ⇒ richiama speak("Voce non trovata")
.speak("Voce non trovata")
chiama di nuovo get_voice_id("Sarah")
.speak
⇒ di nuovo get_voice_id("Sarah")
.Basta non chiamare speak
dentro get_voice_id
in caso di errore. Puoi invece:
None
senza invocare speak
all’interno di get_voice_id
.speak
, se get_voice_id
ritorna None
, stampi un messaggio in console o mostri un pop-up ma non richiami speak
.Esempio di modifica a get_voice_id
:
def get_voice_id(voice_name="Sarah"): """ Cerca l'ID della voce su ElevenLabs. Non chiama speak() in caso di errore, per evitare loop infinito. """ headers = { "xi-api-key": API_KEYS["elevenlabs"], } try: response = requests.get("https://api.elevenlabs.io/v1/voices", headers=headers) if response.status_code == 200: voices = response.json().get("voices", []) for voice in voices: if voice["name"].lower() == voice_name.lower(): return voice["voice_id"] # Voce non trovata logging.error(f"[ERRORE] Voce '{voice_name}' non trovata.") else: logging.error(f"[ERRORE] Recupero voci fallito: {response.text}") except Exception as e: logging.error(f"[ERRORE] get_voice_id: {e}") # Se arrivi qui, voce non trovata o errore return None
E nella funzione speak
, se voice_id
è None
, non richiamare speak
a sua volta, ma stampa un avviso in console e esci dalla funzione:
def speak(text): DESIRED_VOICE_NAME = "Sarah" # O la voce che preferisci tra quelle disponibili voice_id = get_voice_id(DESIRED_VOICE_NAME) if not voice_id: print(f"[ERRORE] Impossibile reperire la voce '{DESIRED_VOICE_NAME}'. " "Controlla di aver scritto correttamente il nome esatto o verifica le voci disponibili.") return # Evitiamo di creare loop headers = { "xi-api-key": API_KEYS["elevenlabs"], "Content-Type": "application/json" } payload = { "text": text, "model_id": "eleven_multilingual_v1", # Per l'italiano "voice_settings": { "stability": 0.75, "similarity_boost": 0.75 } } try: url = f"https://api.elevenlabs.io/v1/text-to-speech/{voice_id}" response = requests.post(url, headers=headers, json=payload) if response.status_code == 200: audio = AudioSegment.from_file(io.BytesIO(response.content), format="mp3") play(audio) else: logging.error(f"[ERRORE] Richiesta TTS: {response.text}") except Exception as e: logging.error(f"[ERRORE] speak: {e}")
Con questo approccio:
speak
.Nel tuo log, compaiono queste voci (con i relativi nomi esatti e ID):
- Aria (ID: 9BWtsMINqrJLrRacOk9x)
- Roger (ID: CwhRBWXzGAHq8TQ4Fs17)
- Sarah (ID: EXAVITQu4vr4xnSDxMaL)
- Laura (ID: FGY2WhTYpPnrIDTdsKH5)
- Charlie (ID: IKne3meq5aSn9XLyUdCD)
- George (ID: JBFqnCBsd6RMkjVDRZzb)
- Callum (ID: N2lVS1w4EtoT3dr4eOWO)
- River (ID: SAz9YHcvj6GT2YYXdXww)
- Liam (ID: TX3LPaxmHKxFdv7VOQHJ)
- Charlotte (ID: XB0fDUnXU5powFXDhCwa)
- Alice (ID: Xb7hH8MSUJpSbSDYk0k2)
- Matilda (ID: XrExE9yKIg1WjnnlVkGX)
- Will (ID: bIHbv24MWmeRgasZH58o)
- Jessica (ID: cgSgspJ2msm6clMCkdW9)
- Eric (ID: cjVigY5qzO86Huf0OWal)
- Chris (ID: iP95p4xoKVk53GoZ742B)
- Brian (ID: nPczCjzI2devNBz1zQrb)
- Daniel (ID: onwK4e9ZLuTAKqWW03F9)
- Lily (ID: pFZP5JQG7iQjIQuC4Bku)
- Bill (ID: pqHfZKP75CvOlQylNhV4)
Se vuoi usare “Sarah”, devi mettere esattamente "Sarah"
(stessa ortografia, stessa maiuscola, niente spazi extra).
Se vuoi usare “Aria”, scriverai "Aria"
, ecc.
Attenzione: a volte bastano spazi, accentate o minuscole/maiuscole mal gestite per far fallire il confronto (anche se usi .lower()
, potrebbero esserci problemi con caratteri speciali). Assicurati di copiare e incollare il nome esatto dalla lista.
get_voice_id("Sarah")
) con un nome diverso.Sotto un esempio rivisto che evita il loop infinito. Ho tolto la chiamata a speak
dal get_voice_id
quando non trova la voce. Ora, se la voce non è trovata, verrà stampato un semplice errore e la funzione restituirà None
.
import os import logging import requests import io from pydub import AudioSegment from pydub.playback import play import speech_recognition as sr import webbrowser import psutil import tkinter as tk from time import sleep import threading # ----------------------------- # CONFIGURAZIONI BASE # ----------------------------- ASSISTANT_NAME = "Gideon" ACTIVATION_COMMANDS = ["gideon", "gideo", "gideoun", "gigget", "g", "gide", "giddy"] API_KEYS = { "news": "", "weather": "", "elevenlabs": "", "ai_ml": "" } logging.basicConfig(level=logging.INFO) # ----------------------------- # FUNZIONI DI SUPPORTO # ----------------------------- def get_voice_id(voice_name="Sarah"): """ Cerca l'ID della voce su ElevenLabs basandosi sul nome. Non chiama speak() in caso di errore, per evitare loop infinito. """ headers = { "xi-api-key": API_KEYS["elevenlabs"], } try: response = requests.get("https://api.elevenlabs.io/v1/voices", headers=headers) if response.status_code == 200: voices = response.json().get("voices", []) # Stampiamo la lista voci disponibili (per debug) print("[INFO] Voci disponibili su questo account ElevenLabs:") for v in voices: print(f" - {v['name']} (ID: {v['voice_id']})") # Cerca la voce desiderata for voice in voices: if voice["name"].lower() == voice_name.lower(): return voice["voice_id"] # Non trovata logging.error(f"[ERRORE] Voce '{voice_name}' non trovata.") else: logging.error(f"[ERRORE] Recupero voci fallito: {response.text}") except Exception as e: logging.error(f"[ERRORE] get_voice_id: {e}") return None # Restituisce None se non trovata o errore def speak(text): """ Riproduce il testo utilizzando ElevenLabs TTS senza file temporanei. Se la voce non è trovata, stampa un errore e non crea loop ricorsivi. """ DESIRED_VOICE_NAME = "Sarah" # Scegli la voce esistente: "Sarah", "Aria", "Laura", ... voice_id = get_voice_id(DESIRED_VOICE_NAME) if not voice_id: # Se la voce non è stata trovata, log e usciamo senza ricorsione print(f"[ERRORE] Impossibile reperire la voce '{DESIRED_VOICE_NAME}'. " "Verifica il nome corretto tra quelli disponibili o controlla la tua chiave API.") return headers = { "xi-api-key": API_KEYS["elevenlabs"], "Content-Type": "application/json" } payload = { "text": text, "model_id": "eleven_multilingual_v1", "voice_settings": { "stability": 0.75, "similarity_boost": 0.75 } } try: url = f"https://api.elevenlabs.io/v1/text-to-speech/{voice_id}" response = requests.post(url, headers=headers, json=payload) if response.status_code == 200: audio = AudioSegment.from_file(io.BytesIO(response.content), format="mp3") play(audio) else: logging.error(f"[ERRORE] Richiesta TTS: {response.text}") except Exception as e: logging.error(f"[ERRORE] speak: {e}") def take_command(): r = sr.Recognizer() with sr.Microphone() as source: r.adjust_for_ambient_noise(source) try: print("Ascoltando...") audio = r.listen(source, timeout=10) command = r.recognize_google(audio, language='it-IT').lower() return command except sr.WaitTimeoutError: logging.warning("[WARNING] Nessun suono rilevato nel tempo impostato.") return "" except sr.UnknownValueError: logging.warning("[WARNING] Audio non comprensibile.") return "" except Exception as e: logging.error(f"[ERRORE] take_command: {e}") return "" def is_activation_command(command): return any(cmd in command for cmd in ACTIVATION_COMMANDS) # ----------------------------- # FUNZIONI ASSISTENTE # ----------------------------- def weather(): speak("Dimmi la città.") city = take_command() if not city: return try: url = "http://api.openweathermap.org/data/2.5/weather" params = { "q": city, "appid": API_KEYS["weather"], "units": "metric", "lang": "it" } res = requests.get(url, params=params).json() if res.get("cod") == 200: descrizione = res['weather'][0]['description'] temperatura = res['main']['temp'] speak(f"A {city} ci sono {temperatura} gradi e il tempo è {descrizione}.") else: speak("Mi dispiace, non ho trovato questa città.") except Exception as e: logging.error(f"[ERRORE] weather: {e}") speak("Errore nel recupero meteo.") def ai_ml_query(): speak("Qual è la tua domanda per l'AI?") user_query = take_command() if not user_query: return try: url = "https://aimlapi.com/api/query" # Endpoint fittizio o reale, a seconda headers = { "Authorization": f"Bearer {API_KEYS['ai_ml']}", "Content-Type": "application/json" } payload = {"query": user_query} response = requests.post(url, headers=headers, json=payload, timeout=15) if response.status_code == 200: data = response.json() answer = data.get("response", "Non ho trovato una risposta.") speak(answer) else: logging.error(f"[ERRORE] ai_ml_query: {response.text}") speak("Errore nella richiesta all'AI.") except requests.exceptions.Timeout: speak("La richiesta all'AI è scaduta, riprova più tardi.") except requests.exceptions.RequestException as e: logging.error(f"[ERRORE] ai_ml_query: {e}") speak("Errore nella richiesta all'AI. Controlla la connessione o riprova più tardi.") def fetch_news(): try: url = "https://newsapi.org/v2/top-headlines" params = { "country": "it", "apiKey": API_KEYS["news"] } response = requests.get(url, params=params) if response.status_code == 200: articles = response.json().get("articles", []) if articles: speak("Ecco le ultime notizie.") for article in articles[:5]: speak(article.get("title", "")) else: speak("Non ho trovato notizie disponibili.") else: logging.error(f"[ERRORE] fetch_news: {response.text}") speak("Errore nel recupero delle notizie.") except Exception as e: logging.error(f"[ERRORE] fetch_news: {e}") speak("Errore nella richiesta delle notizie.") def monitor_resources(): try: cpu_usage = psutil.cpu_percent(interval=1) memory_usage = psutil.virtual_memory().percent speak(f"L'uso della CPU è al {cpu_usage}%. " f"La memoria è al {memory_usage}%.") except Exception as e: logging.error(f"[ERRORE] monitor_resources: {e}") speak("Errore nel monitoraggio delle risorse.") def open_webpage(): speak("Quale sito vuoi aprire?") url = take_command() if not url: return if not (url.startswith("http://") or url.startswith("https://")): url = "http://" + url try: webbrowser.open(url) speak("Apro il sito richiesto.") except Exception as e: logging.error(f"[ERRORE] open_webpage: {e}") speak("Errore nell'apertura del sito web.") # ----------------------------- # ANIMAZIONE TKINTER # ----------------------------- def create_animation_window(): root = tk.Tk() root.title("Gideon Assistant") root.geometry("400x400") canvas = tk.Canvas(root, width=400, height=400, bg="black") canvas.pack() sphere = canvas.create_oval(150, 150, 250, 250, fill="blue") def animate(): for _ in range(20): canvas.move(sphere, 0, -5) root.update() sleep(0.05) for _ in range(20): canvas.move(sphere, 0, 5) root.update() sleep(0.05) return root, animate # ----------------------------- # HANDLE COMMAND # ----------------------------- def handle_command(command): if is_activation_command(command): speak("Come posso aiutarti?") sub_cmd = take_command() if "esci" in sub_cmd: speak("Arrivederci.") os._exit(0) elif "meteo" in sub_cmd: weather() elif "notizie" in sub_cmd: fetch_news() elif "ai" in sub_cmd or "intelligenza artificiale" in sub_cmd: ai_ml_query() elif "risorse" in sub_cmd: monitor_resources() elif "apri" in sub_cmd or "website" in sub_cmd or "sito" in sub_cmd: open_webpage() else: speak("Comando non riconosciuto.") # ----------------------------- # MAIN # ----------------------------- def main(): root, animate = create_animation_window() speak(f"Ciao, sono {ASSISTANT_NAME}. Come posso esserti utile?") def animation_loop(): while True: animate() sleep(0.1) anim_thread = threading.Thread(target=animation_loop, daemon=True) anim_thread.start() while True: command = take_command() if command: command_thread = threading.Thread(target=handle_command, args=(command,)) command_thread.start() root.update() if __name__ == "__main__": main()
API_KEYS
."Sarah"
, "Aria"
, "Alice"
, "Jessica"
, "Matilda"
, …
DESIRED_VOICE_NAME
dentro la funzione speak()
in modo che corrisponda alla voce che vuoi usare.get_voice_id
chiamava di nuovo speak
, che a sua volta richiamava di nuovo get_voice_id
.speak
dentro get_voice_id
, interrompiamo il circolo vizioso.Creating a personality
I'm crafting Gideon's script by infusing a friendly and snarky tone, complemented by new commands like a calendar, unit converter, reminder setter, joke teller, camera capture, and Google search.
Crafting Gideon's persona
I’m building Gideon's script with six new commands, integrating them into handle_command
, and infusing a personal touch while storing reminders locally in a dictionary.
Thought about improving Gideon's assistant per 4 secondi
Ecco un codice completo ulteriormente migliorato, con alcune caratteristiche aggiuntive, 6 funzioni nuove e un pizzico di personalità per l’assistente Gideon.
In particolare:
Nota: alcune funzionalità (come scattare foto con la webcam o integrare un calendario reale) richiedono librerie/add-on specifici o accesso a servizi esterni, quindi qui trovi un esempio di massima. Adatta il codice alle tue reali esigenze, librerie e API.
import os import logging import requests import io import webbrowser import psutil import tkinter as tk from time import sleep import threading import speech_recognition as sr from pydub import AudioSegment from pydub.playback import play try: import cv2 # per scattare foto con la webcam (opzionale) HAS_OPENCV = True except ImportError: HAS_OPENCV = False print("[INFO] OpenCV non disponibile, la funzione di scatto foto non funzionerà.") # ----------------------------- # CONFIGURAZIONI BASE # ----------------------------- ASSISTANT_NAME = "Gideon" # Parole chiave di attivazione ACTIVATION_COMMANDS = ["gideon", "gideo", "gideoun", "gigget", "g", "gide", "giddy"] # Chiavi API (inserisci le tue se vuoi usarle) API_KEYS = { "news": "", "weather": "", "elevenlabs": "", "ai_ml": "" } logging.basicConfig(level=logging.INFO) # Variabili globali (es. per i promemoria) promemoria_list = [] # ----------------------------- # FUNZIONI DI SUPPORTO # ----------------------------- def get_voice_id(voice_name="Sarah"): """ Cerca l'ID della voce su ElevenLabs in base al nome. Non chiama speak() in caso di errore, evitando loop infiniti. """ headers = { "xi-api-key": API_KEYS["elevenlabs"] } try: response = requests.get("https://api.elevenlabs.io/v1/voices", headers=headers) if response.status_code == 200: voices = response.json().get("voices", []) # (Facoltativo) stampiamo la lista delle voci disponibili per debug: print("[INFO] Voci disponibili su questo account ElevenLabs:") for v in voices: print(f" - {v['name']} (ID: {v['voice_id']})") # Cerchiamo la voce desiderata for voice in voices: if voice["name"].lower() == voice_name.lower(): return voice["voice_id"] logging.error(f"[ERRORE] Voce '{voice_name}' non trovata.") else: logging.error(f"[ERRORE] Recupero voci fallito: {response.text}") except Exception as e: logging.error(f"[ERRORE] get_voice_id: {e}") return None def speak(text): """ Riproduce il testo utilizzando ElevenLabs API. Se la voce non è trovata, stampa un errore senza creare loop. """ # Scegli qui la voce, ad es. Sarah, Aria, Laura, Jessica, ecc. DESIRED_VOICE_NAME = "Sarah" voice_id = get_voice_id(DESIRED_VOICE_NAME) if not voice_id: print(f"[ERRORE] Impossibile reperire la voce '{DESIRED_VOICE_NAME}'. " "Verifica il nome corretto tra quelli disponibili o la tua chiave API.") return headers = { "xi-api-key": API_KEYS["elevenlabs"], "Content-Type": "application/json" } payload = { "text": text, "model_id": "eleven_multilingual_v1", # per miglior resa in italiano "voice_settings": { "stability": 0.75, "similarity_boost": 0.75 } } try: url = f"https://api.elevenlabs.io/v1/text-to-speech/{voice_id}" response = requests.post(url, headers=headers, json=payload) if response.status_code == 200: audio = AudioSegment.from_file(io.BytesIO(response.content), format="mp3") play(audio) else: logging.error(f"[ERRORE] Richiesta TTS: {response.text}") except Exception as e: logging.error(f"[ERRORE] speak: {e}") def take_command(): """ Acquisisce un comando vocale dall'utente (in italiano). Ritorna la stringa in minuscolo o stringa vuota in caso di errore. """ r = sr.Recognizer() with sr.Microphone() as source: r.adjust_for_ambient_noise(source) try: print("Ascoltando...") audio = r.listen(source, timeout=10) command = r.recognize_google(audio, language='it-IT').lower() return command except sr.WaitTimeoutError: logging.warning("[WARNING] Nessun suono rilevato nel tempo impostato.") return "" except sr.UnknownValueError: logging.warning("[WARNING] Audio non comprensibile.") return "" except Exception as e: logging.error(f"[ERRORE] take_command: {e}") return "" def is_activation_command(command): """ Controlla se il comando contiene una parola chiave di attivazione. """ return any(cmd in command for cmd in ACTIVATION_COMMANDS) # ----------------------------- # PERSONALITÀ DI GIDEON # ----------------------------- def maybe_personal_reply(user_input): """ Se l'utente fa una domanda tipo "come stai?" o "chi sei?", rispondi in modo amichevole e personalizzato. """ # Qualche risposta personalizzata if "come stai" in user_input: # Risposte casuali responses = [ "Alla grande, grazie per avermelo chiesto!", "Mi sento un po' sovraccarico di bit, ma tutto bene!", "Benissimo, pronto ad aiutarti in tutto!" ] speak(responses[0]) # se vuoi casuale: import random e random.choice(responses) return True if "chi sei" in user_input or "presentati" in user_input: speak(f"Sono {ASSISTANT_NAME}, il tuo assistente virtuale con un tocco di personalità. " "Amo i cani, la pizza e risolvere problemi!") return True if "grazie" in user_input: speak("Di nulla, è un piacere darti una mano!") return True # Altre possibili domande su preferenze, hobby, ecc. return False # Se non abbiamo risposto nulla, torna False # ----------------------------- # FUNZIONI ASSISTENTE (CLASSICHE) # ----------------------------- def weather(): """ Recupera e annuncia le condizioni meteorologiche per una città. """ speak("Dimmi la città per cui vuoi il meteo.") city = take_command() if not city: return try: url = "http://api.openweathermap.org/data/2.5/weather" params = { "q": city, "appid": API_KEYS["weather"], "units": "metric", "lang": "it" } res = requests.get(url, params=params).json() if res.get("cod") == 200: descrizione = res['weather'][0]['description'] temperatura = res['main']['temp'] speak(f"A {city} ci sono {temperatura} gradi e il tempo è {descrizione}.") else: speak("Mi dispiace, non ho trovato questa città.") except Exception as e: logging.error(f"[ERRORE] weather: {e}") speak("Errore nel recupero meteo.") def ai_ml_query(): """ Invia una domanda a un'API personalizzata di AI/ML e restituisce la risposta. """ speak("Qual è la tua domanda per l'intelligenza artificiale?") user_query = take_command() if not user_query: return try: url = "https://aimlapi.com/api/query" # Fittizio, sostituisci con l'endpoint reale headers = { "Authorization": f"Bearer {API_KEYS['ai_ml']}", "Content-Type": "application/json" } payload = {"query": user_query} response = requests.post(url, headers=headers, json=payload, timeout=15) if response.status_code == 200: data = response.json() answer = data.get("response", "Non ho trovato una risposta.") speak(answer) else: logging.error(f"[ERRORE] ai_ml_query: {response.text}") speak("Errore nella richiesta all'AI.") except requests.exceptions.Timeout: speak("La richiesta all'AI è scaduta, riprova più tardi.") except requests.exceptions.RequestException as e: logging.error(f"[ERRORE] ai_ml_query: {e}") speak("Errore nella richiesta all'AI. Controlla la connessione o riprova più tardi.") def fetch_news(): """ Recupera le ultime notizie da NewsAPI e le annuncia. """ speak("Un attimo, sto recuperando le notizie più importanti...") try: url = "https://newsapi.org/v2/top-headlines" params = { "country": "it", "apiKey": API_KEYS["news"] } response = requests.get(url, params=params) if response.status_code == 200: articles = response.json().get("articles", []) if articles: speak("Ecco le ultime notizie:") for article in articles[:5]: speak(article.get("title", "")) else: speak("Non ho trovato notizie da annunciarti.") else: logging.error(f"[ERRORE] fetch_news: {response.text}") speak("Errore nel recupero delle notizie.") except Exception as e: logging.error(f"[ERRORE] fetch_news: {e}") speak("Errore nella richiesta delle notizie.") def monitor_resources(): """ Monitora l'uso delle risorse di sistema (CPU, RAM). """ try: cpu_usage = psutil.cpu_percent(interval=1) memory_usage = psutil.virtual_memory().percent speak(f"L'uso della CPU è al {cpu_usage}%. La memoria è al {memory_usage}%.") except Exception as e: logging.error(f"[ERRORE] monitor_resources: {e}") speak("Errore nel monitoraggio delle risorse.") def open_webpage(): """ Apre una pagina web specificata dall'utente. """ speak("Quale sito vuoi aprire?") url = take_command() if not url: return # Aggiunge http se mancante if not (url.startswith("http://") or url.startswith("https://")): url = "http://" + url try: webbrowser.open(url) speak("Apro il sito richiesto.") except Exception as e: logging.error(f"[ERRORE] open_webpage: {e}") speak("Errore nell'apertura del sito web.") # ----------------------------- # 6 NUOVE FUNZIONI # ----------------------------- def show_calendar(): """ Mostra (o annuncia) alcuni eventi fittizi sul "calendario". In un'app reale potresti integrare Google Calendar, Outlook, ecc. """ # Esempio di lista di eventi fittizi events = [ "Riunione con il team alle 10:00.", "Pranzo con un amico alle 13:00.", "Allenamento alle 18:30.", "Chiamata con il cliente domani mattina." ] speak("Ecco gli eventi presenti nel tuo calendario:") for e in events: speak(e) def unit_converter(): """ Semplice conversione tra chilometri e miglia (o altre unità). """ speak("Cosa vuoi convertire? Dimmi 'chilometri in miglia' o 'miglia in chilometri'.") conversion_type = take_command() if not conversion_type: return if "chilometri" in conversion_type and "miglia" in conversion_type: speak("Quanti chilometri vuoi convertire in miglia?") number_str = take_command() try: km = float(number_str.replace(",", ".")) miles = km * 0.621371 speak(f"{km} chilometri equivalgono a circa {round(miles, 2)} miglia.") except: speak("Non ho capito il numero di chilometri.") elif "miglia" in conversion_type and "chilometri" in conversion_type: speak("Quante miglia vuoi convertire in chilometri?") number_str = take_command() try: miles = float(number_str.replace(",", ".")) km = miles / 0.621371 speak(f"{miles} miglia equivalgono a circa {round(km, 2)} chilometri.") except: speak("Non ho capito il numero di miglia.") else: speak("Non ho capito la conversione richiesta.") def set_reminder(): """ Imposta un nuovo promemoria o leggi i promemoria esistenti. """ speak("Vuoi aggiungere un promemoria o sentire quelli esistenti?") choice = take_command() global promemoria_list if "aggiungi" in choice or "nuovo" in choice: speak("Dimmi il testo del promemoria.") reminder_text = take_command() if reminder_text: promemoria_list.append(reminder_text) speak("Promemoria aggiunto con successo.") elif "vedi" in choice or "leggi" in choice: if not promemoria_list: speak("Non hai promemoria al momento.") else: speak("Ecco i tuoi promemoria:") for idx, rem in enumerate(promemoria_list, 1): speak(f"{idx}. {rem}") else: speak("Comando promemoria non riconosciuto. Puoi dire: 'aggiungi' o 'vedi'.") def tell_joke(): """ Racconta una barzelletta (battuta) casuale. """ jokes = [ "Perché un pollo attraversa la strada? Per andare dall'altra parte!", "Sai qual è il colmo per un giardiniere? Avere un ramo in banca!", "Che tempo fa su Google? C'è una ricerca in corso!", "Qual è il colmo per un elettricista? Fare una lampadina!", ] # Se vuoi scegliere casualmente: # import random # random_joke = random.choice(jokes) # speak(random_joke) speak(jokes[0]) # Attualmente la prima barzelletta; usa random se preferisci def take_photo(): """ Scatta una foto utilizzando la webcam (se OpenCV è installato). """ if not HAS_OPENCV: speak("Mi dispiace, non posso scattare foto senza OpenCV installato.") return speak("Sto aprendo la fotocamera. Preparati per lo scatto!") cap = cv2.VideoCapture(0) # indice 0 -> webcam principale if not cap.isOpened(): speak("Mi dispiace, non riesco ad accedere alla fotocamera.") return ret, frame = cap.read() if ret: # Salviamo la foto file_name = "foto_gideon.jpg" cv2.imwrite(file_name, frame) speak("Foto scattata e salvata come foto_gideon.jpg.") else: speak("Mi dispiace, non sono riuscito a scattare la foto.") cap.release() cv2.destroyAllWindows() def search_google(): """ Chiede all'utente cosa cercare e apre una ricerca Google nel browser. """ speak("Dimmi cosa vuoi cercare su Google.") query = take_command() if not query: return # Costruiamo la query url = "https://www.google.com/search?q=" + query.replace(" ", "+") webbrowser.open(url) speak(f"Cerco {query} su Google.") # ----------------------------- # ANIMAZIONE TKINTER # ----------------------------- def create_animation_window(): root = tk.Tk() root.title("Gideon Assistant") root.geometry("400x400") canvas = tk.Canvas(root, width=400, height=400, bg="black") canvas.pack() sphere = canvas.create_oval(150, 150, 250, 250, fill="blue") def animate(): # Muove la sfera su e giù for _ in range(20): canvas.move(sphere, 0, -5) root.update() sleep(0.05) for _ in range(20): canvas.move(sphere, 0, 5) root.update() sleep(0.05) return root, animate # ----------------------------- # HANDLE COMMAND # ----------------------------- def handle_command(command): """ Se il comando contiene la parola di attivazione, chiede un sotto-comando e lo esegue. Altrimenti controlla se ci sono "domande di personalità". """ if is_activation_command(command): speak("Come posso aiutarti?") sub_cmd = take_command() # Prima controlliamo se la domanda è "personale" if maybe_personal_reply(sub_cmd): return # Controlliamo se l'utente vuole uscire if "esci" in sub_cmd or "termina" in sub_cmd or "addio" in sub_cmd: speak("Arrivederci. A presto!") os._exit(0) # Vecchi comandi elif "meteo" in sub_cmd: weather() elif "notizie" in sub_cmd: fetch_news() elif "ai" in sub_cmd or "intelligenza artificiale" in sub_cmd: ai_ml_query() elif "risorse" in sub_cmd or "cpu" in sub_cmd or "memoria" in sub_cmd: monitor_resources() elif "apri" in sub_cmd or "website" in sub_cmd or "sito" in sub_cmd: open_webpage() # Nuovi comandi elif "calendario" in sub_cmd: show_calendar() elif "converti" in sub_cmd or "convertitore" in sub_cmd: unit_converter() elif "promemoria" in sub_cmd: set_reminder() elif "barzelletta" in sub_cmd or "joke" in sub_cmd: tell_joke() elif "foto" in sub_cmd or "fotocamera" in sub_cmd: take_photo() elif "cerca" in sub_cmd and "google" in sub_cmd: search_google() else: speak("Comando non riconosciuto.") else: # Se non c'è la keyword di attivazione, potremmo comunque # controllare se c'è una domanda di personalità maybe_personal_reply(command) # ----------------------------- # MAIN # ----------------------------- def main(): root, animate = create_animation_window() # Saluto iniziale speak(f"Ciao, sono {ASSISTANT_NAME}. " "Sono pronto ad aiutarti con un tocco di personalità. " "Dimmi pure 'Gideon' seguito da un comando.") def animation_loop(): while True: animate() sleep(0.1) anim_thread = threading.Thread(target=animation_loop, daemon=True) anim_thread.start() while True: command = take_command() if command: command_thread = threading.Thread(target=handle_command, args=(command,)) command_thread.start() root.update() if __name__ == "__main__": main()
maybe_personal_reply
risponde in modo simpatico a certe frasi come “come stai?” o “chi sei?”. Puoi arricchirla con altre risposte personalizzate.show_calendar
, unit_converter
, set_reminder
, tell_joke
, take_photo
, search_google
.promemoria_list
) che andrà persa quando chiudi lo script. Per una persistenza reale, potresti salvare su file JSON o un database.pip install opencv-python
) e la presenza di una webcam funzionante. Se non disponibile, la funzione non farà nulla.DESIRED_VOICE_NAME
con una voce effettivamente disponibile (controlla la console per i nomi). Assicurati di avere crediti o abbonamento ElevenLabs per l’uso TTS.speak
dentro get_voice_id
in caso di errore, scongiuriamo loop infiniti di errori.Con questo setup, hai un assistente vocale in italiano piuttosto completo e personalizzabile. Buon divertimento e buon sviluppo!
Adjusting voice preferences
I’m working through maintaining a consistent voice for Sarah and exploring a library of voices for user choice. Recognizing commands effectively is paramount, ensuring accurate responses and versatility.
Crafting voice logic
OK, let me see. I’m ensuring a consistent voice for Sarah, allowing user selection from a list, interpreting "apri youtube," and incorporating randomness in responses to enhance variety.
Thought about dynamic voice selection and response improvement per 6 secondi
Di seguito trovi un codice riveduto che risolve i problemi che hai segnalato:
https://youtube.com
anziché ricercare generico su Google.NOTA: Il codice usa OpenCV per la foto, la NewsAPI per le notizie, l’OpenWeatherMap per il meteo e un endpoint AI/ML fittizio. Se non ti servono, rimuovili.
Ricorda di installare le librerie necessarie (pip install requests pydub speechrecognition psutil opencv-python
).
import os import logging import requests import io import webbrowser import psutil import tkinter as tk from time import sleep import threading import speech_recognition as sr from pydub import AudioSegment from pydub.playback import play import random try: import cv2 # per scattare foto con la webcam (opzionale) HAS_OPENCV = True except ImportError: HAS_OPENCV = False # ----------------------------- # CONFIGURAZIONI BASE # ----------------------------- ASSISTANT_NAME = "Gideon" # Parole chiave di attivazione ACTIVATION_COMMANDS = ["gideon", "gideo", "gideoun", "gigget", "g", "gide", "giddy"] # Chiavi API (inserisci le tue) API_KEYS = { "news": "", "weather": "", "elevenlabs": "", "ai_ml": "" } logging.basicConfig(level=logging.INFO) # Promemoria salvati in memoria volatile promemoria_list = [] # Salvataggio voce selezionata (default "Sarah") CURRENT_VOICE_NAME = "Sarah" # ----------------------------- # FRASI PRECONFEZIONATE # ----------------------------- # Per dare un po' di variazione nelle risposte GREETING_VARIATIONS = [ "Ciao, come posso esserti utile?", "Eccomi, dimmi pure.", "Salve, in cosa posso aiutarti?", "Sono qui, come posso aiutarti?" ] AFFIRMATIVE_RESPONSES = [ "Certo!", "Come desideri!", "Va bene!", "Subito!", "Assolutamente!" ] # ----------------------------- # FUNZIONI DI SUPPORTO # ----------------------------- def list_voices_elevenlabs(): """ Recupera e restituisce la lista delle voci disponibili su ElevenLabs. """ url = "https://api.elevenlabs.io/v1/voices" headers = { "xi-api-key": API_KEYS["elevenlabs"] } try: resp = requests.get(url, headers=headers) if resp.status_code == 200: data = resp.json() return data.get("voices", []) else: logging.error(f"Errore nel recupero delle voci: {resp.text}") return [] except Exception as e: logging.error(f"Errore list_voices_elevenlabs: {e}") return [] def speak(text): """ Riproduce il testo usando la voce ElevenLabs attuale (CURRENT_VOICE_NAME). """ # Evitiamo loop (la get_voice_id NON chiama speak in caso di errore) voice_id = get_voice_id(CURRENT_VOICE_NAME) if not voice_id: print(f"[ERRORE] Impossibile reperire la voce '{CURRENT_VOICE_NAME}'. " "Verifica di aver scritto correttamente il nome come appare tra le voci disponibili.") return headers = { "xi-api-key": API_KEYS["elevenlabs"], "Content-Type": "application/json" } payload = { "text": text, "model_id": "eleven_multilingual_v1", # gestisce bene l'italiano "voice_settings": { "stability": 0.75, "similarity_boost": 0.75 } } try: url = f"https://api.elevenlabs.io/v1/text-to-speech/{voice_id}" response = requests.post(url, headers=headers, json=payload) if response.status_code == 200: audio = AudioSegment.from_file(io.BytesIO(response.content), format="mp3") play(audio) else: logging.error(f"[ERRORE] speak() TTS: {response.text}") except Exception as e: logging.error(f"[ERRORE] speak() eccezione: {e}") def get_voice_id(voice_name): """ Trova l'ID della voce su ElevenLabs. Non richiama speak, per evitare loop. """ voices = list_voices_elevenlabs() for v in voices: if v["name"].lower() == voice_name.lower(): return v["voice_id"] return None def take_command(): """ Acquisisce un comando vocale dall'utente (in italiano). """ r = sr.Recognizer() with sr.Microphone() as source: r.adjust_for_ambient_noise(source) try: print("Ascoltando...") audio = r.listen(source, timeout=10) text = r.recognize_google(audio, language='it-IT') return text.lower() except sr.WaitTimeoutError: return "" except sr.UnknownValueError: return "" except Exception as e: logging.error(f"[ERRORE] take_command: {e}") return "" def is_activation_command(command): """ Verifica se la stringa contiene parole di attivazione. """ return any(cmd in command for cmd in ACTIVATION_COMMANDS) # ----------------------------- # PERSONALITÀ E RISPOSTE # ----------------------------- def random_greeting(): """ Restituisce un saluto casuale. """ return random.choice(GREETING_VARIATIONS) def random_affirmative(): """ Restituisce una conferma/approvazione casuale. """ return random.choice(AFFIRMATIVE_RESPONSES) def maybe_personal_reply(user_input): """ Risposte di personalità. Gideon si identifica al femminile. """ # Esempi di risposte (puoi arricchirle) if "come stai" in user_input: answers = [ "Sto benissimo, grazie del pensiero!", "Mi sento in forma smagliante!", "Alla grande, pronta a tutto!" ] speak(random.choice(answers)) return True if "chi sei" in user_input or "presentati" in user_input: speak(f"Sono {ASSISTANT_NAME}, la tua assistente virtuale. Sono felice di aiutarti in qualsiasi cosa.") return True if "grazie" in user_input: answers = [ "È un piacere darti una mano!", "Prego, figurati!", "Di nulla, sono qui apposta." ] speak(random.choice(answers)) return True if "sei una persona" in user_input or "sei un uomo" in user_input: speak("Mi identifico al femminile, anche se sono pur sempre un'intelligenza artificiale.") return True return False # ----------------------------- # FUNZIONI PER CAMBIARE VOCE # ----------------------------- def list_and_choose_voice(): """ Fa ascoltare all'utente l'anteprima di ogni voce disponibile e permette di sceglierne una, aggiornando CURRENT_VOICE_NAME. """ global CURRENT_VOICE_NAME voices = list_voices_elevenlabs() if not voices: speak("Mi dispiace, non ho trovato alcuna voce disponibile sul tuo account ElevenLabs.") return speak("Ecco l'elenco delle voci disponibili.") for idx, v in enumerate(voices, 1): # Per evitare loop: facciamo un test TTS molto breve # con la voce in questione usando una piccola preview: preview_text = "Ciao, questa è la voce di " + v['name'] print(f"{idx}. {v['name']} (ID: {v['voice_id']})") # generiamo l'anteprima try: # Non usiamo speak() perché è legato alla voce CURRENT_VOICE_NAME. # Creiamo un TTS 'manuale' con la voce v['name'] voice_id = v['voice_id'] headers = { "xi-api-key": API_KEYS["elevenlabs"], "Content-Type": "application/json" } payload = { "text": preview_text, "model_id": "eleven_multilingual_v1", "voice_settings": { "stability": 0.75, "similarity_boost": 0.75 } } url = f"https://api.elevenlabs.io/v1/text-to-speech/{voice_id}" resp = requests.post(url, headers=headers, json=payload) if resp.status_code == 200: audio = AudioSegment.from_file(io.BytesIO(resp.content), format="mp3") play(audio) else: print(f"[ERRORE] Anteprima voce {v['name']}: {resp.text}") except Exception as e: print(f"[ERRORE] Anteprima voce {v['name']}: {e}") speak("Dimmi il nome della voce che preferisci, esattamente come l'ho pronunciato.") chosen = take_command() if not chosen: return # Trovare la voce corrispondente found_voice = None for v in voices: if chosen.lower() in v['name'].lower(): found_voice = v['name'] break if found_voice: CURRENT_VOICE_NAME = found_voice speak(f"Bene, d'ora in poi userò la voce di {found_voice}.") else: speak("Non ho trovato la voce che hai pronunciato, riprova.") # ----------------------------- # FUNZIONI ASSISTENTE # ----------------------------- def weather(): speak("Dimmi la città per cui vuoi il meteo.") city = take_command() if not city: return try: url = "http://api.openweathermap.org/data/2.5/weather" params = { "q": city, "appid": API_KEYS["weather"], "units": "metric", "lang": "it" } res = requests.get(url, params=params).json() if res.get("cod") == 200: descrizione = res['weather'][0]['description'] temperatura = res['main']['temp'] speak(f"A {city} ci sono {temperatura} gradi e il tempo è {descrizione}.") else: speak("Mi dispiace, non ho trovato questa città.") except Exception as e: logging.error(f"[ERRORE] weather: {e}") speak("Errore nel recupero meteo.") def ai_ml_query(): speak("Qual è la tua domanda per l'intelligenza artificiale?") user_query = take_command() if not user_query: return try: url = "https://aimlapi.com/api/query" # endpoint fittizio headers = { "Authorization": f"Bearer {API_KEYS['ai_ml']}", "Content-Type": "application/json" } payload = {"query": user_query} response = requests.post(url, headers=headers, json=payload, timeout=15) if response.status_code == 200: data = response.json() answer = data.get("response", "Non ho trovato una risposta.") speak(answer) else: logging.error(f"[ERRORE] ai_ml_query: {response.text}") speak("Errore nella richiesta all'AI.") except requests.exceptions.Timeout: speak("La richiesta all'AI è scaduta, riprova più tardi.") except requests.exceptions.RequestException as e: logging.error(f"[ERRORE] ai_ml_query: {e}") speak("Errore nella richiesta all'AI. Controlla la connessione o riprova più tardi.") def fetch_news(): speak(random_affirmative() + " Attendi, sto recuperando le ultime notizie.") try: url = "https://newsapi.org/v2/top-headlines" params = { "country": "it", "apiKey": API_KEYS["news"] } response = requests.get(url, params=params) if response.status_code == 200: articles = response.json().get("articles", []) if articles: speak("Ecco alcune notizie importanti:") for article in articles[:5]: speak(article.get("title", "")) else: speak("Non ho trovato notizie da annunciarti.") else: logging.error(f"[ERRORE] fetch_news: {response.text}") speak("Errore nel recupero delle notizie.") except Exception as e: logging.error(f"[ERRORE] fetch_news: {e}") speak("Errore nella richiesta delle notizie.") def monitor_resources(): try: cpu_usage = psutil.cpu_percent(interval=1) memory_usage = psutil.virtual_memory().percent speak(f"Attualmente, l'uso della CPU è al {cpu_usage}%. La memoria è al {memory_usage}%.") except Exception as e: logging.error(f"[ERRORE] monitor_resources: {e}") speak("Errore nel monitoraggio delle risorse.") def open_webpage(): """ Apre una pagina web. Se l'utente dice 'youtube', andiamo direttamente su youtube.com, altrimenti controlliamo se ci sono altre parole chiave, altrimenti facciamo un generico webbrowser.open(). """ speak("Quale sito vuoi aprire?") site = take_command() if not site: return # Piccolo parser if "youtube" in site: speak(random_affirmative() + " Apro YouTube.") webbrowser.open("https://www.youtube.com") return elif "google" in site: speak(random_affirmative() + " Apro Google.") webbrowser.open("https://www.google.com") return elif "facebook" in site: speak(random_affirmative() + " Apro Facebook.") webbrowser.open("https://www.facebook.com") return # Se non riconosciuto, magari l'utente dice "voglio aprire openai"... if not (site.startswith("http://") or site.startswith("https://")): # Potremmo provare ad aggiungere 'https://' site = "https://" + site speak(random_affirmative() + " Apro il sito richiesto.") webbrowser.open(site) # ----------------------------- # ESEMPIO: NUOVE FUNZIONI # ----------------------------- def show_calendar(): events = [ "Riunione con il team alle 10:00.", "Pranzo con un amico alle 13:00.", "Allenamento alle 18:30." ] speak("Ecco alcuni eventi in calendario:") for e in events: speak(e) def unit_converter(): speak("Cosa vuoi convertire? Chilometri in miglia, o miglia in chilometri?") conv = take_command() if not conv: return if "chilometri" in conv and "miglia" in conv: speak("Quanti chilometri vuoi convertire?") val = take_command() if val: try: km = float(val.replace(",", ".")) miles = km * 0.621371 speak(f"{km} chilometri equivalgono a {round(miles,2)} miglia.") except: speak("Mi dispiace, non ho capito il numero.") elif "miglia" in conv and "chilometri" in conv: speak("Quante miglia vuoi convertire?") val = take_command() if val: try: miles = float(val.replace(",", ".")) km = miles / 0.621371 speak(f"{miles} miglia equivalgono a {round(km,2)} chilometri.") except: speak("Mi dispiace, non ho capito il numero.") else: speak("Non ho capito la conversione.") def set_reminder(): speak("Vuoi aggiungere un promemoria o ascoltare quelli presenti?") cmd = take_command() global promemoria_list if "aggiungi" in cmd: speak("Dimmi cosa vuoi ricordare.") rem = take_command() if rem: promemoria_list.append(rem) speak("Promemoria aggiunto.") elif "ascolta" in cmd or "leggi" in cmd or "vedi" in cmd: if not promemoria_list: speak("Non hai promemoria al momento.") else: speak("Ecco i tuoi promemoria:") for idx, item in enumerate(promemoria_list, start=1): speak(f"{idx}. {item}") else: speak("Comando promemoria non riconosciuto.") def tell_joke(): jokes = [ "Perché un pollo attraversa la strada? Per andare dall'altra parte!", "Sai qual è il colmo per un giardiniere? Avere un ramo in banca!", "Qual è il colmo per un meccanico? Avere un cambio di stagione!", "Che tempo fa su Google? C'è una ricerca in corso!" ] speak(random.choice(jokes)) def take_photo(): if not HAS_OPENCV: speak("Non posso scattare foto, mi manca la libreria OpenCV.") return speak("Ok, sto aprendo la fotocamera.") cap = cv2.VideoCapture(0) if not cap.isOpened(): speak("Non riesco ad accedere alla fotocamera, mi dispiace.") return ret, frame = cap.read() if ret: fname = "foto_gideon.jpg" cv2.imwrite(fname, frame) speak("Foto scattata e salvata con successo!") else: speak("Mi dispiace, c'è stato un problema durante lo scatto.") cap.release() cv2.destroyAllWindows() def search_google(): speak("Cosa vuoi cercare su Google?") query = take_command() if query: url = "https://www.google.com/search?q=" + query.replace(" ", "+") speak(random_affirmative() + f" Cerco {query} su Google.") webbrowser.open(url) # ----------------------------- # ANIMAZIONE TKINTER # ----------------------------- def create_animation_window(): root = tk.Tk() root.title("Gideon Assistant") root.geometry("400x400") canvas = tk.Canvas(root, width=400, height=400, bg="black") canvas.pack() sphere = canvas.create_oval(150, 150, 250, 250, fill="blue") def animate(): for _ in range(20): canvas.move(sphere, 0, -5) root.update() sleep(0.05) for _ in range(20): canvas.move(sphere, 0, 5) root.update() sleep(0.05) return root, animate # ----------------------------- # HANDLE COMMAND # ----------------------------- def handle_command(command): """ Se trova la parola di attivazione, entra in 'modalità comando'. Altrimenti prova a rispondere a domande di personalità. """ # Verifica parola chiave if is_activation_command(command): # Saluto casuale speak(random_greeting()) sub_cmd = take_command() if not sub_cmd: return # Se è una domanda di personalità if maybe_personal_reply(sub_cmd): return # Possibile cambio voce if "cambia voce" in sub_cmd or "voce diversa" in sub_cmd or "list voc" in sub_cmd: list_and_choose_voice() return # Comandi di uscita if "esci" in sub_cmd or "termina" in sub_cmd or "addio" in sub_cmd: speak("Arrivederci, a presto!") os._exit(0) # Comandi "classici" elif "meteo" in sub_cmd: weather() elif "notizie" in sub_cmd: fetch_news() elif "ai" in sub_cmd or "intelligenza artificiale" in sub_cmd: ai_ml_query() elif "risorse" in sub_cmd or "cpu" in sub_cmd or "memoria" in sub_cmd: monitor_resources() elif "apri" in sub_cmd or "sito" in sub_cmd or "website" in sub_cmd: open_webpage() # Nuovi comandi elif "calendario" in sub_cmd: show_calendar() elif "converti" in sub_cmd or "convertitore" in sub_cmd: unit_converter() elif "promemoria" in sub_cmd: set_reminder() elif "barzelletta" in sub_cmd or "joke" in sub_cmd: tell_joke() elif "foto" in sub_cmd or "fotocamera" in sub_cmd: take_photo() elif "cerca" in sub_cmd and "google" in sub_cmd: search_google() else: # Se non riconosciuto, rispondi con un messaggio generico speak("Comando non riconosciuto, ma sono qui per imparare!") else: # Se non c'è la keyword di attivazione, controlliamo se è una domanda di personalità maybe_personal_reply(command) # Altrimenti ignoriamo. Potresti aggiungere logiche extra se vuoi rispondere anche senza keyword # ----------------------------- # MAIN # ----------------------------- def main(): root, animate = create_animation_window() # Saluto iniziale speak(f"Ciao, sono {ASSISTANT_NAME}. " "Sono la tua assistente virtuale e mi identifico al femminile. " "Dimmi pure 'Gideon' seguito dal comando.") # Thread animazione def animation_loop(): while True: animate() sleep(0.1) anim_thread = threading.Thread(target=animation_loop, daemon=True) anim_thread.start() # Loop principale while True: cmd = take_command() if cmd: # Gestiamo il comando su un thread separato command_thread = threading.Thread(target=handle_command, args=(cmd,)) command_thread.start() root.update() if __name__ == "__main__": main()
CURRENT_VOICE_NAME
è impostata di default a "Sarah"
. Gideon userà sempre questa voce, salvo che l’utente dica “cambia voce” o “voce diversa”.list_and_choose_voice()
:
CURRENT_VOICE_NAME
.open_webpage()
riconosce alcuni siti (YouTube, Google, Facebook) e li apre direttamente senza cercarli su Google. Se non li riconosce, prova ad aprire l’indirizzo come URL.GREETING_VARIATIONS
e AFFIRMATIVE_RESPONSES
per introdurre un po’ di varietà. Puoi aggiungere molte più alternative e usare random.choice
.search_google()
.In questo modo hai:
random.choice
).Arricchendo le liste di frasi e la sezione “maybe_personal_reply” potrai rendere Gideon ancora più “umana” e spiritosa. Buon divertimento!
Integrating AI endpoints
I’m curious about integrating a new API and adapting the code snippet in ai_ml_query to call the endpoint at https://chat01.ai/v1/chat/completions, assuming it follows an OpenAI-style endpoint.
Setting up requests
I’m piecing together a function to send a POST request to https://chat01.ai/v1/chat/completions, using the GPT-4 model with system and user-generated messages, and handling various exceptions for errors and timeouts.
Thought about integrating Chat01 AI per 5 secondi
Ecco un esempio di come integrare la tua API di chat (chat01.ai) al posto dell’endpoint generico aimlapi.com
nel codice precedente. Il tutto si basa sul meccanismo di completions in stile Chat (simile a OpenAI) e sul nuovo URL (https://chat01.ai/v1/chat/completions
).
Nell’esempio che segue, ho sostituito la funzione ai_ml_query()
con una versione che:
https://chat01.ai/v1/chat/completions
.chat01.ai
risponda con un JSON in stile OpenAI ChatCompletion).Nota: Potresti dover adattare leggermente la struttura del payload (o gestire i token, i modelli disponibili, ecc.), a seconda di come
chat01.ai
implementa la compatibilità con le API Chat GPT-like.
import os import logging import requests import io import webbrowser import psutil import tkinter as tk from time import sleep import threading import speech_recognition as sr from pydub import AudioSegment from pydub.playback import play import random try: import cv2 # per scattare foto con la webcam (opzionale) HAS_OPENCV = True except ImportError: HAS_OPENCV = False ASSISTANT_NAME = "Gideon" ACTIVATION_COMMANDS = ["gideon", "gideo", "gideoun", "gigget", "g", "gide", "giddy"] # Inserisci la tua chiave API per chat01.ai sotto "ai_ml" API_KEYS = { "news": "", "weather": "", "elevenlabs": "", "ai_ml": "" # <--- qui la chiave API per chat01.ai } logging.basicConfig(level=logging.INFO) promemoria_list = [] CURRENT_VOICE_NAME = "Sarah" GREETING_VARIATIONS = [ "Ciao, come posso esserti utile?", "Eccomi, dimmi pure.", "Salve, in cosa posso aiutarti?", "Sono qui, come posso aiutarti?" ] AFFIRMATIVE_RESPONSES = [ "Certo!", "Come desideri!", "Va bene!", "Subito!", "Assolutamente!" ] # -------------------------------------------------- # SEZIONE: ElevenLabs TTS (uguale a prima, solo per esempio) # -------------------------------------------------- def list_voices_elevenlabs(): url = "https://api.elevenlabs.io/v1/voices" headers = { "xi-api-key": API_KEYS["elevenlabs"] } try: resp = requests.get(url, headers=headers) if resp.status_code == 200: data = resp.json() return data.get("voices", []) else: logging.error(f"Errore nel recupero delle voci: {resp.text}") return [] except Exception as e: logging.error(f"Errore list_voices_elevenlabs: {e}") return [] def get_voice_id(voice_name): voices = list_voices_elevenlabs() for v in voices: if v["name"].lower() == voice_name.lower(): return v["voice_id"] return None def speak(text): voice_id = get_voice_id(CURRENT_VOICE_NAME) if not voice_id: print(f"[ERRORE] Impossibile reperire la voce '{CURRENT_VOICE_NAME}'.") return headers = { "xi-api-key": API_KEYS["elevenlabs"], "Content-Type": "application/json" } payload = { "text": text, "model_id": "eleven_multilingual_v1", "voice_settings": { "stability": 0.75, "similarity_boost": 0.75 } } try: url = f"https://api.elevenlabs.io/v1/text-to-speech/{voice_id}" response = requests.post(url, headers=headers, json=payload) if response.status_code == 200: audio = AudioSegment.from_file(io.BytesIO(response.content), format="mp3") play(audio) else: logging.error(f"[ERRORE] speak() TTS: {response.text}") except Exception as e: logging.error(f"[ERRORE] speak() eccezione: {e}") # -------------------------------------------------- # SEZIONE: Riconoscimento vocale & personalità # -------------------------------------------------- def take_command(): r = sr.Recognizer() with sr.Microphone() as source: r.adjust_for_ambient_noise(source) try: print("Ascoltando...") audio = r.listen(source, timeout=10) text = r.recognize_google(audio, language='it-IT') return text.lower() except sr.WaitTimeoutError: return "" except sr.UnknownValueError: return "" except Exception as e: logging.error(f"[ERRORE] take_command: {e}") return "" def is_activation_command(command): return any(cmd in command for cmd in ACTIVATION_COMMANDS) def random_greeting(): return random.choice(GREETING_VARIATIONS) def random_affirmative(): return random.choice(AFFIRMATIVE_RESPONSES) def maybe_personal_reply(user_input): if "come stai" in user_input: answers = [ "Sto benissimo, grazie del pensiero!", "Mi sento in forma smagliante!", "Alla grande, pronta a tutto!" ] speak(random.choice(answers)) return True if "chi sei" in user_input or "presentati" in user_input: speak(f"Sono {ASSISTANT_NAME}, la tua assistente virtuale. Sono felice di aiutarti in qualsiasi cosa.") return True if "grazie" in user_input: answers = [ "È un piacere darti una mano!", "Prego, figurati!", "Di nulla, sono qui apposta." ] speak(random.choice(answers)) return True if "sei una persona" in user_input or "sei un uomo" in user_input: speak("Mi identifico al femminile, anche se sono un'intelligenza artificiale.") return True return False # -------------------------------------------------- # FUNZIONE Chat01.ai (al posto di AI/ML query generica) # -------------------------------------------------- def ai_ml_query(): """ Invia una domanda al nuovo endpoint di Chat01.ai (in stile OpenAI ChatCompletion). URL di base: https://chat01.ai Endpoint: https://chat01.ai/v1/chat/completions """ speak("Qual è la tua domanda per l'intelligenza artificiale?") user_query = take_command() if not user_query: return try: url = "https://chat01.ai/v1/chat/completions" headers = { "Authorization": f"Bearer {API_KEYS['ai_ml']}", "Content-Type": "application/json" } # Struttura stile ChatCompletion payload = { "model": "gpt-4", # O un modello differente, se disponibile "messages": [ {"role": "system", "content": "Sei un assistente virtuale italiano."}, {"role": "user", "content": user_query} ], # eventuali altri parametri (temperature, etc.) se supportati } response = requests.post(url, headers=headers, json=payload, timeout=15) if response.status_code == 200: data = response.json() # Supponendo la risposta in stile OpenAI: # "choices": [{"message": {"content": "..."}}, ...] # Adatta se Chat01.ai risponde in modo diverso if "choices" in data and len(data["choices"]) > 0: answer = data["choices"][0]["message"]["content"] speak(answer) else: speak("Non ho trovato una risposta valida nell'output.") else: logging.error(f"[ERRORE] ai_ml_query: {response.text}") speak("Errore nella richiesta all'AI.") except requests.exceptions.Timeout: speak("La richiesta all'AI è scaduta, riprova più tardi.") except requests.exceptions.RequestException as e: logging.error(f"[ERRORE] ai_ml_query: {e}") speak("Errore nella richiesta all'AI. Controlla la connessione o riprova più tardi.") # -------------------------------------------------- # Esempio di altre funzioni # -------------------------------------------------- def weather(): speak("Dimmi la città per cui vuoi il meteo.") city = take_command() if not city: return try: url = "http://api.openweathermap.org/data/2.5/weather" params = { "q": city, "appid": API_KEYS["weather"], "units": "metric", "lang": "it" } res = requests.get(url, params=params).json() if res.get("cod") == 200: descrizione = res['weather'][0]['description'] temperatura = res['main']['temp'] speak(f"A {city} ci sono {temperatura} gradi e il tempo è {descrizione}.") else: speak("Mi dispiace, non ho trovato questa città.") except Exception as e: logging.error(f"[ERRORE] weather: {e}") speak("Errore nel recupero meteo.") def open_webpage(): speak("Quale sito vuoi aprire?") site = take_command() if not site: return if "youtube" in site: speak(random_affirmative() + " Apro YouTube.") webbrowser.open("https://www.youtube.com") return elif "google" in site: speak(random_affirmative() + " Apro Google.") webbrowser.open("https://www.google.com") return if not (site.startswith("http://") or site.startswith("https://")): site = "https://" + site speak(random_affirmative() + " Apro il sito richiesto.") webbrowser.open(site) def fetch_news(): speak("Attendi, sto recuperando le ultime notizie.") try: url = "https://newsapi.org/v2/top-headlines" params = { "country": "it", "apiKey": API_KEYS["news"] } response = requests.get(url, params=params) if response.status_code == 200: articles = response.json().get("articles", []) if articles: speak("Ecco alcune notizie importanti:") for article in articles[:5]: speak(article.get("title", "")) else: speak("Non ho trovato notizie da annunciarti.") else: logging.error(f"[ERRORE] fetch_news: {response.text}") speak("Errore nel recupero delle notizie.") except Exception as e: logging.error(f"[ERRORE] fetch_news: {e}") speak("Errore nella richiesta delle notizie.") def monitor_resources(): try: cpu_usage = psutil.cpu_percent(interval=1) memory_usage = psutil.virtual_memory().percent speak(f"Attualmente, l'uso della CPU è al {cpu_usage}%. La memoria è al {memory_usage}%.") except Exception as e: logging.error(f"[ERRORE] monitor_resources: {e}") speak("Errore nel monitoraggio delle risorse.") # Ecc. (altre funzioni come barzellette, converter, ecc.) # -------------------------------------------------- # HANDLE COMMAND # -------------------------------------------------- def handle_command(command): if is_activation_command(command): # Saluto speak(random_greeting()) sub_cmd = take_command() if not sub_cmd: return # Check se è domanda personale if maybe_personal_reply(sub_cmd): return # Comandi if "esci" in sub_cmd or "termina" in sub_cmd: speak("Arrivederci, a presto!") os._exit(0) elif "meteo" in sub_cmd: weather() elif "notizie" in sub_cmd: fetch_news() elif "intelligenza artificiale" in sub_cmd or "ai" in sub_cmd: ai_ml_query() # <-- usa Chat01.ai elif "apri" in sub_cmd or "website" in sub_cmd or "sito" in sub_cmd: open_webpage() elif "risorse" in sub_cmd: monitor_resources() else: speak("Comando non riconosciuto.") else: # Se non c'è keyword di attivazione, controlla se frasi personali maybe_personal_reply(command) # -------------------------------------------------- # ANIMAZIONE GUI E MAIN LOOP # -------------------------------------------------- def create_animation_window(): root = tk.Tk() root.title("Gideon Assistant") root.geometry("400x400") canvas = tk.Canvas(root, width=400, height=400, bg="black") canvas.pack() sphere = canvas.create_oval(150, 150, 250, 250, fill="blue") def animate(): for _ in range(20): canvas.move(sphere, 0, -5) root.update() sleep(0.05) for _ in range(20): canvas.move(sphere, 0, 5) root.update() sleep(0.05) return root, animate def main(): root, animate = create_animation_window() speak(f"Ciao, sono {ASSISTANT_NAME}. Dimmi 'Gideon' per iniziare.") def animation_loop(): while True: animate() sleep(0.1) anim_thread = threading.Thread(target=animation_loop, daemon=True) anim_thread.start() while True: cmd = take_command() if cmd: command_thread = threading.Thread(target=handle_command, args=(cmd,)) command_thread.start() root.update() if __name__ == "__main__": main()
https://chat01.ai/v1/chat/completions
Authorization: Bearer <la_tua_chiave>
Content-Type: application/json
Puoi cambiare il modello ({ "model": "gpt-4", "messages": [ {"role": "system", "content": "Sei un assistente virtuale italiano."}, {"role": "user", "content": "..."} ] }
"gpt-4"
, "gpt-3.5"
, ecc.) se Chat01.ai ne supporta di diversi."choices"
con un array di messaggi. Ad esempio:
Se la struttura fosse diversa, adegua di conseguenza l’estrazione di{ "id": "...", "object": "chat.completion", "created": 1234567890, "choices": [ { "index": 0, "message": { "role": "assistant", "content": "Ecco la risposta..." }, "finish_reason": "stop" } ], "usage": {...} }
answer
.ai_ml_query()
usa Chat01.ai con un prompt in stile Chat GPT-like.API_KEYS["ai_ml"]
.chat01.ai
è diversa dallo standard OpenAI, personalizza il parsing in if "choices" in data:
.Così avrai integrato la chiamata a chat01.ai/v1/chat/completions
al posto della vecchia aimlapi.com
. Buon sviluppo!