rwayz commited on
Commit
23bfddb
·
verified ·
1 Parent(s): 028a34b

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +161 -0
  2. requirements.txt +11 -0
app.py ADDED
@@ -0,0 +1,161 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import time
3
+ import pandas as pd
4
+ from sqlalchemy import create_engine
5
+ from langchain_openai import ChatOpenAI
6
+ from langchain_community.agent_toolkits import create_sql_agent
7
+ from langchain_community.utilities import SQLDatabase
8
+ from huggingface_hub import InferenceClient
9
+ import gradio as gr
10
+ from dotenv import load_dotenv
11
+ import logging
12
+
13
+ load_dotenv()
14
+
15
+ CSV_FILE_PATH = "anomalia_vendas.csv"
16
+ SQL_DB_PATH = "data.db"
17
+ HUGGINGFACE_API_KEY = os.getenv("HUGGINGFACE_API_KEY")
18
+ OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
19
+ LLAMA_MODEL = "meta-llama/Llama-3.3-70B-Instruct"
20
+
21
+ hf_client = InferenceClient(api_key=HUGGINGFACE_API_KEY)
22
+ os.environ["OPENAI_API_KEY"] = OPENAI_API_KEY
23
+
24
+ query_cache = {}
25
+ history_log = []
26
+ recent_history = []
27
+ show_history_flag = False
28
+
29
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
30
+
31
+ def create_or_load_sql_database(csv_path, sql_db_path):
32
+ if os.path.exists(sql_db_path):
33
+ print("Banco de dados SQL já existe. Carregando...")
34
+ return create_engine(f"sqlite:///{sql_db_path}")
35
+ else:
36
+ print("Banco de dados SQL não encontrado. Criando...")
37
+ engine = create_engine(f"sqlite:///{sql_db_path}")
38
+ df = pd.read_csv(csv_path, sep=";", on_bad_lines="skip")
39
+ print(f"CSV carregado: {len(df)} linhas, {len(df.columns)} colunas")
40
+ df.to_sql("anomalia_vendas", engine, index=False, if_exists="replace")
41
+ print("Banco de dados SQL criado com sucesso!")
42
+ return engine
43
+
44
+ engine = create_or_load_sql_database(CSV_FILE_PATH, SQL_DB_PATH)
45
+ db = SQLDatabase(engine=engine)
46
+
47
+ llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
48
+ sql_agent = create_sql_agent(llm, db=db, agent_type="openai-tools", verbose=True, max_iterations=40, return_intermediate_steps=True)
49
+
50
+ def generate_initial_context(db_sample):
51
+ return (
52
+ f"Você é um assistente que gera queries SQL objetivas e eficientes. Sempre inclua LIMIT 15 nas queries. Aqui está o banco de dados:\n\n"
53
+ ###f"Colunas: {', '.join(db_sample.columns)}\n"
54
+ f"Exemplos do banco de dados:\n{db_sample.head().to_string(index=False)}\n\n"
55
+ "\n***IMPORTANTE***: Detecte automaticamente o idioma da pergunta do usuário e responda sempre no mesmo idioma.\n"
56
+ "Essa base de dados representa o sellout de 2025, janeiro, fevereiro e março até dia 11, de uma farmácia.\n"
57
+ "Cada linha representa a venda de um SKU em uma determinada data.\n"
58
+ "\nRetorne apenas a pergunta e a query SQL mais eficiente para entregar ao agent SQL do LangChain para gerar uma resposta para a pergunta. O formato deve ser:\n"
59
+ "\nPergunta: <pergunta do usuário>\n"
60
+ "\nOpção de Query SQL:\n<query SQL>"
61
+ "\nIdioma: <idioma>"
62
+ )
63
+
64
+ def is_greeting(user_query):
65
+ greetings = ["olá", "oi", "bom dia", "boa tarde", "boa noite", "oi, tudo bem?"]
66
+ return user_query.lower().strip() in greetings
67
+
68
+ def query_with_llama(user_query, db_sample):
69
+ initial_context = generate_initial_context(db_sample)
70
+ formatted_history = "\n".join(
71
+ [f"{msg['role'].capitalize()}: {msg['content']}" for msg in recent_history[-2:]]
72
+ )
73
+
74
+ full_prompt = f"{initial_context}\n\nHistórico recente:\n{formatted_history}\n\nPergunta do usuário:\n{user_query}"
75
+
76
+ logging.info(f"[DEBUG] Contexto enviado ao Llama:\n{full_prompt}\n")
77
+
78
+ start_time = time.time()
79
+ try:
80
+ response = hf_client.chat.completions.create(
81
+ model=LLAMA_MODEL,
82
+ messages=[{"role": "system", "content": full_prompt}],
83
+ max_tokens=500,
84
+ stream=False
85
+ )
86
+ llama_response = response["choices"][0]["message"]["content"]
87
+ end_time = time.time()
88
+ 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")
89
+ return llama_response.strip()
90
+ except Exception as e:
91
+ logging.error(f"[ERRO] Falha ao interagir com o Llama: {e}")
92
+ return None
93
+
94
+ def query_sql_agent(user_query):
95
+ try:
96
+ if user_query in query_cache:
97
+ print(f"[CACHE] Retornando resposta do cache para a consulta: {user_query}")
98
+ return query_cache[user_query]
99
+
100
+ if is_greeting(user_query):
101
+ greeting_response = "Olá! Estou aqui para ajudar com suas consultas. Pergunte algo relacionado aos dados carregados no agente!"
102
+ query_cache[user_query] = greeting_response # Armazena saudação no cache
103
+ return greeting_response
104
+
105
+ column_data = pd.read_sql_query("SELECT * FROM anomalia_vendas LIMIT 10", engine)
106
+ llama_instruction = query_with_llama(user_query, column_data)
107
+ if not llama_instruction:
108
+ return "Erro: O modelo Llama não conseguiu gerar uma instrução válida."
109
+
110
+ print("------- Agent SQL: Executando query -------")
111
+ response = sql_agent.invoke({"input": llama_instruction})
112
+ sql_response = response.get("output", "Erro ao obter a resposta do agente.")
113
+
114
+ query_cache[user_query] = sql_response
115
+ return sql_response
116
+
117
+ except Exception as e:
118
+ return f"Erro ao consultar o agente SQL: {e}"
119
+
120
+ def chatbot_response(user_input):
121
+ start_time = time.time()
122
+ response = query_sql_agent(user_input)
123
+ end_time = time.time()
124
+
125
+ history_log.append({"Pergunta": user_input, "Resposta": response, "Tempo de Resposta (s)": round(end_time - start_time, 2)})
126
+ recent_history.append({"role": "user", "content": user_input})
127
+ recent_history.append({"role": "assistant", "content": response})
128
+
129
+ if len(recent_history) > 4:
130
+ recent_history.pop(0)
131
+ recent_history.pop(0)
132
+
133
+ return response
134
+
135
+ def toggle_history():
136
+ global show_history_flag
137
+ show_history_flag = not show_history_flag
138
+ return history_log if show_history_flag else {}
139
+
140
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
141
+ gr.Markdown("# Anomalia Agent")
142
+ chatbot = gr.Chatbot(height=600)
143
+ msg = gr.Textbox(placeholder="Digite sua pergunta aqui...", label=" ", lines=1)
144
+
145
+ def respond(message, chat_history):
146
+ response = chatbot_response(message)
147
+ chat_history.append((message, response))
148
+ return "", chat_history
149
+
150
+ with gr.Row():
151
+ btn = gr.Button("Enviar", variant="primary")
152
+ history_btn = gr.Button("Histórico", variant="secondary")
153
+
154
+ msg.submit(respond, [msg, chatbot], [msg, chatbot])
155
+ btn.click(respond, [msg, chatbot], [msg, chatbot])
156
+
157
+ history_output = gr.JSON()
158
+ history_btn.click(toggle_history, inputs=[], outputs=history_output)
159
+
160
+ if __name__ == "__main__":
161
+ demo.launch(share=False)
requirements.txt ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
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