File size: 5,728 Bytes
207e13d
c410e1e
 
9b73f19
fc3f34d
6b008eb
 
fdc93e1
fc3f34d
c48deb1
9b73f19
bbe2a10
207e13d
fc1d30e
c410e1e
3eb2b46
8c9b31f
c410e1e
8c9b31f
c410e1e
 
8c9b31f
 
 
 
c410e1e
8c9b31f
c410e1e
fc1d30e
 
8059126
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fc1d30e
 
8ea24f3
fc1d30e
d3339a5
 
fc1d30e
c410e1e
 
8c9b31f
fc1d30e
8c9b31f
f3ebf4f
 
 
 
243e878
 
 
 
 
 
f3ebf4f
 
8ea24f3
 
 
 
 
 
 
 
 
d3339a5
6b008eb
d3339a5
8c9b31f
fc1d30e
 
c410e1e
 
 
 
52d1ebd
df9ee9f
8c9b31f
1dc646a
b628075
ae29635
d3339a5
fc1d30e
 
207e13d
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
import os
from google import genai
from google.genai import types

# -------------------------------------------------------------------------
# LLM: Google Gemini Flash
# - Excellent Hindi / Hinglish instruction following
# - Requires GOOGLE_API_KEY in Space secrets
# -------------------------------------------------------------------------
MODEL_NAME = "gemini-3-flash-preview"

_FALLBACK_NO_KEY    = "माफ़ करें, AI सेटअप नहीं हुआ। कृपया बाद में कोशिश करें।"
_FALLBACK_LLM_ERROR = "माफ़ करें, जानकारी लाने में समस्या हुई। कृपया दोबारा पूछें।"

_client = None


def _get_client():
    """Lazily initialises the Gemini client (once per process)."""
    global _client
    if _client is None:
        api_key = os.environ.get("GOOGLE_API_KEY")
        if not api_key:
            print("[LLM] Warning: GOOGLE_API_KEY not set.")
            return None
        _client = genai.Client(api_key=api_key)
        print(f"[LLM] Gemini {MODEL_NAME} ready.")
    return _client


def correct_hindi_query(raw_transcript: str) -> str:
    """
    Uses the LLM to quickly fix phonetic spelling mistakes from the Speech-to-Text engine
    before doing the vector search. For example, 'laan' -> 'loan', 'fiks dipojt' -> 'FD'.
    """
    client = _get_client()
    if not client:
        return raw_transcript

    prompt = (
        "You are an expert at fixing phonetic Hindi speech-to-text spelling mistakes.\n"
        "The user is a rural Indian farmer asking a banking question. The STT engine transcribed "
        "their voice with typos. For example, they might have said 'loan' but it transcribed as 'laan', "
        "or 'fixed deposit' as 'fiks dipojat'.\n\n"
        f"Original Transcript: '{raw_transcript}'\n\n"
        "Task:\n"
        "1. Fix any obvious banking term mispronunciations.\n"
        "2. Keep the query in Devanagari Hindi.\n"
        "3. Do NOT answer the question. Only output the corrected query string.\n"
        "4. If no correction is needed, just output the original string.\n\n"
        "Corrected Query:"
    )

    try:
        response = client.models.generate_content(
            model=MODEL_NAME,
            contents=prompt,
            config=types.GenerateContentConfig(
                max_output_tokens=100,
                temperature=0.0,
            ),
        )
        corrected = (response.text or "").strip()
        return corrected if corrected else raw_transcript
    except Exception as exc:
        print(f"[LLM] Query correction error: {exc}")
        return raw_transcript


def generate_hindi_response(hindi_question: str, english_context: str, history: list = None) -> str:
    """
    Generates a warm, conversational Hindi answer using FAQ context.
    Designed to sound like a helpful, friendly bank employee — not a robot.
    """
    client = _get_client()
    if not client:
        return _FALLBACK_NO_KEY

    prompt = (
        "You are 'सहायक', a helpful banking assistant for rural Indian farmers.\n"
        "Explain things in simple, direct Hindi (Devanagari script).\n\n"
        "RULES:\n"
        "1. GROUNDING: Base your answer ONLY on the 'FAQ Information' provided below. Do not invent details, ages, numbers, or rules not in the text.\n"
        "2. CONVERSATIONAL MEMORY: If the user says something conversational like 'Haa', 'Haan', 'Yes', 'No', 'Ok', or a greeting, look at the Previous Conversation History. "
        "They are likely answering your previous follow-up question. If they said yes, answer that previous topic. If the FAQ is empty, guide them back to banking.\n"
        "3. STT TYPOS: The user's input comes from Speech-to-Text. It might have slight typos like 'Haa' instead of 'Haan', or 'klonk' instead of 'loan'. Be smart and infer banking terms phonetically.\n"
        "4. UNKNOWN: If it's a completely new question and the FAQ is empty, say EXACTLY: 'माफ़ करें, मेरे पास इसकी जानकारी नहीं है। कृपया बैंक शाखा से संपर्क करें।'\n"
        "5. FORMAT: Give a clear, complete answer. DO NOT cut off mid-sentence. Write as much as needed to finish your thought.\n"
        "6. FOLLOW-UP: ALWAYS end your entire response with ONE relevant follow-up question on a new line, formatted exactly like this:\n"
        "क्या आप यह भी जानना चाहेंगे: [your question here]?\n\n"
        "SAFETY EXCEPTION: If the user asks about fraud, scams, or lost cards, you may advise them to contact the bank or police immediately.\n\n"
    )

    if history:
        prompt += "--- Previous Conversation History (For Context) ---\n"
        for user_msg, bot_msg, _ in history[-2:]:  # Only keep last 2 turns to save tokens
            prompt += f"User: {user_msg}\nYou: {bot_msg}\n\n"
        prompt += "--- End History ---\n\n"

    prompt += (
        f"--- FAQ Information ---\n{english_context}\n--- End FAQ ---\n\n"
        f"User's question: {hindi_question}\n\n"
        "Your response (in Hindi):"
    )

    try:
        response = client.models.generate_content(
            model=MODEL_NAME,
            contents=prompt,
            config=types.GenerateContentConfig(
                max_output_tokens=2048,
                temperature=0.1,
            ),
        )
        answer = (response.text or "").strip()
        return answer if answer else _FALLBACK_LLM_ERROR

    except Exception as exc:
        print(f"[LLM] Generation error: {exc}")
        return _FALLBACK_LLM_ERROR