Upload 3 files
Browse files
README.md
CHANGED
|
@@ -28,4 +28,7 @@ Without `BACKEND_URL`, the Space can still run the same style of workflow locall
|
|
| 28 |
|
| 29 |
- `LLM_BASE_URL`, `LLM_API_KEY`, `LLM_MODEL` for the AMD/vLLM tutor
|
| 30 |
- `TRANSLATION_PROVIDER=gemini`, `GEMINI_API_KEY`, `GEMINI_MODEL` for Nepali adaptation and romanized question normalization
|
|
|
|
| 31 |
- `OCR_PROVIDER=gemini`, `OCR_MAX_PAGES=5` for scanned or custom-font PDFs
|
|
|
|
|
|
|
|
|
| 28 |
|
| 29 |
- `LLM_BASE_URL`, `LLM_API_KEY`, `LLM_MODEL` for the AMD/vLLM tutor
|
| 30 |
- `TRANSLATION_PROVIDER=gemini`, `GEMINI_API_KEY`, `GEMINI_MODEL` for Nepali adaptation and romanized question normalization
|
| 31 |
+
- `TRANSLATION_PROVIDER=openai`, `OPENAI_API_KEY`, `OPENAI_MODEL` if you want to use OpenAI for Nepali adaptation instead
|
| 32 |
- `OCR_PROVIDER=gemini`, `OCR_MAX_PAGES=5` for scanned or custom-font PDFs
|
| 33 |
+
|
| 34 |
+
Use `LLM_MODEL=Qwen/Qwen2.5-7B-Instruct` to match the project default unless your vLLM endpoint exposes a different model name.
|
app.py
CHANGED
|
@@ -15,10 +15,12 @@ APP_NAME = os.getenv("APP_NAME", "Pathshala AI")
|
|
| 15 |
BACKEND_URL = os.getenv("BACKEND_URL", "").rstrip("/")
|
| 16 |
LLM_BASE_URL = os.getenv("LLM_BASE_URL", "").strip().rstrip("/")
|
| 17 |
LLM_API_KEY = os.getenv("LLM_API_KEY", "")
|
| 18 |
-
LLM_MODEL = os.getenv("LLM_MODEL", "Qwen/Qwen2.5-
|
| 19 |
TRANSLATION_PROVIDER = os.getenv("TRANSLATION_PROVIDER", "mock").strip().lower()
|
| 20 |
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY", "")
|
| 21 |
GEMINI_MODEL = os.getenv("GEMINI_MODEL", "gemini-2.5-flash")
|
|
|
|
|
|
|
| 22 |
OCR_PROVIDER = os.getenv("OCR_PROVIDER", "off").strip().lower()
|
| 23 |
OCR_MAX_PAGES = int(os.getenv("OCR_MAX_PAGES", "5") or "5")
|
| 24 |
EMBEDDING_MODEL = os.getenv(
|
|
@@ -256,7 +258,19 @@ def adapt_nepali_answer(question, english_answer, sources):
|
|
| 256 |
except (requests.RequestException, KeyError, IndexError, TypeError, ValueError):
|
| 257 |
pass
|
| 258 |
|
| 259 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 260 |
|
| 261 |
|
| 262 |
def translate_with_gemini(question, english_answer):
|
|
@@ -271,6 +285,46 @@ def translate_with_gemini(question, english_answer):
|
|
| 271 |
return gemini_generate_text(prompt, temperature=0.1, max_output_tokens=450)
|
| 272 |
|
| 273 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 274 |
def normalize_with_gemini(question):
|
| 275 |
prompt = (
|
| 276 |
"Convert this student question into one clear, simple English question for "
|
|
@@ -320,23 +374,53 @@ def fallback_english_answer(sources):
|
|
| 320 |
return "I do not have enough textbook context to answer this question."
|
| 321 |
|
| 322 |
topic_text = " ".join(str(source.get("text", "")) for source in sources[:3]).lower()
|
| 323 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 324 |
return (
|
| 325 |
"Soil erosion means the top fertile layer of soil is carried away by "
|
| 326 |
"water, wind, or other causes. It makes land less useful for growing "
|
| 327 |
"plants, so protecting soil with plants and controlled water flow is important."
|
| 328 |
)
|
| 329 |
-
|
|
|
|
| 330 |
return (
|
| 331 |
"Photosynthesis is the process by which green plants make their own food "
|
| 332 |
"using sunlight, water, and carbon dioxide. Chlorophyll in leaves helps "
|
| 333 |
"plants capture sunlight, and oxygen is released during the process."
|
| 334 |
)
|
| 335 |
|
| 336 |
-
return
|
| 337 |
-
" ".join(context.split()),
|
| 338 |
-
500,
|
| 339 |
-
)
|
| 340 |
|
| 341 |
|
| 342 |
def format_sources_for_prompt(sources):
|
|
@@ -673,17 +757,122 @@ def normalize_question(question):
|
|
| 673 |
pass
|
| 674 |
|
| 675 |
text = cleaned.lower()
|
| 676 |
-
if
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 677 |
return "What is soil erosion?"
|
| 678 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 679 |
return "What is photosynthesis?"
|
| 680 |
-
|
|
|
|
| 681 |
return "What is a fraction?"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 682 |
return cleaned
|
| 683 |
|
| 684 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 685 |
def display_topic(question):
|
| 686 |
normalized = str(question).lower()
|
|
|
|
|
|
|
|
|
|
|
|
|
| 687 |
if "photosynthesis" in normalized or "prakash" in normalized:
|
| 688 |
return "प्रकाश संश्लेषण"
|
| 689 |
if "soil erosion" in normalized or ("mato" in normalized and "katan" in normalized):
|
|
@@ -692,22 +881,23 @@ def display_topic(question):
|
|
| 692 |
return "भिन्न"
|
| 693 |
if "oxygen" in normalized:
|
| 694 |
return "अक्सिजन"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 695 |
return str(question).strip() or "आजको पाठ"
|
| 696 |
|
| 697 |
|
| 698 |
def nepali_answer(question, context):
|
| 699 |
text = f"{question} {context}".lower()
|
| 700 |
-
|
| 701 |
-
|
| 702 |
-
|
| 703 |
-
|
| 704 |
-
"रोप्दा माटो जोगाउन मद्दत हुन्छ।"
|
| 705 |
-
)
|
| 706 |
-
if "photosynthesis" in text or "प्रकाश संश्लेषण" in context:
|
| 707 |
-
return (
|
| 708 |
-
"प्रकाश संश्लेषण भनेको हरिया बिरुवाले घामको प्रकाश, पानी र कार्बन "
|
| 709 |
-
"डाइअक्साइड प्रयोग गरेर खाना बनाउने प्रक्रिया हो। यस क्रममा अक्सिजन पनि निस्कन्छ।"
|
| 710 |
-
)
|
| 711 |
if has_devanagari(context):
|
| 712 |
return "अपलोड गरिएको पाठ्यपुस्तकको सन्दर्भअनुसार मुख्य कुरा यस्तो छ:\n\n" + truncate(context, 700)
|
| 713 |
return (
|
|
@@ -716,6 +906,88 @@ def nepali_answer(question, context):
|
|
| 716 |
)
|
| 717 |
|
| 718 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 719 |
def nepali_quiz_questions(context):
|
| 720 |
short_context = truncate(first_sentence(context), 140)
|
| 721 |
return [
|
|
@@ -824,6 +1096,8 @@ def startup_status():
|
|
| 824 |
nepali_status = (
|
| 825 |
"Gemini Nepali adaptation enabled."
|
| 826 |
if TRANSLATION_PROVIDER == "gemini" and GEMINI_API_KEY
|
|
|
|
|
|
|
| 827 |
else "Mock Nepali adaptation enabled."
|
| 828 |
)
|
| 829 |
ocr_status = (
|
|
|
|
| 15 |
BACKEND_URL = os.getenv("BACKEND_URL", "").rstrip("/")
|
| 16 |
LLM_BASE_URL = os.getenv("LLM_BASE_URL", "").strip().rstrip("/")
|
| 17 |
LLM_API_KEY = os.getenv("LLM_API_KEY", "")
|
| 18 |
+
LLM_MODEL = os.getenv("LLM_MODEL", "Qwen/Qwen2.5-7B-Instruct")
|
| 19 |
TRANSLATION_PROVIDER = os.getenv("TRANSLATION_PROVIDER", "mock").strip().lower()
|
| 20 |
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY", "")
|
| 21 |
GEMINI_MODEL = os.getenv("GEMINI_MODEL", "gemini-2.5-flash")
|
| 22 |
+
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "")
|
| 23 |
+
OPENAI_MODEL = os.getenv("OPENAI_MODEL", "gpt-4o")
|
| 24 |
OCR_PROVIDER = os.getenv("OCR_PROVIDER", "off").strip().lower()
|
| 25 |
OCR_MAX_PAGES = int(os.getenv("OCR_MAX_PAGES", "5") or "5")
|
| 26 |
EMBEDDING_MODEL = os.getenv(
|
|
|
|
| 258 |
except (requests.RequestException, KeyError, IndexError, TypeError, ValueError):
|
| 259 |
pass
|
| 260 |
|
| 261 |
+
if TRANSLATION_PROVIDER == "openai" and OPENAI_API_KEY:
|
| 262 |
+
try:
|
| 263 |
+
translated = translate_with_openai(question, english_answer)
|
| 264 |
+
translated = remove_source_lines(translated)
|
| 265 |
+
if is_valid_nepali(translated):
|
| 266 |
+
return translated
|
| 267 |
+
except (requests.RequestException, KeyError, IndexError, TypeError, ValueError):
|
| 268 |
+
pass
|
| 269 |
+
|
| 270 |
+
return nepali_answer(
|
| 271 |
+
question,
|
| 272 |
+
" ".join(str(source.get("text", "")) for source in sources),
|
| 273 |
+
)
|
| 274 |
|
| 275 |
|
| 276 |
def translate_with_gemini(question, english_answer):
|
|
|
|
| 285 |
return gemini_generate_text(prompt, temperature=0.1, max_output_tokens=450)
|
| 286 |
|
| 287 |
|
| 288 |
+
def translate_with_openai(question, english_answer):
|
| 289 |
+
response = requests.post(
|
| 290 |
+
"https://api.openai.com/v1/chat/completions",
|
| 291 |
+
json={
|
| 292 |
+
"model": OPENAI_MODEL,
|
| 293 |
+
"messages": [
|
| 294 |
+
{
|
| 295 |
+
"role": "system",
|
| 296 |
+
"content": (
|
| 297 |
+
"You adapt English tutoring answers into natural Nepali for "
|
| 298 |
+
"primary-school students. Write only Nepali Devanagari. Do not "
|
| 299 |
+
"add source labels, markdown, or English sentences."
|
| 300 |
+
),
|
| 301 |
+
},
|
| 302 |
+
{
|
| 303 |
+
"role": "user",
|
| 304 |
+
"content": (
|
| 305 |
+
"Translate and simplify this grounded English tutoring answer "
|
| 306 |
+
"into natural Nepali for a primary-school student in Nepal. "
|
| 307 |
+
"Keep the same meaning. Use Nepali Devanagari only. Do not add "
|
| 308 |
+
"new facts. Do not include source citations or headings.\n\n"
|
| 309 |
+
f"Student question:\n{question}\n\n"
|
| 310 |
+
f"English answer:\n{english_answer}"
|
| 311 |
+
),
|
| 312 |
+
},
|
| 313 |
+
],
|
| 314 |
+
"temperature": 0.1,
|
| 315 |
+
"max_tokens": 450,
|
| 316 |
+
},
|
| 317 |
+
headers={
|
| 318 |
+
"Authorization": f"Bearer {OPENAI_API_KEY}",
|
| 319 |
+
"Content-Type": "application/json",
|
| 320 |
+
},
|
| 321 |
+
timeout=45,
|
| 322 |
+
)
|
| 323 |
+
response.raise_for_status()
|
| 324 |
+
data = response.json()
|
| 325 |
+
return data["choices"][0]["message"]["content"]
|
| 326 |
+
|
| 327 |
+
|
| 328 |
def normalize_with_gemini(question):
|
| 329 |
prompt = (
|
| 330 |
"Convert this student question into one clear, simple English question for "
|
|
|
|
| 374 |
return "I do not have enough textbook context to answer this question."
|
| 375 |
|
| 376 |
topic_text = " ".join(str(source.get("text", "")) for source in sources[:3]).lower()
|
| 377 |
+
concept_answer = known_english_concept_answer(topic_text)
|
| 378 |
+
if concept_answer:
|
| 379 |
+
return concept_answer
|
| 380 |
+
|
| 381 |
+
return "Based on the textbook context, here is the simple explanation: " + truncate(
|
| 382 |
+
" ".join(context.split()),
|
| 383 |
+
500,
|
| 384 |
+
)
|
| 385 |
+
|
| 386 |
+
|
| 387 |
+
def known_english_concept_answer(text):
|
| 388 |
+
if (
|
| 389 |
+
"living thing" in text
|
| 390 |
+
or "living things" in text
|
| 391 |
+
or "organism" in text
|
| 392 |
+
or "organisms" in text
|
| 393 |
+
):
|
| 394 |
+
return (
|
| 395 |
+
"Living things are organisms that show the signs of life. They need food "
|
| 396 |
+
"or energy, breathe or exchange gases, grow, respond to their surroundings, "
|
| 397 |
+
"and can reproduce. Plants, animals, fungi, and microorganisms are "
|
| 398 |
+
"examples of living things."
|
| 399 |
+
)
|
| 400 |
+
|
| 401 |
+
if "reflection" in text or "mirror" in text or "image of that object" in text:
|
| 402 |
+
return (
|
| 403 |
+
"Reflection of light means light bounces back after hitting a surface. "
|
| 404 |
+
"A mirror reflects light in an orderly way, so we can see a clear image "
|
| 405 |
+
"of an object in it. Smooth, flat surfaces make clearer reflections, while "
|
| 406 |
+
"rough surfaces scatter light and do not show a clear image."
|
| 407 |
+
)
|
| 408 |
+
|
| 409 |
+
if "soil erosion" in text or "erosion" in text:
|
| 410 |
return (
|
| 411 |
"Soil erosion means the top fertile layer of soil is carried away by "
|
| 412 |
"water, wind, or other causes. It makes land less useful for growing "
|
| 413 |
"plants, so protecting soil with plants and controlled water flow is important."
|
| 414 |
)
|
| 415 |
+
|
| 416 |
+
if "photosynthesis" in text or "chlorophyll" in text:
|
| 417 |
return (
|
| 418 |
"Photosynthesis is the process by which green plants make their own food "
|
| 419 |
"using sunlight, water, and carbon dioxide. Chlorophyll in leaves helps "
|
| 420 |
"plants capture sunlight, and oxygen is released during the process."
|
| 421 |
)
|
| 422 |
|
| 423 |
+
return None
|
|
|
|
|
|
|
|
|
|
| 424 |
|
| 425 |
|
| 426 |
def format_sources_for_prompt(sources):
|
|
|
|
| 757 |
pass
|
| 758 |
|
| 759 |
text = cleaned.lower()
|
| 760 |
+
if has_any(
|
| 761 |
+
text,
|
| 762 |
+
[
|
| 763 |
+
"living thing",
|
| 764 |
+
"living things",
|
| 765 |
+
"organism",
|
| 766 |
+
"organisms",
|
| 767 |
+
"sajeev",
|
| 768 |
+
"sajiv",
|
| 769 |
+
"जीवित",
|
| 770 |
+
"सजीव",
|
| 771 |
+
],
|
| 772 |
+
):
|
| 773 |
+
return "What are living things?"
|
| 774 |
+
|
| 775 |
+
if (
|
| 776 |
+
"soil erosion" in text
|
| 777 |
+
or "erosion" in text
|
| 778 |
+
or "माटो कटान" in cleaned
|
| 779 |
+
or (
|
| 780 |
+
has_any(text, ["mati", "mato", "matto", "maato"])
|
| 781 |
+
and has_any(text, ["katan", "katne", "katnu", "bagcha", "bagdai"])
|
| 782 |
+
)
|
| 783 |
+
):
|
| 784 |
return "What is soil erosion?"
|
| 785 |
+
|
| 786 |
+
if has_any(text, ["oxygen", "aksijan", "akshijan", "अक्सिजन"]):
|
| 787 |
+
return "What is oxygen?"
|
| 788 |
+
|
| 789 |
+
if (
|
| 790 |
+
"photosynthesis" in text
|
| 791 |
+
or "प्रकाश संश्लेषण" in cleaned
|
| 792 |
+
or (
|
| 793 |
+
has_any(text, ["prakash", "prakaash"])
|
| 794 |
+
and has_any(text, ["sansleshan", "samsleshan", "sanshleshan"])
|
| 795 |
+
)
|
| 796 |
+
):
|
| 797 |
return "What is photosynthesis?"
|
| 798 |
+
|
| 799 |
+
if has_any(text, ["fraction", "bhinn", "vag", "bhaag", "भाग", "भिन्न"]):
|
| 800 |
return "What is a fraction?"
|
| 801 |
+
|
| 802 |
+
if has_any(text, ["mitochondria", "mitochondrion", "mitokondria"]):
|
| 803 |
+
return "What is mitochondria?"
|
| 804 |
+
|
| 805 |
+
if has_any(text, ["chloroplast", "kloroplast", "chlorophyll"]):
|
| 806 |
+
return "What is chloroplast?"
|
| 807 |
+
|
| 808 |
+
if has_any(text, ["cell", "koshika", "kosika", "कोषिका"]):
|
| 809 |
+
return "What is a cell?"
|
| 810 |
+
|
| 811 |
+
if has_any(text, ["energy", "urja", "oorja", "ऊर्जा"]):
|
| 812 |
+
return "What is energy?"
|
| 813 |
+
|
| 814 |
+
mixed_topic = extract_mixed_language_topic(text)
|
| 815 |
+
if mixed_topic:
|
| 816 |
+
return f"What is {mixed_topic}?"
|
| 817 |
+
|
| 818 |
return cleaned
|
| 819 |
|
| 820 |
|
| 821 |
+
def has_any(text, keywords):
|
| 822 |
+
return any(keyword in text for keyword in keywords)
|
| 823 |
+
|
| 824 |
+
|
| 825 |
+
def extract_mixed_language_topic(text):
|
| 826 |
+
markers = [
|
| 827 |
+
" vaneko ",
|
| 828 |
+
" bhaneko ",
|
| 829 |
+
" vanya ",
|
| 830 |
+
" bhanya ",
|
| 831 |
+
" vanne ",
|
| 832 |
+
" bhanne ",
|
| 833 |
+
]
|
| 834 |
+
|
| 835 |
+
if not any(marker in f" {text} " for marker in markers):
|
| 836 |
+
return ""
|
| 837 |
+
|
| 838 |
+
topic = f" {text} "
|
| 839 |
+
removable_phrases = [
|
| 840 |
+
" vaneko ",
|
| 841 |
+
" bhaneko ",
|
| 842 |
+
" vanya ",
|
| 843 |
+
" bhanya ",
|
| 844 |
+
" vanne ",
|
| 845 |
+
" bhanne ",
|
| 846 |
+
" ke ho ",
|
| 847 |
+
" k ho ",
|
| 848 |
+
" kya ho ",
|
| 849 |
+
" ho ",
|
| 850 |
+
" ? ",
|
| 851 |
+
]
|
| 852 |
+
|
| 853 |
+
for phrase in removable_phrases:
|
| 854 |
+
topic = topic.replace(phrase, " ")
|
| 855 |
+
|
| 856 |
+
topic = " ".join(topic.split()).strip(" ?.,")
|
| 857 |
+
if not topic:
|
| 858 |
+
return ""
|
| 859 |
+
|
| 860 |
+
blocked_words = {"malai", "please", "explain", "bujhau", "bujhaunu", "sir", "mam"}
|
| 861 |
+
topic_words = [word for word in topic.split() if word not in blocked_words]
|
| 862 |
+
topic = " ".join(topic_words)
|
| 863 |
+
|
| 864 |
+
if not topic or len(topic) > 80:
|
| 865 |
+
return ""
|
| 866 |
+
|
| 867 |
+
return topic
|
| 868 |
+
|
| 869 |
+
|
| 870 |
def display_topic(question):
|
| 871 |
normalized = str(question).lower()
|
| 872 |
+
if "living thing" in normalized or "organism" in normalized:
|
| 873 |
+
return "सजीव वस्तु"
|
| 874 |
+
if "reflection" in normalized:
|
| 875 |
+
return "प्रकाशको परावर्तन"
|
| 876 |
if "photosynthesis" in normalized or "prakash" in normalized:
|
| 877 |
return "प्रकाश संश्लेषण"
|
| 878 |
if "soil erosion" in normalized or ("mato" in normalized and "katan" in normalized):
|
|
|
|
| 881 |
return "भिन्न"
|
| 882 |
if "oxygen" in normalized:
|
| 883 |
return "अक्सिजन"
|
| 884 |
+
if "mitochondria" in normalized or "mitochondrion" in normalized:
|
| 885 |
+
return "माइटोकन्ड्रिया"
|
| 886 |
+
if "chloroplast" in normalized:
|
| 887 |
+
return "क्लोरोप्लास्ट"
|
| 888 |
+
if "cell" in normalized:
|
| 889 |
+
return "कोषिका"
|
| 890 |
+
if "energy" in normalized:
|
| 891 |
+
return "ऊर्जा"
|
| 892 |
return str(question).strip() or "आजको पाठ"
|
| 893 |
|
| 894 |
|
| 895 |
def nepali_answer(question, context):
|
| 896 |
text = f"{question} {context}".lower()
|
| 897 |
+
known_answer = known_nepali_concept_answer(text)
|
| 898 |
+
if known_answer:
|
| 899 |
+
return known_answer
|
| 900 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 901 |
if has_devanagari(context):
|
| 902 |
return "अपलोड गरिएको पाठ्यपुस्तकको सन्दर्भअनुसार मुख्य कुरा यस्तो छ:\n\n" + truncate(context, 700)
|
| 903 |
return (
|
|
|
|
| 906 |
)
|
| 907 |
|
| 908 |
|
| 909 |
+
def known_nepali_concept_answer(text):
|
| 910 |
+
if (
|
| 911 |
+
"living thing" in text
|
| 912 |
+
or "living things" in text
|
| 913 |
+
or "organism" in text
|
| 914 |
+
or "organisms" in text
|
| 915 |
+
or "sajeev" in text
|
| 916 |
+
or "sajiv" in text
|
| 917 |
+
or "सजीव" in text
|
| 918 |
+
or "जीवित वस्तु" in text
|
| 919 |
+
):
|
| 920 |
+
return (
|
| 921 |
+
"सजीव वा जीवित वस्तु भनेको जीवनका लक्षण देखाउने वस्तु हो। सजीवले "
|
| 922 |
+
"खाना वा ऊर्जा लिन्छ, सास फेर्छ, बढ्छ, वातावरणको परिवर्तनमा प्रतिक्रिया "
|
| 923 |
+
"दिन्छ, र प्रजनन गर्न सक्छ। बिरुवा, जनावर, ढुसी र सूक्ष्म जीवहरू "
|
| 924 |
+
"सजीवका उदाहरण हुन्।"
|
| 925 |
+
)
|
| 926 |
+
|
| 927 |
+
if "reflection" in text or "mirror" in text or "ऐना" in text or "प्रतिबिम्ब" in text:
|
| 928 |
+
return (
|
| 929 |
+
"प्रकाशको परावर्तन भनेको प्रकाश कुनै सतहमा ठोक्किएर फर्कनु हो। ऐनाले "
|
| 930 |
+
"प्रकाशलाई राम्रोसँग फर्काउँछ, त्यसैले त्यसमा वस्तुको प्रतिबिम्ब देखिन्छ। "
|
| 931 |
+
"समथर र चिल्लो सतहमा प्रतिबिम्ब प्रस्ट देखिन्छ, तर खस्रो सतहमा प्रकाश धेरै "
|
| 932 |
+
"दिशामा छरिने भएकाले प्रतिबिम्ब प्रस्ट देखिँदैन।"
|
| 933 |
+
)
|
| 934 |
+
|
| 935 |
+
if "soil erosion" in text or "erosion" in text or "माटो कटान" in text:
|
| 936 |
+
return (
|
| 937 |
+
"माटो कटान भनेको हावा, पानी वा अन्य कारणले माटोको माथिल्लो मलिलो भाग "
|
| 938 |
+
"बिस्तारै बगेर वा उडेर जानु हो। यसले खेतबारीको उर्वर शक्ति घटाउँछ। "
|
| 939 |
+
"त्यसैले बिरुवा रोप्ने, घाँस जोगाउने र पानीको बहाव नियन्त्रण गर्ने काम "
|
| 940 |
+
"माटो जोगाउन उपयोगी हुन्छ।"
|
| 941 |
+
)
|
| 942 |
+
|
| 943 |
+
if "oxygen" in text or "अक्सिजन" in text:
|
| 944 |
+
return (
|
| 945 |
+
"अक्सिजन एउटा ग्यास हो। जीवित प्राणीले सास फेर्दा अक्सिजन प्रयोग गर्छन्। "
|
| 946 |
+
"कोषिकाले खाना तोडेर ऊर्जा बनाउन पनि अक्सिजनको मद्दत लिन्छ। "
|
| 947 |
+
"त्यसैले अक्सिजन जीवनका लागि धेरै महत्त्वपूर्ण हु��्छ।"
|
| 948 |
+
)
|
| 949 |
+
|
| 950 |
+
if "photosynthesis" in text or "chlorophyll" in text or "प्रकाश संश्लेषण" in text:
|
| 951 |
+
return (
|
| 952 |
+
"प्रकाश संश्लेषण भनेको हरिया बिरुवाले घामको प्रकाश, पानी र कार्बन डाइअक्साइड "
|
| 953 |
+
"प्रयोग गरेर आफ्नो खाना बनाउने प्रक्रिया हो। यो काम पातमा हुने हरियो पदार्थ "
|
| 954 |
+
"क्लोरोफिलको मद्दतले हुन्छ। यस प्रक्रियामा अक्सिजन पनि निस्कन्छ।"
|
| 955 |
+
)
|
| 956 |
+
|
| 957 |
+
if "fraction" in text or "भिन्न" in text:
|
| 958 |
+
return (
|
| 959 |
+
"भिन्न भनेको कुनै पूर्ण वस्तुको भाग देखाउने संख्या हो। माथिको संख्या अंश हो, "
|
| 960 |
+
"जसले कति भाग लिइयो भनेर देखाउँछ। तलको संख्या हर हो, जसले पूर्ण वस्तु कति "
|
| 961 |
+
"बराबर भागमा बाँडिएको छ भनेर देखाउँछ।"
|
| 962 |
+
)
|
| 963 |
+
|
| 964 |
+
if "mitochondria" in text or "mitochondrion" in text:
|
| 965 |
+
return (
|
| 966 |
+
"माइटोकन्ड्रिया कोषिकाभित्र हुने सानो अंगक हो। यसको मुख्य काम खानाबाट ऊर्जा "
|
| 967 |
+
"बनाउनु हो। त्यसैले यसलाई कोषिकाको ऊर्जा घर पनि भनिन्छ।"
|
| 968 |
+
)
|
| 969 |
+
|
| 970 |
+
if "chloroplast" in text or "plastid" in text:
|
| 971 |
+
return (
|
| 972 |
+
"क्लोरोप्लास्ट बिरुवाको कोषिकामा पाइने हरियो अंगक हो। यसमा क्लोरोफिल हुन्छ। "
|
| 973 |
+
"क्लोरोफिलले घामको प्रकाश लिन मद्दत गर्छ र बिरुवाले खाना बनाउन सक्छ।"
|
| 974 |
+
)
|
| 975 |
+
|
| 976 |
+
if "cell" in text or "कोषिका" in text:
|
| 977 |
+
return (
|
| 978 |
+
"कोषिका जीवित वस्तुको सबैभन्दा सानो आधारभूत एकाइ हो। हाम्रो शरीर, बिरुवा "
|
| 979 |
+
"र धेरै जीवहरू कोषिकाबाट बनेका हुन्छन्। कोषिकाले जीवनका आवश्यक कामहरू गर्छ।"
|
| 980 |
+
)
|
| 981 |
+
|
| 982 |
+
if "energy" in text or "ऊर्जा" in text:
|
| 983 |
+
return (
|
| 984 |
+
"ऊर्जा भनेको काम गर्न चाहिने शक्ति हो। जीवित प्राणीले खाना र सास फेर्ने "
|
| 985 |
+
"प्रक्रियाबाट ऊर्जा पाउँछन्। कोषिकाले यही ऊर्जा प्रयोग गरेर जीवनका काम गर्छ।"
|
| 986 |
+
)
|
| 987 |
+
|
| 988 |
+
return None
|
| 989 |
+
|
| 990 |
+
|
| 991 |
def nepali_quiz_questions(context):
|
| 992 |
short_context = truncate(first_sentence(context), 140)
|
| 993 |
return [
|
|
|
|
| 1096 |
nepali_status = (
|
| 1097 |
"Gemini Nepali adaptation enabled."
|
| 1098 |
if TRANSLATION_PROVIDER == "gemini" and GEMINI_API_KEY
|
| 1099 |
+
else "OpenAI Nepali adaptation enabled."
|
| 1100 |
+
if TRANSLATION_PROVIDER == "openai" and OPENAI_API_KEY
|
| 1101 |
else "Mock Nepali adaptation enabled."
|
| 1102 |
)
|
| 1103 |
ocr_status = (
|