Sanchit7 commited on
Commit
f32382f
·
1 Parent(s): 22e811b

$(cat <<EOF

Browse files

Fix JSON parsing and enhance Gradio UI with full analysis

- Simplify JSON sanitization: strip all newlines/tabs before parsing
- Add Key Opportunities field to Gradio interface
- Add Detailed Analysis/Reasoning field (8 lines)
- Update how-it-works to mention Gemini integration
- Fix return tuple to include all 6 output fields

Now displays complete Gemini analysis instead of partial results.

:robot: Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
EOF
)

Files changed (2) hide show
  1. src/agents/synthesis_agent.py +9 -11
  2. src/api/server.py +25 -8
src/agents/synthesis_agent.py CHANGED
@@ -261,20 +261,18 @@ IMPORTANT: Return ONLY valid JSON. No markdown, no code blocks, no extra text. U
261
  elif "```" in response_text:
262
  response_text = response_text.split("```")[1].split("```")[0].strip()
263
 
264
- # Aggressive sanitization: replace ALL control characters with space
265
- # Only preserve spaces and printable ASCII
266
- response_text = ''.join(
267
- char if (char.isprintable() or char in [' ', '\n', '\r', '\t']) else ' '
268
- for char in response_text
269
- )
270
 
271
  # Replace multiple spaces with single space
272
- response_text = re.sub(r'[ \t]+', ' ', response_text)
273
 
274
- # Clean up newlines in JSON strings (replace with space)
275
- # This handles cases where Gemini puts literal newlines inside quoted strings
276
- response_text = re.sub(r'"\s*\n\s*', '" ', response_text)
277
- response_text = re.sub(r'\s*\n\s*"', ' "', response_text)
 
278
 
279
  try:
280
  result = json.loads(response_text)
 
261
  elif "```" in response_text:
262
  response_text = response_text.split("```")[1].split("```")[0].strip()
263
 
264
+ # Simple approach: Remove ALL newlines and tabs from JSON
265
+ # JSON doesn't need pretty-printing to be valid
266
+ response_text = response_text.replace('\n', ' ').replace('\r', ' ').replace('\t', ' ')
 
 
 
267
 
268
  # Replace multiple spaces with single space
269
+ response_text = re.sub(r'\s+', ' ', response_text)
270
 
271
+ # Remove non-printable control characters (but we already removed \n, \r, \t)
272
+ response_text = ''.join(
273
+ char if char.isprintable() or char == ' ' else ' '
274
+ for char in response_text
275
+ )
276
 
277
  try:
278
  result = json.loads(response_text)
src/api/server.py CHANGED
@@ -28,17 +28,17 @@ class AnalysisServer:
28
  filing_type: str = "10-K",
29
  include_news: bool = True,
30
  include_technicals: bool = True,
31
- ) -> Tuple[str, str, str, str]:
32
  """
33
  Main analysis function for Gradio interface
34
 
35
  Returns:
36
- Tuple of (sentiment, confidence, risks, recommendation)
37
  """
38
  try:
39
  # Validate input
40
  if not ticker:
41
- return ("Error", "N/A", "Ticker symbol required", "N/A")
42
 
43
  ticker = ticker.strip().upper()
44
 
@@ -65,16 +65,23 @@ class AnalysisServer:
65
  ]
66
  )
67
 
 
 
 
 
 
68
  return (
69
  rec.sentiment,
70
  rec.confidence,
71
  risks_text if risks_text else "No significant risks identified",
 
72
  rec.recommended_action,
 
73
  )
74
 
75
  except Exception as e:
76
  logger.error(f"Error in analysis: {str(e)}")
77
- return ("Error", "N/A", f"Analysis failed: {str(e)}", "N/A")
78
 
79
  def create_interface(self) -> gr.Blocks:
80
  """Create Gradio interface"""
@@ -123,11 +130,21 @@ class AnalysisServer:
123
  lines=5,
124
  interactive=False,
125
  )
 
 
 
 
 
126
  action = gr.Textbox(
127
  label="Recommended Action",
128
  lines=2,
129
  interactive=False,
130
  )
 
 
 
 
 
131
 
132
  # Examples
133
  gr.Examples(
@@ -155,7 +172,7 @@ class AnalysisServer:
155
  include_news,
156
  include_technicals,
157
  ],
158
- outputs=[sentiment, confidence, risks, action],
159
  )
160
 
161
  gr.Markdown("---")
@@ -163,10 +180,10 @@ class AnalysisServer:
163
  """
164
  ### How it works:
165
  1. **SEC Filing Agent** - Analyzes SEC filings with FinBERT/SEC-BERT + LIME explainability
166
- 2. **Market Intelligence Agent** - Gathers real-time price data, technicals, and news
167
- 3. **Synthesis Agent** - Cross-references fundamental vs. market data for final recommendation
168
 
169
- Built with multi-agent architecture for deep, explainable equity analysis.
170
  """
171
  )
172
 
 
28
  filing_type: str = "10-K",
29
  include_news: bool = True,
30
  include_technicals: bool = True,
31
+ ) -> Tuple[str, str, str, str, str]:
32
  """
33
  Main analysis function for Gradio interface
34
 
35
  Returns:
36
+ Tuple of (sentiment, confidence, risks, opportunities, recommendation, reasoning)
37
  """
38
  try:
39
  # Validate input
40
  if not ticker:
41
+ return ("Error", "N/A", "Ticker symbol required", "N/A", "N/A", "N/A")
42
 
43
  ticker = ticker.strip().upper()
44
 
 
65
  ]
66
  )
67
 
68
+ # Format opportunities
69
+ opps_text = "\n".join(
70
+ [f"• {opp}" for opp in rec.key_opportunities]
71
+ )
72
+
73
  return (
74
  rec.sentiment,
75
  rec.confidence,
76
  risks_text if risks_text else "No significant risks identified",
77
+ opps_text if opps_text else "No significant opportunities identified",
78
  rec.recommended_action,
79
+ rec.reasoning,
80
  )
81
 
82
  except Exception as e:
83
  logger.error(f"Error in analysis: {str(e)}")
84
+ return ("Error", "N/A", f"Analysis failed: {str(e)}", "N/A", "N/A", "N/A")
85
 
86
  def create_interface(self) -> gr.Blocks:
87
  """Create Gradio interface"""
 
130
  lines=5,
131
  interactive=False,
132
  )
133
+ opportunities = gr.Textbox(
134
+ label="Key Opportunities",
135
+ lines=3,
136
+ interactive=False,
137
+ )
138
  action = gr.Textbox(
139
  label="Recommended Action",
140
  lines=2,
141
  interactive=False,
142
  )
143
+ reasoning = gr.Textbox(
144
+ label="Detailed Analysis",
145
+ lines=8,
146
+ interactive=False,
147
+ )
148
 
149
  # Examples
150
  gr.Examples(
 
172
  include_news,
173
  include_technicals,
174
  ],
175
+ outputs=[sentiment, confidence, risks, opportunities, action, reasoning],
176
  )
177
 
178
  gr.Markdown("---")
 
180
  """
181
  ### How it works:
182
  1. **SEC Filing Agent** - Analyzes SEC filings with FinBERT/SEC-BERT + LIME explainability
183
+ 2. **Market Intelligence Agent** - Gathers real-time price data, technicals, and news (Gemini-powered sentiment)
184
+ 3. **Synthesis Agent** - Gemini 2.0 Flash synthesizes fundamental vs. market data for final recommendation
185
 
186
+ Built with multi-agent architecture for deep, explainable equity analysis. Combines domain-specific ML models with LLM reasoning.
187
  """
188
  )
189