Bladeren bron

[TG-125] Phase 3 Security, Llama 3.2 11B, and Network Mode

Lange François 1 maand geleden
bovenliggende
commit
96d90b11fb

+ 9 - 6
app.py

@@ -685,8 +685,8 @@ 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='qwen2.5:1.5b', messages=[{'role': 'user', 'content': eval_prompt}], stream=True)
-                                    st.write_stream(chunk['message']['content'] for chunk in response_stream)
+                                    response = ollama.chat(model='llama3.2:11b', messages=[{'role': 'user', 'content': eval_prompt}], stream=True)
+                                    st.write_stream(chunk['message']['content'] for chunk in response)
                                 except Exception as e:
                                     error_msg = str(e).lower()
                                     if "404" in error_msg or "not found" in error_msg:
@@ -767,7 +767,7 @@ with tab_plate:
                         pro = float(i['proteins_100g'] or 0) * (float(i['quantity_grams'])/100.0)
                         fat = float(i['fat_100g'] or 0) * (float(i['quantity_grams'])/100.0)
                         carb = float(i['carbohydrates_100g'] or 0) * (float(i['quantity_grams'])/100.0)
-                        c1.markdown(f"<li><b>{i['quantity_grams']}g</b> of {safe_name} (Pro: {pro:.2f}g | Fat: {fat:.2f}g | Carb: {carb:.2f}g)</li>", unsafe_allow_html=True)
+                        c1.markdown(f"<li><b>{i['quantity_grams']}g</b> of {i['product_name']} (Pro: {pro:.2f}g | Fat: {fat:.2f}g | Carb: {carb:.2f}g)</li>", unsafe_allow_html=True)
                         if c2.button("🗑️", key=f"del_item_{i['id']}"):
                             cursor.execute("DELETE FROM plate_items WHERE id = %s", (i['id'],))
                             conn.commit()
@@ -941,13 +941,16 @@ with tab_planner:
             - 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.'}]
+            st.info("🧠 AI is analyzing nutritional synergies and generating your plan...")
             
             # Stream the response instantly!
             try:
                 start_llm = time.time()
-                response_stream = ollama.chat(model='qwen2.5:1.5b', messages=temp_messages, stream=True)
-                clean_stream = filter_scratchpad_stream(response_stream)
+                response = ollama.chat(model='llama3.2:11b', messages=[
+                    {'role': 'system', 'content': sys_prompt},
+                    {'role': 'user', 'content': 'Generate my meal plan as a markdown table.'}
+                ], stream=True)
+                clean_stream = filter_scratchpad_stream(response)
                 ai_reply = st.write_stream(clean_stream)
                 st.caption(f"⏱️ AI Meal Plan generated in {time.time() - start_llm:.2f} seconds")
                 

+ 6 - 5
configure_zabbix_alerts.py

@@ -1,13 +1,14 @@
 import json
+#ident "@(#)$Format:LocalFoodAI:configure_zabbix_alerts.py:%an:%ae:%ad:%cn:%ce:%cd:%H:%D:%N$"
 import urllib.request
 import os
 
 ZABBIX_URL = os.environ.get('ZABBIX_URL', 'http://192.168.130.170:8081/api_jsonrpc.php')
-ZABBIX_USER = 'Admin'
-ZABBIX_PASS = 'zabbix'
-DISCORD_WEBHOOK = 'https://discord.com/api/webhooks/1504740323576774739/2-MNclIGcYSxtLrQ-jzIXWl6miW3dOFTvB6KZsTQIX1FFis6JFoszATegAJoosJD7CMT'
-EMAIL_USER = 'lanfr144@gmail.com'
-EMAIL_PASS = '321iaSTB'
+ZABBIX_USER = os.environ.get('ZABBIX_USER', 'Admin')
+ZABBIX_PASS = os.environ.get('ZABBIX_PASS', '')
+DISCORD_WEBHOOK = os.environ.get('DISCORD_WEBHOOK', '')
+EMAIL_USER = os.environ.get('EMAIL_USER', 'lanfr144@gmail.com')
+EMAIL_PASS = os.environ.get('EMAIL_PASS', '')
 
 def zabbix_request(method, params, auth=None):
     payload = {

BIN
delivery.zip


+ 1 - 1
docs/Operator_Installation_Guide.md

@@ -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?' | Qwen2.5:7b retrieves database context and flags raw fish as forbidden for pregnancy. | `[ ]` |
+| **TC-OP-03** | Ask Chat: 'Can I eat sushi?' | Qwen2.5:1.5b 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. | `[ ]` |

+ 44 - 0
scripts/create_delivery_zip.py

@@ -21,7 +21,51 @@ def main():
     zip_path = os.path.join(repo_root, "delivery.zip")
     print(f"Building {zip_path}...")
     
+    dummy_env = """# ==========================================
+# LOCAL FOOD AI - DUMMY CONFIGURATION
+# ==========================================
+
+# ------------------------------------------
+# 1. NETWORK & ENVIRONMENT MODE
+# ------------------------------------------
+# NETWORK_MODE: Controls network call execution.
+# Possible values: 'local' (or 'server')
+NETWORK_MODE=server
+
+# ------------------------------------------
+# 2. DATABASE CREDENTIALS (MySQL)
+# ------------------------------------------
+MYSQL_ROOT_PASSWORD=your_mysql_root_pass
+DB_READER_PASS=your_db_reader_pass
+DB_LOADER_PASS=your_db_loader_pass
+DB_APP_AUTH_PASS=your_db_auth_pass
+MYSQL_ZABBIX_PASSWORD=your_mysql_zabbix_pass
+
+# ------------------------------------------
+# 3. ZABBIX & SNMP CREDENTIALS
+# ------------------------------------------
+ZABBIX_USER=Admin
+ZABBIX_PASS=your_zabbix_pass
+ZABBIX_SNMP_USER=zabbix_snmp
+ZABBIX_SNMP_AUTHKEY=your_snmp_authkey
+ZABBIX_SNMP_PRIVKEY=your_snmp_privkey
+DISCORD_WEBHOOK=your_discord_webhook
+
+# ------------------------------------------
+# 4. EMAIL ALERTS CONFIGURATION
+# ------------------------------------------
+EMAIL_USER=your_email@gmail.com
+EMAIL_PASS=your_email_app_password
+
+# ------------------------------------------
+# 5. TAIGA PROJECT MANAGEMENT CREDENTIALS
+# ------------------------------------------
+TAIGA_USER=your_taiga_user
+TAIGA_PASS=your_taiga_pass
+"""
+    
     with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
+        zipf.writestr('.env', dummy_env)
         for root, dirs, files in os.walk(repo_root):
             for file in files:
                 full_path = os.path.join(root, file)

+ 2 - 2
scripts/manage_models.sh

@@ -1,8 +1,8 @@
 #!/bin/bash
 #ident "@(#)$Format:LocalFoodAI:manage_models.sh:%an:%ae:%ad:%cn:%ce:%cd:%H:%D:%N$"
 
-echo "Pulling the new efficient billion-parameter model (qwen2.5:1.5b)..."
-docker exec food-ollama-1 ollama pull qwen2.5:1.5b
+echo "Pulling the new efficient billion-parameter model (llama3.2:11b)..."
+docker exec food-ollama-1 ollama pull llama3.2:11b
 
 echo "Cleaning up unused models to free up disk space..."
 docker exec food-ollama-1 ollama rm qwen2.5:7b

+ 5 - 1
scripts/taiga_sync_final.py

@@ -1,4 +1,5 @@
 import requests
+#ident "@(#)$Format:LocalFoodAI:taiga_sync_final.py:%an:%ae:%ad:%cn:%ce:%cd:%H:%D:%N$"
 import urllib3
 import os
 import re
@@ -6,11 +7,14 @@ import re
 urllib3.disable_warnings()
 
 TAIGA_USER = os.environ.get('TAIGA_USER', 'FrancoisLange')
-TAIGA_PASS = os.environ.get('TAIGA_PASS', 'BTSai123')
+TAIGA_PASS = os.environ.get('TAIGA_PASS', '')
 
 base_url = 'https://192.168.130.161/taiga/api/v1'
 
 def run_sync():
+    if os.environ.get('NETWORK_MODE', 'server') == 'local':
+        print("[OFFLINE MODE] Bypassing Taiga Synchronization.")
+        return
     auth_resp = requests.post(f'{base_url}/auth', json={'type': 'normal', 'username': TAIGA_USER, 'password': TAIGA_PASS}, verify=False)
     if auth_resp.status_code != 200:
         print("Auth failed!")

+ 8 - 3
snmp_notifier.py

@@ -1,15 +1,20 @@
 import os
 import socket
+#ident "@(#)$Format:LocalFoodAI:snmp_notifier.py:%an:%ae:%ad:%cn:%ce:%cd:%H:%D:%N$"
+import socket
 
 class SNMPNotifier:
     def __init__(self, target_host=None, target_port=162):
         self.target_host = target_host or os.environ.get('ZABBIX_HOST', '192.168.130.170')
         self.target_port = target_port
-        self.user = 'zabbix_snmp'
-        self.auth_key = 'authkey123'
-        self.priv_key = 'privkey123'
+        self.user = os.environ.get('ZABBIX_SNMP_USER', '')
+        self.auth_key = os.environ.get('ZABBIX_SNMP_AUTHKEY', '')
+        self.priv_key = os.environ.get('ZABBIX_SNMP_PRIVKEY', '')
 
     def send_alert(self, message):
+        if os.environ.get('NETWORK_MODE', 'server') == 'local':
+            print(f"[OFFLINE MODE] Suppressed SNMP trap: {message}")
+            return
         try:
             # Using the standard snmptrap CLI which is more stable than pysnmp v7
             hostname = socket.gethostname()