AQ2000 commited on
Commit
a3a649e
·
verified ·
1 Parent(s): 7d5e592

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +103 -30
app.py CHANGED
@@ -1,38 +1,111 @@
1
  import gradio as gr
2
  import subprocess
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
 
4
- def suggest_subjects(text, limit):
5
  try:
6
- # استدعاء annif بدون --json
7
- result = subprocess.run(
8
- ["annif", "suggest", "ar-annif", "-", "--limit", str(limit)],
9
- input=text,
10
  capture_output=True,
11
  text=True,
12
- check=True
13
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
- # مثال: Annif يرجع سطور مثل:
16
- # http://id.loc.gov/authorities/subjects/sh85026371 Computer science 0.95
17
- lines = result.stdout.strip().split("\n")
18
- html_output = "<ul>"
19
- for line in lines:
20
- parts = line.split("\t")
21
- if len(parts) >= 3:
22
- uri, label, score = parts[0], parts[1], parts[2]
23
- html_output += f'<li><a href="{uri}" target="_blank">{label}</a> ({score})</li>'
24
- html_output += "</ul>"
25
-
26
- return html_output if html_output != "<ul></ul>" else "لا توجد نتائج"
27
- except Exception as e:
28
- return f"خطأ: {str(e)}"
29
-
30
- with gr.Blocks() as demo:
31
- gr.Markdown("## تجربة Annif مع الواجهة")
32
- text_input = gr.Textbox(label="النص", lines=5)
33
- limit_input = gr.Number(label="عدد النتائج", value=5)
34
- output = gr.HTML(label="الموضوعات المقترحة")
35
- btn = gr.Button("اقتراح رؤوس الموضوعات")
36
- btn.click(suggest_subjects, inputs=[text_input, limit_input], outputs=output)
37
-
38
- demo.launch()
 
1
  import gradio as gr
2
  import subprocess
3
+ import html
4
+
5
+ def clean_uri(raw: str) -> str:
6
+ """تنظيف URI بإزالة زوايا < > وأي بقايا مثل ;http:"""
7
+ uri = raw.strip()
8
+ # إزالة الزوايا إن وُجدت
9
+ if uri.startswith("<") and uri.endswith(">"):
10
+ uri = uri[1:-1].strip()
11
+ # إزالة أي بقايا مسار تالفة تأتي أحياناً من البيانات
12
+ if ";http" in uri:
13
+ uri = uri.split(";http")[0]
14
+ # إزالة فواصل/فراغات زائدة
15
+ uri = uri.rstrip(" ,;")
16
+ return uri
17
+
18
+ def parse_annif_output(text: str) -> str:
19
+ """
20
+ يحول خرج annif (TSV: uri \t label \t score)
21
+ إلى HTML مرتب بروابط قابلة للنقر.
22
+ """
23
+ lines = [ln for ln in text.strip().split("\n") if ln.strip()]
24
+ if not lines:
25
+ return "<p>لا توجد نتائج.</p>"
26
+
27
+ items = []
28
+ for ln in lines:
29
+ # تجاهل أي سطور تعليق محتملة
30
+ if ln.lstrip().startswith("#"):
31
+ continue
32
+ parts = ln.split("\t")
33
+ if len(parts) < 3:
34
+ continue
35
+ raw_uri, raw_label, raw_score = parts[0], parts[1], parts[2]
36
+ uri = clean_uri(raw_uri)
37
+ label = html.escape(raw_label.strip().strip('"'))
38
+ # تنسيق الدرجة
39
+ try:
40
+ score = float(raw_score)
41
+ score_str = f"{score:.3f}"
42
+ except Exception:
43
+ score_str = html.escape(raw_score)
44
+
45
+ # نبني عنصر HTML مع رابط مطلق وفتح في تبويب جديد
46
+ # ملاحظة: إذا الـ URI لا يبدأ بـ http(s)، المتصفح قد يعامل الرابط كنسبي.
47
+ items.append(
48
+ f'<tr>'
49
+ f'<td><a href="{uri}" target="_blank" rel="noopener noreferrer">{html.escape(uri)}</a></td>'
50
+ f'<td>{label}</td>'
51
+ f'<td style="text-align:right">{score_str}</td>'
52
+ f'</tr>'
53
+ )
54
+
55
+ if not items:
56
+ return "<p>لا توجد نتائج.</p>"
57
+
58
+ table = (
59
+ "<table style='width:100%; border-collapse:collapse'>"
60
+ "<thead>"
61
+ "<tr>"
62
+ "<th style='text-align:right; padding:6px; border-bottom:1px solid #ddd'>URI</th>"
63
+ "<th style='text-align:right; padding:6px; border-bottom:1px solid #ddd'>المصطلح</th>"
64
+ "<th style='text-align:right; padding:6px; border-bottom:1px solid #ddd'>الدرجة</th>"
65
+ "</tr>"
66
+ "</thead>"
67
+ "<tbody>"
68
+ + "".join(items) +
69
+ "</tbody>"
70
+ "</table>"
71
+ )
72
+ return table
73
+
74
+ def suggest_subjects(input_text: str, limit: int):
75
+ if not input_text or not input_text.strip():
76
+ return "<p>من فضلك أدخل نصًا.</p>"
77
 
 
78
  try:
79
+ # نستدعي annif بصيغة TSV بدون --json
80
+ proc = subprocess.run(
81
+ ["annif", "suggest", "ar-annif", "-", "--limit", str(int(limit))],
82
+ input=input_text,
83
  capture_output=True,
84
  text=True,
85
+ check=True,
86
  )
87
+ return parse_annif_output(proc.stdout)
88
+ except subprocess.CalledProcessError as e:
89
+ # نعرض stderr للمساعدة في التشخيص
90
+ err = html.escape(e.stderr or "")
91
+ out = html.escape(e.stdout or "")
92
+ return f"<pre>خطأ من annif suggest:\nSTDERR:\n{err}\n\nSTDOUT:\n{out}</pre>"
93
+ except Exception as ex:
94
+ return f"<pre>خطأ: {html.escape(str(ex))}</pre>"
95
+
96
+ with gr.Blocks(css="""
97
+ .gradio-container { direction: rtl; font-family: 'Noto Naskh Arabic', system-ui, sans-serif; }
98
+ """) as demo:
99
+ gr.Markdown("## 🔎 استخراج رؤوس الموضوعات (Annif)")
100
+ with gr.Row():
101
+ text = gr.Textbox(label="النص", lines=6, placeholder="ألصق هنا نصًا عربيًا...")
102
+ with gr.Row():
103
+ limit = gr.Slider(1, 20, value=5, step=1, label="عدد النتائج")
104
+ btn = gr.Button("اقتراح الرؤوس", variant="primary")
105
+ out = gr.HTML(label="النتائج")
106
+
107
+ btn.click(fn=suggest_subjects, inputs=[text, limit], outputs=out)
108
 
109
+ if __name__ == "__main__":
110
+ # على Spaces لا حاجة لـ share=True عادةً
111
+ demo.launch(server_name="0.0.0.0", server_port=7860)