File size: 7,558 Bytes
1768992
 
 
 
 
 
 
 
 
7d20361
 
 
 
 
 
 
 
 
 
 
 
 
9474502
ad73f05
 
 
9474502
 
 
 
 
f819bed
7243c9b
 
f819bed
7d20361
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73bbdbf
7d20361
00f6446
7d20361
 
 
00f6446
7d20361
 
 
 
1768992
ad73f05
 
 
 
1768992
ad73f05
1768992
 
 
 
 
 
 
 
 
fbe315c
 
1768992
 
 
 
 
 
4d5bf0e
1768992
 
 
 
 
 
 
 
 
 
7243c9b
 
 
 
1768992
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fbe315c
1768992
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fbe315c
1768992
 
 
 
 
 
 
 
b0fb599
 
 
1768992
 
 
 
 
 
9474502
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
import os
import yaml
import gradio as gr # Importe o Gradio
from langchain_huggingface import ChatHuggingFace
from langchain_huggingface.llms.huggingface_endpoint import HuggingFaceEndpoint
from langchain_community.vectorstores import FAISS
from langchain.chains import RetrievalQA
from langchain_huggingface.embeddings import HuggingFaceEmbeddings
from langchain.prompts import PromptTemplate 
from langchain_community.document_loaders import WebBaseLoader
from langchain_text_splitters import CharacterTextSplitter
from langchain_community.vectorstores import FAISS
from langchain_huggingface import HuggingFaceEmbeddings
from dotenv import load_dotenv
import os
import logging
logging.getLogger("langchain.text_splitter").setLevel(logging.ERROR)
import warnings
warnings.filterwarnings("ignore")
from langchain_community.document_loaders import RecursiveUrlLoader
import yaml

# #----------- local paths -----------
CACHE_FOLDER = "./model/"
LOCAL_FOLDER = "./model/"
VS_BASE = "./vector_store/vs_base"

os.makedirs(CACHE_FOLDER, exist_ok=True)
os.makedirs(LOCAL_FOLDER, exist_ok=True)
os.makedirs(VS_BASE, exist_ok=True)

# --- CONFIGURAÇÕES DE MODELOS ---
# LLM_MODEL = 'google/gemma-3-4b-it'
LLM_MODEL = 'google/gemma-3-12b-it'
EMBEDDING_MODEL = "sentence-transformers/all-MiniLM-L6-v2"

# ------------ criando vs -----------------

## knowledge base offline
url_list = [
"https://www.infinitepay.io", 
"https://www.infinitepay.io/maquininha", 
"https://www.infinitepay.io/maquininha-celular", 
"https://www.infinitepay.io/tap-to-pay", 
"https://www.infinitepay.io/pdv", 
"https://www.infinitepay.io/receba-na-hora", 
"https://www.infinitepay.io/gestao-de-cobranca",  
"https://www.infinitepay.io/gestao-de-cobranca-2",  
"https://www.infinitepay.io/link-de-pagamento", 
"https://www.infinitepay.io/loja-online", 
"https://www.infinitepay.io/boleto", 
"https://www.infinitepay.io/conta-digital", 
"https://www.infinitepay.io/conta-pj", 
"https://www.infinitepay.io/pix",
"https://www.infinitepay.io/pix-parcelado", 
"https://www.infinitepay.io/emprestimo", 
"https://www.infinitepay.io/cartao", 
"https://www.infinitepay.io/rendimento",
'https://www.infinitepay.io/taxas',
'https://www.cloudwalk.io/',
'https://www.cloudwalk.io/#our-mission',
'https://www.cloudwalk.io/#our-pillars',
'https://www.cloudwalk.io/#our-products',
]

# Carregue o conteúdo da página web como documentos LangChain
loader = WebBaseLoader(web_paths=url_list)
docs = loader.load()
#print(f"Total de páginas carregadas: {len(docs)}")

text_splitter = CharacterTextSplitter(chunk_size=1500, chunk_overlap=100)
split_docs = text_splitter.split_documents(docs)
embeddings = HuggingFaceEmbeddings(model_name=EMBEDDING_MODEL)
vector_store = FAISS.from_documents(split_docs, embeddings)
os.makedirs(VS_BASE, exist_ok=True)
vector_store.save_local(VS_BASE)
print(f"vs_base salva em {VS_BASE}")

# --- CONFIGURAÇÃO HF ---
HF_TOKEN = os.getenv("HF_TOKEN") # Use os.getenv para ler a variável de ambiente
if not HF_TOKEN:
    raise ValueError("HF_TOKEN não encontrado. Por favor, defina-o nos segredos do Hugging Face Space.")

os.environ["HF_HUB_USER_AGENT"] = "CloudWalk_Chatbot" 

# --- 1. Inicializa o LLM Hugging Face ---
llm = HuggingFaceEndpoint(
    repo_id=LLM_MODEL,
    task="text-generation",
    max_new_tokens=1024,
    do_sample=False,
    repetition_penalty=1.03,
    huggingfacehub_api_token=HF_TOKEN,
)

chat_model = ChatHuggingFace(llm=llm)

# --- 2. Inicializa os embeddings ---
embeddings = HuggingFaceEmbeddings(model_name=EMBEDDING_MODEL)

# --- 3. Carregando a vector store FAISS salva localmente ---
vector_store_path = './vector_store/vs_base/'
try:
    faiss_store = FAISS.load_local(vector_store_path, embeddings, allow_dangerous_deserialization=True)
except Exception as e:
    print(f"Erro ao carregar a vector store FAISS: {e}")
    print("Verifique se o caminho está correto e se o arquivo não está corrompido.")
    exit()

# --- 4. Retriever a partir da vector store (usando similarity como exemplo) ---
retriever = faiss_store.as_retriever(search_type="similarity", search_kwargs={"k": 10})

# retriever = faiss_store.as_retriever(
#     search_type="mmr",
#     search_kwargs={"k": 5, "fetch_k": 20, "lambda_mult": 0.7}
# )

# --- 5. PromptTemplate personalizado ---
custom_prompt_template = """
You are a useful chatbot for customer service.
If you don't know the answer, just say that you don't know, don't try to make up an answer.
ALWAYS RESPONDE IN THE SAME LANGUAGE AS THE INPUT.

Use the following pieces of context to answer the user's question.
{context}

Question: {question}
Helpful Answer:"""

# Crie um objeto PromptTemplate a partir da string
QA_CHAIN_PROMPT = PromptTemplate.from_template(custom_prompt_template)

# --- 6. Cria uma cadeia de QA que usa o retriever e o modelo ---
qa_chain = RetrievalQA.from_chain_type(
    llm=chat_model,
    chain_type="stuff",
    retriever=retriever,
    return_source_documents=True,
    chain_type_kwargs={"prompt": QA_CHAIN_PROMPT}
)

# --- 7. Função principal para a interface do Gradio ---
def chat_response(question: str, history: list): # `history` é um parâmetro obrigatório para gr.ChatInterface
    """
    Gera a resposta do chatbot usando o modelo de QA e formata para exibição no Gradio.

    Args:
        question (str): A pergunta do usuário.
        history (list): Histórico de conversas (não usado diretamente aqui, mas necessário para a interface).

    Returns:
        str: A resposta formatada do chatbot, incluindo as fontes.
    """
    print(f"Recebida pergunta: '{question}'") # Para debug no console

    try:
        result = qa_chain.invoke({"query": question})
        answer = result["result"]
        sources = result.get("source_documents", [])

        response_text = f"**Resposta:** {answer}\n\n"

        if sources:
            response_text += "**Saiba mais em:**\n"
            unique_sources = set()
            source_list_for_printing = []

            for doc in sources:
                source_name = doc.metadata.get('source', 'Fonte desconhecida')
                if source_name not in unique_sources:
                    unique_sources.add(source_name)
                    source_list_for_printing.append(source_name)

            for i, source_name in enumerate(source_list_for_printing):
                response_text += f"- {i+1}. '{source_name}'\n"
        else:
            response_text += "Nenhuma fonte específica foi utilizada para esta resposta.\n"
        
        return response_text

    except Exception as e:
        error_message = f"Ocorreu um erro ao processar sua pergunta: {e}. Por favor, tente novamente."
        print(error_message) # Para debug no console
        return error_message

# --- 8. Criação da Interface Gradio ---
if __name__ == "__main__":
    print("Iniciando a interface Gradio...")
    demo = gr.ChatInterface(
        type="messages",
        fn=chat_response, # A função que processa a pergunta e retorna a resposta
        title="CloudWalk Chatbot",
        description="Olá! Estou aqui para responder suas dúvidas.",
        submit_btn="Enviar Pergunta",
        examples=[
            #["What product and services InfinitePay offer ?"],
            #['What are the fees for the card machine?'],
            #['How can I order one card machine?'],
            ["Quais serviços a infinite pay oferece?"],
            ["Quais as taxas da maquininha?"],
            ["Como pedir uma maquininha?"],
        ],
        chatbot=gr.Chatbot(type="messages")
    )
    demo.launch()