rairo commited on
Commit
b82d56d
·
verified ·
1 Parent(s): 44d369e

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +62 -12
main.py CHANGED
@@ -663,25 +663,55 @@ def call_gemini(prompt_text, is_json_output_expected=True):
663
  {"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT", "threshold": "BLOCK_MEDIUM_AND_ABOVE"},
664
  {"category": "HARM_CATEGORY_DANGEROUS_CONTENT", "threshold": "BLOCK_MEDIUM_AND_ABOVE"},
665
  ]
666
- gen_config = genai.types.GenerationConfig(response_mime_type="application/json") if is_json_output_expected else None
667
- response = model.generate_content(prompt_text, generation_config=gen_config, safety_settings=safety_settings)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
668
 
669
  if not response.parts:
670
  reason = "Unknown"
671
  try:
672
  reason = response.prompt_feedback.block_reason.name if hasattr(response, 'prompt_feedback') and response.prompt_feedback.block_reason else None
673
- if not reason and response.candidates: reason = response.candidates[0].finish_reason.name
674
- except Exception: pass
 
 
675
  return None, f"AI response empty or blocked. Reason: {reason}"
 
676
  if not hasattr(response, 'text') or not response.text:
677
  return None, "AI response text empty."
678
 
679
  if is_json_output_expected:
680
- parsed_json, err = safe_json_loads(response.text)
681
- if err: return None, f"AI response received, but failed to parse as JSON: {err}. Raw: {response.text[:500]}..."
 
 
 
 
 
 
 
 
 
 
 
 
682
  return parsed_json, None
683
  else:
684
- return response.text, None
 
685
  except Exception as e:
686
  app.logger.error(f"Gemini API Call Error: {e} (Type: {type(e).__name__})")
687
  return None, f"Gemini API Call Error: {e}"
@@ -703,6 +733,8 @@ JSON Output:
703
  """
704
  return call_gemini(prompt, is_json_output_expected=True)
705
 
 
 
706
  def generate_quiz_questions_gemini(members, relationships, num_questions=3):
707
  if not members or len(members) < 2: return None, "Need at least 2 members for a quiz."
708
  id_to_name = {p["id"]: p.get("name", "Unknown") for p in members if isinstance(p, dict)}
@@ -1498,24 +1530,42 @@ def get_proposal_diff_api(proposer_phone_to_review):
1498
 
1499
  # --- AI Feature Endpoints (Protected as they operate on user's tree or consume user quota) ---
1500
  @app.route('/ai/build_tree_from_text', methods=['POST'])
1501
- @token_required # AI features should be protected
1502
  def ai_build_tree_api():
1503
- # This endpoint doesn't directly modify a tree, just provides analysis.
1504
- # The owner_phone_of_tree context isn't strictly needed here unless we log usage against a tree.
1505
- # For now, it's a general utility for an authenticated user.
1506
- if api_key_error: return jsonify({"error": "Gemini API not configured"}), 503
 
 
 
 
 
 
 
 
 
 
 
 
1507
 
1508
  req_data = request.json
1509
  if not req_data or "description" not in req_data:
1510
  return jsonify({"error": "Missing description in request body"}), 400
 
1511
  description = req_data["description"]
 
 
 
1512
 
1513
  ai_result, error = generate_tree_from_description_gemini(description)
1514
  if error:
1515
  return jsonify({"error": "AI analysis failed", "detail": error}), 500
 
1516
  return jsonify(ai_result), 200
1517
 
1518
 
 
1519
  @app.route('/tree/<string:owner_phone_of_tree>/ai_merge_suggestions', methods=['POST'])
1520
  @token_required
1521
  @phone_required
 
663
  {"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT", "threshold": "BLOCK_MEDIUM_AND_ABOVE"},
664
  {"category": "HARM_CATEGORY_DANGEROUS_CONTENT", "threshold": "BLOCK_MEDIUM_AND_ABOVE"},
665
  ]
666
+
667
+ # Fixed: Use proper GenerationConfig parameters
668
+ gen_config = None
669
+ if is_json_output_expected:
670
+ gen_config = genai.types.GenerationConfig(
671
+ temperature=0.2, # Lower temperature for more consistent JSON
672
+ top_p=0.8,
673
+ top_k=40,
674
+ max_output_tokens=2048,
675
+ )
676
+
677
+ response = model.generate_content(
678
+ prompt_text,
679
+ generation_config=gen_config,
680
+ safety_settings=safety_settings
681
+ )
682
 
683
  if not response.parts:
684
  reason = "Unknown"
685
  try:
686
  reason = response.prompt_feedback.block_reason.name if hasattr(response, 'prompt_feedback') and response.prompt_feedback.block_reason else None
687
+ if not reason and response.candidates:
688
+ reason = response.candidates[0].finish_reason.name
689
+ except Exception:
690
+ pass
691
  return None, f"AI response empty or blocked. Reason: {reason}"
692
+
693
  if not hasattr(response, 'text') or not response.text:
694
  return None, "AI response text empty."
695
 
696
  if is_json_output_expected:
697
+ # Clean the response text to extract JSON
698
+ response_text = response.text.strip()
699
+ # Remove markdown code blocks if present
700
+ if response_text.startswith('```json'):
701
+ response_text = response_text[7:]
702
+ if response_text.startswith('```'):
703
+ response_text = response_text[3:]
704
+ if response_text.endswith('```'):
705
+ response_text = response_text[:-3]
706
+ response_text = response_text.strip()
707
+
708
+ parsed_json, err = safe_json_loads(response_text)
709
+ if err:
710
+ return None, f"AI response received, but failed to parse as JSON: {err}. Raw: {response_text[:500]}..."
711
  return parsed_json, None
712
  else:
713
+ return response_text, None
714
+
715
  except Exception as e:
716
  app.logger.error(f"Gemini API Call Error: {e} (Type: {type(e).__name__})")
717
  return None, f"Gemini API Call Error: {e}"
 
733
  """
734
  return call_gemini(prompt, is_json_output_expected=True)
735
 
736
+
737
+
738
  def generate_quiz_questions_gemini(members, relationships, num_questions=3):
739
  if not members or len(members) < 2: return None, "Need at least 2 members for a quiz."
740
  id_to_name = {p["id"]: p.get("name", "Unknown") for p in members if isinstance(p, dict)}
 
1530
 
1531
  # --- AI Feature Endpoints (Protected as they operate on user's tree or consume user quota) ---
1532
  @app.route('/ai/build_tree_from_text', methods=['POST'])
1533
+ @token_required
1534
  def ai_build_tree_api():
1535
+ """
1536
+ Endpoint to analyze family description text and extract people and relationships.
1537
+
1538
+ Request body:
1539
+ {
1540
+ "description": "Family description text here..."
1541
+ }
1542
+
1543
+ Response:
1544
+ {
1545
+ "people": [...],
1546
+ "relationships": [...]
1547
+ }
1548
+ """
1549
+ if api_key_error:
1550
+ return jsonify({"error": "Gemini API not configured"}), 503
1551
 
1552
  req_data = request.json
1553
  if not req_data or "description" not in req_data:
1554
  return jsonify({"error": "Missing description in request body"}), 400
1555
+
1556
  description = req_data["description"]
1557
+
1558
+ if not description.strip():
1559
+ return jsonify({"error": "Description cannot be empty"}), 400
1560
 
1561
  ai_result, error = generate_tree_from_description_gemini(description)
1562
  if error:
1563
  return jsonify({"error": "AI analysis failed", "detail": error}), 500
1564
+
1565
  return jsonify(ai_result), 200
1566
 
1567
 
1568
+
1569
  @app.route('/tree/<string:owner_phone_of_tree>/ai_merge_suggestions', methods=['POST'])
1570
  @token_required
1571
  @phone_required