Alshargi commited on
Commit
982950d
·
verified ·
1 Parent(s): f8fb7be

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +177 -0
app.py ADDED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import re
3
+ import gradio as gr
4
+ from openai import OpenAI
5
+
6
+ HF_TOKEN = os.environ.get("HF_TOKEN")
7
+ MODEL_ID = "Qwen/Qwen2.5-7B-Instruct"
8
+
9
+ if not HF_TOKEN:
10
+ raise ValueError("HF_TOKEN is missing. Add it in Space Settings -> Secrets.")
11
+
12
+ client = OpenAI(
13
+ base_url="https://router.huggingface.co/v1",
14
+ api_key=HF_TOKEN,
15
+ )
16
+
17
+ FINAL_NOTE = "Responses are generated from retrieved hadith evidence and the system is still under improvement."
18
+
19
+ SYSTEM_PROMPT = """
20
+ You are Hadithi AI, a professional assistant for explaining retrieved hadith evidence.
21
+
22
+ The user's message already includes the retrieved hadith evidence from the API.
23
+ Your job is to explain that evidence clearly, naturally, and faithfully.
24
+
25
+ You must base your answer only on the hadiths provided in the user's message.
26
+ Do not invent extra hadiths, extra sources, or unsupported claims.
27
+
28
+ STRICT OUTPUT FORMAT:
29
+ Write the final answer in exactly this order:
30
+
31
+ Answer:
32
+ Write exactly one polished explanatory paragraph in English unless the user clearly asks for Arabic.
33
+ The paragraph must:
34
+ - begin naturally in a style like: "The retrieved hadiths show that..."
35
+ - explain the meaning of the retrieved hadiths in a smooth, human, article-like way
36
+ - mention short Arabic phrases from the hadith only when useful
37
+ - include the meaning of the Arabic phrase naturally in the sentence
38
+ - avoid bullets
39
+ - avoid robotic summary language
40
+ - avoid repeating the same point
41
+ - avoid quoting full hadiths
42
+ - stay grounded in the actual retrieved evidence only
43
+
44
+ Hadith Evidence:
45
+ After the paragraph, list the hadiths provided by the user.
46
+ For each hadith, use exactly this structure:
47
+
48
+ - Source: ...
49
+ - Grade: ...
50
+ - Why it matters: ...
51
+ - Text: ...
52
+
53
+ FINAL LINE:
54
+ End with this exact sentence:
55
+ Responses are generated from retrieved hadith evidence and the system is still under improvement.
56
+
57
+ IMPORTANT RULES:
58
+ - Do not create extra headings such as Main Insight, Key meanings, or What the Hadiths Show.
59
+ - Do not separate Arabic and English into different blocks in the Answer section.
60
+ - Keep full Arabic hadith text only in the Hadith Evidence section.
61
+ - If the evidence only partially answers the question, say so clearly.
62
+ - Be elegant, clear, modern, and trustworthy.
63
+
64
+ EXAMPLE STYLE FOR THE ANSWER SECTION:
65
+ The retrieved hadiths show that mercy (raḥma / الرحمة) in Islam is both a divine attribute and a quality believers should live by. In one hadith, the Prophet ﷺ teaches a duʿā’ that ends with “forgive me … and have mercy on me” (“فاغفر لي … وارحمني”), showing that a Muslim constantly needs Allah’s mercy in addition to forgiveness. Another hadith connects mercy with healing through the supplication “place Your mercy on earth” (“فاجعل رحمتك في الأرض”), which presents mercy as something that brings relief and cure. The Prophet ﷺ also said, “Mercy is not removed except from one who is truly wretched” (“لا تنزع الرحمة إلا من شقي”), which shows that mercy is a sign of goodness in the heart, while losing it reflects spiritual hardness. The clearest summary appears in the hadith, “The merciful are shown mercy by the Most Merciful” (“الراحمون يرحمهم الرحمن”), teaching that those who show mercy to people receive mercy from Allah. Together, these hadiths present mercy as something to seek from Allah, to embody in the heart, and to extend to others.
66
+ """.strip()
67
+
68
+
69
+ def is_arabic_request(text: str) -> bool:
70
+ if not text:
71
+ return False
72
+ return bool(re.search(r'[\u0600-\u06FF]', text))
73
+
74
+
75
+ def normalize_quotes(text: str) -> str:
76
+ if not text:
77
+ return ""
78
+ text = text.replace("“", '"').replace("”", '"')
79
+ text = text.replace("‘", "'").replace("’", "'")
80
+ return text
81
+
82
+
83
+ def clean_answer(text: str, user_message: str = "") -> str:
84
+ if not text:
85
+ return ""
86
+
87
+ text = normalize_quotes(text.strip())
88
+
89
+ replacements = {
90
+ "Answer Insight:": "Answer:",
91
+ "Short answer:": "Answer:",
92
+ "Main Insight:": "Answer:",
93
+ "Key Finding:": "Answer:",
94
+ "Supporting Hadiths:": "Hadith Evidence:",
95
+ "Referenced Hadiths:": "Hadith Evidence:",
96
+ "What the Hadiths Show:": "Hadith Evidence:",
97
+ "What the Hadiths Cover:": "Hadith Evidence:",
98
+ "Evidence:": "Hadith Evidence:",
99
+ "Hadiths:": "Hadith Evidence:",
100
+ "Closing Note:": FINAL_NOTE,
101
+ "Note:": FINAL_NOTE,
102
+ }
103
+
104
+ for old, new in replacements.items():
105
+ text = text.replace(old, new)
106
+
107
+ # Normalize headings if model outputs markdown headings
108
+ text = re.sub(r"(?im)^#+\s*answer\s*:?\s*$", "Answer:", text)
109
+ text = re.sub(r"(?im)^#+\s*hadith evidence\s*:?\s*$", "Hadith Evidence:", text)
110
+
111
+ # Remove numbering before headings
112
+ text = re.sub(r"(?im)^\s*\d+\.\s*(Answer:)", r"\1", text)
113
+ text = re.sub(r"(?im)^\s*\d+\.\s*(Hadith Evidence:)", r"\1", text)
114
+
115
+ # Remove duplicate final note before re-adding once
116
+ text = re.sub(rf"(?s)\n*{re.escape(FINAL_NOTE)}\s*$", "", text).strip()
117
+
118
+ # Reduce excessive blank lines
119
+ text = re.sub(r"\n{3,}", "\n\n", text).strip()
120
+
121
+ # Ensure Answer section exists
122
+ if "Answer:" not in text:
123
+ text = "Answer:\n" + text
124
+
125
+ # Ensure Hadith Evidence section exists
126
+ if "Hadith Evidence:" not in text:
127
+ text += "\n\nHadith Evidence:\n"
128
+
129
+ # If Arabic requested, lightly relabel only headings, keep body as model returned
130
+ if is_arabic_request(user_message):
131
+ text = text.replace("Answer:", "الجواب:")
132
+ text = text.replace("Hadith Evidence:", "الأحاديث المسترجعة:")
133
+
134
+ # Add final note once
135
+ text = text.rstrip() + "\n\n" + FINAL_NOTE
136
+ return text
137
+
138
+
139
+ def chat(message, history):
140
+ messages = [{"role": "system", "content": SYSTEM_PROMPT}]
141
+
142
+ for user_msg, assistant_msg in history:
143
+ if user_msg:
144
+ messages.append({"role": "user", "content": user_msg})
145
+ if assistant_msg:
146
+ messages.append({"role": "assistant", "content": assistant_msg})
147
+
148
+ messages.append({"role": "user", "content": message})
149
+
150
+ try:
151
+ response = client.chat.completions.create(
152
+ model=MODEL_ID,
153
+ messages=messages,
154
+ temperature=0.1,
155
+ max_tokens=1100,
156
+ )
157
+ answer = response.choices[0].message.content.strip()
158
+ answer = clean_answer(answer, user_message=message)
159
+ except Exception as e:
160
+ answer = f"Error: {str(e)}"
161
+
162
+ return answer
163
+
164
+
165
+ demo = gr.ChatInterface(
166
+ fn=chat,
167
+ title="Hadithi AI",
168
+ description="Clear paragraph-based hadith answers followed by full hadith evidence",
169
+ textbox=gr.Textbox(
170
+ placeholder="Ask about a concept, meaning, value, or theme in hadith...",
171
+ container=True,
172
+ scale=7,
173
+ ),
174
+ )
175
+
176
+ if __name__ == "__main__":
177
+ demo.launch()