Spaces:
Sleeping
Sleeping
File size: 3,790 Bytes
0c591a7 5766b78 0c591a7 3e0da39 0c591a7 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
"""
Analysis and workflow route handlers.
Handles SWOT analysis workflow lifecycle.
"""
import uuid
import threading
from fastapi import APIRouter, HTTPException
from src.api.schemas import AnalysisRequest, WorkflowStartResponse
from src.services.workflow_store import (
WORKFLOWS,
add_activity_log,
add_metric,
run_workflow_background,
)
router = APIRouter()
@router.post("/analyze", response_model=WorkflowStartResponse)
async def start_analysis(request: AnalysisRequest):
"""Start a new SWOT analysis workflow."""
workflow_id = str(uuid.uuid4())
# Initialize workflow state
WORKFLOWS[workflow_id] = {
"status": "starting",
"current_step": "input",
"revision_count": 0,
"score": 0,
"company_name": request.name,
"ticker": request.ticker,
"strategy_focus": request.strategy_focus,
"activity_log": [],
"metrics": [],
"mcp_status": {
"fundamentals": "idle",
"valuation": "idle",
"volatility": "idle",
"macro": "idle",
"news": "idle",
"sentiment": "idle"
},
"llm_status": {
"groq": "idle",
"gemini": "idle",
"openrouter": "idle"
}
}
# Start workflow in background thread
thread = threading.Thread(
target=run_workflow_background,
args=(workflow_id, request.name, request.ticker, request.strategy_focus,
request.skip_cache, request.user_api_keys),
daemon=True
)
thread.start()
return {"workflow_id": workflow_id}
@router.get("/workflow/{workflow_id}/status")
async def get_workflow_status(workflow_id: str):
"""Get current status of a workflow."""
if workflow_id not in WORKFLOWS:
raise HTTPException(status_code=404, detail="Workflow not found")
workflow = WORKFLOWS[workflow_id]
response = {
"status": workflow.get("status", "unknown"),
"current_step": workflow.get("current_step", "unknown"),
"revision_count": workflow.get("revision_count", 0),
"score": workflow.get("score", 0),
"activity_log": workflow.get("activity_log", []),
"metrics": workflow.get("metrics", []),
"mcp_status": workflow.get("mcp_status", {}),
"llm_status": workflow.get("llm_status", {}),
"provider_used": workflow.get("provider_used"),
"data_source": workflow.get("data_source")
}
# Include error message for error/aborted states
if workflow.get("status") in ("error", "aborted"):
response["error"] = workflow.get("error", "Unknown error")
return response
@router.post("/workflow/{workflow_id}/retry-mcp/{mcp_name}")
async def retry_mcp_server(workflow_id: str, mcp_name: str):
"""
Retry fetching data from a specific MCP server.
Note: MCP servers are now managed by the external Research Service.
Individual MCP retries are not available in this architecture.
Start a new analysis to refresh all data.
"""
raise HTTPException(
status_code=501,
detail="MCP retry not available. MCP servers are managed by the external Research Service. Please start a new analysis to refresh data."
)
@router.get("/workflow/{workflow_id}/result")
async def get_workflow_result(workflow_id: str):
"""Get final result of a completed workflow."""
if workflow_id not in WORKFLOWS:
raise HTTPException(status_code=404, detail="Workflow not found")
workflow = WORKFLOWS[workflow_id]
if workflow.get("status") != "completed":
raise HTTPException(
status_code=400,
detail=f"Workflow not completed. Status: {workflow.get('status')}"
)
return workflow.get("result", {})
|