rwayz commited on
Commit
a8f41dd
·
verified ·
1 Parent(s): 5b7f9ec

Upload 3 files

Browse files
Files changed (3) hide show
  1. app.py +232 -0
  2. model_training_part1.json +0 -0
  3. requirements.txt +14 -0
app.py ADDED
@@ -0,0 +1,232 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import time
3
+ import json
4
+ import pandas as pd
5
+ import numpy as np
6
+ from sqlalchemy import create_engine
7
+ from langchain_openai import ChatOpenAI
8
+ from langchain_community.agent_toolkits import create_sql_agent
9
+ from langchain_community.utilities import SQLDatabase
10
+ from huggingface_hub import InferenceClient
11
+ import gradio as gr
12
+ from dotenv import load_dotenv
13
+ import logging
14
+
15
+ load_dotenv()
16
+
17
+ JSON_FILE_PATH = "model_training_part1.json"
18
+ SQL_DB_PATH = "data.db"
19
+ HF_API_KEY = os.getenv("HF_API_KEY")
20
+ OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
21
+ LLAMA_MODEL = "meta-llama/Llama-3.3-70B-Instruct"
22
+ LLAMA_MODEL_ALTERNATIVO = "meta-llama/Llama-3.1-8B-Instruct"
23
+
24
+ hf_client = InferenceClient(api_key=HF_API_KEY)
25
+ os.environ["OPENAI_API_KEY"] = OPENAI_API_KEY
26
+
27
+ query_cache = {}
28
+ history_log = []
29
+ recent_history = []
30
+ show_history_flag = False
31
+ advanced_mode_enabled = False
32
+
33
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
34
+
35
+ def create_or_load_sql_database(json_path, sql_db_path):
36
+ if os.path.exists(sql_db_path):
37
+ print("Banco de dados SQL já existe. Carregando...")
38
+ return create_engine(f"sqlite:///{sql_db_path}")
39
+ else:
40
+ print("Banco de dados SQL não encontrado. Criando...")
41
+ engine = create_engine(f"sqlite:///{sql_db_path}")
42
+
43
+ with open(json_path, "r", encoding="utf-8") as f:
44
+ data = json.load(f)
45
+
46
+ df = pd.DataFrame(data)
47
+ df.to_sql("perguntas_respostas", engine, index=False, if_exists="replace")
48
+ print("Banco de dados SQL criado com sucesso!")
49
+ return engine
50
+
51
+ engine = create_or_load_sql_database(JSON_FILE_PATH, SQL_DB_PATH)
52
+ db = SQLDatabase(engine=engine)
53
+
54
+ llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.2)
55
+ sql_agent = create_sql_agent(llm, db=db, agent_type="openai-tools", verbose=True, max_iterations=50, return_intermediate_steps=True)
56
+
57
+ def generate_initial_context(db_sample):
58
+ return (
59
+ f"Você é um assistente que gera queries SQL objetivas e eficientes. Sempre inclua `LIMIT 20` nas queries. Aqui está o banco de dados:\n\n"
60
+ f"Exemplos de valores:\n{db_sample.head().to_string(index=False)}\n\n"
61
+
62
+ "**📌 Estrutura do Banco de Dados:**\n"
63
+ "A base de dados contém informações sobre perguntas e respostas relacionadas à reforma tributária, bem como artigos e leis tributárias.\n\n"
64
+
65
+ "**📍 Colunas e seus Significados:**\n"
66
+ "- `instruction` → Pergunta do usuário\n"
67
+ "- `response` → Resposta correspondente à pergunta\n"
68
+ "- `text` → Explicação detalhada da resposta\n"
69
+ "- `title` → Título da lei\n"
70
+ "- `chapter` → Capítulo da lei\n"
71
+ "- `section` → Seção da lei\n"
72
+ "- `content` → Aritgo e texto completo da lei\n\n"
73
+
74
+ "**📌 Importante:**\n"
75
+ "- Nem todas as colunas estarão preenchidas em todos os registros. Por exemplo, leis não têm `instruction` ou `response`, enquanto perguntas não têm `title`, `chapter`, `section` ou `content`.\n"
76
+ "- Ao buscar perguntas e respostas, utilize as colunas `instruction` e `response`.\n"
77
+ "- Ao buscar informações sobre leis, use `title`, `chapter`, `section` e `content`.\n\n"
78
+
79
+ "**📝 Exemplo de Queries SQL Bem Formadas:**\n"
80
+ "1️⃣ **Buscar uma pergunta e resposta específica:**\n"
81
+ "```sql\n"
82
+ "SELECT response FROM perguntas_respostas WHERE instruction = 'Qual é o objetivo da reforma tributária?' LIMIT 20;\n"
83
+ "```\n"
84
+ "2️⃣ **Buscar um artigo de lei específico pelo seu conteúdo:**\n"
85
+ "```sql\n"
86
+ "SELECT content FROM perguntas_respostas WHERE content LIKE '%Art. 146%' LIMIT 20;\n"
87
+ "```\n\n"
88
+
89
+ "**🔎 Instruções para a Geração da Query SQL:**\n"
90
+ "- Analise a pergunta do usuário e determine se a resposta deve vir de `instruction/response` (perguntas e respostas) ou `content` (leis e artigos).\n"
91
+ "- Se a pergunta estiver relacionada a um artigo de lei, use `content` e busque por palavras-chave relevantes.\n"
92
+ "- Pode realizar a busca por perguntas nos artigos de lei também caso seja conveniente.\n"
93
+ "- Se a pergunta for aberta e não encontrar correspondência exata, use `LIKE` para busca aproximada.\n\n"
94
+
95
+ "**🔄 Formato de Saída Esperado:**\n"
96
+ "Pergunta: <pergunta do usuário>\n"
97
+ "Opção de Query SQL:\n<query SQL>\n"
98
+ "Idioma: Português"
99
+ )
100
+
101
+ def is_greeting(user_query):
102
+ greetings = ["olá", "oi", "bom dia", "boa tarde", "boa noite", "oi, tudo bem?"]
103
+ return user_query.lower().strip() in greetings
104
+
105
+ def query_with_llama(user_query, db_sample):
106
+ initial_context = generate_initial_context(db_sample)
107
+ formatted_history = "\n".join([
108
+ f"{msg['role'].capitalize()}: {msg['content']}" for msg in recent_history[-2:]
109
+ ])
110
+
111
+ full_prompt = f"{initial_context}\n\nHistórico recente:\n{formatted_history}\n\nPergunta do usuário:\n{user_query}"
112
+ logging.info(f"[DEBUG] Contexto enviado ao Llama:\n{full_prompt}\n")
113
+ start_time = time.time()
114
+
115
+ try:
116
+ response = hf_client.chat.completions.create(
117
+ model=LLAMA_MODEL,
118
+ messages=[{"role": "system", "content": full_prompt}],
119
+ max_tokens=900,
120
+ stream=False
121
+ )
122
+ llama_response = response["choices"][0]["message"]["content"]
123
+ end_time = time.time()
124
+ logging.info(f"[DEBUG] Resposta do Llama para o Agent SQL:\n{llama_response.strip()}\n[Tempo de execução: {end_time - start_time:.2f}s]\n")
125
+ return llama_response.strip()
126
+ except Exception as e:
127
+ logging.error(f"[ERRO] Falha ao interagir com o Llama: {e}")
128
+ return None
129
+
130
+ def refine_response_with_llm(user_question, sql_response):
131
+ prompt = (
132
+ f"Pergunta do usuário:\n{user_question}\n\n"
133
+ f"Resposta gerada pelo agente SQL:\n{sql_response}\n\n"
134
+ "Sua tarefa é refinar, complementar e melhorar a resposta."
135
+ )
136
+
137
+ logging.info(f"[DEBUG] Prompt enviado ao modelo de refinamento:\n{prompt}\n")
138
+
139
+ try:
140
+ response = hf_client.chat.completions.create(
141
+ model=LLAMA_MODEL,
142
+ messages=[{"role": "system", "content": prompt}],
143
+ max_tokens=1200,
144
+ stream=False
145
+ )
146
+ improved_response = response["choices"][0]["message"]["content"]
147
+ logging.info(f"[DEBUG] Resposta do modelo de refinamento:\n{improved_response}\n")
148
+ return improved_response
149
+
150
+ except Exception as e:
151
+ logging.error(f"[ERRO] Falha ao refinar resposta com LLM: {e}")
152
+ return sql_response
153
+
154
+ def query_sql_agent(user_query):
155
+ try:
156
+ if user_query in query_cache:
157
+ print(f"[CACHE] Retornando resposta do cache para a consulta: {user_query}")
158
+ return query_cache[user_query]
159
+
160
+ if is_greeting(user_query):
161
+ greeting_response = "Olá! Estou aqui para ajudar com suas consultas. Pergunte algo relacionado aos dados carregados no agente!"
162
+ query_cache[user_query] = greeting_response
163
+ return greeting_response
164
+
165
+ column_data = pd.read_sql_query("SELECT * FROM perguntas_respostas LIMIT 10", engine)
166
+ llama_instruction = query_with_llama(user_query, column_data)
167
+ if not llama_instruction:
168
+ return "Erro: O modelo Llama não conseguiu gerar uma instrução válida."
169
+
170
+ print("------- Agent SQL: Executando query -------")
171
+ response = sql_agent.invoke({"input": llama_instruction})
172
+ sql_response = response.get("output", "Erro ao obter a resposta do agente.")
173
+
174
+ if advanced_mode_enabled:
175
+ sql_response = refine_response_with_llm(user_query, sql_response)
176
+
177
+ query_cache[user_query] = sql_response
178
+ return sql_response
179
+
180
+ except Exception as e:
181
+ return f"Erro ao consultar o agente SQL: {e}"
182
+
183
+ def chatbot_response(user_input):
184
+ start_time = time.time()
185
+ response = query_sql_agent(user_input)
186
+ end_time = time.time()
187
+
188
+ history_log.append({"Pergunta": user_input, "Resposta": response, "Tempo de Resposta (s)": round(end_time - start_time, 2)})
189
+ recent_history.append({"role": "user", "content": user_input})
190
+ recent_history.append({"role": "assistant", "content": response})
191
+
192
+ if len(recent_history) > 4:
193
+ recent_history.pop(0)
194
+ recent_history.pop(0)
195
+
196
+ return response
197
+
198
+ def toggle_history():
199
+ global show_history_flag
200
+ show_history_flag = not show_history_flag
201
+ return history_log if show_history_flag else {}
202
+
203
+ def toggle_advanced_mode(state):
204
+ global advanced_mode_enabled
205
+ advanced_mode_enabled = state
206
+ logging.info(f"[MODO AVANÇADO] {'Ativado' if state else 'Desativado'}")
207
+ return "Modo avançado ativado." if state else "Modo avançado desativado."
208
+
209
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
210
+ gr.Markdown("# Tributario Agent")
211
+ chatbot = gr.Chatbot(height=600)
212
+ msg = gr.Textbox(placeholder="Digite sua pergunta aqui...", label=" ", lines=1)
213
+
214
+ def respond(message, chat_history):
215
+ response = chatbot_response(message)
216
+ chat_history.append((message, response))
217
+ return "", chat_history
218
+
219
+ with gr.Row():
220
+ btn = gr.Button("Enviar", variant="primary")
221
+ history_btn = gr.Button("Histórico", variant="secondary")
222
+ advanced_toggle = gr.Checkbox(label="MODO AVANÇADO", value=False)
223
+
224
+ msg.submit(respond, [msg, chatbot], [msg, chatbot])
225
+ btn.click(respond, [msg, chatbot], [msg, chatbot])
226
+ advanced_toggle.change(toggle_advanced_mode, inputs=[advanced_toggle], outputs=[])
227
+
228
+ history_output = gr.JSON()
229
+ history_btn.click(toggle_history, inputs=[], outputs=history_output)
230
+
231
+ if __name__ == "__main__":
232
+ demo.launch(share=False)
model_training_part1.json ADDED
The diff for this file is too large to render. See raw diff
 
requirements.txt ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ pandas
2
+ sqlalchemy
3
+ langchain-openai
4
+ langchain-community
5
+ langchain-core
6
+ huggingface-hub
7
+ gradio
8
+ python-dotenv
9
+ openai
10
+ PyPDF2
11
+ pdfplumber
12
+ matplotlib
13
+ pillow
14
+ numpy