import gradio as gr import subprocess import html def clean_uri(raw: str) -> str: """تنظيف URI بإزالة زوايا < > وأي بقايا مثل ;http:""" uri = raw.strip() # إزالة الزوايا إن وُجدت if uri.startswith("<") and uri.endswith(">"): uri = uri[1:-1].strip() # إزالة أي بقايا مسار تالفة تأتي أحياناً من البيانات if ";http" in uri: uri = uri.split(";http")[0] # إزالة فواصل/فراغات زائدة uri = uri.rstrip(" ,;") return uri def parse_annif_output(text: str) -> str: """ يحول خرج annif (TSV: uri \t label \t score) إلى HTML مرتب بروابط قابلة للنقر. """ lines = [ln for ln in text.strip().split("\n") if ln.strip()] if not lines: return "
لا توجد نتائج.
" items = [] for ln in lines: # تجاهل أي سطور تعليق محتملة if ln.lstrip().startswith("#"): continue parts = ln.split("\t") if len(parts) < 3: continue raw_uri, raw_label, raw_score = parts[0], parts[1], parts[2] uri = clean_uri(raw_uri) label = html.escape(raw_label.strip().strip('"')) # تنسيق الدرجة try: score = float(raw_score) score_str = f"{score:.3f}" except Exception: score_str = html.escape(raw_score) # نبني عنصر HTML مع رابط مطلق وفتح في تبويب جديد # ملاحظة: إذا الـ URI لا يبدأ بـ http(s)، المتصفح قد يعامل الرابط كنسبي. items.append( f'لا توجد نتائج.
" table = ( "| URI | " "المصطلح | " "الدرجة | " "
|---|
من فضلك أدخل نصًا.
" try: # نستدعي annif بصيغة TSV بدون --json proc = subprocess.run( ["annif", "suggest", "ar-annif", "-", "--limit", str(int(limit))], input=input_text, capture_output=True, text=True, check=True, ) return parse_annif_output(proc.stdout) except subprocess.CalledProcessError as e: # نعرض stderr للمساعدة في التشخيص err = html.escape(e.stderr or "") out = html.escape(e.stdout or "") return f"خطأ من annif suggest:\nSTDERR:\n{err}\n\nSTDOUT:\n{out}"
except Exception as ex:
return f"خطأ: {html.escape(str(ex))}"
with gr.Blocks(css="""
.gradio-container { direction: rtl; font-family: 'Noto Naskh Arabic', system-ui, sans-serif; }
""") as demo:
gr.Markdown("## 🔎 استخراج رؤوس الموضوعات (Annif)")
with gr.Row():
text = gr.Textbox(label="النص", lines=6, placeholder="ألصق هنا نصًا عربيًا...")
with gr.Row():
limit = gr.Slider(1, 20, value=5, step=1, label="عدد النتائج")
btn = gr.Button("اقتراح الرؤوس", variant="primary")
out = gr.HTML(label="النتائج")
btn.click(fn=suggest_subjects, inputs=[text, limit], outputs=out)
if __name__ == "__main__":
# على Spaces لا حاجة لـ share=True عادةً
demo.launch(server_name="0.0.0.0", server_port=7860)