mo-456 commited on
Commit
f6eafcd
ยท
verified ยท
1 Parent(s): a37294b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +244 -71
app.py CHANGED
@@ -261,15 +261,45 @@ retriever = HybridRetriever(kb)
261
  class ResponseGenerator:
262
  def __init__(self):
263
  self.response_templates = {
264
- 'definition': "๐Ÿ“– **ุชุนุฑูŠู {topic}:**\n\n{content}\n\n",
265
- 'how': "๐Ÿ”ง **ูƒูŠููŠุฉ {topic}:**\n\n{content}\n\n",
266
- 'why': "๐Ÿ’ก **ุฃุณุจุงุจ {topic}:**\n\n{content}\n\n",
267
- 'list': "๐Ÿ“‹ **ู‚ุงุฆู…ุฉ {topic}:**\n\n{content}\n\n",
268
- 'general': "๐Ÿ’ฌ **ุญูˆู„ {topic}:**\n\n{content}\n\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
269
  }
270
 
271
  def generate_response(self, question: str, retrieved_chunks: List[Tuple[str, float, str]], question_type: str) -> str:
272
- """Generate contextually appropriate Arabic responses"""
273
  try:
274
  if not retrieved_chunks:
275
  return self._generate_fallback_response(question)
@@ -281,89 +311,191 @@ class ResponseGenerator:
281
  sections[section] = []
282
  sections[section].append((chunk, score))
283
 
284
- # Build response
285
- response = f"**ุจุฎุตูˆุต ุณุคุงู„ูƒ:** {question}\n\n"
286
 
287
- # Main section (highest scoring)
288
- main_section = max(sections.keys(),
289
- key=lambda k: max(score for _, score in sections[k]))
290
-
291
- main_content = self._format_section_content(sections[main_section], main_section)
292
-
293
- # Apply appropriate template
294
- topic = self._extract_topic(question)
295
- template = self.response_templates.get(question_type, self.response_templates['general'])
296
- response += template.format(topic=topic, content=main_content)
297
-
298
- # Add related information from other sections
299
- other_sections = [s for s in sections.keys() if s != main_section]
300
- if other_sections and len(other_sections) <= 2:
301
- response += "๐Ÿ” **ู…ุนู„ูˆู…ุงุช ุฐุงุช ุตู„ุฉ:**\n\n"
302
- for section in other_sections[:2]:
303
- content = self._format_section_content(sections[section][:2], section)
304
- response += f"**{section}:**\n{content}\n\n"
305
-
306
- # Add helpful suggestions
307
- response += self._generate_suggestions(sections.keys(), question_type)
308
 
309
  return response
310
 
311
  except Exception as e:
312
  logger.error(f"Response generation failed: {str(e)}")
313
- return "โš ๏ธ ุญุฏุซ ุฎุทุฃ ุฃุซู†ุงุก ุชุญุถูŠุฑ ุงู„ุฅุฌุงุจุฉ. ูŠุฑุฌู‰ ุฅุนุงุฏุฉ ุตูŠุงุบุฉ ุงู„ุณุคุงู„."
314
 
315
- def _format_section_content(self, chunk_list: List[Tuple[str, float]], section_name: str) -> str:
316
- """Format content from chunks in a section"""
317
- content_parts = []
318
- for chunk, score in sorted(chunk_list, key=lambda x: x[1], reverse=True):
319
- # Extract content after section name
320
- if ":" in chunk:
321
- content = chunk.split(":", 1)[1].strip()
322
- content_parts.append(f"โ€ข {content}")
 
 
 
 
 
 
 
 
 
 
 
 
323
 
324
- return "\n".join(content_parts[:3]) # Limit to top 3 for readability
 
 
 
 
 
 
 
 
 
 
325
 
326
- def _extract_topic(self, question: str) -> str:
327
- """Extract the main topic from the question"""
328
- # Simple topic extraction - can be enhanced
329
- keywords = query_processor.extract_keywords(question)
330
- if keywords:
331
- return " ".join(keywords[:2]) # Take first 2 keywords
332
- return "ุงู„ู…ูˆุถูˆุน ุงู„ู…ุทู„ูˆุจ"
 
 
 
 
 
 
 
 
 
 
 
333
 
334
- def _generate_suggestions(self, available_sections: List[str], question_type: str) -> str:
335
- """Generate helpful suggestions based on available content"""
336
  suggestions = []
337
 
338
  # Section-based suggestions
339
  for section in list(available_sections)[:3]:
340
- if len(section.split()) <= 4: # Only short section names
341
- suggestions.append(f"ุงู„ู…ุฒูŠุฏ ุนู† {section}")
342
 
343
  # Type-based suggestions
344
- if question_type == 'definition':
345
- suggestions.append("ุฃู‡ุฏุงู ูˆููˆุงุฆุฏ ุงู„ู…ูˆุงุฒู†ุฉ ุงู„ุชุดุงุฑูƒูŠุฉ")
346
- elif question_type == 'how':
347
- suggestions.append("ุฎุทูˆุงุช ุงู„ู…ุดุงุฑูƒุฉ ููŠ ุงู„ู…ูˆุงุฒู†ุฉ")
 
 
 
 
 
348
 
349
  if suggestions:
350
- return "โœจ **ูŠู…ูƒู†ูƒ ุฃูŠุถุงู‹ ุงู„ุงุณุชูุณุงุฑ ุนู†:**\n" + "\n".join(f"โ€ข {s}" for s in suggestions[:3])
 
 
 
 
351
 
352
  return ""
353
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
354
  def _generate_fallback_response(self, question: str) -> str:
355
- """Generate response when no relevant content is found"""
356
- suggestions = [
357
- "ุญุงูˆู„ ุตูŠุงุบุฉ ุณุคุงู„ูƒ ุจุทุฑูŠู‚ุฉ ู…ุฎุชู„ูุฉ ู…ุซู„: 'ู…ุง ู‡ูŠ ุฃู‡ุฏุงู ุงู„ู…ูˆุงุฒู†ุฉ ุงู„ุชุดุงุฑูƒูŠุฉุŸ'",
358
- "ุงุจุญุซ ููŠ ุงู„ู…ูˆุถูˆุนุงุช ุงู„ุฑุฆูŠุณูŠุฉ ู…ุซู„ 'ุงู„ุดูุงููŠุฉ ุงู„ู…ุงู„ูŠุฉ' ุฃูˆ 'ุงู„ู…ุดุงุฑูƒุฉ ุงู„ู…ุฌุชู…ุนูŠุฉ'",
359
- "ุฑุงุฌุน ุงู„ูˆุซุงุฆู‚ ุงู„ุฑุณู…ูŠุฉ ู„ูˆุฒุงุฑุฉ ุงู„ู…ุงู„ูŠุฉ ู„ู„ู…ุฒูŠุฏ ู…ู† ุงู„ุชูุงุตูŠู„"
360
- ]
361
-
362
- return (
363
- f"๐Ÿ” **ู„ู… ุฃุชู…ูƒู† ู…ู† ุงู„ุนุซูˆุฑ ุนู„ู‰ ุฅุฌุงุจุฉ ู…ุญุฏุฏุฉ ู„ุณุคุงู„ูƒ:** {question}\n\n"
364
- "๐Ÿ’ก **ุงู‚ุชุฑุงุญุงุช ู„ู„ุจุญุซ:**\n"
365
- + "\n".join(f"โ€ข {suggestion}" for suggestion in suggestions)
366
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
367
 
368
  # Initialize response generator
369
  response_generator = ResponseGenerator()
@@ -395,13 +527,13 @@ def answer_question(question: str) -> str:
395
  logger.error(f"Question processing failed: {str(e)}")
396
  return "โณ ุญุฏุซ ุฎุทุฃ ุบูŠุฑ ู…ุชูˆู‚ุน. ูŠุฑุฌู‰ ุงู„ู…ุญุงูˆู„ุฉ ู…ุฑุฉ ุฃุฎุฑู‰."
397
 
398
- # Enhanced UI with better styling
399
  css = """
400
  .arabic-ui {
401
  direction: rtl;
402
  text-align: right;
403
  font-family: 'Tahoma', 'Arial', sans-serif;
404
- line-height: 1.6;
405
  }
406
  .header {
407
  background: linear-gradient(135deg, #2c3e50, #3498db);
@@ -428,14 +560,55 @@ css = """
428
  background: #fafafa;
429
  }
430
  .answer-box {
431
- min-height: 250px;
432
  line-height: 1.8;
433
  font-size: 14px;
 
 
 
 
 
 
 
434
  }
435
  .question-input {
436
  font-size: 16px;
437
  padding: 12px;
438
  border-radius: 8px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
439
  }
440
  """
441
 
@@ -501,4 +674,4 @@ if __name__ == "__main__":
501
  server_port=7860,
502
  share=False,
503
  show_error=True
504
- )
 
261
  class ResponseGenerator:
262
  def __init__(self):
263
  self.response_templates = {
264
+ 'definition': {
265
+ 'icon': '๐Ÿ“–',
266
+ 'title': 'ุงู„ุชุนุฑูŠู ูˆุงู„ู…ูู‡ูˆู…',
267
+ 'structure': 'definition'
268
+ },
269
+ 'how': {
270
+ 'icon': '๐Ÿ”ง',
271
+ 'title': 'ุงู„ุขู„ูŠุฉ ูˆุงู„ุทุฑูŠู‚ุฉ',
272
+ 'structure': 'process'
273
+ },
274
+ 'why': {
275
+ 'icon': '๐Ÿ’ก',
276
+ 'title': 'ุงู„ุฃุณุจุงุจ ูˆุงู„ู…ุจุฑุฑุงุช',
277
+ 'structure': 'reasons'
278
+ },
279
+ 'who': {
280
+ 'icon': '๐Ÿ‘ฅ',
281
+ 'title': 'ุงู„ุฃุดุฎุงุต ูˆุงู„ุฌู‡ุงุช',
282
+ 'structure': 'entities'
283
+ },
284
+ 'when': {
285
+ 'icon': '๐Ÿ“…',
286
+ 'title': 'ุงู„ุชูˆู‚ูŠุช ูˆุงู„ู…ุฑุงุญู„',
287
+ 'structure': 'timeline'
288
+ },
289
+ 'list': {
290
+ 'icon': '๐Ÿ“‹',
291
+ 'title': 'ุงู„ู‚ุงุฆู…ุฉ ูˆุงู„ุนู†ุงุตุฑ',
292
+ 'structure': 'list'
293
+ },
294
+ 'general': {
295
+ 'icon': '๐Ÿ’ฌ',
296
+ 'title': 'ู…ุนู„ูˆู…ุงุช ุนุงู…ุฉ',
297
+ 'structure': 'general'
298
+ }
299
  }
300
 
301
  def generate_response(self, question: str, retrieved_chunks: List[Tuple[str, float, str]], question_type: str) -> str:
302
+ """Generate professionally formatted Arabic responses"""
303
  try:
304
  if not retrieved_chunks:
305
  return self._generate_fallback_response(question)
 
311
  sections[section] = []
312
  sections[section].append((chunk, score))
313
 
314
+ # Get template info
315
+ template_info = self.response_templates.get(question_type, self.response_templates['general'])
316
 
317
+ # Build professional response
318
+ response = self._build_response_header(question, template_info)
319
+ response += self._build_main_content(sections, template_info)
320
+ response += self._build_additional_info(sections)
321
+ response += self._build_suggestions(sections.keys(), question_type)
322
+ response += self._build_footer()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
323
 
324
  return response
325
 
326
  except Exception as e:
327
  logger.error(f"Response generation failed: {str(e)}")
328
+ return self._generate_error_response()
329
 
330
+ def _build_response_header(self, question: str, template_info: Dict) -> str:
331
+ """Build professional response header"""
332
+ header = f"""
333
+ โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
334
+ โ•‘ {template_info['icon']} **{template_info['title']}**
335
+ โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
336
+
337
+ **๐Ÿ” ุงุณุชุนู„ุงู…ูƒ:** {question}
338
+
339
+ """
340
+ return header
341
+
342
+ def _build_main_content(self, sections: Dict, template_info: Dict) -> str:
343
+ """Build the main content section"""
344
+ if not sections:
345
+ return ""
346
+
347
+ # Find the most relevant section
348
+ main_section = max(sections.keys(),
349
+ key=lambda k: max(score for _, score in sections[k]))
350
 
351
+ content = f"## ๐Ÿ“Œ **{main_section}**\n\n"
352
+
353
+ # Format main content based on structure type
354
+ main_content = self._format_section_content_professional(
355
+ sections[main_section], template_info['structure']
356
+ )
357
+
358
+ content += main_content + "\n\n"
359
+ content += "---\n\n"
360
+
361
+ return content
362
 
363
+ def _build_additional_info(self, sections: Dict) -> str:
364
+ """Build additional information section"""
365
+ other_sections = list(sections.keys())[1:3] # Take up to 2 additional sections
366
+
367
+ if not other_sections:
368
+ return ""
369
+
370
+ content = "## ๐Ÿ” **ู…ุนู„ูˆู…ุงุช ุฅุถุงููŠุฉ ุฐุงุช ุตู„ุฉ**\n\n"
371
+
372
+ for i, section in enumerate(other_sections, 1):
373
+ content += f"### {i}. **{section}**\n"
374
+ section_content = self._format_section_content_professional(
375
+ sections[section][:2], 'general'
376
+ )
377
+ content += section_content + "\n\n"
378
+
379
+ content += "---\n\n"
380
+ return content
381
 
382
+ def _build_suggestions(self, available_sections: List[str], question_type: str) -> str:
383
+ """Build suggestions section"""
384
  suggestions = []
385
 
386
  # Section-based suggestions
387
  for section in list(available_sections)[:3]:
388
+ if len(section.split()) <= 4:
389
+ suggestions.append(f"ุงู„ู…ุฒูŠุฏ ุญูˆู„ {section}")
390
 
391
  # Type-based suggestions
392
+ type_suggestions = {
393
+ 'definition': ["ุงู„ุฃู‡ุฏุงู ูˆุงู„ููˆุงุฆุฏ", "ุงู„ุชุทุจูŠู‚ ุงู„ุนู…ู„ูŠ"],
394
+ 'how': ["ุงู„ุฎุทูˆุงุช ุงู„ุชูุตูŠู„ูŠุฉ", "ุงู„ู…ุชุทู„ุจุงุช ูˆุงู„ุดุฑูˆุท"],
395
+ 'who': ["ุงู„ุฃุฏูˆุงุฑ ูˆุงู„ู…ุณุคูˆู„ูŠุงุช", "ุงู„ุชูˆุงุตู„ ูˆุงู„ุงุชุตุงู„"],
396
+ 'when': ["ุงู„ุฌุฏูˆู„ ุงู„ุฒู…ู†ูŠ", "ุงู„ู…ุฑุงุญู„ ุงู„ู‚ุงุฏู…ุฉ"]
397
+ }
398
+
399
+ if question_type in type_suggestions:
400
+ suggestions.extend(type_suggestions[question_type])
401
 
402
  if suggestions:
403
+ content = "## โœจ **ุงู‚ุชุฑุงุญุงุช ู„ู„ุงุณุชูุณุงุฑุงุช ุงู„ุฅุถุงููŠุฉ**\n\n"
404
+ for i, suggestion in enumerate(suggestions[:4], 1):
405
+ content += f"{i}. {suggestion}\n"
406
+ content += "\n"
407
+ return content
408
 
409
  return ""
410
 
411
+ def _build_footer(self) -> str:
412
+ """Build response footer"""
413
+ footer = """
414
+ ---
415
+ ๐Ÿ“ž **ู„ู„ู…ุฒูŠุฏ ู…ู† ุงู„ู…ุนู„ูˆู…ุงุช:** ุชูˆุงุตู„ ู…ุน ูˆุญุฏุฉ ุงู„ุดูุงููŠุฉ ูˆุงู„ู…ุดุงุฑูƒุฉ ุงู„ู…ุฌุชู…ุนูŠุฉ
416
+ ๐ŸŒ **ุงู„ู…ุตุฏุฑ:** ูˆุฒุงุฑุฉ ุงู„ู…ุงู„ูŠุฉ - ุฌู…ู‡ูˆุฑูŠุฉ ู…ุตุฑ ุงู„ุนุฑุจูŠุฉ
417
+ """
418
+ return footer
419
+
420
+ def _format_section_content_professional(self, chunk_list: List[Tuple[str, float]], structure_type: str) -> str:
421
+ """Format content professionally based on structure type"""
422
+ content_parts = []
423
+
424
+ for chunk, score in sorted(chunk_list, key=lambda x: x[1], reverse=True)[:3]:
425
+ if ":" in chunk:
426
+ content = chunk.split(":", 1)[1].strip()
427
+
428
+ if structure_type == 'definition':
429
+ content_parts.append(f"๐Ÿ”ธ **{content}**")
430
+ elif structure_type == 'process':
431
+ content_parts.append(f"โžค {content}")
432
+ elif structure_type == 'list':
433
+ content_parts.append(f"โ€ข {content}")
434
+ elif structure_type == 'entities':
435
+ content_parts.append(f"๐Ÿ‘ค {content}")
436
+ elif structure_type == 'timeline':
437
+ content_parts.append(f"๐Ÿ“… {content}")
438
+ else: # general
439
+ content_parts.append(f"โ–ช {content}")
440
+
441
+ return "\n\n".join(content_parts)
442
+
443
+ def _extract_topic(self, question: str) -> str:
444
+ """Extract the main topic from the question"""
445
+ keywords = query_processor.extract_keywords(question)
446
+ if keywords:
447
+ return " ".join(keywords[:2])
448
+ return "ุงู„ู…ูˆุถูˆุน ุงู„ู…ุทู„ูˆุจ"
449
+
450
  def _generate_fallback_response(self, question: str) -> str:
451
+ """Generate professional fallback response"""
452
+ return f"""
453
+ โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
454
+ โ•‘ ๐Ÿ” **ุงู„ุจุญุซ ููŠ ู‚ุงุนุฏุฉ ุงู„ู…ุนุฑูุฉ**
455
+ โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
456
+
457
+ **๐Ÿ” ุงุณุชุนู„ุงู…ูƒ:** {question}
458
+
459
+ ## โš ๏ธ **ู„ู… ูŠุชู… ุงู„ุนุซูˆุฑ ุนู„ู‰ ู†ุชุงุฆุฌ ู…ุทุงุจู‚ุฉ**
460
+
461
+ ู„ู… ุฃุชู…ูƒู† ู…ู† ุงู„ุนุซูˆุฑ ุนู„ู‰ ู…ุนู„ูˆู…ุงุช ู…ุญุฏุฏุฉ ุชุฌูŠุจ ุนู„ู‰ ุงุณุชูุณุงุฑูƒ ููŠ ู‚ุงุนุฏุฉ ุงู„ู…ุนุฑูุฉ ุงู„ุญุงู„ูŠุฉ.
462
+
463
+ ## ๐Ÿ’ก **ุงู‚ุชุฑุงุญุงุช ู„ุชุญุณูŠู† ุงู„ุจุญุซ**
464
+
465
+ 1. **ุฅุนุงุฏุฉ ุตูŠุงุบุฉ ุงู„ุณุคุงู„:** ุฌุฑุจ ุงุณุชุฎุฏุงู… ูƒู„ู…ุงุช ู…ูุชุงุญูŠุฉ ู…ุฎุชู„ูุฉ
466
+ 2. **ุงู„ุจุญุซ ููŠ ุงู„ู…ูˆุถูˆุนุงุช ุงู„ุฑุฆูŠุณูŠุฉ:**
467
+ - ุงู„ู…ูˆุงุฒู†ุฉ ุงู„ุชุดุงุฑูƒูŠุฉ
468
+ - ุงู„ุดูุงููŠุฉ ุงู„ู…ุงู„ูŠุฉ
469
+ - ุงู„ู…ุดุงุฑูƒุฉ ุงู„ู…ุฌุชู…ุนูŠุฉ
470
+ - ูˆุญุฏุฉ ุงู„ุดูุงููŠุฉ
471
+
472
+ 3. **ุฃู…ุซู„ุฉ ุนู„ู‰ ุฃุณุฆู„ุฉ ู…ููŠุฏุฉ:**
473
+ - ู…ุง ู‡ูŠ ุฃู‡ุฏุงู ุงู„ู…ูˆุงุฒู†ุฉ ุงู„ุชุดุงุฑูƒูŠุฉุŸ
474
+ - ูƒูŠู ูŠู…ูƒู† ู„ู„ู…ูˆุงุทู† ุงู„ู…ุดุงุฑูƒุฉุŸ
475
+ - ู…ู† ู‡ู… ุฃุนุถุงุก ูุฑูŠู‚ ุงู„ุนู…ู„ุŸ
476
+
477
+ ---
478
+ ๐Ÿ“ž **ู„ู„ู…ุฒูŠุฏ ู…ู† ุงู„ู…ุนู„ูˆู…ุงุช:** ุชูˆุงุตู„ ู…ุน ูˆุญุฏุฉ ุงู„ุดูุงููŠุฉ ูˆุงู„ู…ุดุงุฑูƒุฉ ุงู„ู…ุฌุชู…ุนูŠุฉ
479
+ """
480
+
481
+ def _generate_error_response(self) -> str:
482
+ """Generate professional error response"""
483
+ return """
484
+ โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
485
+ โ•‘ โš ๏ธ **ุฎุทุฃ ููŠ ุงู„ู†ุธุงู…**
486
+ โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
487
+
488
+ ุญุฏุซ ุฎุทุฃ ุบูŠุฑ ู…ุชูˆู‚ุน ุฃุซู†ุงุก ู…ุนุงู„ุฌุฉ ุงุณุชูุณุงุฑูƒ.
489
+
490
+ ## ๐Ÿ”„ **ุงู„ุฎุทูˆุงุช ุงู„ู…ู‚ุชุฑุญุฉ**
491
+
492
+ 1. ุชุฃูƒุฏ ู…ู† ุตุญุฉ ุตูŠุงุบุฉ ุงู„ุณุคุงู„
493
+ 2. ุฃุนุฏ ุงู„ู…ุญุงูˆู„ุฉ ุจุนุฏ ู‚ู„ูŠู„
494
+ 3. ุชูˆุงุตู„ ู…ุน ุงู„ุฏุนู… ุงู„ูู†ูŠ ุฅุฐุง ุงุณุชู…ุฑ ุงู„ุฎุทุฃ
495
+
496
+ ---
497
+ ๐Ÿ“ž **ุงู„ุฏุนู… ุงู„ูู†ูŠ:** ูˆุญุฏุฉ ุงู„ุดูุงููŠุฉ ูˆุงู„ู…ุดุงุฑูƒุฉ ุงู„ู…ุฌุชู…ุนูŠุฉ
498
+ """
499
 
500
  # Initialize response generator
501
  response_generator = ResponseGenerator()
 
527
  logger.error(f"Question processing failed: {str(e)}")
528
  return "โณ ุญุฏุซ ุฎุทุฃ ุบูŠุฑ ู…ุชูˆู‚ุน. ูŠุฑุฌู‰ ุงู„ู…ุญุงูˆู„ุฉ ู…ุฑุฉ ุฃุฎุฑู‰."
529
 
530
+ # Enhanced UI with better styling for professional responses
531
  css = """
532
  .arabic-ui {
533
  direction: rtl;
534
  text-align: right;
535
  font-family: 'Tahoma', 'Arial', sans-serif;
536
+ line-height: 1.8;
537
  }
538
  .header {
539
  background: linear-gradient(135deg, #2c3e50, #3498db);
 
560
  background: #fafafa;
561
  }
562
  .answer-box {
563
+ min-height: 300px;
564
  line-height: 1.8;
565
  font-size: 14px;
566
+ font-family: 'Tahoma', 'Arial', monospace;
567
+ background: #ffffff;
568
+ border: 1px solid #e0e0e0;
569
+ border-radius: 8px;
570
+ padding: 15px;
571
+ white-space: pre-wrap;
572
+ overflow-y: auto;
573
  }
574
  .question-input {
575
  font-size: 16px;
576
  padding: 12px;
577
  border-radius: 8px;
578
+ font-family: 'Tahoma', 'Arial', sans-serif;
579
+ }
580
+ /* Enhanced markdown support for Arabic */
581
+ .answer-box h1, .answer-box h2, .answer-box h3 {
582
+ color: #2c3e50;
583
+ margin-top: 20px;
584
+ margin-bottom: 10px;
585
+ }
586
+ .answer-box h2 {
587
+ border-bottom: 2px solid #3498db;
588
+ padding-bottom: 5px;
589
+ }
590
+ .answer-box h3 {
591
+ color: #34495e;
592
+ }
593
+ .answer-box hr {
594
+ border: none;
595
+ border-top: 1px solid #bdc3c7;
596
+ margin: 20px 0;
597
+ }
598
+ .answer-box strong {
599
+ color: #2c3e50;
600
+ font-weight: bold;
601
+ }
602
+ .answer-box ul, .answer-box ol {
603
+ margin: 10px 0;
604
+ padding-right: 20px;
605
+ }
606
+ .answer-box li {
607
+ margin: 5px 0;
608
+ }
609
+ /* Box drawing characters support */
610
+ .answer-box {
611
+ font-feature-settings: "liga" 1, "calt" 1;
612
  }
613
  """
614
 
 
674
  server_port=7860,
675
  share=False,
676
  show_error=True
677
+ )