Spaces:
Running
Running
| """ | |
| ResearchForge v2 β Quality Gate Node | |
| Scores the report 0β10. Routes back to synthesizer if below threshold. | |
| """ | |
| import time | |
| import re | |
| from graph.state import ResearchState | |
| from graph.llm_factory import get_llm | |
| QUALITY_THRESHOLD = 7.0 | |
| MAX_RETRIES = 2 | |
| def quality_gate_node(state: ResearchState) -> dict: | |
| t0 = time.time() | |
| report = state.get("final_report", "") | |
| retry = state.get("retry_count", 0) | |
| logs = list(state.get("agent_logs", [])) | |
| timings = dict(state.get("agent_timings", {})) | |
| logs.append("[Quality Gate] Evaluating report quality...") | |
| llm = get_llm(temperature=0.1) | |
| prompt = f"""You are a strict research quality evaluator. Score this report from 0 to 10. | |
| Report: | |
| {report[:4000]} | |
| Scoring criteria: | |
| - Depth and comprehensiveness (0-2 points) | |
| - Evidence and factual support (0-2 points) | |
| - Structure and clarity (0-2 points) | |
| - Analytical insight beyond surface facts (0-2 points) | |
| - Practical value and actionable conclusions (0-2 points) | |
| Respond with ONLY this format (no other text): | |
| SCORE: X.X | |
| REASON: one sentence explaining the score""" | |
| response = llm.invoke(prompt) | |
| text = response.content.strip() | |
| # Parse score | |
| score = 0.0 | |
| match = re.search(r"SCORE:\s*(\d+\.?\d*)", text) | |
| if match: | |
| score = min(10.0, float(match.group(1))) | |
| reason_match = re.search(r"REASON:\s*(.+)", text) | |
| reason = reason_match.group(1) if reason_match else "No reason provided." | |
| logs.append(f"[Quality Gate] Score: {score}/10 β {reason}") | |
| timings["quality_gate"] = round(time.time() - t0, 2) | |
| return { | |
| "quality_score": score, | |
| "retry_count": retry + 1, | |
| "agent_logs": logs, | |
| "agent_timings": timings, | |
| } | |
| def should_retry(state: ResearchState) -> str: | |
| """Conditional edge function: 'retry' β synthesizer, 'done' β end.""" | |
| score = state.get("quality_score", 0) | |
| retry = state.get("retry_count", 0) | |
| if score < QUALITY_THRESHOLD and retry <= MAX_RETRIES: | |
| return "retry" | |
| return "done" | |