File size: 8,262 Bytes
9c22a69
4aff160
 
 
 
 
 
 
 
 
 
 
 
9c22a69
4aff160
9c22a69
 
 
 
4aff160
 
 
 
 
9c22a69
4aff160
 
 
 
 
 
9c22a69
4aff160
 
 
 
 
 
 
9c22a69
4aff160
 
 
 
 
 
9c22a69
4aff160
 
 
9c22a69
4aff160
9c22a69
 
4aff160
 
 
9c22a69
4aff160
 
 
9c22a69
 
 
4aff160
9c22a69
 
4aff160
 
 
 
9c22a69
 
4aff160
9c22a69
4aff160
 
9c22a69
 
 
 
 
 
 
 
 
 
 
 
4aff160
 
 
9c22a69
 
4aff160
9c22a69
 
 
4aff160
 
 
9c22a69
4aff160
 
 
 
9c22a69
4aff160
9c22a69
4aff160
9c22a69
 
 
 
 
 
 
4aff160
 
 
 
 
 
 
 
 
 
9c22a69
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4aff160
 
 
 
 
 
 
 
 
 
9c22a69
 
4aff160
 
 
9c22a69
 
 
 
4aff160
 
9c22a69
 
 
 
 
4aff160
9c22a69
 
 
4aff160
9c22a69
4aff160
9c22a69
 
 
4aff160
 
9c22a69
4aff160
 
9c22a69
4aff160
 
9c22a69
4aff160
 
 
 
 
 
9c22a69
 
 
 
 
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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
import requests
import gradio as gr
import os
import uuid
import PyPDF2
from PIL import Image
import imageio
import random
from gtts import gTTS
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Paragraph
from reportlab.lib.styles import getSampleStyleSheet

# Configuração da API do Google Gemini
API_KEYS = [
    'AIzaSyAgmf1ZvNrvzAmlNCQvQbyZDJJPdMwecqY',
    'AIzaSyB18Z-Ct2-IKYGZ9vKaChcee-BDVS77Ksg',
    'AIzaSyBB5Tp0xdXcemLMGDm8_cL6L37wTe_8sjg',
    'AIzaSyCefvhXMsgHmAF_0KVkZ0UAeZ5nNC41v-A',
]

def escolher_chave_api():
    return random.choice(API_KEYS)

GEMINI_API_URL = "https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key={}"

class AssistenteAcademico:
    def __init__(self):
        self.contexto_atual = {}
        self.ultima_imagem_path = None
        self.pasta_temp = 'assistente_temp'
        
        for pasta in [self.pasta_temp, 'audios_assistente', 'pdfs_respostas']:
            os.makedirs(pasta, exist_ok=True)

    def gerar_pdf_resposta(self, texto, nome_arquivo=None):
        try:
            nome_arquivo = nome_arquivo or f'resposta_{uuid.uuid4()}.pdf'
            caminho_pdf = os.path.join('pdfs_respostas', nome_arquivo)
            
            doc = SimpleDocTemplate(caminho_pdf, pagesize=letter)
            styles = getSampleStyleSheet()
            story = [Paragraph(texto.replace('\n', '<br/>'), styles['Normal'])]
            doc.build(story)
            return caminho_pdf
        except Exception as e:
            return f"Erro ao criar PDF: {str(e)}"

    def texto_para_audio(self, texto, nome_arquivo=None):
        try:
            nome_arquivo = nome_arquivo or f'audio_{uuid.uuid4()}.mp3'
            caminho_audio = os.path.join('audios_assistente', nome_arquivo)
            
            tts = gTTS(texto, lang='pt-br')
            tts.save(caminho_audio)
            return caminho_audio
        except Exception as e:
            return f"Erro ao criar áudio: {str(e)}"

    def codificar_imagem(self, imagem_path):
        try:
            if not os.path.exists(imagem_path):
                raise ValueError("Arquivo de imagem não encontrado")
                
            extensao = os.path.splitext(imagem_path)[1].lower()
            formatos_suportados = {'.png', '.jpg', '.jpeg', '.bmp', '.gif', '.tiff', '.webp'}
            if extensao not in formatos_suportados:
                raise ValueError(f"Formato de imagem não suportado: {extensao}")

            imagem = imageio.imread(imagem_path)
            imagem_pil = Image.fromarray(imagem)
            imagem_pil.thumbnail((800, 800), Image.Resampling.LANCZOS)
            
            temp_path = os.path.join(self.pasta_temp, f'temp_image_{uuid.uuid4()}{extensao}')
            imagem_pil.convert('RGB').save(temp_path, quality=95)
            return temp_path
        except Exception as e:
            return f"Erro ao codificar imagem: {str(e)}"

    def extrair_texto_pdf(self, arquivo_pdf):
        try:
            if not arquivo_pdf or not os.path.exists(arquivo_pdf):
                return "Nenhum PDF válido fornecido"
                
            leitor_pdf = PyPDF2.PdfReader(arquivo_pdf)
            texto = "\n".join(pagina.extract_text() or "" for pagina in leitor_pdf.pages)
            return texto if texto.strip() else "Nenhum texto extraído do PDF"
        except Exception as e:
            return f"Erro ao extrair texto do PDF: {str(e)}"

    def processar_input(self, pergunta, pdf=None, imagem=None):
        try:
            if not pergunta:
                return "Por favor, forneça uma pergunta", None, None

            # Preparar o conteúdo para a API
            conteudo = [{"role": "user", "parts": [{"text": self.contexto_atual.get('pdf_texto', '')}]}]
            
            if pdf:
                texto_pdf = self.extrair_texto_pdf(pdf)
                self.contexto_atual['pdf_texto'] = texto_pdf
                conteudo[0]["parts"].append({"text": texto_pdf})

            if imagem:
                if self.ultima_imagem_path and os.path.exists(self.ultima_imagem_path):
                    os.remove(self.ultima_imagem_path)
                    
                imagem_path = self.codificar_imagem(imagem)
                if isinstance(imagem_path, str) and os.path.exists(imagem_path):
                    self.ultima_imagem_path = imagem_path
                    with open(imagem_path, "rb") as img_file:
                        conteudo[0]["parts"].append({
                            "inline_data": {
                                "mime_type": f"image/{os.path.splitext(imagem_path)[1][1:]}",
                                "data": base64.b64encode(img_file.read()).decode('utf-8')
                            }
                        })

            prompt = f"""Como um assistente acadêmico avançado:
            - Seja objetivo e acadêmico
            - Forneça explicações claras
            - Use linguagem técnica quando apropriado
            - Cite referências se possível
            - Mantenha a explicação acessível

            Pergunta atual: {pergunta}
            """
            conteudo[0]["parts"].append({"text": prompt})

            # Fazer a requisição à API
            headers = {"Content-Type": "application/json"}
            api_key = escolher_chave_api()
            response = requests.post(
                GEMINI_API_URL.format(api_key),
                json={"contents": conteudo},
                headers=headers
            )
            
            if response.status_code != 200:
                return f"Erro na API: {response.status_code} - {response.text}", None, None
                
            resposta_json = response.json()
            texto_resposta = resposta_json["candidates"][0]["content"]["parts"][0]["text"]

            caminho_audio = self.texto_para_audio(texto_resposta)
            caminho_pdf = self.gerar_pdf_resposta(texto_resposta)

            return texto_resposta, caminho_audio, caminho_pdf
        except Exception as e:
            return f"Erro no processamento: {str(e)}", None, None

    def limpar_arquivos_temporarios(self):
        import time
        pastas = [self.pasta_temp, 'audios_assistente', 'pdfs_respostas']
        for pasta in pastas:
            for arquivo in os.listdir(pasta):
                caminho = os.path.join(pasta, arquivo)
                if os.path.isfile(caminho) and time.time() - os.path.getctime(caminho) > 3600:
                    try:
                        os.remove(caminho)
                    except:
                        pass

    def chatbot_interface(self):
        with gr.Blocks(title="Assistente Acadêmico") as interface:
            gr.Markdown("# 🎓 Assistente Acadêmico\nFaça suas perguntas e carregue arquivos para análise.")
            
            chatbot = gr.Chatbot(label="Conversa")
            
            with gr.Row():
                audio_output = gr.Audio(label="Resposta em Áudio")
                pdf_output = gr.File(label="Resposta em PDF")
            
            with gr.Row():
                msg = gr.Textbox(label="Pergunta", placeholder="Digite sua pergunta...")
                pdf_input = gr.File(file_types=['.pdf'], label="Carregar PDF")
                img_input = gr.File(file_types=['.png', '.jpg', '.jpeg', '.bmp', '.gif', '.tiff', '.webp'], 
                                  label="Carregar Imagem")
                submit_btn = gr.Button("Enviar")

            def responder(mensagem, historico, pdf=None, imagem=None):
                resposta, audio, pdf_file = self.processar_input(mensagem, pdf, imagem)
                historico.append((mensagem, resposta))
                self.limpar_arquivos_temporarios()
                return "", historico, audio, pdf_file

            submit_btn.click(
                fn=responder,
                inputs=[msg, chatbot, pdf_input, img_input],
                outputs=[msg, chatbot, audio_output, pdf_output]
            )

        return interface

if __name__ == "__main__":
    assistente = AssistenteAcademico()
    interface = assistente.chatbot_interface()
    print("🚀 Assistente Acadêmico inicializado!")
    interface.launch(debug=True, share=True)