🌾 AgriBot — Full Landing Page & Technical Modules 🌾 एग्रीबॉट — पूर्ण लैंडिंग पेज और तकनीकी मॉड्यूल
Author’s Perspective लेखक का दृष्टिकोण
I built AgriBot (FarmerChatBot) as a hybrid Android + serverless AI platform that enables farmers to ask agricultural questions in Hindi and English, both via voice and text, and receive helpful, structured replies powered by Google Gemini LLMs. This case study is my complete documentation of the project — why I built it the way I did, the technical choices I made, the exact workflows and commands I used to set up infrastructure, the issues I faced during development, how I debugged and solved them, and the lessons I took away. मैंने एग्रीबॉट (फार्मरचैटबॉट) को एक हाइब्रिड एंड्रॉयड + सर्वरलेस AI प्लेटफॉर्म के रूप में बनाया, जो किसानों को हिंदी और अंग्रेजी में, वॉयस और टेक्स्ट दोनों के माध्यम से कृषि प्रश्न पूछने और Google Gemini LLMs द्वारा संचालित उपयोगी, संरचित जवाब प्राप्त करने में सक्षम बनाता है। यह केस स्टडी प्रोजेक्ट का मेरा पूरा दस्तावेज़ीकरण है — मैंने इसे इस तरह क्यों बनाया, मैंने जो तकनीकी विकल्प चुने, बुनियादी ढांचे को सेट अप करने के लिए उपयोग की गई सटीक कार्यप्रवाह और कमांड, विकास के दौरान सामना की गई समस्याएं, कैसे मैंने उन्हें डीबग किया और हल किया, और सीखे गए सबक।
This document is both a case study and a reproducible technical guide, structured around: यह दस्तावेज एक केस स्टडी और एक पुनरुत्पादनीय तकनीकी गाइड दोनों है, जो निम्नलिखित के आसपास संरचित है:
- Architecture & design decisions आर्किटेक्चर और डिज़ाइन निर्णय
- Detailed tech stack explanations विस्तृत तकनीकी स्टैक व्याख्या
- Setup & configuration commands सेटअप और कॉन्फ़िगरेशन कमांड
- Problems I faced, root causes, and how I solved them मुझे जिन समस्याओं का सामना करना पड़ा, उनके मूल कारण, और मैंने उन्हें कैसे हल किया
- Trade-offs & alternatives I considered मैंने जिन ट्रेड-ऑफ्स और विकल्पों पर विचार किया
- Actionable lessons for future projects भविष्य के प्रोजेक्ट्स के लिए कार्यसाध्य सबक
Project Vision and Problem Context प्रोजेक्ट विजन और समस्या संदर्भ
Overview अवलोकन
AgriBot was born from the observation that farmers need accessible, real-time agricultural knowledge but often face barriers with literacy, language, and digital interfaces. Most mobile solutions are text-heavy or English-only. I wanted to design a voice-first assistant that felt as natural as speaking to a person. एग्रीबॉट इस अवलोकन से उत्पन्न हुआ कि किसानों को सुलभ, वास्तविक समय में कृषि ज्ञान की आवश्यकता है, लेकिन वे अक्सर साक्षरता, भाषा और डिजिटल इंटरफेस के साथ बाधाओं का सामना करते हैं। अधिकांश मोबाइल समाधान टेक्स्ट-भारी या केवल अंग्रेजी में हैं। मैं एक वॉयस-फर्स्ट सहायक डिज़ाइन करना चाहता था जो किसी व्यक्ति से बात करने जितना स्वाभाविक लगे।
The goals of AgriBot were shaped by three priorities. The first was voice-first, multilingual UX: Hindi and English speech recognition, and Hindi text-to-speech replies. The second was lightweight APK distribution: the app needed to run smoothly even on mid-range or older Android phones. The third was scalability of AI compute: the heavy LLM logic had to be offloaded to a backend rather than bundled into the APK, so that the app remained small and secure. एग्रीबॉट के लक्ष्य तीन प्राथमिकताओं द्वारा आकार लिए गए थे। पहला था वॉयस-फर्स्ट, बहुभाषी UX: हिंदी और अंग्रेजी में भाषण पहचान, और हिंदी टेक्स्ट-टू-स्पीच जवाब। दूसरा था हल्का APK वितरण: ऐप को मध्यम-श्रेणी या पुराने एंड्रॉयड फोनों पर भी सुचारू रूप से चलना था। तीसरा था AI कम्प्यूट की स्केलेबिलिटी: भारी LLM तर्क को APK में शामिल करने के बजाय बैकएंड पर ऑफलोड करना था, ताकि ऐप छोटा और सुरक्षित रहे।
From these goals, AgriBot’s design crystallized as a hybrid mobile + cloud system: a native Android app for user interaction, with serverless backend APIs for large language model orchestration. इन लक्ष्यों से, एग्रीबॉट का डिज़ाइन एक हाइब्रिड मोबाइल + क्लाउड सिस्टम के रूप में स्पष्ट हुआ: उपयोगकर्ता इंटरैक्शन के लिए एक मूल एंड्रॉयड ऐप, और बड़े भाषा मॉडल ऑर्केस्ट्रेशन के लिए सर्वरलेस बैकएंड API।
================================================================================================================ AGRIBOT — EXTENDED WORKFLOW & LIFECYCLE (ASCII STORYBOARD) ================================================================================================================ LEGEND: [UI] = Visual element on device {Local} = Client-side logic / persistence / Chaquopy --> = data/intent flow / network transit [Srv] = Backend (API Gateway -> Lambda -> LLM) (Note) = developer / ops / product note / failure mode Symbols: ┌──┐ , └──┘ , ─── horizontal flows, ↕ vertical flows, ╔ block boundaries ========================================================================================================== TOP: App Landing / Chat Screen (initial UX & affordances) ========================================================================================================== ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────┐ | [APP HEADER] FarmerHelpChatBot | [Search 🔍] [Pinned ▸] [Controls ▾] | | ------------------------------------------------------------------------------------------------------- | | Suggested quick chips: [आर्टिफिशियल इंटेलिजेंस क्या है?] [जैविक खेती] [कीटनाशक क्या?] | | | | CHAT WINDOW (RecyclerView) | | ┌───────────────────────────────────────────────────────────────────────────────────────────────────┐ | | | BOT: (left bubble) "नमस्ते! किस विषय में मदद चाहिए?" | | | | ↳ under each message: [reactions row] [pin icon (visible on bot only)] [audio icon] | | | | USER: (right bubble) "बारिश में क्या उगाऊँ?" | | | | Typing animation: (animated three dots bubble when bot is responding) | | | └───────────────────────────────────────────────────────────────────────────────────────────────────┘ | | | | [Input box] "Type here..." [🎤 Mic] (hold/tap) [📨 Send] [AutoSpeak toggle] [AutoReply toggle] | └─────────────────────────────────────────────────────────────────────────────────────────────────────────┘ (User taps 🎤 Mic) --> PERMISSION + SPEECHFLOW (detailed in MODULE A) | v ========================================================================================================== MODULE A — Microphone & Speech Recognition Flow (permissions, partials, UX) ========================================================================================================== ┌──────────────────────────────────────────────────────────────┐ | [User taps Mic] | | 1) Check runtime permission: | | if (RECORD_AUDIO permission NOT granted) { | | show Android runtime permission dialog (system) | | - user Allow → proceed | | - user Deny → show friendly fallback toast: | | "Mic permission required for voice mode." | | } else proceed | | | | 2) Start SpeechRecognizer (ASR): | | - onReadyForSpeech: statusLabel = "Listening..." | | - onPartialResults: update EditText with partial text | | - onResults: final text -> insert into input | | - onError: show error & fallback to manual typing | | | | (UX) when partials appear: show ephemeral spinner + partial | | (Policy) if mic denied repeatedly: fall back to typed only | └──────────────────────────────────────────────────────────────┘ (User submits) --> CLIENT MESSAGE CREATION & UI UPDATE | v ========================================================================================================== MODULE B — Client Message Creation, Typing Animation & Local Persistence ========================================================================================================== ┌──────────────────────────────────────────────────────────────────────┐ | {Local} create MessageItem: | | id: UUID (string), text: rawText, textHtml: (from | | markdown formatter if backend returns markdown), | | isUser: true/false, createdAt: epoch-ms, reactions:[], | | pinned: false, isTyping: false | | | | UI change: | | - add user bubble (right) immediately | | - save messages -> SharedPreferences JSON (messages_json) | | | | Typing placeholder for bot reply: | | - insert MessageItem(isTyping=true, isUser=false, text="Typing...") | | - visually show three-dot animation | | | | (Note) keep local Chaquopy fallback on-device available | | if backend unreachable (see MODULE E) | └──────────────────────────────────────────────────────────────────────┘ --> NETWORK: call backend POST /prod (payload & headers) | v ========================================================================================================== MODULE C — Network Call & Request Contract (client → API) ========================================================================================================== ┌────────────────────────────────────────────────────────────────────────────────────────────────┐ | HTTP POST to BACKEND_URL (API Gateway) | | Headers: | | Content-Type: application/json | | (optional) X-Client-Version, X-Device-Locale, debug flag | | Body: | | { "message": "बरसात में क्या उगाऊँ?", "metadata": { "lang_hint":"hi", "session_id":"abc123" } } | | Timeout: 15s connect/read | | Error handling: | | 5xx -> show "Internal server error" fallback message | | 4xx -> parse body for error details (JSON) | | network timeout -> trigger Chaquopy fallback / canned | └────────────────────────────────────────────────────────────────────────────────────────────────┘ v [API Gateway] v ========================================================================================================== MODULE D — Server (Lambda) Processing, Prompting & LLM Invocation ========================================================================================================== ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────┐ | [Lambda] lambda_handler(event): | | 1) CORS/OPTIONS quick-return | | 2) _extract_message_from_event(event) -> robustly handle: raw JSON body, base64 body, form-encoded | | 3) Validate non-empty message, trim | | 4) Prompt engineering: | | prompt_template = "You are a helpful farmer assistant. Answer: {q}. Use structured bullets if needed." | | 5) Invoke LangChain/ChatGoogleGenerativeAI (gemini-1.5-flash) | | chain.invoke({"q": user_input}) -> result | | 6) Shape result: result.content or dict["content"] else str(result) | | 7) Return: HTTP 200 { "reply": "" } (json, ensure_ascii=False) | | 8) Logging: structured logs to CloudWatch (user-intent hash not raw PII) | | | | (Failures) LLM quota/exceptions -> friendly fallback message (quota-limit) | | (Security) API key stored in env var/secrets manager — not exposed to client | └───────────────────────────────────────────────────────────────────────────────────────────────────────────┘ v HTTP 200 { "reply": ... } | v ========================================================================================================== MODULE E — Client receives reply: formatting, markdown, TTS, reactions & display ========================================================================================================== ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ | On network success: | | 1) Remove typing placeholder (isTyping true) | | 2) Create MessageItem(isUser=false, text = reply) | | 3) Format: pass reply into markdown.py -> textHtml | | - bold, italics, code, bullets -> HTML-like strings | | 4) Insert into messages list (left bubble) | | 5) saveMessages() -> update SharedPreferences (messages_json) | | 6) show reactions row + pin icon (pin visible for AI msg) | | 7) If AutoSpeak ON -> TTS.speak(reply, locale=hi_IN) | | | | (Accessibility) TTS voice selection & rate available | | (UX) show small "source" tag if reply came from server | | | | (If backend returned structured JSON with "sections" + "bullets", render them with
and bullet styling) | └─────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ ========================================================================================================== MODULE F — Reactions, Pin Pairing, Edit, Delete, Pinned Window UI ========================================================================================================== ┌───────────────────────────────────────────────────────────────────────────────────────────────────┐ | Reactions: | | - Shortpress emoji from picker → toggle in m.reactions | | - UI shows emojis inline below the message | | - Stored in messages_json as array | | | | Pin Pairing (key UX requirement): | | - When pin toggled on bot message → find nearest prev | | user message and set both pinned=true | | - When unpin on bot message → set both pinned=false | | - When pin toggled on user message → find next bot and set both pinned | | - Rationale: preserve Q/A pair in pinned list | | | | PinnedActivity (pinned window): | | - reads messages_json -> filter pinned==true | | - shows cards: [User query] ↔ [Bot reply] | | - Each card: Unpin button (per-card) + Delete (remove pair) | | - No global "Unpin All" (per your request) | | | | Edit/Delete: | | - User message long-press -> Edit / Delete | | - Edit can "Save only" (update message text) or "Send as new" (submit to backend as fresh query) | | - Delete removes message (or pair if requested) | └───────────────────────────────────────────────────────────────────────────────────────────────────┘ ========================================================================================================== MODULE G — Search internals (how search works & advanced options) ========================================================================================================== ┌─────────────────────────────────────────────────────────────────────────────┐ | UI: typing into Search box has immediate feedback: | | - debounce 200ms, case-insensitive substring match | | - filteredMessages = messages.filter(m.text.toLowerCase().contains(query)) | | - highlight matched substrings in message TextView | | - preserve scroll offset when toggling search results | | | | Advanced / future: | | - tokenized/fuzzy search (Fuse.js or lucene-like on-device) | | - search index (persist index + updates) to speed up on large histories | | - server-search (if cross-device history sync planned) | └─────────────────────────────────────────────────────────────────────────────┘ ========================================================================================================== MODULE H — Offline fallback: Chaquopy local + Canned responses ========================================================================================================== ┌─────────────────────────────────────────────────────────────────────────────────────────┐ | If network fails / 5xx / timeout: | | 1) Try local Python module main.generate_response(text, lang) via Chaquopy | | 2) If Chaquopy returns non-empty -> use that (use markdown formatting too) | | 3) If Chaquopy fails -> check canned map of keywords and return human-friendly fallback | | 4) If all fails -> show "Sorry, cannot reach server. Try again later." | | | | (Note) Chaquopy provides quick offline prototyping but must be small & safe (no keys) | └─────────────────────────────────────────────────────────────────────────────────────────┘ ========================================================================================================== MODULE I — Persistence, Data Model & local storage layout ========================================================================================================== ┌──────────────────────────────────────────────────────────────────────────────────────┐ | SharedPreferences Key: "messages_json" -> JSON array of objects | | Message schema (example): | | { | | "id": "uuid-1234", | | "text": "बरसात में क्या उगाऊँ?", | | "textHtml": "बरसात ...", (created via markdown.py) | | "isUser": true/false, | | "createdAt": 169Xxxxx (epoch ms), | | "reactions": ["👍","❤️"], | | "pinned": false, | | "isTyping": false | | } | | (Note) when updating, preserve stable ids so pining and reactions remain consistent | └──────────────────────────────────────────────────────────────────────────────────────┘ ========================================================================================================== MODULE J — Observability, metrics, errors & security ========================================================================================================== ┌────────────────────────────────────────────────────────────────────────────────────────┐ | Observability: | | - CloudWatch: Lambda duration, error count, invocation rate | | - App: record metrics for latency (client→lambda roundtrip), TTS success, ASR errors | | - User analytics: most asked topics, pinned queries frequency, reaction counts | | | | Error handling: | | - Backend 5xx -> return friendly JSON + log full stack (no PII) | | - Client logs visible behind hidden debug toggle (dev builds) | | | | Security: | | - API keys stored in Lambda env/SecretsManager only | | - API Gateway: consider API key or JWT for production | | - No PII shipped in logs; optionally anonymize queries | └────────────────────────────────────────────────────────────────────────────────────────┘ ========================================================================================================== RIGHT: How different stakeholders see & use this flow (Users / Farmers / Hiring managers / Visitors) ========================================================================================================== ┌──────────────────────────────────────────────────────────────────────────────────────────────────────┐ | USER (Farmer) POV: | | - Simple flow: tap mic -> speak -> get reply in Hindi + TTS. | | - Benefits: localized farming tips, crop selection, pest control, soil and fertilizer advice. | | - UX notes: quick suggested chips, offline canned replies when network not available. | | | | HIRING MANAGER / TECH LEAD POV: | | - Architecture: Kotlin UI + Chaquopy for Python reuse, Lambda + LangChain for server prompts. | | - Key questions to ask developer: how do you handle: API key security, cold starts, prompt quality? | | - Assessment checkpoints: extensibility, tests around Chaquopy fallback, and prompt versioning. | | | | PRODUCT / MARKETING / VISITOR POV: | | - Landing-page narrative: voice-first, multilingual, offline-friendly, farmer-centric. | | - What to show: demo GIF of mic -> reply, metrics: avg latency, accuracy (user satisfaction). | | - Calls-to-action: "Try voice demo" (web), "Download APK" (store), "Request pilot" (enterprise). | └──────────────────────────────────────────────────────────────────────────────────────────────────────┘ ========================================================================================================== BOTTOM: Next steps / Improvements / Future roadmap (technical & research-level) ========================================================================================================== ┌───────────────────────────────────────────────────────────────────────────────────────────────────────┐ | 1) Improve on-device search: build lightweight inverted index, support fuzzy match & ranking. | | 2) Session memory: server-side conversation memory per session_id to provide context-aware replies. | | 3) Analytics: instrument top intents + auto-generate FAQ pages from pinned entries. | | 4) Scalability: provisioned concurrency for Lambda or migrate to a container-backed inference layer. | | 5) UX polish: message-level actions (share, forward), richer markdown rendering, multi-media support. | | 6) Safety & moderation: add content filters for disallowed agricultural advice or regulated content. | | 7) Sync: optional cloud sync of history (DynamoDB) for cross-device continuity (consent-based). | └───────────────────────────────────────────────────────────────────────────────────────────────────────┘
Module A — Microphone & Speech Recognition (Permissions + Live ASR) मॉड्यूल A — माइक्रोफोन और भाषण पहचान (अनुमतियां + लाइव ASR)
Intro (short): परिचय (संक्षिप्त):
I make voice the first-class input. when a farmer taps the mic, I check permissions, start ASR, show partials in the input box, and only submit the final recognized text as the query. मैं आवाज को प्रथम श्रेणी इनपुट बनाता हूं। जब एक किसान माइक पर टैप करता है, मैं अनुमतियां जांचता हूं, ASR शुरू करता हूं, इनपुट बॉक्स में आंशिक दिखाता हूं, और केवल अंतिम मान्यता प्राप्त पाठ को क्वेरी के रूप में सबमिट करता हूं।
How it works (flow): यह कैसे काम करता है (प्रवाह):
Tap 🎤 → check RECORD_AUDIO permission. टैप 🎤 → RECORD_AUDIO अनुमति जांचें।
If not granted → show system permission dialog and a friendly explainer; on deny show fallback call-to-action (type instead). यदि प्रदान नहीं की गई → सिस्टम अनुमति डायलॉग और एक दोस्ताना व्याख्याता दिखाएं; अस्वीकार पर फॉलबैक कॉल-टू-एक्शन दिखाएं (इसके बजाय टाइप करें)।
If granted → create SpeechRecognizer and set a RecognitionListener. यदि प्रदान की गई → SpeechRecognizer बनाएं और RecognitionListener सेट करें।
onReadyForSpeech → show “Listening…” UI. onReadyForSpeech → “सुन रहा हूं...” UI दिखाएं।
onPartialResults → show interim transcript in input box (debounced to avoid flicker). onPartialResults → इनपुट बॉक्स में अंतरिम ट्रांसक्रिप्ट दिखाएं (फ्लिकर से बचने के लिए डिबाउंस्ड)।
onResults → place final text into input and either auto-submit (if user expects) or wait for explicit Send. onResults → अंतिम पाठ को इनपुट में रखें और या तो ऑटो-सबमिट करें (यदि उपयोगकर्ता अपेक्षा करता है) या स्पष्ट भेजने की प्रतीक्षा करें।
onError → show friendly message & fallback to typed input / Chaquopy fallback. onError → दोस्ताना संदेश दिखाएं और टाइप्ड इनपुट / Chaquopy फॉलबैक पर वापस जाएं।
Implementation details & code pointers: कार्यान्वयन विवरण और कोड पॉइंटर्स:
Use SpeechRecognizer.createSpeechRecognizer(context) and RecognitionListener. SpeechRecognizer.createSpeechRecognizer(context) और RecognitionListener का उपयोग करें।
Keep a small debounce (100–250ms) before updating the EditText with partials. आंशिकों के साथ EditText अपडेट करने से पहले एक छोटा डिबाउंस (100–250ms) रखें।
Use ActivityCompat.requestPermissions(...) with a consistent REQUEST_CODE (e.g. 101). ActivityCompat.requestPermissions(...) का उपयोग एक सुसंगत REQUEST_CODE (उदा. 101) के साथ करें।
Show a short status label (Listening / Transcribing / Error) in the UI. UI में एक छोटा स्थिति लेबल (Listening / Transcribing / Error) दिखाएं।
Failure modes & how I handle them: विफलता मोड और मैं उन्हें कैसे संभालता हूं:
Permission permanently denied → show modal explaining how to enable in Settings. अनुमति स्थायी रूप से अस्वीकार → सेटिंग्स में सक्षम करने का तरीका बताने वाला मोडल दिखाएं।
No network for cloud ASR (if you use online ASR) → optional fallback to offline ASR or typed entry. क्लाउड ASR के लिए कोई नेटवर्क नहीं (यदि आप ऑनलाइन ASR का उपयोग करते हैं) → ऑफलाइन ASR या टाइप्ड एंट्री पर वैकल्पिक फॉलबैक।
Noisy audio → show “I’m having trouble hearing — please repeat” and log ASR confidence. शोरयुक्त ऑडियो → “मुझे सुनने में परेशानी हो रही है — कृपया दोहराएं” दिखाएं और ASR विश्वास लॉग करें।
Tips (practical): टिप्स (व्यावहारिक):
Keep partials visible — the UX feels much faster than showing nothing. आंशिकों को दृश्यमान रखें — UX कुछ भी न दिखाने से बहुत तेज लगता है।
Always expose a cancel/stop option while listening. सुनते समय हमेशा रद्द/रोक विकल्प उजागर करें।
Log ASR errors to help tune recognition for regional Hindi variants. क्षेत्रीय हिंदी प्रकारों के लिए पहचान को ट्यून करने में मदद के लिए ASR त्रुटियां लॉग करें।
Key info: मुख्य जानकारी:
Permission check → ContextCompat.checkSelfPermission
अनुमति जांच → ContextCompat.checkSelfPermission
Request code suggestion → 101 अनुरोध कोड सुझाव → 101
Debounce for partial updates → 100–250ms आंशिक अपडेट के लिए डिबाउंस → 100–250ms
Module B — Client Message Creation, Typing Animation & Local Persistence मॉड्यूल B — क्लाइंट संदेश निर्माण, टाइपिंग एनिमेशन और स्थानीय संग्रहण
Intro (short): परिचय (संक्षिप्त):
I update UI immediately (optimistic), persist every change locally, and show a typing placeholder so the user knows the bot is working. मैं UI को तुरंत अपडेट करता हूं (आशावादी), हर बदलाव को स्थानीय रूप से संरक्षित करता हूं, और एक टाइपिंग प्लेसहोल्डर दिखाता हूं ताकि उपयोगकर्ता जान सके कि बॉट काम कर रहा है।
How it works (flow): यह कैसे काम करता है (प्रवाह):
Create a MessageItem for the user with fields: id
, text, isUser, createdAt, reactions, pinned, isTyping.
उपयोगकर्ता के लिए MessageItem बनाएं जिसमें फ़ील्ड्स हों: id
, text, isUser, createdAt, reactions, pinned, isTyping।
Insert user message into the RecyclerView immediately. उपयोगकर्ता संदेश को RecyclerView में तुरंत डालें।
Persist messages to SharedPreferences as messages_json. संदेशों को SharedPreferences में messages_json के रूप में संरक्षित करें।
Insert a typing placeholder MessageItem(isTyping=true) for bot response. बॉट उत्तर के लिए एक टाइपिंग प्लेसहोल्डर MessageItem(isTyping=true) डालें।
Replace placeholder with the actual bot message on reply or remove on error. उत्तर पर प्लेसहोल्डर को वास्तविक बॉट संदेश से बदलें या त्रुटि पर हटाएं।
Implementation details & data model: कार्यान्वयन विवरण और डेटा मॉडल:
MessageItem shape (important fields): MessageItem आकार (महत्वपूर्ण फ़ील्ड्स):
id
:String, text:String, textHtml:String?, isUser:Boolean, createdAt:Long, reactions:Listid
:String, text:String, textHtml:String?, isUser:Boolean, createdAt:Long, reactions:List
Use JSONArray → SharedPreferences under key messages_json. JSONArray → SharedPreferences का उपयोग कुंजी messages_json के तहत करें।
For ID use stable string (UUID) not a timestamp-only long — ensures JSON equality and robust pairing. ID के लिए स्थिर स्ट्रिंग (UUID) का उपयोग करें न कि केवल टाइमस्टैम्प लॉन्ग — JSON समानता और मजबूत पेयरिंग सुनिश्चित करता है।
Save after every change: add/update/remove → call saveMessages()
.
हर बदलाव के बाद सहेजें: जोड़ें/अपडेट/हटाएं → saveMessages()
कॉल करें।
Failure modes & notes: विफलता मोड और नोट्स:
Race when concurrently adding messages → always generate unique IDs and synchronize writes (single-threaded UI thread is easiest). समवर्ती रूप से संदेश जोड़ते समय रेस → हमेशा अद्वितीय IDs उत्पन्न करें और लेखन को सिंक्रोनाइज़ करें (सिंगल-थ्रेडेड UI थ्रेड सबसे आसान है)।
Storage growth → prune history (e.g., keep last N messages) or compress. संग्रहण वृद्धि → इतिहास को छांटें (उदा., अंतिम N संदेश रखें) या संपीड़ित करें।
Tips (practical): टिप्स (व्यावहारिक):
Keep typing placeholder removal robust (remove the first isTyping true). टाइपिंग प्लेसहोल्डर हटाना मजबूत रखें (पहला isTyping true हटाएं)।
For UX, animate insertion (slide up) and use a subtle 3-dot typing animation. UX के लिए, इंसर्शन को एनिमेट करें (स्लाइड अप) और एक सूक्ष्म 3-डॉट टाइपिंग एनिमेशन का उपयोग करें।
When editing a message, update in place but preserve ID so pins + reactions remain attached. संदेश संपादित करते समय, जगह पर अपडेट करें लेकिन ID संरक्षित करें ताकि पिन + रिएक्शन्स जुड़े रहें।
Key info: मुख्य जानकारी:
Persistence key → "messages_json" संग्रहण कुंजी → "messages_json"
Use JSON array and preserve stable id values. JSON ऐरे का उपयोग करें और स्थिर id मान संरक्षित करें।
Save after every mutation to keep PinnedActivity accurate. PinnedActivity को सटीक रखने के लिए हर उत्परिवर्तन के बाद सहेजें।
Module C — Network Call & Request Contract (Client → API Gateway) मॉड्यूल C — नेटवर्क कॉल और अनुरोध अनुबंध (क्लाइंट → API गेटवे)
Intro (short): परिचय (संक्षिप्त):
I send a compact JSON POST to my API and handle timeouts, parse varied backend shapes, and fall back when necessary. मैं अपने API को एक कॉम्पैक्ट JSON POST भेजता हूं और टाइमआउट संभालता हूं, विभिन्न बैकएंड आकार पार्स करता हूं, और आवश्यकता पड़ने पर फॉलबैक करता हूं।
How it works (flow): यह कैसे काम करता है (प्रवाह):
POST to BACKEND_URL (API Gateway). Header: Content-Type: application/json. BACKEND_URL (API गेटवे) पर POST। हेडर: Content-Type: application/json।
Body: { "message":"…", "metadata": { "lang_hint":"hi", "session_id":"..."} }. बॉडी: { "message":"…", "metadata": { "lang_hint":"hi", "session_id":"..."} }।
Wait for response (connect/read timeouts ~ 15000 ms). On success parse JSON; on failure fallback to Chaquopy/canned. उत्तर की प्रतीक्षा करें (कनेक्ट/रीड टाइमआउट ~ 15000 ms)। सफलता पर JSON पार्स करें; विफलता पर Chaquopy/कैनेड पर फॉलबैक।
Implementation details & parsing: कार्यान्वयन विवरण और पार्सिंग:
Handle different shapes: {"reply": "…"} or layered responses from API Gateway (sometimes body-wrapped). विभिन्न आकार संभालें: {"reply": "…"} या API गेटवे से स्तरित उत्तर (कभी-कभी बॉडी-रैप्ड)।
Log raw response for debugging: keep developer debug panel accessible. डीबगिंग के लिए कच्चा उत्तर लॉग करें: डेवलपर डिबग पैनल को सुलभ रखें।
Use conn.responseCode to decide success (200–299) vs error stream parsing. conn.responseCode का उपयोग सफलता (200–299) बनाम त्रुटि स्ट्रीम पार्सिंग तय करने के लिए करें।
Failure modes & retry strategy: विफलता मोड और पुनः प्रयास रणनीति:
5xx or 429 → show friendly message & fall back. For 429 show specific rate-limit text. 5xx या 429 → दोस्ताना संदेश दिखाएं और फॉलबैक करें। 429 के लिए विशिष्ट दर-सीमा पाठ दिखाएं।
Timeouts → trigger offline fallback (Chaquopy/canned). टाइमआउट → ऑफलाइन फॉलबैक ट्रिगर करें (Chaquopy/कैनेड)।
JSON parse errors → log raw response for investigation. JSON पार्स त्रुटियां → जांच के लिए कच्चा उत्तर लॉग करें।
Tips (practical): टिप्स (व्यावहारिक):
Keep request timeouts conservative (15s) to avoid a blocked UI feel. अनुरोध टाइमआउट को रूढ़िवादी रखें (15s) ताकि ब्लॉक्ड UI महसूस से बचा जा सके।
Send minimal metadata to protect user privacy. उपयोगकर्ता गोपनीयता की रक्षा के लिए न्यूनतम मेटाडेटा भेजें।
On slow network, keep typing placeholder and update UI only when reply arrives or error occurs. धीमे नेटवर्क पर, टाइपिंग प्लेसहोल्डर रखें और UI को केवल तब अपडेट करें जब उत्तर आता है या त्रुटि होती है।
Key info: मुख्य जानकारी:
Timeout suggestion: connect/read 15000 ms टाइमआउट सुझाव: कनेक्ट/रीड 15000 ms
Typical body shape expected: {"reply":"... (markdown possible) ..."} अपेक्षित सामान्य बॉडी आकार: {"reply":"... (मार्कडाउन संभव) ..."}
Log raw response for the 5 most frequent failing requests. 5 सबसे लगातार विफल अनुरोधों के लिए कच्चा उत्तर लॉग करें।
Module D — Server (Lambda) Processing, Prompting & LLM Invocation मॉड्यूल D — सर्वर (Lambda) प्रसंस्करण, प्रॉम्प्टिंग और LLM आह्वान
Intro (short): परिचय (संक्षिप्त):
I keep the heavy LLM orchestration in Lambda — prompt engineering, language heuristics, and retries live server-side so the client stays small and secure. मैं भारी LLM ऑर्केस्ट्रेशन को Lambda में रखता हूं — प्रॉम्प्ट इंजीनियरिंग, भाषा ह्यूरिस्टिक्स, और पुनः प्रयास सर्वर-साइड रहते हैं ताकि क्लाइंट छोटा और सुरक्षित रहे।
How it works (flow): यह कैसे काम करता है (प्रवाह):
Lambda lambda_handler receives event → robust _extract_message_from_event. Lambda lambda_handler इवेंट प्राप्त करता है → मजबूत _extract_message_from_event।
Validate and sanitize input, construct a prompt template, and call the LangChain/Gemini code. इनपुट को मान्य और सैनिटाइज़ करें, एक प्रॉम्प्ट टेम्पलेट बनाएं, और LangChain/Gemini कोड कॉल करें।
Shape the reply and return {"reply": "..."}; on failure return friendly messages. उत्तर को आकार दें और {"reply": "..."} लौटाएं; विफलता पर दोस्ताना संदेश लौटाएं।
Implementation details (prompting and LLM): कार्यान्वयन विवरण (प्रॉम्प्टिंग और LLM):
Use a clear prompt template: instruct the model to prefer bullets, keep language consistent with input, and avoid unnecessary shortening. एक स्पष्ट प्रॉम्प्ट टेम्पलेट का उपयोग करें: मॉडल को बुलेट्स पसंद करने, भाषा को इनपुट के साथ सुसंगत रखने, और अनावश्यक छोटा करने से बचने का निर्देश दें।
Example LLM client: ChatGoogleGenerativeAI(model="gemini-1.5-flash"). उदाहरण LLM क्लाइंट: ChatGoogleGenerativeAI(model="gemini-1.5-flash")।
Wrap LLM call in try/catch — catch quota errors (429 / ResourceExhausted) and return a clear message. LLM कॉल को try/catch में लपेटें — कोटा त्रुटियां (429 / ResourceExhausted) पकड़ें और एक स्पष्ट संदेश लौटाएं।
Return JSON with ensure_ascii=False to preserve Hindi characters. हिंदी वर्णों को संरक्षित रखने के लिए ensure_ascii=False के साथ JSON लौटाएं।
Failure modes & mitigation: विफलता मोड और शमन:
Indentation / syntax errors in Lambda code (Python) → pre-check with python -m py_compile locally; use CI to validate. Lambda कोड (Python) में इंडेंटेशन / सिंटैक्स त्रुटियां → स्थानीय रूप से python -m py_compile से पूर्व जांच; मान्य करने के लिए CI का उपयोग करें।
Large layers causing cold starts → consider smaller layers, provisioned concurrency, or container-based services. बड़ी लेयर्स कोल्ड स्टार्ट्स का कारण बनती हैं → छोटी लेयर्स, प्रोविज़न्ड कॉनकरेंसी, या कंटेनर-आधारित सेवाओं पर विचार करें।
Exception trace → log stack traces to CloudWatch but don’t return raw stack to clients. अपवाद ट्रेस → CloudWatch में स्टैक ट्रेस लॉग करें लेकिन क्लाइंट्स को कच्चा स्टैक न लौटाएं।
Tips (practical): टिप्स (व्यावहारिक):
Version your prompt templates and keep them in a prompts/ folder so you can A/B test and revert. अपने प्रॉम्प्ट टेम्पलेट्स को संस्करण दें और उन्हें prompts/ फोल्डर में रखें ताकि आप A/B परीक्षण कर सकें और वापस कर सकें।
Add rate-limiting and quota handling with graceful messages. दर-सीमित और कोटा हैंडलिंग को सुंदर संदेशों के साथ जोड़ें।
Add small deterministic post-processing to strip unsafe content or trim enormous outputs. असुरक्षित सामग्री को हटाने या विशाल आउटपुट को ट्रिम करने के लिए छोटा निर्धारक पोस्ट-प्रोसेसिंग जोड़ें।
Key info: मुख्य जानकारी:
Model: gemini-1.5-flash used for balance of cost/perf. मॉडल: gemini-1.5-flash लागत/प्रदर्शन के संतुलन के लिए उपयोग किया गया।
Prompt template must accept {q} and instruct bullets/language. प्रॉम्प्ट टेम्पलेट {q} स्वीकार करना चाहिए और बुलेट्स/भाषा निर्देश दें।
Keep API key in env vars / AWS Secrets Manager — never in client. API कुंजी को env vars / AWS Secrets Manager में रखें — कभी क्लाइंट में नहीं।
Module E — Client receives reply: markdown.py formatting & TTS मॉड्यूल E — क्लाइंट उत्तर प्राप्त करता है: markdown.py फॉर्मेटिंग और TTS
Intro (short): परिचय (संक्षिप्त):
I render the bot’s text attractively, convert markdown into safe HTML for TextView, and optionally speak the answer using TTS. मैं बॉट के पाठ को आकर्षक रूप से रेंडर करता हूं, मार्कडाउन को TextView के लिए सुरक्षित HTML में परिवर्तित करता हूं, और वैकल्पिक रूप से TTS का उपयोग करके उत्तर बोलता हूं।
How it works (flow): यह कैसे काम करता है (प्रवाह):
On reply: remove typing placeholder; run the reply through markdown.py to generate textHtml. उत्तर पर: टाइपिंग प्लेसहोल्डर हटाएं; उत्तर को markdown.py के माध्यम से चलाकर textHtml उत्पन्न करें।
Insert bot MessageItem with text and textHtml. text और textHtml के साथ बॉट MessageItem डालें।
If AutoSpeak is enabled → pass reply to TextToSpeech.speak() with correct locale. यदि AutoSpeak सक्षम है → उत्तर को सही लोकेल के साथ TextToSpeech.speak() में पास करें।
Implementation details (markdown & render): कार्यान्वयन विवरण (मार्कडाउन और रेंडर):
markdown.py currently converts **bold**, *italic*, code', and bullets → HTML +
' for newlines.
markdown.py वर्तमान में **bold**, *italic*, code', और - बुलेट्स → HTML +
'न्यूलाइंस के लिए परिवर्तित करता है।
Render on Android using Html.fromHtml(textHtml, Html.FROM_HTML_MODE_LEGACY). एंड्रॉयड पर Html.fromHtml(textHtml, Html.FROM_HTML_MODE_LEGACY) का उपयोग करके रेंडर करें।
Keep markdown subset small for security and compatibility. सुरक्षा और संगतता के लिए मार्कडाउन सबसेट छोटा रखें।
Failure modes & UI polish: विफलता मोड और UI पॉलिश:
Long replies → paginate visually or allow “expand/collapse.” लंबे उत्तर → दृश्य रूप से पेजिनेट करें या “विस्तार/संक्षिप्त” की अनुमति दें।
Lists/nested lists need better conversion: consider supporting numbered lists and blockquotes later. सूचियां/नेस्टेड सूचियां बेहतर रूपांतरण की आवश्यकता: बाद में क्रमांकित सूचियां और ब्लॉककोट्स का समर्थन करने पर विचार करें।
TTS accents: map language detection (lang_hint) to TTS locale (hi_IN vs en_IN). TTS उच्चारण: भाषा पहचान (lang_hint) को TTS लोकेल (hi_IN बनाम en_IN) से मैप करें।
Tips (practical): टिप्स (व्यावहारिक):
Show a tiny “source” badge (server / local fallback) to increase transparency. पारदर्शिता बढ़ाने के लिए एक छोटा “स्रोत” बैज (सर्वर / स्थानीय फॉलबैक) दिखाएं।
Provide accessibility options for TTS rate and voice choice. TTS दर और आवाज विकल्प के लिए पहुंच विकल्प प्रदान करें।
Sanitize HTML produced by markdown.py — only allow safe tags. markdown.py द्वारा उत्पन्न HTML को सैनिटाइज़ करें — केवल सुरक्षित टैग की अनुमति दें।
Key info: मुख्य जानकारी:
Markdown → HTML (client-side markdown.py or server-side). मार्कडाउन → HTML (क्लाइंट-साइड markdown.py या सर्वर-साइड)।
Render method on Android: Html.fromHtml(...). एंड्रॉयड पर रेंडर विधि: Html.fromHtml(...)।
TTS engine: TextToSpeech, locale set to new Locale("hi","IN") for Hindi. TTS इंजन: TextToSpeech, हिंदी के लिए लोकेल नए Locale("hi","IN") पर सेट।
Module F — Reactions, Pin Pairing, Edit, Delete, Pinned Window UI मॉड्यूल F — रिएक्शन्स, पिन पेयरिंग, संपादित करें, हटाएं, पिन्ड विंडो UI
Intro (short): परिचय (संक्षिप्त):
I let users react, pin (pairing Q/A), edit their messages, and view pinned Q/A pairs in a dedicated window; all actions persist and the pin pairs are the central UX for later reference. मैं उपयोगकर्ताओं को रिएक्ट करने, पिन करने (Q/A पेयरिंग), उनके संदेशों को संपादित करने, और समर्पित विंडो में पिन्ड Q/A पेयर देखने की अनुमति देता हूं; सभी क्रियाएं संरक्षित रहती हैं और पिन पेयर बाद के संदर्भ के लिए केंद्रीय UX हैं।
How it works (flow): यह कैसे काम करता है (प्रवाह):
Reactions: open emoji picker → toggle emoji in m.reactions → update and persist. रिएक्शन्स: इमोजी पिकर खोलें → m.reactions में इमोजी टॉगल करें → अपडेट और संरक्षित करें।
Pin pairing: pin a bot message → find the nearest preceding user message → set both pinned=true. पिन पेयरिंग: बॉट संदेश पिन करें → निकटतम पूर्ववर्ती उपयोगकर्ता संदेश ढूंढें → दोनों pinned=true सेट करें।
Pinned window: read messages_json and show only pinned==true entries as paired cards. पिन्ड विंडो: messages_json पढ़ें और केवल pinned==true एंट्रीज को पेयर्ड कार्ड्स के रूप में दिखाएं।
Implementation details (pin pairing algorithm): कार्यान्वयन विवरण (पिन पेयरिंग एल्गोरिदम):
When toggling pin on a message: संदेश पर पिन टॉगल करते समय:
If message is bot → iterate backwards to first isUser==true and set that user message pinned same as bot. यदि संदेश बॉट है → पहले isUser==true तक पीछे की ओर इटरेट करें और उस उपयोगकर्ता संदेश को बॉट के समान पिन्ड सेट करें।
If message is user → iterate forward to first isUser==false (bot) and set bot pinned to match. यदि संदेश उपयोगकर्ता है → पहले isUser==false (बॉट) तक आगे इटरेट करें और बॉट पिन्ड को मैच करने के लिए सेट करें।
Avoid mass operations: provide per-card Unpin button in PinnedActivity (you asked to remove global “Unpin All”). मास ऑपरेशन्स से बचें: PinnedActivity में प्रति-कार्ड अनपिन बटन प्रदान करें (आपने ग्लोबल “Unpin All” हटाने के लिए कहा था)।
UI behaviors & access patterns: UI व्यवहार और पहुंच पैटर्न:
Pin icon is visible on bot messages (primary) but allow pinning user message too (pairing handled). पिन आइकन बॉट संदेशों पर दृश्यमान है (प्राथमिक) लेकिन उपयोगकर्ता संदेश को भी पिन करने की अनुमति दें (पेयरिंग संभाली गई)।
Long-press: लॉन्ग-प्रेस:
bot: show only “Delete message” (per your spec). बॉट: केवल “Delete message” दिखाएं (आपके स्पेक के अनुसार)।
user: allow “Edit / Delete”. उपयोगकर्ता: “Edit / Delete” की अनुमति दें।
PinnedActivity displays side-by-side query and reply cards with “Unpin” and “Delete Pair” actions. PinnedActivity क्वेरी और उत्तर कार्ड्स को साइड-बाय-साइड दिखाता है जिसमें “Unpin” और “Delete Pair” क्रियाएं हैं।
Failure modes & consistency: विफलता मोड और सुसंगतता:
If pairs are not found (edge cases) → pin only the current message, but log as orphan pin to troubleshoot. यदि पेयर नहीं मिलते (एज केस) → केवल वर्तमान संदेश पिन करें, लेकिन समस्या निवारण के लिए अनाथ पिन के रूप में लॉग करें।
Ensure stable id
across sessions to keep pinned states persistent.
सत्रों में स्थिर id
सुनिश्चित करें ताकि पिन्ड स्थिति संरक्षित रहे।
Tips (practical): टिप्स (व्यावहारिक):
When creating pinned list, show the timestamp and a short excerpt to help scanning. पिन्ड सूची बनाते समय, टाइमस्टैम्प और एक छोटा अंश दिखाएं स्कैनिंग में मदद के लिए।
Expose “Add to FAQ” later: collect frequently pinned Q/A to auto-generate FAQs. बाद में “Add to FAQ” उजागर करें: लगातार पिन्ड Q/A एकत्र करें ऑटो-जनरेट FAQs के लिए।
Test pin/unpin with migration scenarios — if you change the schema add schema_version to messages. माइग्रेशन परिदृश्यों के साथ पिन/अनपिन का परीक्षण करें — यदि आप स्कीमा बदलते हैं तो संदेशों में schema_version जोड़ें।
Key info: मुख्य जानकारी:
Pinned flag stored per message in messages_json. पिन्ड फ्लैग प्रति संदेश messages_json में संग्रहीत।
Pairing logic depends on ordering in message array — preserve order on save. पेयरिंग लॉजिक संदेश ऐरे में क्रम पर निर्भर करता है — सहेजने पर क्रम संरक्षित करें।
Module G — Search Internals (temporary WhatsApp-style / local search) मॉड्यूल G — खोज आंतरिक (अस्थायी व्हाट्सएप-शैली / स्थानीय खोज)
Intro (short): परिचय (संक्षिप्त):
I implement fast on-device search so farmers can quickly find prior queries. It’s simple substring now, but built so I can evolve to fuzzy indexing. मैं डिवाइस पर तेज खोज लागू करता हूं ताकि किसान पूर्व क्वेरी जल्दी ढूंढ सकें। यह अब सरल सबस्ट्रिंग है, लेकिन फजी इंडेक्सिंग में विकसित होने के लिए बनाया गया है।
How it works (flow): यह कैसे काम करता है (प्रवाह):
User types into Search → TextWatcher triggers filterMessages(query) with debounce. उपयोगकर्ता खोज में टाइप करता है → TextWatcher डिबाउंस के साथ filterMessages(query) ट्रिगर करता है।
filteredMessages = messages.filter { m.text.lowercase().contains(query) }. filteredMessages = messages.filter { m.text.lowercase().contains(query) }।
Adapter shows filtered list and we highlight matched substrings. एडाप्टर फ़िल्टर्ड सूची दिखाता है और हम मिलान वाली सबस्ट्रिंग्स को हाइलाइट करते हैं।
Implementation details & optimizations: कार्यान्वयन विवरण और अनुकूलन:
Debounce input: 150–300ms to avoid heavy recompute while typing. इनपुट डिबाउंस: टाइपिंग के दौरान भारी रीकंप्यूट से बचने के लिए 150–300ms।
Highlight matches using SpannableString and BackgroundColorSpan. SpannableString और BackgroundColorSpan का उपयोग करके मिलान हाइलाइट करें।
Keep filtered list separate to avoid mutating main messages. मुख्य संदेशों को उत्परिवर्तित करने से बचने के लिए फ़िल्टर्ड सूची अलग रखें।
Future enrichment (research-grade): भविष्य संवर्धन (शोध-ग्रेड):
Implement a tiny inverted index on device for tokenized search (fast for large histories). टोकनाइज्ड खोज के लिए डिवाइस पर एक छोटा इनवर्टेड इंडेक्स लागू करें (बड़े इतिहास के लिए तेज)।
Use Fuse-like fuzzy search or trigram index for tolerance to typos. टाइपो सहनशीलता के लिए Fuse-जैसे फजी खोज या ट्राइग्राम इंडेक्स का उपयोग करें।
Optionally provide server search and cross-device sync if history grows big. यदि इतिहास बड़ा हो जाता है तो वैकल्पिक रूप से सर्वर खोज और क्रॉस-डिवाइस सिंक प्रदान करें।
Failure modes & UX notes: विफलता मोड और UX नोट्स:
Large histories → initial full-scan could block UI — compute on background thread. बड़े इतिहास → प्रारंभिक पूर्ण-स्कैन UI को ब्लॉक कर सकता है — बैकग्राउंड थ्रेड पर गणना करें।
When search query is empty, revert to full messages and restore scroll position. जब खोज क्वेरी खाली हो, पूर्ण संदेशों पर वापस जाएं और स्क्रॉल स्थिति बहाल करें।
Tips (practical): टिप्स (व्यावहारिक):
Keep search case-insensitive for Hindi and English; normalize diacritics where needed. हिंदी और अंग्रेजी के लिए खोज केस-इंसेंसिटिव रखें; जहां आवश्यक हो डायक्रिटिक्स को सामान्य करें।
Provide quick “search chips” (recent searches / pinned categories) for power users. पावर उपयोगकर्ताओं के लिए त्वरित “खोज चिप्स” (हाल की खोजें / पिन्ड श्रेणियां) प्रदान करें।
Key info: मुख्य जानकारी:
Debounce: 150–300ms डिबाउंस: 150–300ms
Highlighting: SpannableString on Android हाइलाइटिंग: एंड्रॉयड पर SpannableString
Keep search purely client-side for privacy unless user opts in for sync. गोपनीयता के लिए खोज को पूरी तरह क्लाइंट-साइड रखें जब तक उपयोगकर्ता सिंक के लिए ऑप्ट इन न करे।
Module H — Offline fallback: Chaquopy local + Canned responses मॉड्यूल H — ऑफलाइन फॉलबैक: Chaquopy स्थानीय + कैनेड उत्तर
Intro (short): परिचय (संक्षिप्त):
If the backend is unreachable, I gracefully fallback to on-device Python (Chaquopy) or a small canned keyword map so the app still helps. यदि बैकएंड पहुंच से बाहर है, मैं डिवाइस पर Python (Chaquopy) या एक छोटे कैनेड कीवर्ड मैप पर सुंदर रूप से फॉलबैक करता हूं ताकि ऐप अभी भी मदद करे।
How it works (flow): यह कैसे काम करता है (प्रवाह):
Primary: network call (Module C). प्राथमिक: नेटवर्क कॉल (मॉड्यूल C)।
On failure/timeouts: try Chaquopy module main.generate_response(input, lang). विफलता/टाइमआउट पर: Chaquopy मॉड्यूल main.generate_response(input, lang) आजमाएं।
If Chaquopy fails or returns empty → check canned map by keyword → return canned reply. यदि Chaquopy विफल होता है या खाली लौटाता है → कीवर्ड द्वारा कैनेड मैप जांचें → कैनेड उत्तर लौटाएं।
If all fail → show “Unable to reach server” and keep typing placeholder removal/cleanup. यदि सभी विफल → “सर्वर तक पहुंचने में असमर्थ” दिखाएं और टाइपिंग प्लेसहोल्डर हटाना/क्लीनअप रखें।
Implementation details & safety: कार्यान्वयन विवरण और सुरक्षा:
Chaquopy code must contain no keys/credentials and only lightweight logic for canned responses or simple templates. Chaquopy कोड में कोई कुंजी/क्रेडेंशियल नहीं होना चाहिए और केवल कैनेड उत्तरों या सरल टेम्पलेट्स के लिए हल्का लॉजिक।
Canned map: small Map
Always log fallback cases for analytics. एनालिटिक्स के लिए हमेशा फॉलबैक मामलों को लॉग करें।
Failure modes: विफलता मोड:
Chaquopy not installed/available on device → catch exception and fallback immediately to canned. Chaquopy डिवाइस पर स्थापित/उपलब्ध नहीं → अपवाद पकड़ें और तुरंत कैनेड पर फॉलबैक करें।
Chaquopy output poor quality → degrade gracefully and encourage user to try again when online. Chaquopy आउटपुट खराब गुणवत्ता → सुंदर रूप से डिग्रेड करें और उपयोगकर्ता को ऑनलाइन होने पर फिर से प्रयास करने के लिए प्रोत्साहित करें।
Tips (practical): टिप्स (व्यावहारिक):
Use Chaquopy for predictable short replies only — don’t try to emulate full Gemini quality offline. Chaquopy का उपयोग केवल पूर्वानुमानित छोटे उत्तरों के लिए करें — ऑफलाइन पूर्ण Gemini गुणवत्ता की नकल करने की कोशिश न करें।
Keep canned map curated for common farmer intents (soil, rainfall, seed varieties). सामान्य किसान इंटेंट्स (मिट्टी, वर्षा, बीज किस्में) के लिए कैनेड मैप क्यूरेटेड रखें।
Key info: मुख्य जानकारी:
Fallback priority: Network → Chaquopy → Canned → Error message. फॉलबैक प्राथमिकता: नेटवर्क → Chaquopy → कैनेड → त्रुटि संदेश।
Log fallback events to know how often offline flows are used. ऑफलाइन प्रवाह कितनी बार उपयोग किए जाते हैं जानने के लिए फॉलबैक इवेंट्स लॉग करें।
Module I — Persistence, Data Model & Local Storage Layout मॉड्यूल I — संग्रहण, डेटा मॉडल और स्थानीय संग्रहण लेआउट
Intro (short): परिचय (संक्षिप्त):
I persist conversation state locally as a JSON array so pins, reactions, edits, and history survive restarts and can be inspected by the pinned screen. मैं वार्तालाप स्थिति को स्थानीय रूप से JSON ऐरे के रूप में संरक्षित करता हूं ताकि पिन, रिएक्शन्स, संपादन, और इतिहास रीस्टार्ट से बचे रहें और पिन्ड स्क्रीन द्वारा निरीक्षण किया जा सके।
How it works (flow): यह कैसे काम करता है (प्रवाह):
Every mutation calls saveMessages()
→ writes messages_json in SharedPreferences (stringified JSON).
हर उत्परिवर्तन saveMessages()
कॉल करता है → SharedPreferences में messages_json लिखता है (स्ट्रिंगिफाइड JSON)।
On start → loadMessages() parses JSON and recreates list. स्टार्ट पर → loadMessages() JSON पार्स करता है और सूची पुनर्निर्मित करता है।
Schema & example: स्कीमा और उदाहरण:
Message object keys: संदेश ऑब्जेक्ट कुंजियां:
id
(string UUID), text (raw), textHtml (optional), isUser (bool), createdAt (epoch ms), reactions (array of emoji strings), pinned (bool), isTyping (bool), schema_version (optional).
id
(string UUID), text (raw), textHtml (optional), isUser (bool), createdAt (epoch ms), reactions (array of emoji strings), pinned (bool), isTyping (bool), schema_version (optional)।
Keep schema_version to handle future migrations. भविष्य माइग्रेशन संभालने के लिए schema_version रखें।
Example item: उदाहरण आइटम:
{"id":"uuid-1","text":"बरसात में क्या उगाऊँ?","isUser":true,"createdAt":169..., "reactions":["👍"], "pinned":false} {"id":"uuid-1","text":"बरसात में क्या उगाऊँ?","isUser":true,"createdAt":169..., "reactions":["👍"], "pinned":false}
Data hygiene & growth: डेटा स्वच्छता और वृद्धि:
Keep retention policy: e.g., last 200 messages or last 30 days. रिटेंशन नीति रखें: उदा., अंतिम 200 संदेश या अंतिम 30 दिन।
Option: compress JSON or use file storage with SQLite for larger histories and indexing. विकल्प: बड़े इतिहास और इंडेक्सिंग के लिए JSON संपीड़ित करें या SQLite के साथ फाइल संग्रहण का उपयोग करें।
Tips (practical): टिप्स (व्यावहारिक):
Always write to preferences on UI thread (simple) or offload to a background thread with a queue to avoid blocking on large writes. हमेशा UI थ्रेड पर प्रेफरेंस में लिखें (सरल) या बड़े लेखनों पर ब्लॉकिंग से बचने के लिए बैकग्राउंड थ्रेड पर ऑफलोड करें क्यू के साथ।
Maintain insertion order to preserve pairing logic. पेयरिंग लॉजिक संरक्षित करने के लिए इंसर्शन क्रम बनाए रखें।
Key info: मुख्य जानकारी:
Preference key: "messages_json" प्रेफरेंस कुंजी: "messages_json"
Use UUID strings for id
id
के लिए UUID स्ट्रिंग्स का उपयोग करें
Consider schema_version and migration logic for long-lived apps. लंबे समय तक जीवित ऐप्स के लिए schema_version और माइग्रेशन लॉजिक पर विचार करें।
Module J — Observability, Metrics, Errors & Security मॉड्यूल J — निरीक्षणीयता, मेट्रिक्स, त्रुटियां और सुरक्षा
Intro (short): परिचय (संक्षिप्त):
I monitor and secure the whole stack: Lambda metrics and app-side metrics, robust logging, and secrets kept out of the client. मैं पूरे स्टैक की निगरानी और सुरक्षा करता हूं: Lambda मेट्रिक्स और ऐप-साइड मेट्रिक्स, मजबूत लॉगिंग, और क्लाइंट से बाहर रखी गई रहस्य।
What I measure (metrics): मैं क्या मापता हूं (मेट्रिक्स):
Backend: Lambda invocation count, p95/p50 latency, error count, throttles (429), cold start rate. बैकएंड: Lambda आह्वान गिनती, p95/p50 लेटेंसी, त्रुटि गिनती, थ्रॉटल्स (429), कोल्ड स्टार्ट दर।
App: roundtrip latency (send→reply), ASR error rates, TTS success, number of pinned items, reaction counts. ऐप: राउंडट्रिप लेटेंसी (भेजें→उत्तर), ASR त्रुटि दरें, TTS सफलता, पिन्ड आइटम्स की संख्या, रिएक्शन गिनतियां।
Product: top pinned queries, frequent keywords for FAQ generation. उत्पाद: शीर्ष पिन्ड क्वेरी, FAQ जनरेशन के लिए लगातार कीवर्ड।
Error handling & alerts: त्रुटि हैंडलिंग और अलर्ट:
CloudWatch alarms on error rate and latency thresholds. त्रुटि दर और लेटेंसी थ्रेशोल्ड पर CloudWatch अलार्म।
Sentry or similar on the client to capture crashes and stack traces. क्लाइंट पर Sentry या समान क्रैश और स्टैक ट्रेस कैप्चर करने के लिए।
For LLM exceptions (quota), return friendly fallback messages and log the failure. LLM अपवादों (कोटा) के लिए, दोस्ताना फॉलबैक संदेश लौटाएं और विफलता लॉग करें।
Security & privacy (musts): सुरक्षा और गोपनीयता (आवश्यक):
Never embed API keys in APK. कभी API कुंजियां APK में एम्बेड न करें।
Keep model keys in Lambda env or Secrets Manager. मॉडल कुंजियां Lambda env या Secrets Manager में रखें।
If deploying to pilot users, use an API key or Cognito/JWT to limit access. पायलट उपयोगकर्ताओं पर तैनाती करते समय, पहुंच सीमित करने के लिए API कुंजी या Cognito/JWT का उपयोग करें।
Anonymize or hash PII in logs; provide user opt-out for analytics. लॉग्स में PII को अनामित या हैश करें; एनालिटिक्स के लिए उपयोगकर्ता ऑप्ट-आउट प्रदान करें।
Tips (practical): टिप्स (व्यावहारिक):
Instrument fallback events (Chaquopy/canned) separately to see how often server calls fail. फॉलबैक इवेंट्स (Chaquopy/कैनेड) को अलग से इंस्ट्रूमेंट करें ताकि देख सकें कि सर्वर कॉल कितनी बार विफल होते हैं।
Keep a lightweight developer debug mode that dumps raw responses (only in dev builds). एक हल्का डेवलपर डिबग मोड रखें जो कच्चे उत्तर डंप करता है (केवल dev बिल्ड्स में)।
Rate-limit at API Gateway to avoid abuse. दुरुपयोग से बचने के लिए API गेटवे पर दर-सीमित करें।
Key info: मुख्य जानकारी:
Use CloudWatch + alarms for backend. बैकएंड के लिए CloudWatch + अलार्म का उपयोग करें।
Use secure storage for secrets: AWS Secrets Manager or environment variables (never code). रहस्यों के लिए सुरक्षित संग्रहण का उपयोग करें: AWS Secrets Manager या पर्यावरण चर (कभी कोड नहीं)।
Track important product metrics: pinned_count, avg_latency_ms, asr_error_rate. महत्वपूर्ण उत्पाद मेट्रिक्स ट्रैक करें: pinned_count, avg_latency_ms, asr_error_rate।
Final “From my perspective” Implementation Checklist (quick actionable) अंतिम “मेरे दृष्टिकोण से” कार्यान्वयन चेकलिस्ट (त्वरित कार्यसाध्य)
- ✅ Build robust permission flow and partial ASR updates (Module A). ✅ मजबूत अनुमति प्रवाह और आंशिक ASR अपडेट बनाएं (मॉड्यूल A)।
- ✅ Implement optimistic UI + typing placeholder + stable IDs (Module B). ✅ आशावादी UI + टाइपिंग प्लेसहोल्डर + स्थिर IDs लागू करें (मॉड्यूल B)।
- ✅ Harden network call parsing and conservative timeouts (Module C). ✅ नेटवर्क कॉल पार्सिंग को मजबूत करें और रूढ़िवादी टाइमआउट (मॉड्यूल C)।
- ✅ Keep prompt templates versioned and handle LLM errors gracefully (Module D). ✅ प्रॉम्प्ट टेम्पलेट्स को संस्करणित रखें और LLM त्रुटियों को सुंदर रूप से संभालें (मॉड्यूल D)।
- ✅ Use markdown.py HTML + TTS locale mapping for polished response rendering (Module E). ✅ पॉलिश्ड उत्तर रेंडरिंग के लिए markdown.py HTML + TTS लोकेल मैपिंग का उपयोग करें (मॉड्यूल E)।
- ✅ Pin pairing algorithm implemented and PinnedActivity uses per-card Unpin (Module F). ✅ पिन पेयरिंग एल्गोरिदम लागू किया गया और PinnedActivity प्रति-कार्ड अनपिन का उपयोग करता है (मॉड्यूल F)।
- ✅ Fast client-side search with debounce and highlight; plan for fuzzy index (Module G). ✅ डिबाउंस और हाइलाइट के साथ तेज क्लाइंट-साइड खोज; फजी इंडेक्स की योजना (मॉड्यूल G)।
- ✅ Chaquopy + canned fallback with logging to reduce “internal server” UX (Module H). ✅ “आंतरिक सर्वर” UX को कम करने के लिए लॉगिंग के साथ Chaquopy + कैनेड फॉलबैक (मॉड्यूल H)।
- ✅ Persistent messages_json plus schema versioning and prune policy (Module I). ✅ संरक्षित messages_json प्लस स्कीमा संस्करणिंग और छंटाई नीति (मॉड्यूल I)।