Spaces:
Sleeping
Sleeping
File size: 21,092 Bytes
d27b187 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 | """Generate the AgroSense Technical Guide and Standard Operating Procedure (SOP),
each as Word (.docx) and PDF, into docs/.
pip install python-docx fpdf2
python scripts/build_tech_docs.py
"""
from __future__ import annotations
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
from docgen import build_both # noqa: E402
DOCS_DIR = Path(__file__).resolve().parent.parent / "docs"
# --------------------------------------------------------------------------- #
# Technical Guide
# --------------------------------------------------------------------------- #
TECH_TITLE = "AgroSense - Technical Guide"
TECH_SUBTITLE = "Architecture, modules, configuration and deployment - v0.1 (POC)"
TECH_SECTIONS = [
("1. System Overview", [
("p", "AgroSense is a FastAPI application that also serves a single-page web "
"app. At its core is a Retrieval-Augmented Generation (RAG) engine over "
"an agriculture knowledge base, surrounded by data-source modules "
"(weather, satellite, market, hazards, etc.) and service modules "
"(plant vision, telemedicine, live consultation, doctor registry, "
"knowledge-base admin)."),
("h2", "Layers"),
("ul", ["Data layer - static knowledge base plus live sources (Open-Meteo, "
"NASA, data.gov.in, Yahoo Finance, Google News).",
"Knowledge layer - documents embedded into a vector store.",
"Cognitive layer - retrieval + re-ranking + grounded generation, plus "
"decision-fusion advisories and plant vision/telemedicine.",
"Interaction layer - the web app (served by FastAPI), Streamlit UI, CLI.",
"Engagement layer - multilingual, live consultation, notifications."]),
("h2", "RAG pipeline"),
("p", "query -> preprocess/translate -> embed -> vector search (top-k) -> "
"CARO-style metadata re-rank + relevance gate -> grounded extractive "
"generation with citations -> optional translation back to the user "
"language."),
]),
("2. Technology Stack", [
("ul", ["Language/runtime: Python 3.10+ (validated on 3.14).",
"Core: FastAPI + Uvicorn, Pydantic, NumPy.",
"Web app: HTML + CSS + vanilla JS (no build step), served at /ui.",
"Optional accelerators: faiss-cpu (vector search), sentence-transformers "
"(embeddings) - pure-Python fallbacks exist when absent.",
"Optional: TensorFlow (plant-vision CNNs), Earth Engine API (NDVI), "
"Pillow (image heuristic), deep-translator/argostranslate (i18n), "
"python-docx + fpdf2 (these documents).",
"Tests: a self-contained runner (python tests/test_rag.py) plus a "
"jsdom SPA smoke test (node web/smoke.mjs)."]),
]),
("3. Repository Layout", [
("ul", ["agrosense/ - the library (engine + all modules).",
"agrosense/rag.py - RAGEngine, the single orchestration entry point.",
"agrosense/{embeddings,vector_store,retriever,generator}.py - RAG core.",
"agrosense/{weather,satellite,environment,planetary,hazards}.py - data.",
"agrosense/{fusion,crop_profiles}.py - decision-fusion advisories.",
"agrosense/{vision,telemedicine,ipm}.py - plant clinic.",
"agrosense/{consultation,doctors,notifications}.py - live doctor.",
"agrosense/{clubs,traditional}.py - farmer clubs + traditional/Panchang.",
"agrosense/{subsidies,finance,land_records,trading}.py - schemes, loans, "
"land records, produce marketplace.",
"agrosense/{prices,commodities,news,radio,calendars,translation}.py - misc.",
"agrosense/{kb_admin,evaluation}.py - admin + evaluation.",
"api/main.py - FastAPI app and all endpoints.",
"web/ - the single-page app. ui/ - Streamlit UI. cli.py - CLI.",
"data/ - knowledge_base.json, agri_experts.json, subsidies.json, "
"finance.json, land_records.json, eval_set.json, etc.",
"scripts/ - evaluate, train_plant_models, build_manual, build_tech_docs, "
"docgen (shared Word/PDF renderer), build_docs (regenerate all).",
"tests/ - test_rag.py (logic), test_ui_render.py (Streamlit render)."]),
]),
("4. The RAG Engine", [
("p", "RAGEngine (agrosense/rag.py) builds the embedder, generator, documents, "
"vector store and retriever on init, and owns every feature method. "
"Embeddings default to an offline hashing embedder; the vector store "
"defaults to a NumPy cosine store; both upgrade automatically when the "
"optional libraries are installed."),
("ul", ["Retrieval: vector search returns top-k; a CARO-style pass re-weights "
"by metadata overlap (crop, soil, region) and lexical overlap.",
"Relevance gate: a candidate must share a content term with the query "
"(matched against field values, not labels) - off-domain queries hit a "
"safe fallback instead of fabricating advice.",
"Generation: an extractive generator composes the answer ONLY from "
"retrieved KB fields and attaches numbered citations (low hallucination "
"by construction). An OpenAI/Azure seam exists for a real LLM.",
"reload_kb() rebuilds documents + store + retriever after admin edits."]),
]),
("5. Knowledge Base", [
("p", "data/knowledge_base.json is a list of entries (crop, soil_type, "
"rainfall_mm, recommended_fertilizer, disease_prevention, pest_management, "
"source, ...). agrosense/kb_admin.py provides a validated CRUD store "
"(KBStore) used by the admin endpoints; saving rewrites the file and the "
"engine rebuilds the index so changes are live."),
]),
("6. Modules and Data Sources", [
("ul", ["Keyless: weather/environment (Open-Meteo), satellite imagery + "
"agroclimate (NASA GIBS/POWER), hazards (NASA EONET), planetary "
"(local ephemeris), news (Google News), commodities (Yahoo Finance), "
"internet radio (Radio Browser).",
"Keyed: prices + groundwater (data.gov.in), fires (NASA FIRMS), "
"field NDVI (Earth Engine).",
"Curated knowledge bases (no live feed exists): government schemes "
"(subsidies.json), agri-finance products (finance.json), state land-record "
"systems (land_records.json). The land-record guide is rendered to Word/PDF "
"on the fly via scripts/docgen.py.",
"User-generated runtime stores (auto-seeded / gitignored): farmer clubs "
"(clubs.json), produce listings (market_listings.json), loan enquiries "
"(finance_applications.json), doctor registry (plant_doctors.json).",
"Each client degrades gracefully (returns None/empty) when offline or "
"unconfigured; parsing/geometry logic is pure and unit-tested, network "
"calls are mock-tested."]),
]),
("7. API Reference", [
("ul", ["Advisor: POST /query.",
"Location: GET /weather /satellite /environment /planetary /hazards "
"/advisories.",
"Market/info: GET /prices /commodities /news /radio /datetime /languages.",
"Trading: GET/POST /market/listings, GET /market/listings/{id}, "
"POST /market/listings/{id}/inquire, POST /market/listings/{id}/close.",
"Plant clinic: POST /vision/classify, POST /telemedicine.",
"Doctors: GET /experts, GET /doctors/{id}, POST /doctors/{id}/rate, "
"POST /doctors/apply.",
"Consults: POST /consult/request, GET/POST /consult/{id}[/message], "
"GET /notifications.",
"Clubs: GET/POST /clubs, GET /clubs/{id}, POST /clubs/{id}/join|post.",
"Traditional: GET /traditional.",
"Schemes: GET /subsidies[/{id}], GET /subsidies/updates.",
"Finance: GET /finance[/{id}], POST /finance/{id}/apply.",
"Land records: GET /land-records, GET /land-records/guide.{pdf,docx}.",
"Admin (X-Admin-Token): /admin/kb (CRUD), /admin/doctors, "
"/admin/doctors/{id}/verify, /admin/subsidies/{id}/update, "
"/admin/finance/applications.",
"Docs: GET /downloads/{user-manual,technical-guide,sop}.{pdf,docx}.",
"App: GET / -> /ui/ ; interactive API docs at /docs."]),
]),
("8. Configuration (environment variables)", [
("ul", ["AGROSENSE_EMBEDDING_BACKEND - auto | sentence-transformers | hashing.",
"AGROSENSE_GENERATION_BACKEND - extractive | openai.",
"AGROSENSE_ADMIN_TOKEN - admin gate (change the default 'admin').",
"AGROSENSE_DATAGOV_API_KEY - prices + groundwater.",
"AGROSENSE_GROUNDWATER_RESOURCE - CGWB resource id.",
"AGROSENSE_FIRMS_MAP_KEY - active fires.",
"AGROSENSE_EE_PROJECT / _EE_SERVICE_ACCOUNT / _EE_KEY_FILE - NDVI.",
"AGROSENSE_VISION_{DISEASE,PLANT,PEST}_MODEL / _LABELS - vision models.",
"AGROSENSE_TRANSLATION_BACKEND - auto | argos | deep | none.",
"AGROSENSE_NOTIFY_WEBHOOK / SMTP vars - expert notifications.",
"AGROSENSE_VIDEO_BASE - Jitsi base for live video.",
"AGROSENSE_KB_PATH - knowledge base path override."]),
]),
("9. Extending AgroSense", [
("ul", ["Add KB knowledge: use the Admin tab or POST /admin/kb (or edit the "
"JSON and call reload).",
"Add a data source: create a module with a pure parser + a client that "
"returns None on failure; add an engine method and an endpoint; unit-"
"test the parser and mock the fetch.",
"Add a vision model: train with scripts/train_plant_models.py and set "
"the model env vars; inference activates automatically.",
"Add an expert specialization: extend the tag map in doctors.py and the "
"routing map in consultation.py."]),
]),
("10. Testing and Quality", [
("ul", ["Logic suite: python tests/test_rag.py (offline; set "
"AGROSENSE_EMBEDDING_BACKEND=hashing for determinism).",
"Evaluation harness: python scripts/evaluate.py - context relevance, "
"faithfulness, hallucination rate, latency vs targets.",
"SPA smoke: node web/smoke.mjs (jsdom; mocks fetch; asserts no runtime "
"errors and that sections render).",
"Streamlit render: python tests/test_ui_render.py."]),
]),
("11. Deployment", [
("ol", ["Provision a host with Python 3.10+; pip install -r requirements.txt.",
"Set required environment variables (at least change AGROSENSE_ADMIN_TOKEN).",
"Run: uvicorn api.main:app --host 0.0.0.0 --port 8000 (add --workers N "
"behind a process manager; put a reverse proxy / TLS in front).",
"Persist data/ (knowledge_base.json, plant_doctors.json) on durable "
"storage; back it up regularly.",
"Generate docs once (python scripts/build_manual.py ; "
"python scripts/build_tech_docs.py)."]),
("p", "Note: engine state (the consultation/notification stores and the doctor "
"registry) is in-process and per-worker; for multi-worker or multi-host "
"deployments move that state to a shared database."),
]),
("12. Security", [
("ul", ["Admin endpoints use a shared-secret token (X-Admin-Token) - suitable "
"for a single-admin POC; use real auth (accounts, roles, audit) in "
"production.",
"CORS is open by default - restrict allowed origins for a real deployment.",
"Onboarding and ratings are unauthenticated - add accounts and rate "
"limiting to prevent spam/abuse.",
"Keep API keys in environment variables / a secrets manager, never in "
"code. Validate and size-limit uploaded images."]),
]),
]
# --------------------------------------------------------------------------- #
# Standard Operating Procedure
# --------------------------------------------------------------------------- #
SOP_TITLE = "AgroSense - Standard Operating Procedure (SOP)"
SOP_SUBTITLE = "Operational runbook for deploying, running and administering AgroSense"
SOP_SECTIONS = [
("1. Purpose and Scope", [
("p", "This SOP defines the standard procedures to deploy, operate, administer "
"and recover the AgroSense service. It applies to administrators and "
"operators running the FastAPI service and the web app."),
]),
("2. Roles and Responsibilities", [
("ul", ["Operator - starts/stops the service, monitors health, applies config, "
"performs backups and incident response.",
"Administrator - manages the knowledge base and verifies plant doctors "
"(holds the admin token).",
"Plant doctor - onboards, gets verified, handles live consultations.",
"Farmer (end user) - uses the advisor, plant clinic and consultations."]),
]),
("3. Pre-requisites", [
("ol", ["Host with Python 3.10+ and network egress for live features.",
"pip install -r requirements.txt.",
"Environment variables set (see the Technical Guide). At minimum set a "
"strong AGROSENSE_ADMIN_TOKEN.",
"data/ directory present and writable (knowledge base + doctor registry)."]),
]),
("4. Start, Stop, Restart", [
("ol", ["Start: uvicorn api.main:app --host 0.0.0.0 --port 8000 "
"(use a process manager such as systemd/pm2 in production).",
"Verify: open http://HOST:8000/ui/ and GET http://HOST:8000/health.",
"Stop: stop the uvicorn process (Ctrl+C or the process manager).",
"Restart: stop then start; the engine reloads the knowledge base and "
"rebuilds the index at boot."]),
]),
("5. Health Checks and Monitoring", [
("ul", ["GET /health returns status ok and the knowledge-base document count.",
"GET / should redirect (307) to /ui/; /ui/ should return the web app.",
"Watch the uvicorn logs for errors; a feature returning 'unavailable' "
"indicates a missing key or no network, not a service fault.",
"Latency target for the advisor is under 3 seconds; the offline core is "
"typically sub-second."]),
]),
("6. Configuration Management", [
("ol", ["Set configuration via environment variables before starting the "
"service (do not hard-code secrets).",
"To change a key/setting: update the environment, then restart the "
"service.",
"Record changes (who/when/what) in your change log."]),
]),
("7. Knowledge Base Management", [
("ol", ["Back up data/knowledge_base.json before bulk changes.",
"Open the web app Admin tab, enter the admin token, click Unlock.",
"Add an entry (crop and source are required), or Edit/Delete an existing "
"one. Alternatively use POST/PUT/DELETE /admin/kb with the X-Admin-Token "
"header.",
"Saving rebuilds the live index automatically - verify by asking the "
"advisor a question that should hit the new entry."]),
]),
("8. Plant Doctor Onboarding and Verification", [
("ol", ["A doctor applies via the Plant clinic tab's live-doctor section (or "
"POST /doctors/apply).",
"Admin opens the Admin tab -> Plant doctor verification, and reviews the "
"application: name, specialization, region, languages, contact, "
"credentials and the ICAR/registration number.",
"Check the credentials and registration number against your records / "
"the relevant registry (manual step).",
"Click Verify to approve (the doctor enters the directory and can take "
"consults) or Reject. Verified doctors are notified on new consults via "
"the configured channels."]),
]),
("9. Handling Live Consultations", [
("ul", ["A consult request is routed to a matching available verified doctor; a "
"video room link and chat thread are created and the doctor is notified "
"(in-app log always; webhook/email if configured).",
"Operators ensure the video backend (Jitsi) is reachable; for production "
"use a self-hosted Jitsi via AGROSENSE_VIDEO_BASE."]),
]),
("10. Incident Response", [
("ul", ["Service down: check the process and logs; restart; confirm /health.",
"Web app blank: confirm the server is up and open /ui/ (root redirects).",
"A live feature is 'unavailable': verify the relevant key and network "
"egress; the core advisor keeps working offline.",
"Expired/invalid key: rotate the key in the environment and restart.",
"Bad knowledge entry causing wrong answers: edit/delete it in the Admin "
"tab (index rebuilds immediately) or restore the KB backup.",
"Abusive doctor application or rating: reject the doctor / remove the "
"entry; consider enabling authentication and rate limiting."]),
]),
("11. Backup and Recovery", [
("ol", ["Regularly back up the committed content: data/knowledge_base.json, "
"subsidies.json, finance.json and land_records.json.",
"Also back up the runtime state: plant_doctors.json (doctor registry + "
"ratings), clubs.json (clubs + posts), market_listings.json (trading) and "
"finance_applications.json (loan enquiries).",
"To recover: stop the service, restore the JSON files from backup, start "
"the service; the index rebuilds at boot.",
"Keep agri_experts.json under version control; the runtime files above are "
"auto-seeded (or created) if missing."]),
]),
("12. Routine Maintenance", [
("ul", ["Review and update the knowledge base as guidance changes.",
"Keep the curated content current: scheme details in subsidies.json, "
"loan products in finance.json, and state portals in land_records.json; "
"post scheme announcements from the Admin tab as they are released.",
"Review the loan enquiries lodged in the Finance tab "
"(GET /admin/finance/applications) and follow up.",
"Rotate the admin token periodically.",
"Review doctor ratings/reviews and trading listings for abuse.",
"Update dependencies and re-run the test suite + SPA smoke before "
"deploying.",
"Regenerate all documents (python scripts/build_docs.py) after "
"feature changes."]),
]),
("13. Change Management", [
("ol", ["Make changes in a non-production environment first.",
"Run python tests/test_rag.py and node web/smoke.mjs; run "
"scripts/evaluate.py to confirm quality targets.",
"Deploy during a low-traffic window; verify /health and key flows.",
"If a problem appears, roll back to the previous version and restore "
"backed-up data."]),
]),
("14. Compliance and Disclaimer", [
("p", "AgroSense provides decision support, not professional or medical "
"authority. Operators and doctors must ensure recommendations comply with "
"local agricultural regulations. Always confirm product names, dosages and "
"pre-harvest intervals before advising chemical use."),
]),
]
def main() -> int:
build_both(TECH_TITLE, TECH_SUBTITLE, TECH_SECTIONS, DOCS_DIR,
"AgroSense_Technical_Guide")
build_both(SOP_TITLE, SOP_SUBTITLE, SOP_SECTIONS, DOCS_DIR, "AgroSense_SOP")
return 0
if __name__ == "__main__":
raise SystemExit(main())
|