Spaces:
Sleeping
Sleeping
File size: 5,343 Bytes
3832cbe a974e8c c3ca188 a974e8c c3ca188 a974e8c 3832cbe a974e8c d02a476 3832cbe a974e8c c3ca188 a974e8c c3ca188 a974e8c c3ca188 a974e8c 3832cbe a974e8c c3ca188 a974e8c c3ca188 a974e8c c3ca188 a974e8c 3832cbe a974e8c c3ca188 a974e8c d02a476 c3ca188 a974e8c c3ca188 a974e8c c3ca188 a974e8c c3ca188 d02a476 c3ca188 | 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 | 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()
|