ST-x-Tony commited on
Commit
9afda58
Β·
verified Β·
1 Parent(s): b8116ac

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +140 -44
app.py CHANGED
@@ -20,7 +20,7 @@ import spaces
20
  # ============================================================
21
 
22
  APP_NAME = "X-RUDRA"
23
- VERSION = "3.1.0"
24
 
25
  M1_REPO = os.getenv("M1_REPO", "Shrijanagain/M1")
26
  M2_REPO = os.getenv("M2_REPO", "Shrijanagain/M2")
@@ -62,24 +62,74 @@ def safe_dict(value):
62
 
63
 
64
  # ============================================================
65
- # FORMATTERS (same as before, but shortened for brevity)
66
  # ============================================================
67
 
68
  def format_sources(sources):
69
  if not sources:
70
  return "## πŸ“š Sources\n\nNo sources were returned."
71
- # ... (keep your existing implementation) ...
72
- # (I'll include the full code in the final answer)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
 
74
  def format_evidence(claims):
75
  if not claims:
76
  return "## 🧠 Evidence\n\nNo structured evidence was returned."
77
- # ...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
 
79
  def format_verification(contradictions):
80
  if not contradictions:
81
- return "## βš–οΈ Verification\n\nβœ… No contradictions detected."
82
- # ...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
 
84
  def extract_answer(data):
85
  # Try common fields
@@ -87,31 +137,50 @@ def extract_answer(data):
87
  val = data.get(key)
88
  if isinstance(val, str) and val.strip():
89
  return val.strip()
90
- # Fallback to claims
91
- claims = data.get("claims", [])
92
- if claims:
93
- parts = []
94
- for claim in claims:
95
- if isinstance(claim, dict):
96
- text = claim.get("claim", claim.get("text", ""))
97
- if text:
98
- parts.append(str(text).strip())
99
- if parts:
100
- return "\n\n".join(parts[:10])
101
- return None # No answer found
102
 
103
  def build_activity(data, elapsed_ms):
104
- sources = data.get("sources", [])
105
  claims = data.get("claims", [])
106
  contradictions = data.get("contradictions", [])
107
  rounds = data.get("rounds", data.get("research_rounds", "N/A"))
108
  return f"""
109
  ## ⚑ X-RUDRA Research
110
- ...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
  """
112
 
 
113
  # ============================================================
114
- # RESEARCH FUNCTION
115
  # ============================================================
116
 
117
  async def do_research(question, max_results, max_rounds, use_models, freshness):
@@ -133,34 +202,61 @@ async def do_research(question, max_results, max_rounds, use_models, freshness):
133
  data = safe_dict(report)
134
  elapsed_ms = int((time.perf_counter() - started) * 1000)
135
 
136
- # Debug: print raw data to logs
137
  print("\n" + "="*60)
138
  print("RAW ENGINE DATA:")
139
- print(json.dumps(data, indent=2, default=str)[:2000]) # print first 2000 chars
140
  print("="*60 + "\n")
141
 
142
- # Extract answer
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  answer = extract_answer(data)
144
  if answer is None:
145
- # No answer found – build a fallback message
146
- sources_count = len(data.get("sources", []))
147
- claims_count = len(data.get("claims", []))
148
- if sources_count == 0 and claims_count == 0:
149
- answer = (
150
- "❌ **No information found.**\n\n"
151
- "The research engine did not return any sources or evidence. "
152
- "Possible reasons:\n"
153
- "- The M1 or M2 Spaces are not responding (check their API endpoints).\n"
154
- "- The web search failed to extract results.\n"
155
- "- The query might be too specific or ambiguous.\n\n"
156
- "Try rephrasing your question or check the M1/M2 Spaces' logs."
157
- )
158
  else:
159
- answer = "Research completed, but no synthesized answer was generated."
160
-
161
- # Build outputs
162
- sources_md = format_sources(data.get("sources", []))
163
- evidence_md = format_evidence(data.get("claims", []))
 
 
 
 
 
 
 
 
 
164
  verification_md = format_verification(data.get("contradictions", []))
165
  activity_md = build_activity(data, elapsed_ms)
166
 
@@ -208,7 +304,7 @@ def health_check():
208
 
209
 
210
  # ============================================================
211
- # CSS AND UI
212
  # ============================================================
213
 
214
  CSS = """
 
20
  # ============================================================
21
 
22
  APP_NAME = "X-RUDRA"
23
+ VERSION = "3.2.0" # bumped version
24
 
25
  M1_REPO = os.getenv("M1_REPO", "Shrijanagain/M1")
26
  M2_REPO = os.getenv("M2_REPO", "Shrijanagain/M2")
 
62
 
63
 
64
  # ============================================================
65
+ # FORMATTERS (unchanged)
66
  # ============================================================
67
 
68
  def format_sources(sources):
69
  if not sources:
70
  return "## πŸ“š Sources\n\nNo sources were returned."
71
+ output = ["## πŸ“š Sources", ""]
72
+ for idx, src in enumerate(sources, 1):
73
+ if not isinstance(src, dict):
74
+ continue
75
+ title = src.get("title", "Untitled")
76
+ url = src.get("url", "")
77
+ method = src.get("fetch_method", "web")
78
+ score = src.get("source_score", src.get("score", "N/A"))
79
+ snippet = src.get("snippet", src.get("description", ""))
80
+ if url:
81
+ output.append(f"### {idx}. [{title}]({url})")
82
+ else:
83
+ output.append(f"### {idx}. {title}")
84
+ output.append(f"**Fetcher:** `{method}`")
85
+ output.append(f"**Source score:** `{score}`")
86
+ if snippet:
87
+ output.append(f"\n> {snippet}")
88
+ output.append("")
89
+ return "\n".join(output)
90
+
91
 
92
  def format_evidence(claims):
93
  if not claims:
94
  return "## 🧠 Evidence\n\nNo structured evidence was returned."
95
+ output = ["## 🧠 Evidence", ""]
96
+ for idx, claim in enumerate(claims, 1):
97
+ if not isinstance(claim, dict):
98
+ continue
99
+ text = claim.get("claim", claim.get("text", ""))
100
+ score = claim.get("support_score", claim.get("score", "N/A"))
101
+ source = claim.get("source_url", claim.get("url", ""))
102
+ output.append(f"### Evidence {idx}")
103
+ output.append(str(text))
104
+ output.append(f"**Support:** `{score}`")
105
+ if source:
106
+ output.append(f"**Source:** {source}")
107
+ output.append("---")
108
+ return "\n\n".join(output)
109
+
110
 
111
  def format_verification(contradictions):
112
  if not contradictions:
113
+ return "## βš–οΈ Verification\n\nβœ… No major contradictions detected."
114
+ output = ["## βš–οΈ Verification", "", "⚠️ Potential contradictions detected:", ""]
115
+ for idx, item in enumerate(contradictions, 1):
116
+ if not isinstance(item, dict):
117
+ continue
118
+ claim_a = item.get("claim_a", "")
119
+ claim_b = item.get("claim_b", "")
120
+ source_a = item.get("source_a", "")
121
+ source_b = item.get("source_b", "")
122
+ output.append(f"### Contradiction {idx}")
123
+ output.append(f"**A:** {claim_a}")
124
+ if source_a:
125
+ output.append(f"Source A: `{source_a}`")
126
+ output.append("")
127
+ output.append(f"**B:** {claim_b}")
128
+ if source_b:
129
+ output.append(f"Source B: `{source_b}`")
130
+ output.append("---")
131
+ return "\n\n".join(output)
132
+
133
 
134
  def extract_answer(data):
135
  # Try common fields
 
137
  val = data.get(key)
138
  if isinstance(val, str) and val.strip():
139
  return val.strip()
140
+ # If no answer, we'll build one from results in the caller
141
+ return None
142
+
 
 
 
 
 
 
 
 
 
143
 
144
  def build_activity(data, elapsed_ms):
145
+ sources = data.get("sources", []) or data.get("results", [])
146
  claims = data.get("claims", [])
147
  contradictions = data.get("contradictions", [])
148
  rounds = data.get("rounds", data.get("research_rounds", "N/A"))
149
  return f"""
150
  ## ⚑ X-RUDRA Research
151
+
152
+ | Stage | Status |
153
+ |---|---|
154
+ | Task analysis | βœ… Complete |
155
+ | M1 research | {"βœ… Enabled" if data.get("m1") is not None else "βš™οΈ Pipeline"} |
156
+ | M2 research | {"βœ… Enabled" if data.get("m2") is not None else "βš™οΈ Pipeline"} |
157
+ | Web discovery | βœ… Complete |
158
+ | Evidence extraction | {"βœ…" if data.get("claims") else "βš™οΈ"} |
159
+ | Source verification | βœ… Complete |
160
+ | Contradiction check | {"⚠️ Found" if contradictions else "βœ… Clear"} |
161
+ | Final synthesis | {"βœ…" if extract_answer(data) else "βš™οΈ"} |
162
+
163
+ **Sources:** `{len(sources)}`
164
+ **Claims:** `{len(claims)}`
165
+ **Rounds:** `{rounds}`
166
+ **Time:** `{elapsed_ms} ms`
167
+
168
+ ### Engine
169
+
170
+ `M1` β†’ `{M1_REPO}`
171
+
172
+ `M2` β†’ `{M2_REPO}`
173
+
174
+ `Web` β†’ `DuckDuckGo`
175
+
176
+ `Fetcher` β†’ `Scrapling`
177
+
178
+ `Browser` β†’ `Playwright`
179
  """
180
 
181
+
182
  # ============================================================
183
+ # RESEARCH FUNCTION – FIXED TO HANDLE ENGINE OUTPUT
184
  # ============================================================
185
 
186
  async def do_research(question, max_results, max_rounds, use_models, freshness):
 
202
  data = safe_dict(report)
203
  elapsed_ms = int((time.perf_counter() - started) * 1000)
204
 
205
+ # Debug: print raw data to logs (helps with debugging)
206
  print("\n" + "="*60)
207
  print("RAW ENGINE DATA:")
208
+ print(json.dumps(data, indent=2, default=str)[:3000]) # first 3000 chars
209
  print("="*60 + "\n")
210
 
211
+ # ------------------------------------------------------------
212
+ # 1. EXTRACT SOURCES – convert 'results' to 'sources' if needed
213
+ # ------------------------------------------------------------
214
+ sources = data.get("sources", [])
215
+ if not sources:
216
+ # Engine uses 'results' – convert each to source format
217
+ results = data.get("results", [])
218
+ for res in results:
219
+ if isinstance(res, dict):
220
+ sources.append({
221
+ "title": res.get("title", ""),
222
+ "url": res.get("url", ""),
223
+ "snippet": res.get("snippet", ""),
224
+ "fetch_method": "web",
225
+ "source_score": res.get("rank", "N/A"),
226
+ "description": res.get("snippet", ""),
227
+ })
228
+ # Store back for activity and formatters
229
+ data["sources"] = sources
230
+
231
+ # ------------------------------------------------------------
232
+ # 2. EXTRACT ANSWER – if missing, synthesize from sources
233
+ # ------------------------------------------------------------
234
  answer = extract_answer(data)
235
  if answer is None:
236
+ # Build a simple answer from the top sources
237
+ if sources:
238
+ top = sources[:5]
239
+ parts = [f"Based on the top results:"]
240
+ for i, src in enumerate(top, 1):
241
+ title = src.get("title", "Untitled")
242
+ snippet = src.get("snippet", src.get("description", ""))
243
+ parts.append(f"{i}. **{title}** – {snippet[:200]}..." if snippet else f"{i}. **{title}**")
244
+ answer = "\n\n".join(parts)
 
 
 
 
245
  else:
246
+ answer = "No information found. Try rephrasing your question."
247
+
248
+ # ------------------------------------------------------------
249
+ # 3. CLAIMS – if missing, we can keep empty or derive from snippets
250
+ # ------------------------------------------------------------
251
+ claims = data.get("claims", [])
252
+ # (Optional) You could generate simple claims from each source's snippet,
253
+ # but we'll leave it empty for now.
254
+
255
+ # ------------------------------------------------------------
256
+ # 4. BUILD OUTPUTS
257
+ # ------------------------------------------------------------
258
+ sources_md = format_sources(sources)
259
+ evidence_md = format_evidence(claims)
260
  verification_md = format_verification(data.get("contradictions", []))
261
  activity_md = build_activity(data, elapsed_ms)
262
 
 
304
 
305
 
306
  # ============================================================
307
+ # CSS AND UI (unchanged)
308
  # ============================================================
309
 
310
  CSS = """