Necessito que adaptis el que et passare en dos arxius;
Un ha de contenir el codi per que generi tot el necessari + instaacions i tal per executar el següent, pero el següent l'has d'adaptar per a que no utilitzi el model llama que demana descarregar, sino que ha de fer servir un altre model llama creat des de 0 des de el meu ordinador. Tot i que aquest ultim pas ja el farem al final:





#!/bin/bash

# Actualitzar el sistema
sudo apt update
sudo apt upgrade -y

# Instal·lar dependències del sistema
sudo apt install python3-pip git build-essential libasound2-dev portaudio19-dev libportaudio2 libportaudiocpp0 ffmpeg -y

# Crear carpetes necessàries
mkdir -p model_voice
mkdir -p documents

# Descarregar el model de veu de Vosk (castellà com a exemple)
cd model_voice
wget https://alphacephei.com/vosk/models/vosk-model-small-es-0.42.zip
unzip vosk-model-small-es-0.42.zip
rm vosk-model-small-es-0.42.zip
cd ..

# Descarregar el model TinyLlama
pip3 install huggingface-hub
huggingface-cli login  # Introdueix el teu token si se't demana
huggingface-cli repo clone TheBloke/TinyLlama-1.1B-Chat-v1.0-GGUF
mv TinyLlama-1.1B-Chat-v1.0-GGUF/tinyllama-1.1b-chat-v1.0.Q2_K.gguf .
rm -rf TinyLlama-1.1B-Chat-v1.0-GGUF

# Crear fitxer requirements.txt
cat > requirements.txt <<EOL
RPi.GPIO
pyaudio
vosk
pyttsx3
llama-cpp-python
duckduckgo_search
faiss-cpu
transformers
sentence-transformers
huggingface-hub
EOL

# Instal·lar les biblioteques de Python
pip3 install --upgrade pip
pip3 install -r requirements.txt

echo "Configuració completada. Ara pots executar el programa 'xat.py'."




import os
import sys
import json
import pyttsx3
import pyaudio
from vosk import Model, KaldiRecognizer
from llama_cpp import Llama
import RPi.GPIO as GPIO
import time
import threading
from duckduckgo_search import DDGS
import faiss
from transformers import DPRContextEncoder, DPRContextEncoderTokenizer, DPRQuestionEncoder, DPRQuestionEncoderTokenizer
from sentence_transformers import SentenceTransformer
import numpy as np

# ------------------ CONFIGURACIONS ------------------

# GPIO Configuració
BUTTON_GPIO = 17  # GPIO per al botó
BUZZER_GPIO = 18  # GPIO per al buzzer

# Vosk Model
vosk_model_path = "model_voice/vosk-model-small-es-0.42"

# TinyLlama Model
llama_model_path = "./tinyllama-1.1b-chat-v1.0.Q2_K.gguf"

# Memòria de Conversa
memory_enabled = False
memory_file = "memoria_conversa.txt"

# TTS
tts_enabled = True

# Documents per a RAG
documents_path = "documents"  # Carpeta amb documents de text

# ------------------ INICIALITZACIONS ------------------

# Configuració de les GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(BUTTON_GPIO, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(BUZZER_GPIO, GPIO.OUT)

# Configuració del Buzzer amb PWM
buzzer = GPIO.PWM(BUZZER_GPIO, 440)  # 440Hz és la nota A

# Configuració de Vosk
if not os.path.exists(vosk_model_path):
    print("Model de Vosk no trobat.")
    sys.exit(1)
model_vosk = Model(vosk_model_path)
recognizer = KaldiRecognizer(model_vosk, 16000)

# Configuració de TTS amb pyttsx3
engine = pyttsx3.init()
engine.setProperty('rate', 150)  # Velocitat de la parla

# Configuració del model TinyLlama
llm = Llama(
    model_path=llama_model_path,
    n_ctx=2048,
    n_threads=4,  # Ajusta segons els recursos de la Raspberry Pi
    n_gpu_layers=0  # No utilitzis GPU per Raspberry Pi 3 B
)

# Inicialització de DuckDuckGo
ddgs = DDGS()

# Configuració per a RAG
# Carrega el model d'encoding
context_encoder = DPRContextEncoder.from_pretrained("facebook/dpr-ctx_encoder-single-nq-base")
context_tokenizer = DPRContextEncoderTokenizer.from_pretrained("facebook/dpr-ctx_encoder-single-nq-base")
question_encoder = DPRQuestionEncoder.from_pretrained("facebook/dpr-question_encoder-single-nq-base")
question_tokenizer = DPRQuestionEncoderTokenizer.from_pretrained("facebook/dpr-question_encoder-single-nq-base")

# Carrega o crea l'índex FAISS
embedding_dim = 768  # Dimensionalitat del embedding de DPR
index = faiss.IndexFlatL2(embedding_dim)

# Carrega els documents i crea embeddings
documents = []
doc_embeddings = []
for filename in os.listdir(documents_path):
    if filename.endswith(".txt"):
        with open(os.path.join(documents_path, filename), 'r', encoding='utf-8') as f:
            text = f.read()
            documents.append(text)
            inputs = context_tokenizer(text, return_tensors="pt", truncation=True, max_length=512)
            embeddings = context_encoder(**inputs).pooler_output.detach().numpy()
            doc_embeddings.append(embeddings[0])

if doc_embeddings:
    doc_embeddings = np.array(doc_embeddings).astype('float32')
    index.add(doc_embeddings)
else:
    print("No s'han trobat documents per a RAG.")

# ------------------ FUNCIONS ------------------

def text_to_speech(text):
    if not tts_enabled:
        return
    # Reproducció de text mitjançant TTS
    engine.say(text)
    engine.runAndWait()

def speech_to_text():
    p = pyaudio.PyAudio()
    stream = p.open(format=pyaudio.paInt16, channels=1, rate=16000, input=True, frames_per_buffer=8192)
    stream.start_stream()
    print("Escoltant... Digue alguna cosa!")

    while True:
        data = stream.read(4096, exception_on_overflow=False)
        if recognizer.AcceptWaveform(data):
            result = recognizer.Result()
            result_dict = json.loads(result)
            text = result_dict.get("text", "")
            if text:
                print(f"Has dit: {text}")
                if memory_enabled:
                    guardar_memoria(text)
                return text

def guardar_memoria(text):
    with open(memory_file, 'a', encoding='utf-8') as f:
        f.write(text + "\n")

def buscar_internet(query):
    results = []
    try:
        for result in ddgs.text(query, max_results=5):
            results.append(result['body'])
    except Exception as e:
        print(f"Error en la consulta a DuckDuckGo: {e}")
    return " ".join(results)

def consultar_rag(query):
    # Encodeix la pregunta
    inputs = question_tokenizer(query, return_tensors="pt")
    question_embedding = question_encoder(**inputs).pooler_output.detach().numpy()

    # Cerca en l'índex FAISS
    D, I = index.search(question_embedding, k=3)
    context = ""
    for idx in I[0]:
        if idx < len(documents):
            context += documents[idx] + "\n"

    return context

def generar_resposta(prompt, query):
    # Integra RAG
    context = consultar_rag(query)
    if context:
        prompt += f"\nContext:\n{context}\n"

    # Genera la resposta amb TinyLlama
    response = llm(prompt, max_tokens=150)
    response_text = response['choices'][0]['text'].strip()
    return response_text

def process_audio():
    while True:
        # Espera fins que el botó sigui premut
        GPIO.wait_for_edge(BUTTON_GPIO, GPIO.FALLING)
        print("Botó premut! Iniciant reconeixement de veu...")
        user_input = speech_to_text()
        if user_input.lower() in ["surt", "adéu", "sortir"]:
            print("Sortint...")
            text_to_speech("Adéu!")
            os._exit(0)

        # Processa la consulta
        resposta = processar_consulta(user_input)
        print(f"Assistente: {resposta}")
        text_to_speech(resposta)

def processar_consulta(user_input):
    # Si la consulta comença amb "internet:", realitza una cerca a Internet
    if user_input.lower().startswith("internet:"):
        query = user_input[len("internet:"):].strip()
        print(f"Realitzant consulta a Internet per: {query}")
        result_internet = buscar_internet(query)
        resposta = f"Això és el que he trobat a Internet: {result_internet}"
    else:
        # Utilitza RAG per obtenir context dels documents
        prompt = f"
\nEts un assistent amable.\n
\n{user_input}\n
\n"
        resposta = generar_resposta(prompt, user_input)

    if memory_enabled:
        guardar_memoria(resposta)

    return resposta

def processar_input_text():
    while True:
        user_input = input("Escriu la teva consulta (o 'surt' per sortir): ")
        if user_input.lower() in ["surt", "adéu", "sortir"]:
            print("Sortint...")
            text_to_speech("Adéu!")
            os._exit(0)

        # Processa la consulta
        resposta = processar_consulta(user_input)
        print(f"Assistente: {resposta}")
        text_to_speech(resposta)

def toggle_memory():
    global memory_enabled
    while True:
        comando = input("Escriu 'memoria on' o 'memoria off' per activar/desactivar la memòria: ")
        if comando.lower() == "memoria on":
            memory_enabled = True
            print("Memòria activada.")
        elif comando.lower() == "memoria off":
            memory_enabled = False
            print("Memòria desactivada.")
        else:
            print("Comando no reconegut. Utilitza 'memoria on' o 'memoria off'.")

def main():
    try:
        # Iniciar el fil per processar l'àudio
        audio_thread = threading.Thread(target=process_audio, daemon=True)
        audio_thread.start()

        # Iniciar el fil per processar l'entrada de text
        text_thread = threading.Thread(target=processar_input_text, daemon=True)
        text_thread.start()

        # Iniciar el fil per gestionar la memòria
        memory_thread = threading.Thread(target=toggle_memory, daemon=True)
        memory_thread.start()

        # Manté el programa principal actiu
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        print("Interrupció per l'usuari.")
    finally:
        GPIO.cleanup()
        print("GPIO netejat i programa finalitzat.")

if __name__ == "__main__":
    main()