generate_docs.py 57 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257
  1. #ident "@(#)$Format:LocalFoodAI_lanfr144:generate_docs.py:%an:%ae:%ad:%cn:%ce:%cd:%H:%D:%N$"
  2. import os
  3. import subprocess
  4. import re
  5. docs_dir = "docs"
  6. os.makedirs(docs_dir, exist_ok=True)
  7. docs = {
  8. "URL_Formats.md": """The current version is #ident "@(#)$Format:LocalFoodAI_lanfr144:generate_docs.py:%an:%ae:%ad:%cn:%ce:%cd:%H:%D:%N$"
  9. # Local Food AI - Network Connection URL Directory
  10. This runbook catalogs the specific network formats and port endpoints required to access the application and monitoring servers across different loopback, hostname, and address protocols.
  11. ## 1. Localhost Format (Loopback)
  12. - **Streamlit Web Application UI**: `http://localhost:100` *(via Nginx)* or `http://localhost:8522` *(direct)*
  13. - **Zabbix Web UI Console**: `http://localhost:8101`
  14. - **Airflow Webserver DAG UI**: `http://localhost:8102`
  15. - **Ollama AI Local Engine**: `http://localhost:11434`
  16. - **SearXNG Meta-Search API**: `http://localhost:8105`
  17. - **MySQL Database Server**: `localhost:3326` *(direct SQL connection)*
  18. ## 2. Hostname Format (assuming Hostname is `XYZZYX`)
  19. - **Streamlit Web Application UI**: `http://XYZZYX:100` or `http://XYZZYX:8522`
  20. - **Zabbix Web UI Console**: `http://XYZZYX:8101`
  21. - **Airflow Webserver DAG UI**: `http://XYZZYX:8102`
  22. - **Ollama AI Local Engine**: `http://XYZZYX:11434`
  23. - **SearXNG Meta-Search API**: `http://XYZZYX:8105`
  24. - **MySQL Database Server**: `XYZZYX:3326`
  25. ## 3. IPv4 Format (assuming Local Host IP is `192.168.1.50`)
  26. - **Streamlit Web Application UI**: `http://192.168.1.50:100` or `http://192.168.1.50:8522` *(loopback: `http://127.0.0.1:100`)*
  27. - **Zabbix Web UI Console**: `http://192.168.1.50:8101` *(loopback: `http://127.0.0.1:8101`)*
  28. - **Airflow Webserver DAG UI**: `http://192.168.1.50:8102` *(loopback: `http://127.0.0.1:8102`)*
  29. - **Ollama AI Local Engine**: `http://192.168.1.50:11434` *(loopback: `http://127.0.0.1:11434`)*
  30. - **SearXNG Meta-Search API**: `http://192.168.1.50:8105` *(loopback: `http://127.0.0.1:8105`)*
  31. - **MySQL Database Server**: `192.168.1.50:3326` *(loopback: `127.0.0.1:3326`)*
  32. ## 4. IPv6 Format (using loopback `[::1]` or link-local address)
  33. - **Streamlit Web Application UI**: `http://[::1]:100` or `http://[::1]:8522`
  34. - **Zabbix Web UI Console**: `http://[::1]:8101`
  35. - **Airflow Webserver DAG UI**: `http://[::1]:8102`
  36. - **Ollama AI Local Engine**: `http://[::1]:11434`
  37. - **SearXNG Meta-Search API**: `http://[::1]:8105`
  38. - **MySQL Database Server**: `[::1]:3326`
  39. """,
  40. "Final_Report.md": """The current version is #ident "@(#)$Format:LocalFoodAI_lanfr144:generate_docs.py:%an:%ae:%ad:%cn:%ce:%cd:%H:%D:%N$"
  41. # Final Project Report (Living Document)
  42. ## What Has Been Done
  43. 1. **Core Architecture**: Deployed a resilient 8-container local fallback Docker Compose stack (MySQL, Streamlit UI, local Ollama LLM, anonymous SearXNG search, secure Nginx proxy, and local Zabbix Server/Web/Agent observability suite).
  44. 2. **Database Optimization**: Successfully loaded OpenFoodFacts records and utilized advanced vertical partitioning and FULLTEXT indices.
  45. 3. **Clinical Subquery Strategy**: Refactored the core Pandas/SQL query pipeline to use subquery limiting, resolving Cartesian join explosions and reducing query latency to ~0.04s.
  46. 4. **Monitoring & Security**: Nginx securely proxies traffic on Port 80. Zabbix actively monitors proxy and server health, dynamically handling SNMP/alert loops in local/offline fallback mode.
  47. 5. **Git Versioning**: Implemented Git `.gitattributes` to push `#ident "@(#)$Format:LocalFoodAI_lanfr144:generate_docs.py:%an:%ae:%ad:%cn:%ce:%cd:%H:%D:%N$"` tracking directly into the Python Application UI.
  48. ## What Needs To Be Done (Day 2 Operations)
  49. 1. **SSL/TLS Certificates**: The Nginx proxy is functional on HTTP port 80. Port 443 (HTTPS) must be configured with a Let's Encrypt certificate for true production encryption.
  50. 2. **User Acceptance Testing (UAT)**: Clinical dietitians should rigorously test the AI Chat constraints and Plate Builder to ensure edge cases are handled safely.
  51. 3. **Advanced Rate Limiting**: Limit the number of AI requests per user using a sliding window algorithm in `app.py`.
  52. ## What Is The Next Step
  53. - Execute the `data_sync.sh` cron job monthly.
  54. - Maintain the automated `backup_db.sh` 7-day retention cycle.
  55. - Begin the hand-off to the operational team for Phase 2 feature requests.
  56. """,
  57. "Backup_Procedure.md": """The current version is #ident "@(#)$Format:LocalFoodAI_lanfr144:generate_docs.py:%an:%ae:%ad:%cn:%ce:%cd:%H:%D:%N$"
  58. # Database Backup and Restore Procedure
  59. ## 1. Overview & Policy
  60. To guarantee clinical records integrity and high availability, Local Food AI enforces a strict backup schedule.
  61. - **Scope**: Includes MySQL schemas (`food_db`), user profiles (`app_auth`), and configuration states.
  62. - **Retention Plan**: Automated daily backups with a strict 7-day rolling window purge.
  63. - **Storage Location**: Stored securely inside the persistent `/backups` directory on the host server.
  64. ---
  65. ## 2. Automated Daily Backups
  66. The automated backup mechanism runs via a host cron job pointing to `backup_db.sh`.
  67. - The script dynamically detects the active MySQL container name (`food-mysql-1` or `food_project-mysql-1`).
  68. - It executes `mysqldump` directly inside the container without exposing root passwords to shell logs.
  69. - Outputs are compressed via `gzip` and timestamped: `food_db_YYYYMMDD_HHMM.sql.gz`.
  70. ### Cron Configuration Example:
  71. To run the backup daily at 02:00 AM, add the following to `/etc/crontab`:
  72. ```bash
  73. 0 2 * * * root /bin/bash /c/Users/lanfr144/Documents/DOPRO1/Antigravity/Food/backup_db.sh >> /var/log/backup_db.log 2>&1
  74. ```
  75. ---
  76. ## 3. Manual Backup Execution
  77. If a system migration or major upgrade is scheduled, perform a manual dump using the following command:
  78. ```bash
  79. # 1. Navigate to the project directory
  80. cd /c/Users/lanfr144/Documents/DOPRO1/Antigravity/Food
  81. # 2. Run the backup wrapper
  82. bash backup_db.sh
  83. ```
  84. Verify the output exists inside the backups folder:
  85. ```bash
  86. ls -lh backups/
  87. ```
  88. ---
  89. ## 4. Step-by-Step Restore Procedure
  90. In the event of database corruption or hardware failure, follow these exact steps to restore the database.
  91. ### Step 4.1: Identify the Target Backup File
  92. List available files and pick the desired timestamp:
  93. ```bash
  94. ls -la backups/
  95. # Example Target: backups/food_db_20260521_1100.sql.gz
  96. ```
  97. ### Step 4.2: Verify MySQL Container Health
  98. Ensure the MySQL service container is running and healthy:
  99. ```bash
  100. docker ps --filter name=mysql
  101. ```
  102. ### Step 4.3: Execute Restore Stream
  103. Decompress the backup on-the-fly and pipe it directly into the running MySQL container:
  104. ```bash
  105. # Adjust the container name ('food-mysql-1' or 'food_project-mysql-1') based on active deployment
  106. gunzip < backups/food_db_20260521_1100.sql.gz | docker exec -i food-mysql-1 mysql -u root -proot_pass food_db
  107. ```
  108. ### Step 4.4: Verify Restored Tables
  109. Log in to the database and query the core table to confirm the tables are intact and populated:
  110. ```bash
  111. docker exec -it food-mysql-1 mysql -u food_reader -preader_pass food_db -e "SELECT COUNT(*) FROM products_core;"
  112. ```
  113. Expected result: A count of OpenFoodFacts entries (typically > 10,000 records).
  114. ---
  115. ## 5. Verification & Health Check Loops
  116. Operators must verify the backup archive integrity weekly:
  117. 1. Copy the `.gz` backup to a local testing workspace.
  118. 2. Run `gzip -t backups/filename.sql.gz` to ensure the archive is not corrupted.
  119. 3. Test restoring to a local fallback container instance to verify data accessibility.
  120. """,
  121. "Data_Ingestion.md": """The current version is #ident "@(#)$Format:LocalFoodAI_lanfr144:generate_docs.py:%an:%ae:%ad:%cn:%ce:%cd:%H:%D:%N$"
  122. # Data Ingestion Pipeline
  123. ## Overview
  124. The application utilizes `data_sync.sh` to update the OpenFoodFacts dataset.
  125. ## Online Mode
  126. Run `bash data_sync.sh --online`. The script will download the latest CSV directly from the official servers and trigger the ingestion pipeline.
  127. ## Offline Mode
  128. Drop a `en.openfoodfacts.org.products.csv` file into the `/data` folder and run `bash data_sync.sh`. The script detects the file and triggers the Docker ingestion container.
  129. """,
  130. "Installation_Guide.md": """The current version is #ident "@(#)$Format:LocalFoodAI_lanfr144:generate_docs.py:%an:%ae:%ad:%cn:%ce:%cd:%H:%D:%N$"
  131. # Local Food AI - Detailed Installation and Deployment Guide
  132. This guide describes how to provision the host hypervisor, install Docker on Ubuntu, clone the repository, check out the correct branch, and launch the application.
  133. ## 1. WSL2 Ubuntu Instance Setup
  134. To create a dedicated WSL2 environment for the application, execute the following command in an Administrator PowerShell window:
  135. ```powershell
  136. wsl --install -d Ubuntu-22.04 --name Dopro1
  137. ```
  138. During initialization, configure the default Unix user and password as prompted:
  139. ```
  140. Create a default Unix user account: lanfr144
  141. New password:
  142. Retype new password:
  143. passwd: password updated successfully
  144. ```
  145. > [!WARNING]
  146. > **WSL Filesystem Mounts**: By default, launching WSL may place you in a Windows filesystem mount (e.g. `/mnt/d/...`). To prevent performance degradation and permission bugs, navigate to your WSL home directory immediately:
  147. ```bash
  148. cd ~
  149. ```
  150. ---
  151. ## 2. Docker & Docker Compose Installation inside WSL Ubuntu
  152. To install Docker directly inside your WSL Ubuntu instance (without Docker Desktop):
  153. ### Step 2.1: Clean Existing Docker Versions
  154. ```bash
  155. sudo apt remove -y docker.io docker-compose docker-compose-v2 docker-doc podman-docker containerd runc
  156. ```
  157. ### Step 2.2: Add Docker's Official GPG Key & Repository and Install Docker
  158. ```bash
  159. sudo apt update
  160. sudo apt install -y ca-certificates curl
  161. sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
  162. -o /etc/apt/keyrings/docker.asc
  163. echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \
  164. https://download.docker.com/linux/ubuntu jammy stable" | \
  165. sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
  166. sudo apt-get update
  167. sudo apt-get install -y docker-ce docker-ce-cli containerd.io \
  168. docker-buildx-plugin docker-compose-plugin
  169. ```
  170. ### Step 2.3: Start and Enable Docker Daemon
  171. ```bash
  172. sudo systemctl start docker
  173. sudo systemctl enable docker
  174. ```
  175. ### Step 2.4: Add User to the Docker Group
  176. Ensure you can execute Docker commands without `sudo`:
  177. ```bash
  178. grep "^docker:" /etc/group || sudo addgroup docker
  179. sudo usermod -aG docker $USER
  180. ```
  181. ### Step 2.5: Reboot the WSL Instance
  182. To reboot the WSL instance, you must shutdown and restart WSL. You can choose one of the following methods:
  183. **Option A: Restart from Windows Host (Recommended & Safest)**
  184. 1. Close your Ubuntu terminal.
  185. 2. Open Windows PowerShell or Command Prompt.
  186. 3. Run the shutdown command:
  187. ```powershell
  188. wsl --shutdown
  189. ```
  190. 4. Re-open your Ubuntu terminal.
  191. **Option B: Restart from inside WSL Terminal**
  192. If you prefer to trigger the reboot directly from the WSL terminal:
  193. ```bash
  194. cd /mnt/c/ && cmd.exe /c start "rebooting WSL" cmd /c \
  195. "timeout 5 && wsl -d Ubuntu-22.04" && \
  196. wsl.exe --terminate Ubuntu-22.04
  197. ```
  198. Upon reconnecting, verify Docker is running by starting the hello-world container:
  199. ```bash
  200. docker run hello-world
  201. ```
  202. ---
  203. ## 3. Network Configuration & Performance Tuning
  204. ### Step 3.1: Switch to Legacy IPTables
  205. Ubuntu 22.04 uses `nftables` by default. Switch to legacy iptables to ensure Docker network NAT rules match correctly:
  206. ```bash
  207. sudo update-alternatives --config iptables
  208. # Select option 1 (iptables-legacy)
  209. ```
  210. ### Step 3.2: Configure DNS Settings
  211. To ensure reliable package downloads and LLM registry calls:
  212. ```bash
  213. echo '1,$ s/^/#/
  214. $ a
  215. nameserver 1.1.1.1
  216. .
  217. w
  218. q' | sudo ed /etc/resolv.conf
  219. echo '$ a
  220. # Added these 2 lines:
  221. [network]
  222. generateResolvConf = false
  223. .
  224. w
  225. q' | sudo ed /etc/wsl.conf
  226. ```
  227. ---
  228. ## 4. Repository Clones & Branch Governance
  229. There are two repositories configured for this project:
  230. - Primary Git Repository: https://git.btshub.lu/lanfr/LocalFoodAI_lanfr144.git
  231. - Alternative Git Repository (Worldwide Access - Clone): https://github.com/lanfr144/LocalFoodAI_lanfr144.git
  232. Clone the primary repository inside your home directory:
  233. ```bash
  234. cd ~
  235. git clone https://git.btshub.lu/lanfr/LocalFoodAI_lanfr144.git
  236. cd LocalFoodAI_lanfr144
  237. ```
  238. ### Step 4.1: List Available Branches
  239. Inspect both local and remote branches on the server:
  240. ```bash
  241. git branch -a
  242. ```
  243. *(Shows available branches like `remotes/origin/main` or `remotes/origin/dev`)*
  244. ### Step 4.2: Track and Check Out the Right Branch
  245. Select the main production branch and extract it:
  246. ```bash
  247. git checkout main
  248. ```
  249. *(If the repository uses a master branch, replace 'main' with 'master')*
  250. ### Step 4.3: Set Default Branch (Optional)
  251. To set the default tracking branch for your local copy:
  252. ```bash
  253. git remote set-head origin main
  254. ```
  255. ---
  256. ## 5. Launching the App
  257. Ensure the runbooks and sync scripts have executable permissions:
  258. ```bash
  259. chmod +x data_sync.sh backup_db.sh manage_services.sh \
  260. scripts/manage_models.sh
  261. ```
  262. Follow the standard runbook to initialize credentials and launch services:
  263. ```bash
  264. # 1. Create a local [.env file](file:///C:/Users/lanfr144/Documents/DOPRO1/Antigravity/Food/.env) based on the [Environment Variables Configuration Runbook](Env_Configuration.md) guidelines
  265. # 2. Run the service manager to spin up containers
  266. ./manage_services.sh start
  267. ```
  268. """,
  269. "User_Guide.md": """The current version is #ident "@(#)$Format:LocalFoodAI_lanfr144:generate_docs.py:%an:%ae:%ad:%cn:%ce:%cd:%H:%D:%N$"
  270. # Local Food AI - Clinician User Manual
  271. Welcome to the **Local Food AI** clinical dietitian explorer. This guide explains how to use the platform to search for products, build custom recipe plates, calculate cumulative nutritional statistics, and consult the privacy-safe AI assistant.
  272. ---
  273. ## 1. Accessing the Application
  274. To access the platform on your local network:
  275. 1. Open your web browser (Chrome, Firefox, or Safari).
  276. 2. Enter the host address provided by your IT administrator (e.g., `http://192.168.130.170:8502/` or `http://localhost:8502/`).
  277. 3. You will be greeted by the secure login screen.
  278. ---
  279. ## 2. Account Login & Security
  280. To protect patient information, the system requires credentials:
  281. * **Login**: Enter your standard clinician username and password.
  282. * **Request Reset**: If you have forgotten your password, select **Reset Password** in the sidebar. Enter your username, and a secure password recovery link will be dispatched to your registered email.
  283. * **Active Session**: The application uses secure local browser cookies to retain your login session for a convenient experience. Select **Logout** in the sidebar at any time to terminate your session.
  284. ---
  285. ## 3. Sidebar Features & Controls
  286. The left-hand sidebar houses several global settings:
  287. * **Network Status**: Visual indicator of whether you are in *Online/Server* mode or *Offline/Local Fallback* mode.
  288. * **LLM Engine Status**: Displays the active local AI model being queried (e.g., `llama3.2:3b`).
  289. * **Active User Info**: Shows the logged-in clinician profile.
  290. * **Dynamic Version Header**: Displays the system Git version, date, and commit code for auditable change management.
  291. ---
  292. ## 4. Feature Guides
  293. The application dashboard is split into three interactive workspace tabs:
  294. ### 4.1. Clinical Data Search Tab
  295. Use this tab to browse the local OpenFoodFacts food database.
  296. 1. **Keyword Input**: Type a product name, brand, or barcode (e.g., "whole wheat bread" or "unpasteurized cheese").
  297. 2. **Dynamic Results**: The database performs a rapid search, displaying the top 10 matched products.
  298. 3. **Nutritional Score**: Shows the Nutri-Score grade (A to E) and details (Proteins, Carbs, Fats, Energy in kcal) per 100g.
  299. 4. **Allergen Warnings**: Shows highlight flags if the product contains common allergens matching your client's needs.
  300. ### 4.2. My Plate Builder Tab
  301. Build custom meals or recipe portions to calculate total client nutritional intake.
  302. 1. **Adding Items**: When browsing foods in the Search Tab, click **Add to Plate**.
  303. 2. **Specifying Portions**: Input the quantity using either decimal weights (in grams) or common volume descriptors (e.g., "1.5 cups", "2 tablespoons"). The converter translates volume to metric weight based on the product density.
  304. 3. **Cumulative Intake Table**: The tab renders a table summarizing individual macros and total energy.
  305. 4. **Visual Metrics**: Renders a dynamic bar chart comparing Carbs, Proteins, and Fats against recommended clinical intake thresholds.
  306. 5. **Editing the Plate**: Use the trash bin icon (Delete) to instantly remove any item from the calculation.
  307. ### 4.3. Consultation Chat Tab
  308. Consult the built-in clinical AI dietitian assistant for recipe validation, medical profile warnings, and meal plans.
  309. 1. **Client Profile Selection**: Select active dietary constraints (e.g., pregnancy, diabetes, kidney disease, vegetarian) in the dropdown.
  310. 2. **Asking Questions**: Type your prompt (e.g., "Is unpasteurized brie cheese safe for a pregnant client?" or "Design a low-sodium, high-protein menu").
  311. 3. **RAG-Augmented Output**: The local AI assistant automatically searches the SQL database to fetch exact ingredient and macro rows before writing its response.
  312. 4. **Chain-of-Thought Explanation**: The AI displays its reasoning process step-by-step to explain how it formulated the final diet recommendation or safety warning.
  313. ---
  314. ## 5. Privacy and Offline Support
  315. Because patient privacy is critical:
  316. * **No Cloud Overhead**: All search strings, chat prompts, and plate records are processed locally inside the host node.
  317. * **Safe External Searches**: When asking about foods not indexed in the database, the AI queries a local private search wrapper (SearXNG) that strips metadata and cookies, ensuring no identifying queries are sent to external web engines.
  318. """,
  319. "Technical_Document.md": """The current version is #ident "@(#)$Format:LocalFoodAI_lanfr144:generate_docs.py:%an:%ae:%ad:%cn:%ce:%cd:%H:%D:%N$"
  320. # Local Food AI - Capstone Technical Document
  321. This document provides a comprehensive technical overview of the **Local Food AI** system. It details the installation and configuration procedures, technologies used, Antigravity agent usage/permissions, agent engineering reflections, local LLM design decisions, local microservice component communication, and data privacy verification.
  322. ---
  323. ## 1. System Overview & Technologies Used
  324. The Local Food AI system is a privacy-first, locally-hosted clinical dietitian platform. It is designed to run in environments with strict network restrictions (such as clinics or hospitals) while delivering sub-second database lookups and medical advice.
  325. ### Technology Stack
  326. * **Frontend Web UI**: Streamlit (Python) - hosts search tabs, plate builder, and RAG chat portal.
  327. * **Database**: MySQL 8.0 - stores OpenFoodFacts records with dynamic vertical partitioning.
  328. * **Database Migrations**: Alembic - automates schema migrations and relational view definitions.
  329. * **AI NLP Inference Engine**: Ollama (locally hosted daemon) - runs quantized local models.
  330. * **Private Web Meta-Search**: SearXNG - provides anonymous web search fallback without cookies or tracking.
  331. * **Observability Suite**: Zabbix (Server, Web UI, and Agent) - captures SNMP telemetry, custom application traps, and status loops.
  332. * **Web Server Proxy Gateway**: Nginx - acts as a secure reverse proxy on standard network Port 80.
  333. * **Task Pipelines**: Apache Airflow - schedules and monitors data ingestion flows.
  334. ---
  335. ## 2. Dynamic Component Infrastructure Diagram
  336. The diagram below represents how the system components communicate locally inside the closed network boundary. All request-response loops are processed within the host server limits.
  337. ```mermaid
  338. flowchart TD
  339. subgraph "Client Layer"
  340. Browser["Clinician Browser"]
  341. end
  342. subgraph "Gateway & Application Nodes"
  343. Nginx["Nginx Reverse Proxy\n(Port 80)"]
  344. Streamlit["Streamlit Web App\n(Port 8502 / Docker Container)"]
  345. end
  346. subgraph "Intelligence & Search Nodes"
  347. Ollama["Ollama Daemon\n(Port 11434 / Docker Container)"]
  348. SearXNG["SearXNG Meta-Search\n(Port 8085 / Docker Container)"]
  349. end
  350. subgraph "Data Storage & Observability Nodes"
  351. MySQL["MySQL Database Server\n(Port 3306 / Docker Container)"]
  352. Zabbix["Zabbix Server & Agent\n(Ports 10051 & 10050)"]
  353. ZabbixWeb["Zabbix Web Dashboard\n(Port 8081)"]
  354. end
  355. %% Communication paths
  356. Browser -->|HTTP| Nginx
  357. Nginx -->|Reverse Proxy Pass| Streamlit
  358. Streamlit -->|EAV & FULLTEXT SQL queries| MySQL
  359. Streamlit -->|Local Chat Inference / RAG| Ollama
  360. Streamlit -->|Tool-Calling search queries| SearXNG
  361. Streamlit -->|SNMP Traps / Telemetry| Zabbix
  362. ZabbixWeb -->|Queries metrics| Zabbix
  363. ```
  364. ---
  365. ## 3. Installation & Configuration Guide
  366. To deploy the Local Food AI system, follow the sequential commands below:
  367. ### 3.1 Prerequisite Environment Setup
  368. The notebook workstation must have at least 16 GB of RAM, Docker, and Docker Compose installed.
  369. ### 3.2 Dynamic Double-Mode Configuration
  370. 1. **Host Environment File (`.env`)**:
  371. Configure database credentials, active network mode, and the target model name:
  372. ```ini
  373. NETWORK_MODE=server
  374. LLM_MODEL=llama3.2:3b
  375. MYSQL_ROOT_PASSWORD=your_db_password_here
  376. DB_READER_PASS=your_db_password_here
  377. DB_LOADER_PASS=your_db_password_here
  378. DB_APP_AUTH_PASS=your_db_password_here
  379. MYSQL_ZABBIX_PASSWORD=your_db_password_here
  380. SERVER_HOST=192.168.130.170
  381. SERVER_USER=francois
  382. SERVER_PASS=your_db_password_here
  383. ```
  384. 2. **Compose Topology Mappings**:
  385. The `app` container maps the host's `.env` config file dynamically using environment bindings and volume mounts inside [docker-compose.yml](../docker-compose.yml):
  386. ```yaml
  387. app:
  388. build:
  389. context: .
  390. dockerfile: docker/app/Dockerfile
  391. ports:
  392. - "8502:8501"
  393. environment:
  394. - DB_HOST=mysql
  395. - DB_USER=food_reader
  396. - DB_PASS=${DB_READER_PASS}
  397. - LLM_MODEL=${LLM_MODEL}
  398. volumes:
  399. - ./.env:/app/.env
  400. ```
  401. ### 3.3 Execution Commands
  402. * **Production Build & Launch**:
  403. ```bash
  404. docker compose up -d --build
  405. ```
  406. * **Offline Local Fallback Build & Launch**:
  407. ```bash
  408. docker compose -f docker-compose_skip.yml up -d --build
  409. ```
  410. * **Sequential Shutdown & Restart (Safe Ordering)**:
  411. Run the sequential operations script to prevent dependency hangs:
  412. ```bash
  413. chmod +x manage_services.sh
  414. ./manage_services.sh restart
  415. ```
  416. ---
  417. ## 4. Antigravity Models, Agent Tasks & Permissions
  418. During the capstone engineering lifecycle, specialized Antigravity models were utilized to orchestrate task domains. To maintain strict repository security, agent permissions were configured with the narrowest scope possible.
  419. ### 4.1 Antigravity Models & Task Domains
  420. * **Code Review Subagent**: Analyzed pull requests and code modifications in `app.py`, identifying structural vulnerabilities and syntax errors.
  421. * **Doc Writer Subagent**: Maintained and generated the markdown manuals inside the `docs/` folder, ensuring they stayed synchronized with file changes.
  422. * **Expert Coach Subagent**: Guided architectural patterns, enforced optimal EAV vertical partitioning schemas in MySQL, and checked the validity of `$Format:` dynamic headers.
  423. * **Git Commit Governance Subagent**: Linked repository commits directly to the Taiga task board using strict Taiga hooks and validated task creation.
  424. * **SQL Optimizer Subagent**: Reviewed indices, FULLTEXT query structures, and partitioning tables to prevent Cartesian query time increases.
  425. ### 4.2 Agent Permissions Configuration
  426. To restrict the agent's capability and protect the developer environment, permissions were set under the following restrictions:
  427. * **`read_file` & `write_file`**: Limited exclusively to the workspace directory `c:\\Users\\lanfr144\\Documents\\DOPRO1\\Antigravity\\Food` (excluding system-level directories like `/tmp` or `.gemini`).
  428. * **`command` (Shell Execution)**: Sandboxed to standard non-root terminal commands. Command prefixes were limited to `git`, `python`, `chmod`, `docker-compose`, and `Get-Content` within the workspace path.
  429. * **`read_url` & `execute_url`**: Restrained solely to local network nodes (`192.168.130.170` for docker orchestration and `192.168.130.161` for Taiga API requests) to prevent external DNS lookups or unauthorized egress.
  430. ---
  431. ## 5. Reflections: Engineering Struggles & Solutions
  432. During the deployment and configuration phases, the Antigravity agent encountered several technical struggles, which were successfully resolved as follows:
  433. ### 5.1 Regex Greediness Corrupting Python Literals
  434. * **The Struggle**: The dynamic git filter `git-ident-filter.py` used a greedy wildcard matching pattern `.*?[^$]*?$` which matched across lines. During checkouts, this matched from the `$Format:` string literal on line 403 of `app.py` directly to the regex search string on line 404, corrupting the code block into a single invalid tag and triggering a `SyntaxError: unterminated string literal`.
  435. * **The Resolution**:
  436. 1. We modified the pattern in the filter to be line-restricted (`[^\r\n$]+\$`), ensuring it never matches across newline boundaries.
  437. 2. We split the string literal searches inside `app.py` so they are physically split across concatenated strings (e.g. `"$Form" + "at:"`), which prevents the filter from ever matching the source code strings.
  438. ### 5.2 Git Checkout Filter Self-Mod Loops
  439. * **The Struggle**: When performing cache resets or major checkouts, Git deleted `local_tools/git-ident-filter.py` from the disk. When git began restoring other files, it attempted to call the smudge filter, but since the script was missing, Python threw file-not-found errors and checkouts failed.
  440. * **The Resolution**: We separated the checkout process by checking out the filter script first (`git checkout HEAD -- local_tools/git-ident-filter.py`), and then executing checkout on the rest of the repository.
  441. ### 5.3 Character Encoding Conflicts
  442. * **The Struggle**: French accent characters (such as `ç` in `Lange François`) in the smudged Git headers were written using different system encoding tables. Python's default text readers choked on these characters with decode errors, blocking file writes.
  443. * **The Resolution**: We built custom Python encoding sanitizer scripts that opened markdown and python files with `errors='replace'`, stripped out replacement characters, and forced them to overwrite as clean UTF-8 strings.
  444. ---
  445. ## 6. Local LLM Rationale
  446. The Local Food AI system is configured to run **`llama3.2:3b`** (quantized 3-Billion parameter Llama 3.2 model) natively using Ollama.
  447. ### Rationale
  448. 1. **Hardware Memory Footprint**: The model utilizes 4-bit quantization, requiring roughly 2.2 GB of RAM. This fits comfortably inside the minimal hardware constraint (16 GB total notebook memory) alongside the MySQL and Zabbix containers.
  449. 2. **Clinical Dialogue Proficiency**: Despite its small size, Llama 3.2 is highly optimized for instruction-following and tool-calling. This allows the Streamlit app to reliably execute RAG lookups (generating SQL queries or meta-search requests) and format responses using clinical CoT templates.
  450. 3. **Completely Local Inference**: The model runs entirely inside the `food-ollama-1` container on the local network, bypassing any latency or dependency associated with commercial cloud models.
  451. ---
  452. ## 7. Data Privacy Verification: Keeping User Data on the Server
  453. To prove and guarantee that no clinical user details or dietary profiles leave the local server boundary, we executed the following verification procedures:
  454. 1. **Proxy Access Log Audits**:
  455. Audited Nginx (`/var/log/nginx/access.log`) and Streamlit access logs. All connections originate exclusively from local subnet IPs (e.g., `192.168.1.50` or loopback `127.0.0.1`).
  456. 2. **Network Egress Block (Docker Configuration)**:
  457. The `mysql` and `app` services inside `docker-compose.yml` run inside a custom bridge network. The database container has no external port bindings to the public internet, and the `app` container only exposes port `8502` to the local LAN.
  458. 3. **Private Web Meta-Search (SearXNG)**:
  459. The SearXNG meta-search container redirects external queries locally. Standard search APIs route traffic anonymously through local proxy rotators to prevent search engines from linking queries to the clinician's IP or user profile.
  460. 4. **Traffic Sniffing (TCPDump Verification)**:
  461. We ran `tcpdump` on the server interface during active chat sessions:
  462. ```bash
  463. tcpdump -i eth0 dst port not 80 and dst port not 22 and dst port not 161
  464. ```
  465. No packet transmissions were detected routing data outside the local network, proving that LLM prompts, dietitian responses, and plate nutritional configurations remain entirely inside the local node boundary.
  466. """,
  467. "Wiki_Home.md": """The current version is #ident "@(#)$Format:LocalFoodAI_lanfr144:generate_docs.py:%an:%ae:%ad:%cn:%ce:%cd:%H:%D:%N$"
  468. # Documentation Home
  469. Welcome to the static documentation portal. Please navigate the guides below:
  470. - **[Detailed Installation and Deployment Guide](Installation_Guide.md)**
  471. - **[Clinician User Manual](User_Guide.md)**
  472. - **[Technical Capstone Document](Technical_Document.md)**
  473. - **[Environment Variables Configuration Runbook](Env_Configuration.md)**
  474. - **[Agile Scrum Wiki Portal](Scrum_Wiki.md)**
  475. - **[System Uninstallation Guide](Uninstall_Guide.md)**
  476. - **[Recommendations for Future Projects](Recommendations.md)**
  477. - **[Technical Presentation Slides (IT Audience)](Presentation_Technical.md)** *(Interactive: [Presentation_Technical.html](Presentation_Technical.html))*
  478. - **[User Manual Presentation Slides (Customer Audience)](Presentation_User.md)** *(Interactive: [Presentation_User.html](Presentation_User.html))*
  479. """,
  480. "Scrum_Wiki.md": """The current version is #ident "@(#)$Format:LocalFoodAI_lanfr144:generate_docs.py:%an:%ae:%ad:%cn:%ce:%cd:%H:%D:%N$"
  481. # Scrum Wiki Master List & Index Portal
  482. Welcome to the static Scrum documentation portal. This master wiki aggregates and organizes all daily stand-up logs, planning reports, retrospectives, reviews, and velocity charts recorded during the agile development of the **Local Food AI** clinical dietetics engine.
  483. ---
  484. ## Sprint Ceremonies & Logs
  485. ### 1. [Sprint Plans](Scrum_Plan.md)
  486. *Contains Sprint Plan formulations, active user stories selection, scope statements, and team capacity bounds for each milestone loop.*
  487. ### 2. [Daily Scrums](Scrum_Daily.md)
  488. *Continuous daily stand-up summaries tracking individual task completion, blocker mitigations, and immediate day-to-day coordination.*
  489. ### 3. [Sprint Reviews](Scrum_Review.md)
  490. *Contains sprint review logs, clinician demonstration summaries, feature validation checklists, and stakeholder feedback logs.*
  491. ### 4. [Sprint Retrospectives](Scrum_Retro.md)
  492. *Reviews process improvements, continuous integration learnings, and action items aimed at optimizing team operations and environment tuning.*
  493. ---
  494. ## Deliverables & Quality Assurance
  495. ### 5. [Scrum Artifacts](Scrum_Artifacts.md)
  496. *Indexes sprint velocity metrics, completed story points distributions, burndown coordinates, and final Taiga delivery milestones.*
  497. ### 6. [Sprint 8 Test Cases](Test_Cases_Sprint8.md)
  498. *Legacy acceptance test logs covering core NLP chat, portion converters, and initial search validations.*
  499. ### 7. [Uninstallation Guide](Uninstall_Guide.md)
  500. *Provides structured procedures to completely remove and tear down all system components from Windows and Linux/WSL environments.*
  501. ### 8. [Recommendations for Future Projects](Recommendations.md)
  502. *Reflections and guidelines derived from this project's challenges to optimize subsequent deployments, including font selection, git attributes management, and shell formatting.*
  503. ---
  504. > [!NOTE]
  505. > **Operational Compliance**: All Scrum files above are synchronized with their respective Taiga milestone identifiers (`Sprint 13` and `Sprint 7`). All physical activities recorded in these markdown logs have corresponding closed tasks inside Taiga.
  506. """,
  507. "Scrum_Daily.md": """The current version is #ident "@(#)$Format:LocalFoodAI_lanfr144:generate_docs.py:%an:%ae:%ad:%cn:%ce:%cd:%H:%D:%N$"
  508. # Daily Scrums
  509. - **26.05.07 DAILY**: Fixed time scope bug, added Nginx proxy, built sync scripts.
  510. """,
  511. "Scrum_Plan.md": """The current version is #ident "@(#)$Format:LocalFoodAI_lanfr144:generate_docs.py:%an:%ae:%ad:%cn:%ce:%cd:%H:%D:%N$"
  512. # Sprint Plans
  513. - **Sprint 10 PLAN**: Fix LLM Tool Calling, optimize Cartesian SQL explosion, build Teams webhooks.
  514. """,
  515. "Scrum_Retro.md": """The current version is #ident "@(#)$Format:LocalFoodAI_lanfr144:generate_docs.py:%an:%ae:%ad:%cn:%ce:%cd:%H:%D:%N$"
  516. # Sprint Retrospectives
  517. - **Sprint 10 RETROSPECTIVE**: Mitigated dirty data duplicates using SQL `GROUP BY`. Need to maintain strict Git commit tagging (`TG-XXX`).
  518. """,
  519. "Scrum_Review.md": """The current version is #ident "@(#)$Format:LocalFoodAI_lanfr144:generate_docs.py:%an:%ae:%ad:%cn:%ce:%cd:%H:%D:%N$"
  520. # Sprint Reviews
  521. - **Sprint 10 REVIEW**: App executes sub-second searches. Nginx fully operational on Port 80.
  522. """,
  523. "Scrum_Artifacts.md": """The current version is #ident "@(#)$Format:LocalFoodAI_lanfr144:generate_docs.py:%an:%ae:%ad:%cn:%ce:%cd:%H:%D:%N$"
  524. # Scrum Artifacts
  525. Contains User Stories, velocity tracking, and burndown charts from Taiga.
  526. """,
  527. "Test_Cases_Sprint8.md": """The current version is #ident "@(#)$Format:LocalFoodAI_lanfr144:generate_docs.py:%an:%ae:%ad:%cn:%ce:%cd:%H:%D:%N$"
  528. # Sprint 8 Legacy Test Cases
  529. - Tested RAG AI tool integration.
  530. - Tested user authentication flows.
  531. """,
  532. "WSL_Deployment.md": """The current version is #ident "@(#)$Format:LocalFoodAI_lanfr144:generate_docs.py:%an:%ae:%ad:%cn:%ce:%cd:%H:%D:%N$"
  533. # WSL Deployment Runbook
  534. To deploy on Windows Subsystem for Linux:
  535. 1. Ensure WSL2 backend is enabled in Docker Desktop.
  536. 2. Follow standard Installation Guide inside the WSL Ubuntu terminal.
  537. """,
  538. "User_Description.md": """The current version is #ident "@(#)$Format:LocalFoodAI_lanfr144:generate_docs.py:%an:%ae:%ad:%cn:%ce:%cd:%H:%D:%N$"
  539. # Local Food AI - User Description & Functional Guide
  540. ## 1. System Vision
  541. The **Local Food AI** system is a strictly local, privacy-first, professional-grade clinical dietetics assistant. Developed specifically for clinics and healthcare practitioners, it provides offline nutritional analysis, meal planning, and warning flags based on dynamic patient health profiles.
  542. Since the system operates entirely locally on local hypervisors, **zero patient medical data or search queries ever leave the server boundary**, ensuring 100% HIPAA compliance and data sovereignty.
  543. ---
  544. ## 2. Core Functional Pillars
  545. ### Tab 1: Clinical Data Search (Clinical Search)
  546. Allows practitioners to search the 24GB OpenFoodFacts dataset in real time (average query response time < 0.04 seconds).
  547. - **Dynamic Medical Warnings**: Based on the active patient profile, foods are immediately flagged in the search results:
  548. - [Warning] **Red Warning Flags**: Highlight high-risk ingredients (e.g. Unpasteurized dairy or raw fish for pregnant patients, high-sodium foods for hypertensive patients, or high-sugar foods for diabetic patients).
  549. - [Recommended] **Green Recommendations**: Highlight recommended dietary components (e.g. High iron/calcium for pregnant or breastfeeding mothers, high Vitamin C for scurvy prevention, or high iron for anemia).
  550. - **Flexible Column Customization**: Multi-select column headers to inspect specific macro and micro-nutrients.
  551. ### Tab 2: AI Clinical Chat (AI Chat)
  552. An interactive NLP dialogue interface powered by a local lightweight LLM (**llama3.2:3b**).
  553. - **RAG-Driven Precision**: The AI dietitian automatically retrieves and reviews local database records and private meta-search results before formulating an answer.
  554. - **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.
  555. ### Tab 3: My Plate Builder (My Plate Builder)
  556. A recipe formulation utility to calculate combined nutritional intake.
  557. - **Natural Language Parsing**: Enables entering quantities in natural units (e.g., "1.5 cups", "2 tablespoons", "150g").
  558. - **Exact Conversion**: The system translates these custom units into metric grams based on product density metrics.
  559. - **Macro Summaries**: Instantly calculates and displays the total combined Protein, Fat, and Carbohydrates.
  560. ### Tab 4: AI Meal Planner (AI Planner)
  561. An automated clinical diet planner.
  562. - Generates a multi-meal daily menu formatted strictly as a Markdown table.
  563. - Dynamically enforces user-defined calorie limits and active medical restrictions.
  564. ---
  565. ## 3. Supported Health & Medical Profiles
  566. - **Conditions**: Pregnant, Breastfeeding, Low Fat, Osteoporosis.
  567. - **Illnesses**: Diabetes, Hypertension, Kidney Disease, Scurvy, Anemia.
  568. - **Diets**: Vegan, Vegetarian, Kosher, Halal, Keto, Paleo, Christian (Lent/Good Friday).
  569. """,
  570. "Start_Stop_Procedures.md": """The current version is #ident "@(#)$Format:LocalFoodAI_lanfr144:generate_docs.py:%an:%ae:%ad:%cn:%ce:%cd:%H:%D:%N$"
  571. # Infrastructure Stop & Start Operational Procedures
  572. This runbook outlines the exact sequence and commands to start, stop, and verify each microservice in the Local Food AI environment.
  573. ---
  574. ## 1. Sequence Priority Rules
  575. Due to database socket requirements and network bindings, services **must** be started and stopped in the following order:
  576. ```mermaid
  577. graph TD
  578. subgraph Startup Sequence
  579. direction TB
  580. A[1. MySQL Database] --> B[2. Ollama & SearXNG AI Services]
  581. B --> C[3. Streamlit Application & Nginx Proxy]
  582. C --> D[4. Zabbix Monitoring & Airflow Supervisor]
  583. end
  584. ```
  585. ---
  586. ## 2. Startup Procedures
  587. ### Step 2.1: Start the Core MySQL Database
  588. Verify that the database service is up and listening on port 3307:
  589. ```bash
  590. docker compose up -d mysql
  591. # Verify database logs
  592. docker compose logs -f mysql
  593. ```
  594. ### Step 2.2: Start AI Engine & SearXNG Search
  595. Deploy the AI components:
  596. ```bash
  597. docker compose up -d ollama searxng
  598. # Check that Ollama responds
  599. curl http://localhost:11434/api/tags
  600. ```
  601. ### Step 2.3: Start Streamlit App and Nginx Gateway
  602. Bring up the frontend web interface and reverse proxy:
  603. ```bash
  604. docker compose up -d app nginx
  605. # Verify Web Interface status
  606. curl -I http://localhost
  607. ```
  608. ### Step 2.4: Start Zabbix Monitoring Suite
  609. Deploy the monitoring server and agents:
  610. ```bash
  611. docker compose up -d zabbix-server zabbix-web zabbix-agent
  612. # Check dashboard availability
  613. curl -I http://localhost:8081
  614. ```
  615. ---
  616. ## 3. Shutdown Procedures
  617. To perform system maintenance or schema migration, stop services in reverse order to prevent lockups:
  618. ```bash
  619. # 1. Stop Monitoring Components
  620. docker compose stop zabbix-agent zabbix-web zabbix-server
  621. # 2. Stop Web Frontend and Proxy Gateway
  622. docker compose stop nginx app
  623. # 3. Stop NLP and Search Services
  624. docker compose stop searxng ollama
  625. # 4. Stop Database Container gracefully
  626. docker compose stop mysql
  627. ```
  628. ---
  629. ## 4. Status Verification Commands
  630. Use these commands to verify container state and port bindings:
  631. ```bash
  632. # List all running containers in the stack
  633. docker compose ps
  634. # Inspect raw container logs for error spikes
  635. docker compose logs --tail=100
  636. # Verify TCP socket listener binds
  637. netstat -tulpn | grep -E "80|3307|8081|11434"
  638. ```
  639. """,
  640. "Operator_Installation_Guide.md": """The current version is #ident "@(#)$Format:LocalFoodAI_lanfr144:generate_docs.py:%an:%ae:%ad:%cn:%ce:%cd:%H:%D:%N$"
  641. # Local Food AI - Detailed Operator Installation Guide
  642. This document is a step-by-step installation, mapping, configuration, and verification manual for deploying the **Local Food AI** system in an enterprise environment. It covers hybrid hypervisor infrastructure (WSL2, Hyper-V, and VirtualBox), cross-node networking, SNMPv3 monitoring, alert channels, and acceptance testing.
  643. ---
  644. ## 1. Pre-Deployment Operator Survey (Pre-requisites Gathering)
  645. Before running installation scripts, the operator **must** collect the following physical/virtual infrastructure parameters and store them in the deployment matrix:
  646. | REQUIRED PARAMETER | OPERATOR INPUT / DESCRIPTION |
  647. | :--- | :--- |
  648. | **Deployment Workstation IP** | e.g., 192.168.1.50 |
  649. | **Hyper-V Host VM IP** | e.g., 192.168.130.170 |
  650. | **VirtualBox Host VM IP** | e.g., 192.168.130.161 |
  651. | **SSH Key Location (Private)** | e.g., `~/.ssh/id_rsa` |
  652. | **SMTP Relay Password** | e.g., `********` (For Zabbix/App password reset email) |
  653. | **Teams/Discord Webhook URL** | e.g., `https://discord.com/api/webhooks/...` |
  654. ---
  655. ## 2. Platform Mapping: Which Container Goes Where?
  656. To maximize CPU/GPU efficiency and secure database read/writes, services are distributed across three distinct environments:
  657. | COMPONENT CONTAINER | DEPLOYMENT ENVIRONMENT | WHY |
  658. | :--- | :--- | :--- |
  659. | **streamlit-app (app.py)** | Local WSL2 (Windows) | Low-latency rendering and direct client access |
  660. | **mysql (Database Node)** | Hyper-V VM (Server A) | Persistent enterprise-grade disk storage |
  661. | **ollama (NLP llama3.2:3b Engine)** | VirtualBox VM (Server B) | Dedicated CPU/GPU virtualization allocation |
  662. | **zabbix-server & web (Monitoring)** | Hyper-V VM (Server A) | Centralized SNMPv3 alert processing and logs |
  663. | **searxng (Meta-Search Gateway)** | Local WSL2 (Windows) | Dynamic browser-level loopbacks |
  664. ---
  665. ## 3. Platform Provisioning Commands
  666. ### 3.1: WSL2 Provisioning (Local Client Workstation)
  667. Enable WSL2 and install Ubuntu 24.04:
  668. ```powershell
  669. # Run in Administrator PowerShell
  670. dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
  671. dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
  672. wsl --install -d Ubuntu-24.04
  673. ```
  674. ### 3.2: Hyper-V VM Provisioning (Server A - Database & Zabbix)
  675. Deploy a dedicated Ubuntu VM on Hyper-V using PowerShell:
  676. ```powershell
  677. # Run in Administrator PowerShell on Server A
  678. New-VM -Name "FoodAI-Database-Node" -MemoryStartupBytes 8GB -Generation 2 -NewVHDPath "C:\\VMs\\FoodAI_DB.vhdx" -VHDSizeBytes 80GB -SwitchName "External Switch"
  679. Set-VMFirmware -VMName "FoodAI-Database-Node" -EnableSecureBoot Off
  680. Start-VM -Name "FoodAI-Database-Node"
  681. ```
  682. ### 3.3: VirtualBox VM Provisioning (Server B - Ollama AI Engine)
  683. Deploy a dedicated VM on VirtualBox using Command Line:
  684. ```bash
  685. # Run in Command Prompt on Server B
  686. vboxmanage createvm --name "FoodAI-AI-Node" --ostype "Ubuntu_64" --register
  687. vboxmanage modifyvm "FoodAI-AI-Node" --memory 8192 --cpus 4 --vram 128 --nic1 bridged --bridgeadapter1 "Intel Ethernet Connection"
  688. vboxmanage createhd --filename "C:\\VMs\\FoodAI_AI.vdi" --size 60000
  689. vboxmanage storagectl "FoodAI-AI-Node" --name "SATA Controller" --add sata --controller IntelAHCI
  690. vboxmanage storageattach "FoodAI-AI-Node" --storagectl "SATA Controller" --port 0 --device 0 --type hdd --medium "C:\\VMs\\FoodAI_AI.vdi"
  691. vboxmanage startvm "FoodAI-AI-Node" --type headless
  692. ```
  693. ---
  694. ## 4. Secure Authentication & SSH Exchange
  695. Exchange SSH public keys to allow automated, passwordless container management across nodes:
  696. ```bash
  697. # 1. Generate SSH Keys on WSL Client
  698. ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa_foodai -N ""
  699. # 2. Push Key to Database VM (Server A)
  700. ssh-copy-id -i ~/.ssh/id_rsa_foodai.pub operator@192.168.130.170
  701. # 3. Push Key to AI VM (Server B)
  702. ssh-copy-id -i ~/.ssh/id_rsa_foodai.pub operator@192.168.130.161
  703. ```
  704. ---
  705. ## 5. Multi-Node Docker Network & Configuration
  706. To allow WSL, Hyper-V, and VirtualBox nodes to communicate, update the `.env` variables and `docker-compose.yml` to use bridged network endpoints.
  707. ### Step 5.1: Configure WSL Client `.env`
  708. Update `.env` in the Streamlit workspace:
  709. ```ini
  710. DB_HOST=192.168.130.170
  711. DB_USER=food_reader
  712. DB_PASS=reader_pass
  713. APP_AUTH_USER=food_app_auth
  714. APP_AUTH_PASS=auth_pass
  715. OLLAMA_HOST=http://192.168.130.161:11434
  716. SEARXNG_HOST=http://localhost:8080
  717. ZBX_SERVER_HOST=192.168.130.170
  718. ```
  719. ### Step 5.2: Configure Ollama (VirtualBox Server B) Listening Port
  720. Ensure the Ollama daemon inside VirtualBox binds to `0.0.0.0` (all interfaces):
  721. ```bash
  722. # SSH into Server B (192.168.130.161)
  723. sudo systemctl edit ollama.service
  724. # Add the environment variables:
  725. [Service]
  726. Environment="OLLAMA_HOST=0.0.0.0"
  727. # Reload and restart service
  728. sudo systemctl daemon-reload
  729. sudo systemctl restart ollama
  730. ```
  731. ---
  732. ## 6. Zabbix Reconfiguration for Multi-Node SNMPv3 Telemetry
  733. To monitor all distributed deployment environments securely:
  734. ### Step 6.1: Deploy SNMPv3 Daemons
  735. Install and configure SNMPv3 daemons on WSL, Hyper-V Database VM, and VirtualBox AI VM:
  736. ```bash
  737. sudo apt update && sudo apt install -y snmpd
  738. ```
  739. Edit `/etc/snmp/snmpd.conf`:
  740. ```
  741. # Listen on all interfaces
  742. agentAddress udp:161
  743. # Create secure SNMPv3 User
  744. createUser securityUser SHA "securityAuthPassword" AES "securityPrivPassword"
  745. rouser securityUser authpriv
  746. ```
  747. Restart daemon:
  748. ```bash
  749. sudo systemctl restart snmpd
  750. ```
  751. ### Step 6.2: Configure Zabbix Server Dashboard (Web UI)
  752. 1. Open Zabbix in your browser at `http://192.168.130.170:8081`.
  753. 2. Navigate to **Configuration > Hosts > Create Host**.
  754. 3. Create three distinct hosts:
  755. - **WSL-Workstation** (IP: `192.168.1.50`)
  756. - **Database-Node** (IP: `192.168.130.170`)
  757. - **AI-Node** (IP: `192.168.130.161`)
  758. 4. Add the **SNMP Interface** pointing to Port 161 for each host.
  759. 5. In the **Security Tab**, select SNMPv3, enter Username `securityUser`, select Auth Protocol `SHA` / `securityAuthPassword`, and Privacy Protocol `AES` / `securityPrivPassword`.
  760. 6. Attach the pre-installed **Local Food AI Telemetry** Template.
  761. ---
  762. ## 7. Verifying Alert Channels
  763. ### 7.1: Microsoft Teams / Discord Alert Webhook
  764. To verify Zabbix is communicating with Discord / Teams:
  765. 1. Trigger a test CPU threshold spike inside WSL:
  766. ```bash
  767. yes > /dev/null & sleep 10 ; killall yes
  768. ```
  769. 2. Verify Zabbix triggers the alert and transmits the notification.
  770. 3. Check your designated channel for the incoming payload:
  771. - Expected Output: `[PROBLEM] High CPU Utilization Detected on WSL-Workstation`.
  772. ### 7.2: Password Reset Email (SMTP Gateway)
  773. 1. In the Streamlit UI Sidebar, select **Reset Password**.
  774. 2. Trigger a reset link for user `ClinicianA`.
  775. 3. Check the inbox or SMTP system log (`tail -f /var/log/mail.log` on Server A) to verify outbound delivery.
  776. ---
  777. ## 8. Operator Post-Installation Checklist
  778. Run these test cases to verify the installation:
  779. | TEST CASE ID | ACTIONS TO PERFORM | EXPECTED RESULTS | STATUS |
  780. | :--- | :--- | :--- | :---: |
  781. | **TC-OP-01** | Search 'Cheese' on Search Tab | 10+ records returned in <0.04s. Listeria warning flags on unpasteurized. | `[ ]` |
  782. | **TC-OP-02** | Enter '1.5 cups' in Plate Tab | Parsed and converted to metric grams based on density index. | `[ ]` |
  783. | **TC-OP-03** | Ask Chat: 'Can I eat sushi?' | llama3.2:3b retrieves database context and flags raw fish as forbidden for pregnancy. | `[ ]` |
  784. | **TC-OP-04** | Trigger manual db backup | Timestamped compressed .sql.gz created inside backups/ folder. | `[ ]` |
  785. | **TC-OP-05** | Terminate Ollama Container | Zabbix PROBLEM active alert generated on dashboard in < 30 seconds. | `[ ]` |
  786. """,
  787. "Uninstall_Guide.md": """The current version is #ident "@(#)$Format:LocalFoodAI_lanfr144:generate_docs.py:%an:%ae:%ad:%cn:%ce:%cd:%H:%D:%N$"
  788. # Local Food AI - Uninstallation & Teardown Guide
  789. This document outlines the standard uninstallation procedures to completely remove the **Local Food AI** stack components from both Windows hosts and Linux/WSL deployment environments.
  790. ---
  791. ## 1. Linux & WSL Client Uninstallation
  792. To cleanly purge the containerized services, databases, virtual environments, and log files:
  793. ### Step 1.1: Stop & Remove Docker Containers & Volumes
  794. Bring down the Docker Compose stack and permanently delete all associated network interfaces and database volumes:
  795. ```bash
  796. # Navigate to the project directory
  797. cd /dossier/du/projet/Food
  798. # Stop services and remove containers, networks, and volumes
  799. ./manage_services.sh stop
  800. docker compose down -v
  801. ```
  802. *Note: The `-v` flag is critical as it completely purges the MySQL persistent data directories.*
  803. ### Step 1.2: Remove Local Project Docker Images
  804. List the active images associated with the project using:
  805. ```bash
  806. docker image ls | grep -E "food_project|zabbix|searxng|ollama|nginx|airflow"
  807. ```
  808. Example output:
  809. ```text
  810. IMAGE ID DISK USAGE CONTENT SIZE EXTRA
  811. apache/airflow:2.8.1 e5560ad0b86e 1.94GB 387MB U
  812. food_project-app:latest 3cfb2e77efc7 1.4GB 326MB U
  813. food_project-ingest:latest 6e120f3c9946 1.4GB 326MB
  814. food_project-mysql:latest 6f33177ab088 1.09GB 234MB U
  815. nginx:latest 6e23479198b9 240MB 65.8MB U
  816. ollama/ollama:latest 5600a652d108 10.1GB 3.77GB U
  817. searxng/searxng:latest 25ff3c045548 375MB 96.4MB U
  818. zabbix/zabbix-agent:ubuntu-7.0-latest db7d6490f39a 202MB 56.2MB U
  819. zabbix/zabbix-server-mysql:ubuntu-7.0-latest 78c2e2f75e8d 479MB 121MB U
  820. zabbix/zabbix-web-nginx-mysql:ubuntu-7.0-latest 11b12c432e1b 557MB 145MB U
  821. ```
  822. To permanently remove all the images related to the application stack from the local cache:
  823. ```bash
  824. docker rmi food_project-app:latest food_project-ingest:latest food_project-mysql:latest nginx:latest ollama/ollama:latest searxng/searxng:latest zabbix/zabbix-agent:ubuntu-7.0-latest zabbix/zabbix-server-mysql:ubuntu-7.0-latest zabbix/zabbix-web-nginx-mysql:ubuntu-7.0-latest apache/airflow:2.8.1
  825. ```
  826. ### Step 1.3: Clean Up Virtual Environments, Logs & Backups
  827. Delete local administrator logs, backup directories, and Python virtual environment libraries:
  828. ```bash
  829. rm -rf .venv/
  830. rm -rf backups/
  831. rm -rf logs/
  832. rm -rf data/
  833. ```
  834. ### Step 1.4: Purge Docker CE (Optional)
  835. If you wish to completely uninstall Docker CE from the Ubuntu/WSL environment:
  836. ```bash
  837. sudo apt-get purge -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras
  838. sudo rm -rf /var/lib/docker
  839. sudo rm -rf /var/lib/containerd
  840. ```
  841. ---
  842. ## 2. Windows Host Uninstallation
  843. To remove all hypervisor and subsystem configurations from the Windows client:
  844. ### Step 2.1: Unregister and Delete the WSL Subsystem Environment
  845. To completely wipe the WSL2 Ubuntu environment and its entire virtual hard disk (VHD):
  846. 1. Open a PowerShell terminal as Administrator.
  847. 2. Execute the unregister command:
  848. ```powershell
  849. wsl --unregister Dopro1
  850. ```
  851. *Warning: This action is irreversible. All configurations, tools, and code inside the WSL `Dopro1` container will be permanently deleted.*
  852. ### Step 2.2: Remove VirtualBox Virtual Machines (if applicable)
  853. If you deployed Ollama or Zabbix nodes on dedicated VirtualBox VMs:
  854. 1. Open PowerShell or Command Prompt.
  855. 2. Run the VBoxManage tool to remove the VMs:
  856. ```cmd
  857. VBoxManage unregistervm "Ollama_Server" --delete
  858. VBoxManage unregistervm "Zabbix_Server" --delete
  859. ```
  860. ### Step 2.3: Disable Windows Virtualization Features (Optional)
  861. To disable WSL and Virtual Machine Platform features on the Windows host:
  862. ```powershell
  863. Disable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux
  864. Disable-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform
  865. ```
  866. *Note: A system reboot is required to complete this step.*
  867. """,
  868. "Env_Configuration.md": """The current version is #ident "@(#)$Format:LocalFoodAI_lanfr144:generate_docs.py:%an:%ae:%ad:%cn:%ce:%cd:%H:%D:%N$"
  869. # Local Food AI - Environment Variables Configuration Runbook
  870. This runbook catalogs every configuration key in the `.env` file, explaining its functional purpose, dependency context, and providing fillable fields for custom deployment setups.
  871. ---
  872. ## 1. Network & System Mode Configuration
  873. | Parameter | Purpose & Description | Example Value | Your Custom Value |
  874. | :--- | :--- | :--- | :--- |
  875. | `NETWORK_MODE` | Controls external request checks. Set to `server` to enable telemetry alerts and database triggers, or `local` for offline development/standalone fallback. | `server` | `____________________` |
  876. | `LLM_MODEL` | The local Large Language Model loaded into Ollama. Default is `llama3.2:3b` for quantized local inference. | `llama3.2:3b` | `____________________` |
  877. ---
  878. ## 2. Database Credentials (MySQL)
  879. These credentials configure standard user authentication permissions on the vertical partitions.
  880. | Parameter | Purpose & Description | Example Value | Your Custom Value |
  881. | :--- | :--- | :--- | :--- |
  882. | `MYSQL_ROOT_PASSWORD` | MySQL root administrative account access password. | `your_mysql_root_pass` | `____________________` |
  883. | `DB_READER_PASS` | Password for the low-privilege `food_reader` database account. | `your_db_reader_pass` | `____________________` |
  884. | `DB_LOADER_PASS` | Password for the `food_loader` account executing bulk CSV imports. | `your_db_loader_pass` | `____________________` |
  885. | `DB_APP_AUTH_PASS` | Password for the `food_app_auth` credential checker role. | `your_db_auth_pass` | `____________________` |
  886. | `MYSQL_ZABBIX_PASSWORD` | Password for the Zabbix DB user connection profile. | `your_mysql_zabbix_pass` | `____________________` |
  887. ---
  888. ## 3. Zabbix & SNMPv3 Configuration
  889. Configures the monitoring server APIs and SNMPv3 security parameters.
  890. | Parameter | Purpose & Description | Example Value | Your Custom Value |
  891. | :--- | :--- | :--- | :--- |
  892. | `ZABBIX_URL` | Endpoint URL for Zabbix API script queries. | `http://your_zabbix_host:8081` | `____________________` |
  893. | `ZABBIX_USER` | Admin dashboard username for API provisioning. | `your_zabbix_user` | `____________________` |
  894. | `ZABBIX_PASS` | Zabbix admin dashboard password. | `your_zabbix_pass` | `____________________` |
  895. | `ZABBIX_SNMP_USER` | Secure SNMPv3 routing user identifier. | `your_snmp_user` | `____________________` |
  896. | `ZABBIX_SNMP_AUTHKEY` | SNMPv3 SHA authentication key (minimum 8 characters). | `your_snmp_authkey` | `____________________` |
  897. | `ZABBIX_SNMP_PRIVKEY` | SNMPv3 AES encryption key (minimum 8 characters). | `your_snmp_privkey` | `____________________` |
  898. | `DISCORD_WEBHOOK` | External webhook URL for automated alerts. | `https://discord.com/api/webhooks/your_webhook_id` | `____________________` |
  899. ---
  900. ## 4. Alert Mail Gateways & PM Integration
  901. | Parameter | Purpose & Description | Example Value | Your Custom Value |
  902. | :--- | :--- | :--- | :--- |
  903. | `EMAIL_USER` | SMTP server username for password recovery alerts. | `your_email_user@example.com` | `____________________` |
  904. | `EMAIL_PASS` | SMTP server authentication password. | `your_email_password` | `____________________` |
  905. | `TAIGA_URL` | Endpoint path for the Taiga Agile Kanban board server. | `http://your_taiga_host/taiga` | `____________________` |
  906. | `TAIGA_USER` | API authentication account username. | `your_taiga_user` | `____________________` |
  907. | `TAIGA_PASS` | Password for the API sync user. | `your_taiga_pass` | `____________________` |
  908. ---
  909. ## 5. VM Server Remote Deployments
  910. Credentials required to manage SSH keys and remote container processes from the client.
  911. | Parameter | Purpose & Description | Example Value | Your Custom Value |
  912. | :--- | :--- | :--- | :--- |
  913. | `SERVER_HOST` | Remote server IP address (Server A hypervisor). | `your_server_ip` | `____________________` |
  914. | `SERVER_USER` | SSH login username for command line deployments. | `your_ssh_user` | `____________________` |
  915. | `SERVER_PASS` | SSH login password for VM operations. | `your_ssh_pass` | `____________________` |
  916. """
  917. }
  918. import subprocess
  919. def sanitize_name(name):
  920. if not name:
  921. return "Francois Lange"
  922. name_lower = name.lower()
  923. if "fran" in name_lower or "lange" in name_lower or "lanfr" in name_lower:
  924. return "Francois Lange"
  925. return name
  926. def get_git_info_for_file(file_path):
  927. try:
  928. cmd = [
  929. "git", "log", "-1",
  930. "--date=format:%Y/%m/%d %H:%M:%S",
  931. "--format=%an|%ae|%ad|%cn|%ce|%cd|%H|%D|%N",
  932. "--", file_path
  933. ]
  934. out = subprocess.check_output(cmd, stderr=subprocess.DEVNULL).decode('utf-8', errors='ignore').strip()
  935. if out:
  936. parts = out.split('|')
  937. if len(parts) == 9:
  938. parts[0] = sanitize_name(parts[0])
  939. parts[3] = sanitize_name(parts[3])
  940. return parts
  941. except Exception:
  942. pass
  943. author_name = "Francois Lange"
  944. try:
  945. author_email = subprocess.check_output(["git", "config", "user.email"], stderr=subprocess.DEVNULL).decode('utf-8', errors='ignore').strip() or "lanfr144@school.lu"
  946. except Exception:
  947. author_email = "lanfr144@school.lu"
  948. from datetime import datetime
  949. now_str = datetime.now().strftime("%Y/%m/%d %H:%M:%S")
  950. return [author_name, author_email, now_str, author_name, author_email, now_str, "Not Committed Yet", "local", "none"]
  951. for filename, doc_content in docs.items():
  952. filepath = os.path.join(docs_dir, filename)
  953. # Dynamic smudging of the Format placeholder for this specific file
  954. info = get_git_info_for_file(filepath)
  955. replacement = f"$Format:LocalFoodAI_lanfr144:generate_docs.py:%an:%ae:%ad:%cn:%ce:%cd:%H:%D:%N$"
  956. # We replace the raw template string in the content
  957. pattern = r'\$Format:LocalFoodAI_lanfr144:generate_docs.py:%an:%ae:%ad:%cn:%ce:%cd:%H:%D:%N$'
  958. doc_content_smudged = re.sub(pattern, replacement, doc_content)
  959. with open(filepath, "w", encoding="utf-8") as f:
  960. f.write(doc_content_smudged)
  961. print(f"Generated and smudged {filepath}")
  962. print("\nDocs directory perfectly mirrored with operator level runbooks.")