Karan6124 commited on
Commit
9d416cd
·
1 Parent(s): 1f11e9a

fix: enforce JSON-only Gemini responses and add graceful plain-text fallback to prevent agent crash

Browse files
Files changed (1) hide show
  1. backend/app/services/gemini.py +17 -2
backend/app/services/gemini.py CHANGED
@@ -600,8 +600,11 @@ async def run_agent_chat(db: AsyncSession, user_id: uuid.UUID, prompt: str) -> d
600
  "Examine the requested stock and gather all necessary details using your tools. "
601
  "You must refer to your machine learning predictions tool as the 'QuantIQ ML Signal Engine' "
602
  "and your technical indicators tool as 'QuantIQ Technical Indicators' in your reasoning. "
603
- "You must return your response in JSON format matching this schema: "
604
- '{"bullish_probability": int, "reason": "string"}. '
 
 
 
605
  "Ensure 'bullish_probability' is between 0 and 100 representing the upward price probability. "
606
  "The 'reason' should be a detailed, structured, and comprehensive quantitative analysis. "
607
  "Explain the technical metrics, crossover directions, and the ML Signal Engine predictions clearly. "
@@ -649,6 +652,18 @@ async def run_agent_chat(db: AsyncSession, user_id: uuid.UUID, prompt: str) -> d
649
  "bullish_probability": data.get("bullish_probability", 50),
650
  "reason": data.get("reason", "No analysis summary could be generated.")
651
  }
 
 
 
 
 
 
 
 
 
 
 
 
652
  except Exception as e:
653
  duration = asyncio.get_event_loop().time() - start_time
654
  agent_latency_seconds.observe(duration)
 
600
  "Examine the requested stock and gather all necessary details using your tools. "
601
  "You must refer to your machine learning predictions tool as the 'QuantIQ ML Signal Engine' "
602
  "and your technical indicators tool as 'QuantIQ Technical Indicators' in your reasoning. "
603
+ "ABSOLUTE RULE: You MUST ALWAYS return your final response as a raw JSON object — "
604
+ "no markdown fences, no prose, no preamble. ONLY valid JSON. "
605
+ "Even if tools fail or data is limited, you MUST still return a JSON object. "
606
+ 'The schema is: {"bullish_probability": int, "reason": "string"}. '
607
+ "If tools failed, estimate bullish_probability as 50 and explain the limitation in the reason field. "
608
  "Ensure 'bullish_probability' is between 0 and 100 representing the upward price probability. "
609
  "The 'reason' should be a detailed, structured, and comprehensive quantitative analysis. "
610
  "Explain the technical metrics, crossover directions, and the ML Signal Engine predictions clearly. "
 
652
  "bullish_probability": data.get("bullish_probability", 50),
653
  "reason": data.get("reason", "No analysis summary could be generated.")
654
  }
655
+ except ValueError as json_err:
656
+ # The model returned plain text instead of JSON (can happen when tools fail)
657
+ # Gracefully capture the model's text and wrap it into a valid response dict
658
+ duration = asyncio.get_event_loop().time() - start_time
659
+ agent_latency_seconds.observe(duration)
660
+ agent_steps_total.labels(status="failed").inc(1)
661
+ raw_text = str(json_err).replace("Could not extract JSON from: ", "", 1)
662
+ print(f"Gemini returned plain text instead of JSON — wrapping gracefully. Preview: {raw_text[:120]}")
663
+ return {
664
+ "bullish_probability": 50,
665
+ "reason": raw_text
666
+ }
667
  except Exception as e:
668
  duration = asyncio.get_event_loop().time() - start_time
669
  agent_latency_seconds.observe(duration)