File size: 4,717 Bytes
bcdac9f
 
cefc12a
 
 
 
 
 
bcdac9f
cefc12a
87968ae
cefc12a
bcdac9f
cefc12a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bcdac9f
 
cefc12a
 
 
 
 
 
 
bcdac9f
cefc12a
 
 
 
 
 
 
 
 
bcdac9f
cefc12a
bcdac9f
cefc12a
bcdac9f
cefc12a
bcdac9f
cefc12a
 
 
 
 
 
 
 
 
 
 
 
 
 
bcdac9f
 
 
 
 
 
cefc12a
bcdac9f
 
 
cefc12a
bcdac9f
 
 
cefc12a
 
bcdac9f
 
cefc12a
 
 
bcdac9f
cefc12a
 
bcdac9f
 
 
cefc12a
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import gradio as gr
from huggingface_hub import InferenceClient
import PyPDF2
from sentence_transformers import SentenceTransformer
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
import os
from typing import List, Tuple

# Inicialização do cliente de inferência e modelo de embeddings
client = InferenceClient("google/gemma-3-27b-it")
embedder = SentenceTransformer('all-MiniLM-L6-v2')

# Classe para gerenciar o conhecimento dos PDFs
class PDFKnowledgeBase:
    def __init__(self):
        self.documents = []
        self.embeddings = None
        
    def load_pdfs(self, pdf_directory: str):
        """Carrega todos os PDFs de um diretório"""
        self.documents = []
        for filename in os.listdir(pdf_directory):
            if filename.endswith('.pdf'):
                pdf_path = os.path.join(pdf_directory, filename)
                with open(pdf_path, 'rb') as file:
                    pdf_reader = PyPDF2.PdfReader(file)
                    text = ""
                    for page in pdf_reader.pages:
                        text += page.extract_text() + "\n"
                    self.documents.append({
                        'filename': filename,
                        'content': text
                    })
        
        # Gera embeddings para todos os documentos
        contents = [doc['content'] for doc in self.documents]
        self.embeddings = embedder.encode(contents, convert_to_numpy=True)
    
    def get_relevant_context(self, query: str, k: int = 3) -> str:
        """Recupera os k documentos mais relevantes para a query"""
        if self.embeddings is None or len(self.documents) == 0:
            return "Nenhum documento carregado ainda."
            
        query_embedding = embedder.encode(query, convert_to_numpy=True)
        similarities = cosine_similarity([query_embedding], self.embeddings)[0]
        
        # Obtém os índices dos k documentos mais similares
        top_k_indices = np.argsort(similarities)[-k:][::-1]
        
        # Constrói o contexto relevante
        context = ""
        for idx in top_k_indices:
            context += f"Documento: {self.documents[idx]['filename']}\n"
            context += f"Trecho: {self.documents[idx]['content'][:500]}...\n\n"
        
        return context

# Inicializa a base de conhecimento
knowledge_base = PDFKnowledgeBase()

def respond(
    message: str,
    history: List[Tuple[str, str]],
    system_message: str,
    max_tokens: int,
    temperature: float,
    top_p: float,
    pdf_directory: str
):
    # Carrega os PDFs se ainda não foram carregados
    if not knowledge_base.documents:
        knowledge_base.load_pdfs(pdf_directory)
    
    # Obtém contexto relevante da base de conhecimento
    context = knowledge_base.get_relevant_context(message)
    
    # Constrói o prompt com o contexto RAG
    rag_prompt = f"""Você é Grok 3, criado por xAI. Use o seguinte contexto dos documentos para responder à pergunta:

{context}

Pergunta do usuário: {message}

Responda de forma clara e precisa, utilizando o contexto quando relevante."""

    messages = [
        {"role": "system", "content": system_message},
        {"role": "user", "content": rag_prompt}
    ]
    
    # Adiciona histórico se existir
    for user_msg, assistant_msg in history:
        if user_msg:
            messages.append({"role": "user", "content": user_msg})
        if assistant_msg:
            messages.append({"role": "assistant", "content": assistant_msg})

    response = ""
    for message_chunk in client.chat_completion(
        messages,
        max_tokens=max_tokens,
        stream=True,
        temperature=temperature,
        top_p=top_p,
    ):
        token = message_chunk.choices[0].delta.content
        response += token
        yield response

# Interface do Gradio
demo = gr.ChatInterface(
    respond,
    additional_inputs=[
        gr.Textbox(value="Você é um assistente útil que responde com base em documentos PDF.", 
                  label="System message"),
        gr.Slider(minimum=1, maximum=2048, value=512, step=1, label="Max new tokens"),
        gr.Slider(minimum=0.1, maximum=4.0, value=0.7, step=0.1, label="Temperature"),
        gr.Slider(minimum=0.1, maximum=1.0, value=0.95, step=0.05, 
                 label="Top-p (nucleus sampling)"),
        gr.Textbox(value="./pdfs", label="Diretório dos PDFs"),
    ],
    title="RAG Chatbot com PDFs",
    description="Faça perguntas e obtenha respostas baseadas em documentos PDF carregados."
)

if __name__ == "__main__":
    # Crie um diretório 'pdfs' e coloque seus PDFs lá
    if not os.path.exists("./pdfs"):
        os.makedirs("./pdfs")
        
    demo.launch()