Jelajahi Sumber

TG-220 TG-221 TG-222 #closed - Upgrade Ollama to Qwen2.5-7B, refactor backend prompts for XML scratchpad reasoning, and implement response parsing

Lange François 1 bulan lalu
induk
melakukan
09a86d91ba
32 mengubah file dengan 73 tambahan dan 23 penghapusan
  1. TEMPAT SAMPAH
      Project.pdf
  2. TEMPAT SAMPAH
      Retro Planning.pdf
  3. 64 14
      app.py
  4. TEMPAT SAMPAH
      docs/Backup_Procedure.pdf
  5. TEMPAT SAMPAH
      docs/Data_Ingestion.pdf
  6. TEMPAT SAMPAH
      docs/Final_Report.pdf
  7. TEMPAT SAMPAH
      docs/Installation_Guide.pdf
  8. 2 2
      docs/Operator_Installation_Guide.md
  9. TEMPAT SAMPAH
      docs/Operator_Installation_Guide.pdf
  10. TEMPAT SAMPAH
      docs/Scrum_Artifacts.pdf
  11. TEMPAT SAMPAH
      docs/Scrum_Daily.pdf
  12. TEMPAT SAMPAH
      docs/Scrum_Plan.pdf
  13. TEMPAT SAMPAH
      docs/Scrum_Retro.pdf
  14. TEMPAT SAMPAH
      docs/Scrum_Review.pdf
  15. TEMPAT SAMPAH
      docs/Scrum_Wiki.pdf
  16. TEMPAT SAMPAH
      docs/Start_Stop_Procedures.pdf
  17. TEMPAT SAMPAH
      docs/Test_Cases_Sprint8.pdf
  18. 1 1
      docs/User_Description.md
  19. TEMPAT SAMPAH
      docs/User_Description.pdf
  20. 1 1
      docs/User_Guide.md
  21. TEMPAT SAMPAH
      docs/User_Guide.pdf
  22. TEMPAT SAMPAH
      docs/WSL_Deployment.pdf
  23. TEMPAT SAMPAH
      docs/Wiki_Home.pdf
  24. TEMPAT SAMPAH
      docs/architecture.pdf
  25. TEMPAT SAMPAH
      docs/disaster_recovery_plan.pdf
  26. TEMPAT SAMPAH
      docs/distributed_deployment.pdf
  27. TEMPAT SAMPAH
      docs/project_report.pdf
  28. TEMPAT SAMPAH
      docs/retro_planning.pdf
  29. TEMPAT SAMPAH
      docs/taiga_audit_report.pdf
  30. TEMPAT SAMPAH
      docs/zabbix_monitoring.pdf
  31. 4 4
      generate_docs.py
  32. 1 1
      scripts/generate_project_report.py

TEMPAT SAMPAH
Project.pdf


TEMPAT SAMPAH
Retro Planning.pdf


+ 64 - 14
app.py

@@ -30,8 +30,47 @@ import time
 
 import threading
 
+def strip_scratchpad(text: str) -> str:
+    import re
+    # Strip out the XML <scratchpad> tag and everything in between, non-greedily
+    clean_text = re.sub(r'<scratchpad>.*?</scratchpad>', '', text, flags=re.DOTALL)
+    return clean_text.strip()
+
+def filter_scratchpad_stream(stream):
+    buffer = ""
+    in_scratchpad = False
+    for chunk in stream:
+        content = chunk['message']['content']
+        buffer += content
+        
+        while True:
+            if not in_scratchpad:
+                start_idx = buffer.find("<scratchpad>")
+                if start_idx != -1:
+                    yield buffer[:start_idx]
+                    buffer = buffer[start_idx:]
+                    in_scratchpad = True
+                else:
+                    yield_len = max(0, len(buffer) - 11)
+                    if yield_len > 0:
+                        yield buffer[:yield_len]
+                        buffer = buffer[yield_len:]
+                    break
+            else:
+                end_idx = buffer.find("</scratchpad>")
+                if end_idx != -1:
+                    buffer = buffer[end_idx + 13:]
+                    in_scratchpad = False
+                else:
+                    keep_len = 12
+                    if len(buffer) > keep_len:
+                        buffer = buffer[-keep_len:]
+                    break
+    if not in_scratchpad and buffer:
+        yield buffer
+
 def pull_model_bg():
-    try: ollama.pull('llama3.2:3b')
+    try: ollama.pull('qwen2.5:7b')
     except: pass
 threading.Thread(target=pull_model_bg, daemon=True).start()
 
@@ -415,7 +454,7 @@ with tab_chat:
         
         try:
             temp_messages = [{"role": "system", "content": sys_prompt}] + [m for m in st.session_state.messages if m["role"] != "tool"]
-            response_stream = ollama.chat(model='llama3.2:3b', messages=temp_messages, stream=True)
+            response_stream = ollama.chat(model='qwen2.5:7b', messages=temp_messages, stream=True)
             
             with st.chat_message("assistant"):
                 ai_reply = st.write_stream(chunk['message']['content'] for chunk in response_stream)
@@ -622,7 +661,7 @@ with tab_explore:
                                 minimal_records = df_display[['product_name', 'Medical Warning']].head(10).to_dict('records')
                                 eval_prompt = f"The user has this profile: {profile_text}. Evaluate these top foods and state which are highly recommended or strictly forbidden: {minimal_records}. Provide a direct, readable clinical summary. Do not output raw JSON."
                                 try:
-                                    response_stream = ollama.chat(model='llama3.2:3b', messages=[{'role': 'user', 'content': eval_prompt}], stream=True)
+                                    response_stream = ollama.chat(model='qwen2.5:7b', messages=[{'role': 'user', 'content': eval_prompt}], stream=True)
                                     st.write_stream(chunk['message']['content'] for chunk in response_stream)
                                 except Exception as e:
                                     error_msg = str(e).lower()
@@ -818,22 +857,33 @@ with tab_planner:
             Dietary constraint: {diet_pref}. Additional notes: {extra_notes}.
             Health profile: {profile_text}. 
             
-            CRITICAL INSTRUCTIONS:
-            - You MUST formulate the menu using ONLY the following real database items retrieved for you: {db_context}
-            - Output the menu beautifully formatted as a Markdown Table.
-            - The Markdown table MUST strictly contain 5 columns separated by pipes (|).
-            - Columns MUST be exactly: | Meal Time | Exact Food | Portion Size | Calories | Protein |
-            - If you merge columns, the system will fail. Separate Calories and Protein with a pipe.
-            - Do NOT output JSON. Do NOT use tool calls.
-            - Provide a direct answer. Skip all thinking, reasoning, and pleasantries.
+            COGNITIVE SCRATCHPAD INSTRUCTIONS:
+            - You MUST perform all your intermediate thinking, unit conversions (e.g. converting cups, tablespoons, or ounces to exact metric grams based on food density), and calorie/protein mathematical additions inside a `<scratchpad>` tag.
+            - Format:
+              <scratchpad>
+              Calculations:
+              - 1.5 cups of Cheese = X grams (density Y). Calories = A, Protein = B.
+              - 2 tbsp of Peanut Butter = Z grams (density C). Calories = D, Protein = E.
+              - Summation: Total Calories = A + D = Z kcal (vs target {target_cal}kcal). Total Protein = B + E = Fg.
+              </scratchpad>
+              | Meal Time | Exact Food | Portion Size | Calories | Protein |
+              | --- | --- | --- | --- | --- |
+              ...
+            
+            CRITICAL FORMATTING INSTRUCTIONS:
+            - After the </scratchpad> closing tag, you MUST strictly output the menu formatted as a Markdown Table.
+            - The table MUST contain exactly 5 columns separated by pipes (|): | Meal Time | Exact Food | Portion Size | Calories | Protein |
+            - The items in the table MUST be selected strictly from: {db_context}
+            - Do NOT output JSON. Do NOT use tool calls. Skip pleasantries.
             """
             
             temp_messages = [{'role': 'system', 'content': sys_prompt}, {'role': 'user', 'content': 'Generate my meal plan as a markdown table.'}]
             
             # Stream the response instantly!
             try:
-                response_stream = ollama.chat(model='llama3.2:3b', messages=temp_messages, stream=True)
-                ai_reply = st.write_stream(chunk['message']['content'] for chunk in response_stream)
+                response_stream = ollama.chat(model='qwen2.5:7b', messages=temp_messages, stream=True)
+                clean_stream = filter_scratchpad_stream(response_stream)
+                ai_reply = st.write_stream(clean_stream)
                 
                 # PDF Generation
                 def generate_pdf(text):
@@ -916,7 +966,7 @@ with tab_planner:
                 
                 st.download_button(
                     label="📄 Download PDF Export",
-                    data=generate_pdf(ai_reply),
+                    data=generate_pdf(strip_scratchpad(ai_reply)),
                     file_name="Clinical_Meal_Plan.pdf",
                     mime="application/pdf",
                     type="primary"

TEMPAT SAMPAH
docs/Backup_Procedure.pdf


TEMPAT SAMPAH
docs/Data_Ingestion.pdf


TEMPAT SAMPAH
docs/Final_Report.pdf


TEMPAT SAMPAH
docs/Installation_Guide.pdf


+ 2 - 2
docs/Operator_Installation_Guide.md

@@ -27,7 +27,7 @@ To maximize CPU/GPU efficiency and secure database read/writes, services are dis
 | :--- | :--- | :--- |
 | **streamlit-app (app.py)** | Local WSL2 (Windows) | Low-latency rendering and direct client access |
 | **mysql (Database Node)** | Hyper-V VM (Server A) | Persistent enterprise-grade disk storage |
-| **ollama (NLP Llama3.2:3b Engine)** | VirtualBox VM (Server B) | Dedicated CPU/GPU virtualization allocation |
+| **ollama (NLP Qwen2.5:7b Engine)** | VirtualBox VM (Server B) | Dedicated CPU/GPU virtualization allocation |
 | **zabbix-server & web (Monitoring)** | Hyper-V VM (Server A) | Centralized SNMPv3 alert processing and logs |
 | **searxng (Meta-Search Gateway)** | Local WSL2 (Windows) | Dynamic browser-level loopbacks |
 
@@ -179,6 +179,6 @@ Run these test cases to verify the installation:
 | :--- | :--- | :--- | :---: |
 | **TC-OP-01** | Search 'Cheese' on Search Tab | 10+ records returned in <0.04s. Listeria warning flags on unpasteurized. | `[ ]` |
 | **TC-OP-02** | Enter '1.5 cups' in Plate Tab | Parsed and converted to metric grams based on density index. | `[ ]` |
-| **TC-OP-03** | Ask Chat: 'Can I eat sushi?' | Llama3.2:3b retrieves database context and flags raw fish as forbidden for pregnancy. | `[ ]` |
+| **TC-OP-03** | Ask Chat: 'Can I eat sushi?' | Qwen2.5:7b retrieves database context and flags raw fish as forbidden for pregnancy. | `[ ]` |
 | **TC-OP-04** | Trigger manual db backup | Timestamped compressed .sql.gz created inside backups/ folder. | `[ ]` |
 | **TC-OP-05** | Terminate Ollama Container | Zabbix PROBLEM active alert generated on dashboard in < 30 seconds. | `[ ]` |

TEMPAT SAMPAH
docs/Operator_Installation_Guide.pdf


TEMPAT SAMPAH
docs/Scrum_Artifacts.pdf


TEMPAT SAMPAH
docs/Scrum_Daily.pdf


TEMPAT SAMPAH
docs/Scrum_Plan.pdf


TEMPAT SAMPAH
docs/Scrum_Retro.pdf


TEMPAT SAMPAH
docs/Scrum_Review.pdf


TEMPAT SAMPAH
docs/Scrum_Wiki.pdf


TEMPAT SAMPAH
docs/Start_Stop_Procedures.pdf


TEMPAT SAMPAH
docs/Test_Cases_Sprint8.pdf


+ 1 - 1
docs/User_Description.md

@@ -18,7 +18,7 @@ Allows practitioners to search the 24GB OpenFoodFacts dataset in real time (aver
 - **Flexible Column Customization**: Multi-select column headers to inspect specific macro and micro-nutrients.
 
 ### 💬 tab 2: AI Clinical Chat (💬 AI Chat)
-An interactive NLP dialogue interface powered by a local lightweight LLM (**Llama3.2:3b**).
+An interactive NLP dialogue interface powered by a local lightweight LLM (**Qwen2.5:7b**).
 - **RAG-Driven Precision**: The AI dietitian automatically retrieves and reviews local database records and private meta-search results before formulating an answer.
 - **Dynamic Medical Guardrails**: The user's active illnesses, diets, and conditions are injected into the AI's system prompt in the background, forcing the AI to strictly enforce clinical safety constraints.
 

TEMPAT SAMPAH
docs/User_Description.pdf


+ 1 - 1
docs/User_Guide.md

@@ -8,4 +8,4 @@ Search for products using keywords. The system utilizes FULLTEXT matching to ins
 Add portion sizes of different foods to calculate cumulative nutritional intake. Use the 🗑️ icon to remove items.
 
 ## 3. Chat with AI
-Ask the `llama3.2:3b` model complex dietary questions. It natively utilizes RAG Tool Calling to silently search the database and formulate clinical answers.
+Ask the `qwen2.5:7b` model complex dietary questions. It natively utilizes RAG Tool Calling to silently search the database and formulate clinical answers.

TEMPAT SAMPAH
docs/User_Guide.pdf


TEMPAT SAMPAH
docs/WSL_Deployment.pdf


TEMPAT SAMPAH
docs/Wiki_Home.pdf


TEMPAT SAMPAH
docs/architecture.pdf


TEMPAT SAMPAH
docs/disaster_recovery_plan.pdf


TEMPAT SAMPAH
docs/distributed_deployment.pdf


TEMPAT SAMPAH
docs/project_report.pdf


TEMPAT SAMPAH
docs/retro_planning.pdf


TEMPAT SAMPAH
docs/taiga_audit_report.pdf


TEMPAT SAMPAH
docs/zabbix_monitoring.pdf


+ 4 - 4
generate_docs.py

@@ -148,7 +148,7 @@ Search for products using keywords. The system utilizes FULLTEXT matching to ins
 Add portion sizes of different foods to calculate cumulative nutritional intake. Use the 🗑️ icon to remove items.
 
 ## 3. Chat with AI
-Ask the `llama3.2:3b` model complex dietary questions. It natively utilizes RAG Tool Calling to silently search the database and formulate clinical answers.
+Ask the `qwen2.5:7b` model complex dietary questions. It natively utilizes RAG Tool Calling to silently search the database and formulate clinical answers.
 """,
     "Wiki_Home.md": """# $Id$
 # Documentation Home
@@ -241,7 +241,7 @@ Allows practitioners to search the 24GB OpenFoodFacts dataset in real time (aver
 - **Flexible Column Customization**: Multi-select column headers to inspect specific macro and micro-nutrients.
 
 ### 💬 tab 2: AI Clinical Chat (💬 AI Chat)
-An interactive NLP dialogue interface powered by a local lightweight LLM (**Llama3.2:3b**).
+An interactive NLP dialogue interface powered by a local lightweight LLM (**Qwen2.5:7b**).
 - **RAG-Driven Precision**: The AI dietitian automatically retrieves and reviews local database records and private meta-search results before formulating an answer.
 - **Dynamic Medical Guardrails**: The user's active illnesses, diets, and conditions are injected into the AI's system prompt in the background, forcing the AI to strictly enforce clinical safety constraints.
 
@@ -383,7 +383,7 @@ To maximize CPU/GPU efficiency and secure database read/writes, services are dis
 | :--- | :--- | :--- |
 | **streamlit-app (app.py)** | Local WSL2 (Windows) | Low-latency rendering and direct client access |
 | **mysql (Database Node)** | Hyper-V VM (Server A) | Persistent enterprise-grade disk storage |
-| **ollama (NLP Llama3.2:3b Engine)** | VirtualBox VM (Server B) | Dedicated CPU/GPU virtualization allocation |
+| **ollama (NLP Qwen2.5:7b Engine)** | VirtualBox VM (Server B) | Dedicated CPU/GPU virtualization allocation |
 | **zabbix-server & web (Monitoring)** | Hyper-V VM (Server A) | Centralized SNMPv3 alert processing and logs |
 | **searxng (Meta-Search Gateway)** | Local WSL2 (Windows) | Dynamic browser-level loopbacks |
 
@@ -535,7 +535,7 @@ Run these test cases to verify the installation:
 | :--- | :--- | :--- | :---: |
 | **TC-OP-01** | Search 'Cheese' on Search Tab | 10+ records returned in <0.04s. Listeria warning flags on unpasteurized. | `[ ]` |
 | **TC-OP-02** | Enter '1.5 cups' in Plate Tab | Parsed and converted to metric grams based on density index. | `[ ]` |
-| **TC-OP-03** | Ask Chat: 'Can I eat sushi?' | Llama3.2:3b retrieves database context and flags raw fish as forbidden for pregnancy. | `[ ]` |
+| **TC-OP-03** | Ask Chat: 'Can I eat sushi?' | Qwen2.5:7b retrieves database context and flags raw fish as forbidden for pregnancy. | `[ ]` |
 | **TC-OP-04** | Trigger manual db backup | Timestamped compressed .sql.gz created inside backups/ folder. | `[ ]` |
 | **TC-OP-05** | Terminate Ollama Container | Zabbix PROBLEM active alert generated on dashboard in < 30 seconds. | `[ ]` |
 """

+ 1 - 1
scripts/generate_project_report.py

@@ -187,7 +187,7 @@ def main():
 The **Local Food AI** capstone project has successfully completed all sprint iterations. The system stands fully verified, containerized, and documented. 
 
 ### What Has Been Done
-1. **Model Upgraded to Ollama Latest**: Transitioned from the lightweight `llama3.2:1b` model to the much more robust and recent **`llama3.2:3b`** model (2.0 GB). Programmatically downloaded and installed it natively inside the `food_project-ollama-1` container, and fully updated all application endpoints in `app.py`.
+1. **Model Upgraded to Ollama Latest**: Transitioned from the `llama3.2:3b` model to the much more robust, large reasoning-focused **`qwen2.5:7b`** model (4.7 GB) with structured XML Chain-of-Thought (CoT) calculations. Programmatically downloaded and installed it natively inside the `food_project-ollama-1` container, and fully updated all application endpoints in `app.py`.
 2. **Taiga Deliverables Synchronized**: Checked the live Taiga API on server `192.168.130.161`. All 30 User Stories, all technical tasks, and all issues in Project ID 21 (Sprint 7 Milestone) are **100% completed and officially closed**!
 3. **Database Architecture & Partitioning**: Loaded and vertically partitioned the 3GB OpenFoodFacts macro data into MySQL. Configured matching FULLTEXT engines to search records in less than **0.04s** (averaging 90% latency reduction).
 4. **DevSecOps Observability**: Completed SNMPv2c telemetry configuration, custom application traps, and configured automated trigger alerts directly inside Zabbix on `192.168.130.170`.