Spaces:
Sleeping
Sleeping
| from __future__ import annotations | |
| import uuid | |
| from typing import Generator | |
| from langchain_core.messages import HumanMessage | |
| from agents.graph import app_graph | |
| from agents.state import MathMentorState | |
| from config import Settings, settings | |
| from memory.store import update_feedback | |
| def _make_config(thread_id: str) -> dict: | |
| return {"configurable": {"thread_id": thread_id}} | |
| def run_pipeline( | |
| input_text: str, | |
| input_image: str | None, | |
| input_audio: str | None, | |
| input_mode: str, | |
| thread_id: str, | |
| chat_history: list, | |
| ) -> Generator[dict, None, None]: | |
| """Run the full agent pipeline, yielding partial state updates for streaming.""" | |
| if input_mode == "Image" and input_image: | |
| input_type = "image" | |
| raw_input = input_image | |
| elif input_mode == "Audio" and input_audio: | |
| input_type = "audio" | |
| raw_input = input_audio | |
| else: | |
| input_type = "text" | |
| raw_input = input_text | |
| if not settings.is_llm_configured: | |
| yield { | |
| "node": "error", | |
| "output": {"error": "LLM not configured. Set Base URL and Model in Settings or .env file."}, | |
| } | |
| return | |
| initial_state: MathMentorState = { | |
| "input_type": input_type, | |
| "raw_input": raw_input, | |
| "needs_human_review": False, | |
| "human_approved": False, | |
| "human_edited_text": "", | |
| "agent_trace": [], | |
| "chat_history": chat_history + [HumanMessage(content=raw_input if input_type == "text" else f"[{input_type} input]")], | |
| "solver_retries": 0, | |
| "retrieved_chunks": [], | |
| "similar_past_problems": [], | |
| "solution_steps": [], | |
| } | |
| config = _make_config(thread_id) | |
| try: | |
| for event in app_graph.stream(initial_state, config, stream_mode="updates"): | |
| for node_name, node_output in event.items(): | |
| yield { | |
| "node": node_name, | |
| "output": node_output, | |
| } | |
| except Exception as e: | |
| import traceback | |
| tb = traceback.format_exc() | |
| print(f"[PIPELINE ERROR] {tb}") | |
| yield { | |
| "node": "error", | |
| "output": {"error": f"{e}\n\nTraceback:\n{tb}"}, | |
| } | |
| def resume_after_hitl( | |
| thread_id: str, | |
| human_text: str = "", | |
| approved: bool = True, | |
| ) -> Generator[dict, None, None]: | |
| """Resume the graph after HITL interrupt.""" | |
| config = _make_config(thread_id) | |
| app_graph.update_state( | |
| config, | |
| { | |
| "human_edited_text": human_text, | |
| "human_approved": approved, | |
| "needs_human_review": False, | |
| }, | |
| ) | |
| try: | |
| for event in app_graph.stream(None, config, stream_mode="updates"): | |
| for node_name, node_output in event.items(): | |
| yield { | |
| "node": node_name, | |
| "output": node_output, | |
| } | |
| except Exception as e: | |
| import traceback | |
| tb = traceback.format_exc() | |
| print(f"[HITL RESUME ERROR] {tb}") | |
| yield { | |
| "node": "error", | |
| "output": {"error": f"{e}\n\nTraceback:\n{tb}"}, | |
| } | |
| def submit_feedback( | |
| thread_id: str, | |
| feedback: str, | |
| comment: str = "", | |
| ) -> str: | |
| """Submit user feedback for a solved problem.""" | |
| config = _make_config(thread_id) | |
| try: | |
| from memory.store import get_all_records | |
| records = get_all_records() | |
| if records: | |
| last_id = records[-1].get("id", "") | |
| update_feedback(last_id, feedback, comment) | |
| return f"Feedback recorded: {feedback}" | |
| except Exception as e: | |
| return f"Error saving feedback: {e}" | |
| return "No record found to update." | |
| def update_settings(base_url: str, model: str, api_key: str) -> str: | |
| """Update LLM settings at runtime. Only overwrite fields the user filled in.""" | |
| base_url = base_url.strip() | |
| model = model.strip() | |
| api_key = api_key.strip() | |
| if base_url: | |
| settings.llm_base_url = base_url | |
| if model: | |
| settings.llm_model = model | |
| if api_key: | |
| settings.llm_api_key = api_key | |
| if not settings.is_llm_configured: | |
| return "⚠ LLM not configured. Please set Base URL and Model." | |
| return f"Settings updated: {settings.llm_model} @ {settings.llm_base_url}" | |
| def new_thread_id() -> str: | |
| return str(uuid.uuid4()) | |