import speech_recognition as sr
from llama_cpp import Llama
import threading
import queue
import time

def listen_for_speech(audio_queue):
    r = sr.Recognizer()
    with sr.Microphone() as source:
        print("In ascolto...")
        r.adjust_for_ambient_noise(source)
        while True:
            try:
                audio = r.listen(source, timeout=None, phrase_time_limit=10)
                audio_queue.put(audio)
            except sr.WaitTimeoutError:
                continue

def transcribe_audio(audio):
    r = sr.Recognizer()
    try:
        text = r.recognize_google(audio, language="it-IT")
        return text
    except sr.UnknownValueError:
        print("Nessuna voce")
        return None
    except sr.RequestError as e:
        print(f"Impossibile richiedere risultati dal servizio di riconoscimento vocale; {e}")
        return None

model_path = "Gemma-2.6B-F16.gguf"
llm = Llama(model_path=model_path, n_ctx=8919)

chat_history = []
audio_queue = queue.Queue()
interrupt_event = threading.Event()

listening_thread = threading.Thread(target=listen_for_speech, args=(audio_queue,))
listening_thread.daemon = True
listening_thread.start()

def get_last_role():
    return chat_history[-1]["role"] if chat_history else None

def generate_response(prompt):
    response = ""
    stream = llm.create_chat_completion(
        messages=prompt,
        stream=True,
        temperature=0.7,
        max_tokens=150
    )
    
    for chunk in stream:
        if interrupt_event.is_set():
            break
        if "content" in chunk["choices"][0]["delta"]:
            response_piece = chunk["choices"][0]["delta"]["content"]
            if response_piece.strip() not in ["<end_of_turn>", "<eos>"]:
                response += response_piece
                print(response_piece, end="", flush=True)
            else:
                break
    
    return response.strip()

while True:
    print("\nParla per fare una domanda...")
    audio = audio_queue.get()
    user_query = transcribe_audio(audio)
    
    if user_query:
        print(f"Hai detto: {user_query}")
        
        if get_last_role() != "assistant":
            chat_history.append({"role": "user", "content": user_query})
        else:
            chat_history.append({"role": "user", "content": user_query})
        
        interrupt_event.clear()
        
        def check_for_interrupt():
            while not interrupt_event.is_set():
                if not audio_queue.empty():
                    interrupt_event.set()
                    break
                time.sleep(0.1)
        
        interrupt_checker = threading.Thread(target=check_for_interrupt)
        interrupt_checker.daemon = True
        interrupt_checker.start()
        
        lm_response = generate_response(chat_history)
        
        if interrupt_event.is_set():
            print(" <interruzione>")
            lm_response += " <interruzione>"
        elif not lm_response:
            print(" <nessuna risposta>")
        else:
            print()  # Nuova linea dopo la risposta completa
        
        if lm_response:
            chat_history.append({"role": "assistant", "content": lm_response})
    else:
        print("Nessun discorso rilevato o impossibile trascrivere. Per favore riprova.")

    # Pulisci la coda audio
    while not audio_queue.empty():
        try:
            audio_queue.get_nowait()
        except queue.Empty:
            break


con questo codice posso avere conversazioni fluide e interrompere la risposta streaming del modello. solo che c'è un problema: spesso, avviene l' interruzione dell output streaming perchè vengono rilevati dei rumori, e questo credo che influisca sulla interruzione. come si può regolare solo quando sente la mia voce?