import os from dotenv import load_dotenv from langchain_openai import ChatOpenAI from langchain.prompts import PromptTemplate from langchain.chains import ConversationChain # Keep using this for now, despite deprecation from langchain.memory import ConversationBufferMemory # Keep using this for now import gradio as gr import traceback # Carrega a chave da API load_dotenv() api_key = os.getenv("OPENROUTER_API_KEY") if not api_key: raise ValueError("❌ Variável OPENROUTER_API_KEY não encontrada.") # Define variáveis do ambiente os.environ["OPENAI_API_KEY"] = api_key os.environ["OPENAI_API_BASE"] = "https://openrouter.ai/api/v1" # Instancia o modelo llm = ChatOpenAI( model="mistralai/mistral-7b-instruct:free", temperature=0.5 ) # Lista de Tutores/Matérias subjects = [ "Python", "Java", "Ruby", "Golang", "C++", "C#", "Rust", "SQL", "Tableau", "Power BI", "Excel", "Looker", "Solidity" ] # --- Template Modificado --- # Agora SÓ espera 'history' e 'input'. O contexto da matéria será parte do 'input'. template_string = """Você é um assistente virtual e tutor especialista. A especialidade desejada pelo aluno está indicada claramente no início da pergunta dele (procure por 'Especialidade Foco:'). Ajude os alunos com dúvidas sobre a especialidade mencionada na pergunta atual, sempre de forma clara, objetiva e com exemplos didáticos. Adapte a profundidade da sua resposta ao nível aparente da pergunta. Se a pergunta for muito vaga, peça mais detalhes. Concentre-se estritamente na especialidade indicada na pergunta atual, a menos que o aluno peça explicitamente para comparar com outra tecnologia. Histórico da conversa: {history} Aluno: {input} Resposta:""" # Prompt agora só precisa de 'history' e 'input' template = PromptTemplate( input_variables=["history", "input"], # APENAS history e input template=template_string ) # --- Memória da Conversa --- # Aviso de Depreciação: ConversationBufferMemory está sendo substituída. # Para agora, ela funciona, mas considere migrar para RunnableWithMessageHistory no futuro. memoria = ConversationBufferMemory(return_messages=True) # memory_key='history' é o padrão # --- Criação da Chain --- # Aviso de Depreciação: ConversationChain está sendo substituída. # Para agora, ela funciona com o prompt ajustado. chat_chain = ConversationChain( llm=llm, memory=memoria, prompt=template, # Passa o prompt que agora só espera 'history' e 'input' input_key='input', # Confirma que a chave de entrada principal é 'input' (padrão) verbose=False ) # --- Função para Responder com Contexto Formatado --- def responder(subject, user_message): """ Formata a entrada e gera a resposta do LLM. """ if not subject: return "⚠️ Por favor, selecione uma matéria primeiro." if not user_message or not user_message.strip(): # Verifica se a mensagem não está vazia ou só espaços return "⚠️ Por favor, digite sua dúvida." # **Importante:** Formata a entrada para incluir o contexto da matéria # É ESSENCIAL que o LLM veja essa informação claramente no início do input. formatted_input = f"**Especialidade Foco:** {subject}\n\n**Dúvida do Aluno:** {user_message}" try: # Passa a string formatada como a única entrada 'input' para a chain response = chat_chain.run(formatted_input) return response except Exception as e: print(f"❌ Erro ao processar a solicitação:\n{traceback.format_exc()}") return f"❌ Desculpe, ocorreu um erro ao processar sua solicitação. Detalhes: {str(e)}" # --- Interface Gradio (sem alterações na estrutura) --- with gr.Blocks(theme=gr.themes.Soft()) as app: # Adicionando um tema suave gr.Markdown("# Tutor Poliglota com IA 🤖🎓") gr.Markdown("Selecione a matéria e tire suas dúvidas com um assistente que lembra da conversa.") with gr.Row(): subject_selector = gr.Dropdown( choices=subjects, label="Selecione a Matéria", info="Escolha sobre qual linguagem ou ferramenta você quer perguntar." ) with gr.Row(): input_textbox = gr.Textbox( placeholder="Ex: Como declarar uma variável em Java?", label="Sua Dúvida", lines=3, show_copy_button=True ) with gr.Row(): submit_button = gr.Button("Perguntar ao Tutor", variant="primary") # Botão com destaque with gr.Row(): output_textbox = gr.Textbox( label="Resposta do Tutor", lines=10, # Mais espaço para resposta show_copy_button=True ) clear_button = gr.ClearButton( components=[input_textbox, output_textbox, subject_selector], # Limpa também o dropdown value="Limpar Campos e Memória" ) submit_button.click( fn=responder, inputs=[subject_selector, input_textbox], outputs=output_textbox ) def clear_memory_and_interface(): try: memoria.clear() # Limpa a memória da conversa print("Memória da conversa limpa.") except Exception as e: print(f"Erro ao limpar a memória: {e}") # Retorna valor padrão para dropdown (None) e vazio para textbox return [None, "", ""] # Atualiza a ação do clear_button para retornar valores para todos os componentes clear_button.click(fn=clear_memory_and_interface, outputs=[subject_selector, input_textbox, output_textbox]) # Lança a aplicação app.launch(share=True, debug=True) # Adiciona debug=True para mais informações no console