MSARABIC / app.py
Ultraman1968's picture
Update app.py
ec2c2d4 verified
Raw
History Blame Contribute Delete
5.23 kB
import os
import io
import sys
import asyncio
import random
import logging
import requests
import chromadb
import gradio as gr
import pytesseract
import edge_tts
from PIL import Image
from pdf2image import convert_from_path
from pathlib import Path
# =========================
# CONFIGURAÇÕES E ESTILO
# =========================
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
GROQ_API_KEY = os.getenv("GROQ_API_KEY")
GROQ_URL = "https://api.groq.com/openai/v1/chat/completions"
CHROMA_PATH = Path("./chroma_arabic_tutor")
DOCS_PATH = Path("./docs_arabic")
DOCS_PATH.mkdir(parents=True, exist_ok=True)
# CSS para organizar o layout e destacar o Árabe
custom_css = """
.gradio-container { background-color: #f8fafc; }
.arabic-display {
font-size: 32px !important;
line-height: 1.6;
direction: rtl;
text-align: right;
background: #fff;
padding: 15px;
border-radius: 8px;
border: 1px solid #e2e8f0;
}
.explanation-box { margin-bottom: 20px; padding: 10px; border-left: 4px solid #0369a1; }
"""
# =========================
# AUTO-INDEXAÇÃO (RAG)
# =========================
chroma_client = chromadb.PersistentClient(path=str(CHROMA_PATH))
collection = chroma_client.get_or_create_collection(name="arabic_lessons")
def auto_indexar():
if collection.count() > 0:
return f"✅ Biblioteca Ativa: {collection.count()} trechos."
pdfs = list(DOCS_PATH.glob("*.pdf"))
if not pdfs: return "⚠️ Pasta 'docs_arabic' vazia."
for pdf in pdfs:
try:
images = convert_from_path(pdf, last_page=20)
for i, image in enumerate(images):
text = pytesseract.image_to_string(image, lang='ara+eng')
if text and len(text.strip()) > 50:
chunks = [text[j:j+1000] for j in range(0, len(text), 800)]
ids = [f"{pdf.name}_p{i}_{k}" for k in range(len(chunks))]
collection.add(ids=ids, documents=chunks)
except Exception as e: print(f"Erro OCR: {e}")
return f"✅ Pronta: {collection.count()} trechos."
status_inicial = auto_indexar()
# =========================
# MOTOR DE ÁUDIO PREMIUM (EDGE-TTS)
# =========================
async def gerar_audio_premium(texto):
# Selecionamos uma voz árabe natural (Fatima ou Hamed)
voice = "ar-SA-ZariyahNeural"
output_path = "pronuncia_premium.mp3"
communicate = edge_tts.Communicate(texto, voice)
await communicate.save(output_path)
return output_path
# =========================
# MOTOR DO TUTOR
# =========================
def tutor_engine(mensagem, historico):
if not GROQ_API_KEY:
return historico + [["Erro", "Configure a GROQ_API_KEY."]], "", None
contexto = ""
if collection.count() > 0:
busca = collection.query(query_texts=[mensagem], n_results=3)
contexto = "\n".join(busca['documents'][0])
# Prompt instruindo organização visual clara
prompt_sistema = (
"Você é Al-Mu'allim. Responda com organização visual impecável em Markdown.\n"
"Use títulos (###), listas e negrito. Separe a parte árabe da explicação.\n"
"IMPORTANTE: Não retorne códigos JSON, colchetes ou termos como {'text': }.\n"
f"CONTEXTO TÉCNICO:\n{contexto}"
)
api_msgs = [{"role": "system", "content": prompt_sistema}]
for u, b in historico:
api_msgs.append({"role": "user", "content": u})
api_msgs.append({"role": "assistant", "content": b})
api_msgs.append({"role": "user", "content": mensagem})
try:
r = requests.post(GROQ_URL,
headers={"Authorization": f"Bearer {GROQ_API_KEY}"},
json={"model": "llama-3.1-8b-instant", "messages": api_msgs, "temperature": 0.3})
resposta = r.json()['choices'][0]['message']['content']
# Limpeza de caracteres indesejados caso a IA os gere
resposta = resposta.replace("{'text':", "").replace("}", "").strip()
except:
resposta = "Houve um erro na comunicação."
# Gera o áudio de alta qualidade de forma assíncrona
audio_path = asyncio.run(gerar_audio_premium(resposta))
historico.append((mensagem, resposta))
return historico, "", audio_path
# =========================
# INTERFACE ORGANIZADA
# =========================
with gr.Blocks(css=custom_css) as demo:
gr.Markdown("## 🌙 Al-Mu'allim: Tutor de Árabe Premium")
with gr.Row():
with gr.Column(scale=3):
chatbot = gr.Chatbot(label="Aula e Explicações", height=500)
with gr.Row():
msg = gr.Textbox(placeholder="Sua pergunta aqui...", scale=4, show_label=False)
btn = gr.Button("Enviar", variant="primary", scale=1)
with gr.Column(scale=1):
gr.Markdown("### 🔊 Pronúncia Nativa")
audio_out = gr.Audio(label="Clique para ouvir", autoplay=True)
gr.Markdown("---")
gr.Markdown(f"**Status da Biblioteca:**\n{status_inicial}")
btn.click(tutor_engine, [msg, chatbot], [chatbot, msg, audio_out])
msg.submit(tutor_engine, [msg, chatbot], [chatbot, msg, audio_out])
if __name__ == "__main__":
demo.launch()