File size: 5,662 Bytes
f241c48
 
 
 
91c1358
 
f241c48
91c1358
f241c48
 
 
 
 
 
 
 
 
 
 
 
 
 
91c1358
 
f241c48
 
91c1358
f241c48
91c1358
 
f241c48
 
91c1358
 
 
 
 
 
f241c48
 
 
 
 
 
 
91c1358
f241c48
91c1358
f241c48
 
 
91c1358
 
 
 
f241c48
91c1358
 
 
f241c48
 
 
91c1358
 
 
f241c48
 
91c1358
f241c48
 
91c1358
f241c48
 
 
91c1358
f241c48
 
91c1358
 
 
 
f241c48
91c1358
 
f241c48
 
 
 
 
91c1358
 
f241c48
 
 
 
 
 
 
 
 
 
 
 
 
 
91c1358
 
f241c48
 
 
91c1358
f241c48
 
 
 
91c1358
 
f241c48
 
 
91c1358
 
f241c48
 
 
 
91c1358
f241c48
 
 
 
91c1358
 
 
 
 
 
 
f241c48
91c1358
 
f241c48
 
91c1358
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
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