saiteja020 commited on
Commit
13c01ef
·
1 Parent(s): ebe0bd3
backend/api/llm_evaluator.py CHANGED
@@ -5,6 +5,7 @@ All models (Gemma, Qwen, GPT) are routed via the Hugging Face OpenAI-compatible
5
  """
6
  import os
7
  import json
 
8
  import requests
9
  import openai
10
 
@@ -34,6 +35,34 @@ _FALLBACK_BASE = {
34
  "provider": "UNKNOWN"
35
  }
36
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  def _get_heuristic_analysis(data: dict) -> dict:
38
  """Provides a rule-based assessment when LLMs are unavailable."""
39
  scores = data.get("scores", {})
@@ -109,12 +138,13 @@ Peak Shaving Adh. : {scores.get('ps_adherence', 0):.3f}
109
  Cycle Discipline : {scores.get('cycle_discipline', 0):.3f}
110
 
111
  == INSTRUCTIONS ==
112
- 1. Prioritize **Energy Arbitrage (Profit)** and **SOC Readiness** in your assessment.
113
- 2. DO NOT be overly strict about Peak Shaving violations. Minor misses (<10%) are acceptable if the agent is generating strong profit and managing battery health (Cycle Discipline) well.
114
- 3. Return ONLY a single valid JSON object with exactly these keys:
 
115
  {{
116
  "verdict": "Excellent|Good|Needs Improvement|Poor",
117
- "score": <float between 0.0 and 1.0 representing overall system performance>,
118
  "summary": "<2-3 sentence executive summary>",
119
  "strengths": ["<strength 1>", "<strength 2>"],
120
  "weaknesses": ["<weakness 1>", "<weakness 2>"],
@@ -130,7 +160,6 @@ def _get_router_analysis(data: dict, model_id: str) -> dict:
130
  if not api_token:
131
  raise ValueError("Hugging Face token not found (expected HF_TOKEN).")
132
 
133
- # Initialize OpenAI client pointing to HF Router
134
  client = openai.OpenAI(
135
  base_url="https://router.huggingface.co/v1",
136
  api_key=api_token
@@ -142,28 +171,30 @@ def _get_router_analysis(data: dict, model_id: str) -> dict:
142
  model=model_id,
143
  messages=[{"role": "user", "content": prompt}],
144
  temperature=0.3,
 
145
  response_format={"type": "json_object"}
146
  )
147
 
148
  content = response.choices[0].message.content
149
- return {**json.loads(content), "available": True, "provider": f"HF:{model_id}"}
 
 
 
 
150
 
151
  def get_llm_analysis(data: dict, provider: str = "GEMINI", model_name: str = None) -> dict:
152
  """Main entry point for LLM analysis. Routes all providers through HF Router."""
 
153
  try:
154
- # Map provider to specific model ID on HF Router
155
  if provider == "GEMINI":
156
- # Using Gemma 4 as the replacement for Gemini
157
  model_id = model_name or DEFAULT_GEMMA_MODEL
158
  elif provider == "QWEN":
159
  model_id = model_name or DEFAULT_QWEN_MODEL
160
  elif provider == "OPENAI":
161
- # Routing OpenAI requests through HF Router as requested
162
  model_id = model_name or DEFAULT_GPT_MODEL
163
  elif provider == "HF":
164
  model_id = model_name or DEFAULT_GEMMA_MODEL
165
  else:
166
- # Fallback for unknown providers
167
  model_id = model_name or DEFAULT_GEMMA_MODEL
168
 
169
  return _get_router_analysis(data, model_id)
@@ -175,5 +206,5 @@ def get_llm_analysis(data: dict, provider: str = "GEMINI", model_name: str = Non
175
  "available": False,
176
  "summary": f"Evaluation Failed: {error_msg}",
177
  "error": error_msg,
178
- "detailed_analysis": f"The requested {provider} analysis could not be completed using model {model_id if 'model_id' in locals() else 'unknown'}.\n\nReason: {error_msg}\n\nPlease check your Hugging Face Space secrets and token permissions."
179
  }
 
5
  """
6
  import os
7
  import json
8
+ import re
9
  import requests
10
  import openai
11
 
 
35
  "provider": "UNKNOWN"
36
  }
37
 
38
+ def _extract_json(text: str) -> dict:
39
+ """Robustly extracts JSON from a string, handling markdown or surrounding text."""
40
+ text = text.strip()
41
+
42
+ # Try direct parse first
43
+ try:
44
+ return json.loads(text)
45
+ except json.JSONDecodeError:
46
+ pass
47
+
48
+ # Try finding JSON block in markdown
49
+ match = re.search(r"```(?:json)?\s*(\{.*?\})\s*```", text, re.DOTALL)
50
+ if match:
51
+ try:
52
+ return json.loads(match.group(1))
53
+ except json.JSONDecodeError:
54
+ pass
55
+
56
+ # Final attempt: search for first { and last }
57
+ match = re.search(r"(\{.*\})", text, re.DOTALL)
58
+ if match:
59
+ try:
60
+ return json.loads(match.group(1))
61
+ except json.JSONDecodeError:
62
+ pass
63
+
64
+ raise ValueError("Response did not contain valid JSON format.")
65
+
66
  def _get_heuristic_analysis(data: dict) -> dict:
67
  """Provides a rule-based assessment when LLMs are unavailable."""
68
  scores = data.get("scores", {})
 
138
  Cycle Discipline : {scores.get('cycle_discipline', 0):.3f}
139
 
140
  == INSTRUCTIONS ==
141
+ 1. **PRIMARY FOCUS**: Energy Arbitrage (Profit/Reward Score). This is the most important metric.
142
+ 2. **SECONDARY FOCUS**: SOC Readiness. Managing battery state before peak hours is vital.
143
+ 3. **LOW IMPORTANCE**: Frequency Regulation and Peak Shaving. Give these very small weights in your assessment.
144
+ 4. Return ONLY a single valid JSON object with exactly these keys:
145
  {{
146
  "verdict": "Excellent|Good|Needs Improvement|Poor",
147
+ "score": <float between 0.0 and 1.0 representing overall system performance based on the focus above>,
148
  "summary": "<2-3 sentence executive summary>",
149
  "strengths": ["<strength 1>", "<strength 2>"],
150
  "weaknesses": ["<weakness 1>", "<weakness 2>"],
 
160
  if not api_token:
161
  raise ValueError("Hugging Face token not found (expected HF_TOKEN).")
162
 
 
163
  client = openai.OpenAI(
164
  base_url="https://router.huggingface.co/v1",
165
  api_key=api_token
 
171
  model=model_id,
172
  messages=[{"role": "user", "content": prompt}],
173
  temperature=0.3,
174
+ # Note: some OS models ignore response_format, hence the robust extractor
175
  response_format={"type": "json_object"}
176
  )
177
 
178
  content = response.choices[0].message.content
179
+ try:
180
+ parsed = _extract_json(content)
181
+ return {**parsed, "available": True, "provider": f"HF:{model_id}"}
182
+ except Exception as e:
183
+ raise ValueError(f"Failed to parse LLM response: {str(e)}\nRaw Content: {content[:200]}...")
184
 
185
  def get_llm_analysis(data: dict, provider: str = "GEMINI", model_name: str = None) -> dict:
186
  """Main entry point for LLM analysis. Routes all providers through HF Router."""
187
+ model_id = "unknown"
188
  try:
 
189
  if provider == "GEMINI":
 
190
  model_id = model_name or DEFAULT_GEMMA_MODEL
191
  elif provider == "QWEN":
192
  model_id = model_name or DEFAULT_QWEN_MODEL
193
  elif provider == "OPENAI":
 
194
  model_id = model_name or DEFAULT_GPT_MODEL
195
  elif provider == "HF":
196
  model_id = model_name or DEFAULT_GEMMA_MODEL
197
  else:
 
198
  model_id = model_name or DEFAULT_GEMMA_MODEL
199
 
200
  return _get_router_analysis(data, model_id)
 
206
  "available": False,
207
  "summary": f"Evaluation Failed: {error_msg}",
208
  "error": error_msg,
209
+ "detailed_analysis": f"The requested {provider} analysis could not be completed using model {model_id}.\n\nReason: {error_msg}\n\nPlease check your Hugging Face Space secrets and token permissions."
210
  }
frontend/src/pages/Evaluate.jsx CHANGED
@@ -108,8 +108,13 @@ export default function Evaluate() {
108
  <div className="gap-14">
109
  <div className="chart-grid">
110
  <div className="overall-hero" style={{gridRow: 'span 2'}}>
111
- <div className="overall-num">{result.scores.overall.toFixed(3)}</div>
112
- <div className="overall-label">Overall Readiness Score</div>
 
 
 
 
 
113
  <div className="divider" style={{width: '60%'}}/>
114
  <div className="row gap-14 text-2" style={{fontSize: 12}}>
115
  <div>Tasks Tested: <b>{result.task.toUpperCase()}</b></div>
 
108
  <div className="gap-14">
109
  <div className="chart-grid">
110
  <div className="overall-hero" style={{gridRow: 'span 2'}}>
111
+ <div className="overall-num">
112
+ {llmResult && llmResult.available ? llmResult.score.toFixed(3) : result.scores.overall.toFixed(3)}
113
+ </div>
114
+ <div className="overall-label row gap-14">
115
+ {llmResult && llmResult.available && <Sparkles size={14} className="text-accent" />}
116
+ {llmResult && llmResult.available ? 'AI-Verified Readiness Score' : 'Overall Readiness Score'}
117
+ </div>
118
  <div className="divider" style={{width: '60%'}}/>
119
  <div className="row gap-14 text-2" style={{fontSize: 12}}>
120
  <div>Tasks Tested: <b>{result.task.toUpperCase()}</b></div>