voice_GUFF / app.py
shimaa22's picture
Update app.py
c3ca188 verified
Raw
History Blame Contribute Delete
5.34 kB
import os
import tempfile
import requests
import speech_recognition as sr
from pydub import AudioSegment
from huggingface_hub import hf_hub_download
from llama_cpp import Llama
import gradio as gr
from fastapi import Request, Response
from twilio.twiml.messaging_response import MessagingResponse
# ============ إعدادات (من Space Secrets) ============
HF_TOKEN = os.environ.get("HF_TOKEN")
TWILIO_SID = os.environ.get("TWILIO_ACCOUNT_SID")
TWILIO_AUTH = os.environ.get("TWILIO_AUTH_TOKEN")
SYSTEM_PROMPT = (
"أنت مساعد ذكي ودود. أجب باللغة العربية فقط مهما كانت لغة السؤال. "
"ممنوع استخدام أي لغة أخرى أو أي حروف غير عربية. "
"أجب باختصار وبأسلوب محادثاتي طبيعي."
)
# ============ تحميل موديل Qwen 2.5 3B GGUF ============
print("⏳ بتحميل موديل Qwen 2.5 3B GGUF ...")
model_path = hf_hub_download(
repo_id="Qwen/Qwen2.5-3B-Instruct-GGUF",
filename="qwen2.5-3b-instruct-q4_k_m.gguf",
token=HF_TOKEN,
)
llm = Llama(model_path=model_path, n_ctx=2048, n_threads=4, verbose=False)
print("✅ الموديل جاهز")
def chat_llm(user_text: str, history: list | None = None) -> str:
messages = [{"role": "system", "content": SYSTEM_PROMPT}]
if history:
for u, a in history:
messages.append({"role": "user", "content": u})
messages.append({"role": "assistant", "content": a})
messages.append({"role": "user", "content": user_text})
out = llm.create_chat_completion(
messages=messages, max_tokens=400, temperature=0.7,
)
return out["choices"][0]["message"]["content"].strip()
# ============ Speech Recognition (Google - مجاني) ============
def transcribe_audio(audio_path: str) -> str:
sound = AudioSegment.from_file(audio_path)
sound = sound.set_channels(1).set_frame_rate(16000)
with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as f:
sound.export(f.name, format="wav")
wav_path = f.name
r = sr.Recognizer()
with sr.AudioFile(wav_path) as source:
audio = r.record(source)
try:
return r.recognize_google(audio, language="ar-EG")
except sr.UnknownValueError:
return ""
# ============ واجهة Gradio ============
def handle_text(message, history):
if not message.strip():
return "", history
reply = chat_llm(message, history)
return "", history + [(message, reply)]
def handle_voice(audio, history):
if not audio:
return history
text = transcribe_audio(audio)
if not text:
return history + [("(رسالة صوتية)", "معلش، ما قدرتش أفهم الصوت.")]
reply = chat_llm(text, history)
return history + [(f"🎤 {text}", reply)]
with gr.Blocks(title="المساعد الصوتي الذكي") as demo:
gr.Markdown("# 🤖 المساعد الصوتي الذكي بالعربي\nاكتبي أو سجّلي صوت — الرد بالعربي.")
chatbot = gr.Chatbot(height=420, rtl=True)
with gr.Row():
txt = gr.Textbox(placeholder="اكتبي رسالتك...", rtl=True, scale=4, show_label=False)
send = gr.Button("إرسال", scale=1, variant="primary")
mic = gr.Audio(sources=["microphone"], type="filepath", label="🎤 سجّلي صوت")
send.click(handle_text, [txt, chatbot], [txt, chatbot])
txt.submit(handle_text, [txt, chatbot], [txt, chatbot])
mic.stop_recording(handle_voice, [mic, chatbot], [chatbot])
# ============ WhatsApp Webhook داخل نفس Gradio app ============
# Gradio بيستخدم FastAPI جوّه، فنقدر نضيف route عادي.
@demo.app.post("/whatsapp")
async def whatsapp_webhook(request: Request):
form = await request.form()
body = (form.get("Body") or "").strip()
num_media = int(form.get("NumMedia") or 0)
resp = MessagingResponse()
try:
if num_media > 0:
media_url = form.get("MediaUrl0")
media_type = form.get("MediaContentType0", "")
if media_url and media_type.startswith("audio"):
r = requests.get(media_url, auth=(TWILIO_SID, TWILIO_AUTH))
r.raise_for_status()
with tempfile.NamedTemporaryFile(suffix=".ogg", delete=False) as f:
f.write(r.content)
audio_path = f.name
transcript = transcribe_audio(audio_path)
if not transcript:
resp.message("معلش، مقدرتش أفهم الرسالة الصوتية.")
return Response(str(resp), media_type="application/xml")
body = f"{body}\n{transcript}" if body else transcript
if not body:
resp.message("اكتبي سؤالك أو ابعتي رسالة صوتية 🎤")
return Response(str(resp), media_type="application/xml")
reply = chat_llm(body)
resp.message(reply)
except Exception as e:
print("whatsapp error:", e)
resp.message("حصل خطأ مؤقت، حاولي تاني.")
return Response(str(resp), media_type="application/xml")
@demo.app.get("/whatsapp")
def whatsapp_get():
return {"status": "WhatsApp webhook OK"}
if __name__ == "__main__":
demo.launch()