rairo commited on
Commit
e0f7143
·
verified ·
1 Parent(s): 05c0163

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +64 -65
main.py CHANGED
@@ -1881,90 +1881,85 @@ def get_price_trends():
1881
 
1882
  @app.route("/api/ai/chat", methods=["POST"])
1883
  def ai_chat():
1884
- auth_header = request.headers.get("Authorization", "");
1885
  uid = None
1886
- response_obj_gemini = None
1887
- intent = "unknown"
1888
  try:
1889
  if not FIREBASE_INITIALIZED or not gemini_client:
1890
  return jsonify({'error': 'Server or AI service not ready.'}), 503
1891
 
1892
  uid = verify_token(auth_header)
1893
-
1894
  data = request.get_json()
1895
  if not data:
1896
  return jsonify({"error": "Invalid request data."}), 400
1897
-
1898
  user_message = data.get("message", "").strip()
1899
  if not user_message:
1900
  return jsonify({"error": "Message cannot be empty."}), 400
1901
 
 
1902
  classify_prompt = f"""
1903
- Analyze the user's query for the Tunasonga Agri platform. Classify the primary intent into ONE of these categories:
1904
- - "platform_data_query": User is asking about current listings, demands, or specific items available *right now* on the platform. (e.g., "any maize for sale?", "who needs beans in Harare?")
1905
- - "price_trend_query": User is asking about historical price trends, market analysis, or future price predictions. (e.g., "how are maize prices trending?", "what was the price of sorghum last month?")
1906
- - "general_agri_info": User is asking for general agricultural advice, farming techniques, business tips, or information not tied to current platform data or specific historical trends. (e.g., "how to grow tomatoes?", "best fertilizer for sandy soils", "exporting crops in SADC")
1907
- - "other": If the query doesn't fit well or is a simple greeting/chit-chat.
1908
- User Query: "{user_message}"
1909
- Return ONLY the category string (e.g., "platform_data_query").
1910
- """
1911
-
1912
- response_obj_gemini = gemini_client.generate_content( # Corrected: use generate_content directly
1913
- model='gemini-2.0-flash',
1914
- contents=[{'parts': [{'text': classify_prompt}]}] # Pass contents as a list
1915
- )
1916
-
1917
- intent = response_obj_gemini.text.strip().replace('"', '') if response_obj_gemini.text else "general_agri_info"
1918
-
 
 
 
 
 
 
1919
  valid_intents = ["platform_data_query", "price_trend_query", "general_agri_info", "other"]
1920
- if intent not in valid_intents:
1921
- logger.warning(f"AI Chat: Unexpected intent: '{intent}' for query '{user_message}'. Defaulting to general_agri_info.")
 
 
1922
  intent = "general_agri_info"
1923
-
1924
- context_for_gemini = ""
1925
- platform_data_summary = ""
1926
- trend_analysis_summary = ""
1927
 
 
 
1928
  if intent == "platform_data_query":
1929
  platform_data_summary, _ = _fetch_platform_data_for_chat(user_message)
1930
  if platform_data_summary:
1931
- context_for_gemini += f"Current Platform Data Context (summarized for you):\n{platform_data_summary}\n\n"
1932
-
1933
  elif intent == "price_trend_query":
1934
- crop_match = re.search(r"(?:trend for|prices of|price of|trend of)\s+([\w\s]+?)(?:\s+in\s+([\w\s]+?))?(?:\s|$)", user_message.lower())
1935
- trend_crop, trend_location = (None, None)
1936
- if crop_match:
1937
- trend_crop = crop_match.group(1).strip()
1938
- if crop_match.group(2):
1939
- trend_location = crop_match.group(2).strip()
1940
-
1941
- trend_analysis_summary, _ = _get_price_trend_analysis_for_chat(crop_type=trend_crop, location=trend_location)
1942
  if trend_analysis_summary:
1943
- context_for_gemini += f"Price Trend Analysis Context (generated for you):\n{trend_analysis_summary}\n\n"
1944
 
 
1945
  main_prompt = f"""
1946
- You are Tunasonga Agri Assistant, an AI for an agricultural marketplace in Zimbabwe and SADC.
1947
- Your goal is to provide helpful, concise, and accurate information. Your persona is professional, friendly, and supportive of farmers and agri-businesses.
1948
- The user's original query intent was classified as: {intent}
1949
- {context_for_gemini}
1950
- Based on the user's query and any provided context above, please formulate your answer to the user.
1951
  User Query: "{user_message}"
1952
- Specific Instructions based on intent:
1953
- - If the intent was 'platform_data_query': Use the "Current Platform Data Context" to answer. If the context says no items were found, relay that and suggest they browse the marketplace or refine their search. Do not invent listings.
1954
- - If the intent was 'price_trend_query': Use the "Price Trend Analysis Context". If the context says trends couldn't be generated, relay that. Do not invent trends.
1955
- - For 'general_agri_info': Use your broad agricultural knowledge. Focus on practices relevant to the SADC region, smallholder farmers, climate-smart agriculture, market access, and agri-business development. Provide actionable advice if possible.
1956
- - If the query is unclear, classified as "other", or if the context is insufficient for a specific query: Provide a polite general response, ask for clarification, or gently guide the user on how you can help (e.g., "I can help with finding produce, getting price trends, or general farming advice. What would you like to know?").
1957
- Keep your answers clear and easy to understand. Avoid overly technical jargon unless necessary and explain it.
1958
- Answer:
1959
  """
1960
-
1961
- response_obj_gemini = gemini_client.generate_content( # Corrected
1962
- model='gemini-2.0-flash',
1963
- contents=[{'parts': [{'text': main_prompt}]}]
1964
- )
1965
-
1966
- ai_response_text = response_obj_gemini.text.strip() if response_obj_gemini.text else "I'm having trouble generating a response right now. Please try again."
1967
-
 
 
 
1968
  try:
1969
  db.reference(f'ai_chat_history/{uid}/{str(uuid.uuid4())}', app=db_app).set({
1970
  'user_message': user_message,
@@ -1974,15 +1969,19 @@ Answer:
1974
  })
1975
  except Exception as chat_history_error:
1976
  logger.error(f"Failed to store chat history for UID {uid}: {chat_history_error}")
1977
-
 
1978
  return jsonify({"response": ai_response_text, "intent": intent})
1979
 
1980
- except AttributeError as ae:
1981
- logger.error(f"Gemini Response Attribute Error in ai_chat (UID: {uid}): {ae}. Response object: {response_obj_gemini}")
1982
- ai_response_text = "I'm having a little trouble understanding that. Could you try rephrasing?"
1983
- return jsonify({"response": ai_response_text, "intent": intent, "error_detail": "AI_RESPONSE_FORMAT_ISSUE"}), 200
1984
- except Exception as e:
1985
- return handle_route_errors(e, uid_context=uid)
 
 
 
1986
 
1987
  @app.route('/api/user/ai-chat-history', methods=['GET'])
1988
  def get_ai_chat_history():
 
1881
 
1882
  @app.route("/api/ai/chat", methods=["POST"])
1883
  def ai_chat():
1884
+ auth_header = request.headers.get("Authorization", "")
1885
  uid = None
1886
+ intent = "general_agri_info" # start with a valid default rather than "unknown"
 
1887
  try:
1888
  if not FIREBASE_INITIALIZED or not gemini_client:
1889
  return jsonify({'error': 'Server or AI service not ready.'}), 503
1890
 
1891
  uid = verify_token(auth_header)
1892
+
1893
  data = request.get_json()
1894
  if not data:
1895
  return jsonify({"error": "Invalid request data."}), 400
1896
+
1897
  user_message = data.get("message", "").strip()
1898
  if not user_message:
1899
  return jsonify({"error": "Message cannot be empty."}), 400
1900
 
1901
+ # 1) Build a more constrained classification prompt
1902
  classify_prompt = f"""
1903
+ Classify the users query into exactly one of these categories (and nothing else):
1904
+ platform_data_query
1905
+ price_trend_query
1906
+ general_agri_info
1907
+ other
1908
+
1909
+ User Query: "{user_message}"
1910
+
1911
+ Return exactly one of the four category names above, with no extra words or punctuation.
1912
+ """
1913
+ # 2) Call Gemini for classification, with explicit logging
1914
+ try:
1915
+ response_obj_gemini = gemini_client.generate_content(
1916
+ model='gemini-2.0-flash',
1917
+ contents=[{'parts': [{'text': classify_prompt}]}]
1918
+ )
1919
+ raw_intent = response_obj_gemini.text or ""
1920
+ except Exception as classify_ex:
1921
+ logger.error(f"Classification call failed: {classify_ex}")
1922
+ raw_intent = ""
1923
+ # 3) Normalize and validate
1924
+ normalized = raw_intent.strip().replace('"', '').lower()
1925
  valid_intents = ["platform_data_query", "price_trend_query", "general_agri_info", "other"]
1926
+ if normalized in valid_intents:
1927
+ intent = normalized
1928
+ else:
1929
+ logger.warning(f"Unexpected or empty classification '{raw_intent}'. Defaulting intent to general_agri_info.")
1930
  intent = "general_agri_info"
 
 
 
 
1931
 
1932
+ # 4) Build context based on intent...
1933
+ context_for_gemini = ""
1934
  if intent == "platform_data_query":
1935
  platform_data_summary, _ = _fetch_platform_data_for_chat(user_message)
1936
  if platform_data_summary:
1937
+ context_for_gemini += f"Current Platform Data Context:\n{platform_data_summary}\n\n"
 
1938
  elif intent == "price_trend_query":
1939
+ # trend logic
1940
+ trend_analysis_summary, _ = _get_price_trend_analysis_for_chat(...)
 
 
 
 
 
 
1941
  if trend_analysis_summary:
1942
+ context_for_gemini += f"Price Trend Analysis Context:\n{trend_analysis_summary}\n\n"
1943
 
1944
+ # 5) Main answer prompt
1945
  main_prompt = f"""
1946
+ You are Tunasonga Agri Assistant
 
 
 
 
1947
  User Query: "{user_message}"
1948
+ The classified intent is: {intent}
1949
+ {context_for_gemini}
1950
+ Answer accordingly.
 
 
 
 
1951
  """
1952
+ try:
1953
+ response_obj_gemini = gemini_client.generate_content(
1954
+ model='gemini-2.0-flash',
1955
+ contents=[{'parts': [{'text': main_prompt}]}]
1956
+ )
1957
+ ai_response_text = response_obj_gemini.text.strip() or "I’m having trouble generating a response right now."
1958
+ except Exception as answer_ex:
1959
+ logger.error(f"Answer generation failed: {answer_ex}")
1960
+ ai_response_text = "I’m having trouble generating a response right now."
1961
+
1962
+ # 6) Save to Firebase history
1963
  try:
1964
  db.reference(f'ai_chat_history/{uid}/{str(uuid.uuid4())}', app=db_app).set({
1965
  'user_message': user_message,
 
1969
  })
1970
  except Exception as chat_history_error:
1971
  logger.error(f"Failed to store chat history for UID {uid}: {chat_history_error}")
1972
+
1973
+ # 7) Return JSON with valid intent
1974
  return jsonify({"response": ai_response_text, "intent": intent})
1975
 
1976
+ except AttributeError as ae:
1977
+ # In this branch, always return a valid default intent
1978
+ logger.error(f"AttributeError in ai_chat (UID: {uid}): {ae}")
1979
+ ai_response_text = "I’m having a little trouble understanding that. Could you try rephrasing?"
1980
+ return jsonify({"response": ai_response_text, "intent": "general_agri_info", "error_detail": "AI_RESPONSE_FORMAT_ISSUE"}), 200
1981
+ except Exception as e:
1982
+ # For any other exception, ensure we return a valid intent instead of "unknown"
1983
+ logger.error(f"Unhandled exception in ai_chat (UID: {uid}): {e}")
1984
+ return jsonify({"error": str(e), "intent": "general_agri_info"}), 500
1985
 
1986
  @app.route('/api/user/ai-chat-history', methods=['GET'])
1987
  def get_ai_chat_history():