Spaces:
Sleeping
Sleeping
File size: 6,125 Bytes
8752160 46e8b1c 8752160 46e8b1c 8752160 46e8b1c 8752160 fada342 46e8b1c 8752160 46e8b1c 8752160 46e8b1c 8752160 46e8b1c 8752160 46e8b1c 8752160 | 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 | import streamlit as st
import os
import json
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_community.document_loaders import DirectoryLoader, TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_chroma import Chroma
from langchain_huggingface import HuggingFaceEmbeddings
from prompts import PROMPT_TEMPLATE, CLASSIFIER_PROMPT
# Configuração da página Streamlit
st.set_page_config(page_title="Central da Visão - Assistente", page_icon="👁️")
st.title("👁️ Assistente Virtual - Central da Visão")
load_dotenv()
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
if not OPENAI_API_KEY:
st.error("A chave da API da OpenAI não foi encontrada. Verifique as Secrets do Space.")
st.stop()
# Configurações do banco de dados Chroma
CHROMA_PATH = "chroma_db"
DOCS_PATH = "docs"
with open('know_graph.json', 'r', encoding='utf-8') as f:
knowledge_graph_data = json.dumps(json.load(f), ensure_ascii=False)
@st.cache_resource
def load_or_create_db():
"""
Carrega o banco Chroma se existir, ou cria do zero se não encontrar.
"""
model_name = "Qwen/Qwen3-Embedding-0.6B"
model_kwargs = {"device": "cpu",
"trust_remote_code": True}
encode_kwargs = {"normalize_embeddings": True}
embeddings = HuggingFaceEmbeddings(
model_name=model_name,
model_kwargs=model_kwargs,
encode_kwargs=encode_kwargs
)
# Verifica se o banco já existe
if os.path.exists(CHROMA_PATH) and os.listdir(CHROMA_PATH):
print("Banco de dados encontrado. Carregando...")
return Chroma(persist_directory=CHROMA_PATH, embedding_function=embeddings)
else:
print("Banco não encontrado. Criando nova base de conhecimento...")
# Garante que a pasta docs existe
if not os.path.exists(DOCS_PATH):
os.makedirs(DOCS_PATH)
st.warning(f"A pasta '{DOCS_PATH}' estava vazia. O assistente não tem documentos para ler.")
return Chroma(embedding_function=embeddings)
# Carrega os arquivos .txt
loader = DirectoryLoader(
DOCS_PATH,
glob="**/*.txt",
loader_cls=TextLoader,
loader_kwargs={"encoding": "utf-8"}
)
documents = loader.load()
if not documents:
st.warning("Nenhum arquivo .txt encontrado em 'docs/'.")
return Chroma(embedding_function=embeddings)
# Divide em chunks
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=200
)
chunks = text_splitter.split_documents(documents)
# Cria e salva o banco
db = Chroma.from_documents(
documents=chunks,
embedding=embeddings,
persist_directory=CHROMA_PATH
)
return db
# Inicializa o banco de dados
db_chroma = load_or_create_db()
# Sessão de chat
if "messages" not in st.session_state:
st.session_state.messages = [
{"role": "assistant", "content": "Olá! Sou o consultor virtual da Central da Visão. Como posso ajudar você hoje?"}
]
def get_response(query):
historico = st.session_state.messages[-6:]
chat_history_str = ""
for msg in historico:
prefix = "Usuário: " if msg["role"] == "user" else "Consultor: "
chat_history_str += f"{prefix}{msg['content']}\n"
model = ChatOpenAI(model_name='gpt-4o-mini', openai_api_key=OPENAI_API_KEY)
prompt_classifier = ChatPromptTemplate.from_template(CLASSIFIER_PROMPT)
classifier_input = prompt_classifier.format(
knowledge_graph=knowledge_graph_data,
chat_history=chat_history_str,
question=query
)
classification_response = model.invoke(classifier_input).content
cleaned_res = classification_response.replace("```json", "").replace("```", "").strip()
try:
classification = json.loads(cleaned_res)
except:
classification = {"estagio": "Nao identificado", "objecao_id": "nenhuma", "argumento_base": ""}
# Busca de documentos relevantes
docs_chroma = db_chroma.similarity_search(query, k=5)
context_text = "\n\n".join([doc.page_content for doc in docs_chroma])
diretriz_venda = f"\n[DIRETRIZ ESTRATÉGICA]: Estágio: {classification.get('estagio')}. " \
f"Objeção: {classification.get('objecao_id')}. " \
f"Argumento sugerido: {classification.get('argumento_base')}"
full_context = context_text + diretriz_venda
# Prompt
prompt_template = ChatPromptTemplate.from_template(PROMPT_TEMPLATE)
prompt = prompt_template.format(context=full_context,
chat_history=chat_history_str,
question=query)
# Modelo de linguagem
response = model.invoke(prompt)
return response.content, classification
# Interface
for message in st.session_state.messages:
with st.chat_message(message["role"]):
st.markdown(message["content"])
if query := st.chat_input("Digite sua dúvida aqui..."):
st.session_state.messages.append({"role": "user", "content": query})
with st.chat_message("user"):
st.markdown(query)
with st.chat_message("assistant"):
with st.spinner("Consultando base de dados..."):
try:
response_text, info_vendas = get_response(query)
with st.expander("📊 Log de Vendas (Inteligência)"):
st.write(f"**Estágio:** {info_vendas.get('estagio')}")
st.write(f"**Objeção Identificada:** {info_vendas.get('objecao_id')}")
st.caption(f"Argumento base: {info_vendas.get('argumento_base')}")
st.markdown(response_text)
st.session_state.messages.append({"role": "assistant", "content": response_text})
except Exception as e:
st.error(f"Ocorreu um erro ao processar: {e}") |