feat: compose native research workflows in QuantFlow
This commit is contained in:
@@ -22,6 +22,7 @@ from .workspace_contracts import (
|
||||
ImportCommit,
|
||||
ImportPreview,
|
||||
SettingVariants,
|
||||
WorkflowSpec,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/api/v1/research", tags=["research"], dependencies=[Depends(require_auth)])
|
||||
@@ -41,7 +42,7 @@ async def assets(
|
||||
limit: int = Query(25, ge=1, le=100),
|
||||
offset: int = Query(0, ge=0),
|
||||
):
|
||||
if kind not in ("template", "feature", "view"):
|
||||
if kind not in ("template", "feature", "view", "workflow"):
|
||||
raise HTTPException(422, "当前素材类型尚未开放")
|
||||
async with request.app.state.sessions() as db:
|
||||
return await Assets(db).list(kind, q, limit, offset)
|
||||
@@ -49,7 +50,7 @@ async def assets(
|
||||
|
||||
@router.post("/assets", status_code=201)
|
||||
async def save_asset(body: AssetWrite, request: Request):
|
||||
if body.kind not in ("template", "feature", "view"):
|
||||
if body.kind not in ("template", "feature", "view", "workflow"):
|
||||
raise HTTPException(422, "当前素材类型尚未开放")
|
||||
async with request.app.state.sessions.begin() as db:
|
||||
return await Assets(db).save(body)
|
||||
@@ -63,7 +64,7 @@ async def asset(asset_id: str, request: Request, version: int | None = Query(Non
|
||||
|
||||
@router.put("/assets/{asset_id}")
|
||||
async def update_asset(asset_id: str, body: AssetWrite, request: Request):
|
||||
if body.kind not in ("template", "feature", "view"):
|
||||
if body.kind not in ("template", "feature", "view", "workflow"):
|
||||
raise HTTPException(422, "当前素材类型尚未开放")
|
||||
async with request.app.state.sessions.begin() as db:
|
||||
return await Assets(db).save(body, asset_id)
|
||||
@@ -240,21 +241,42 @@ async def fixed_recipe():
|
||||
async def start_flow(body: FlowStart, request: Request):
|
||||
from .workflows import Workflows
|
||||
|
||||
if body.workflow_id:
|
||||
raise HTTPException(422, "自定义流程将在 QuantFlow 阶段开放")
|
||||
async with request.app.state.sessions.begin() as db:
|
||||
config = await request.app.state.ai.config(db)
|
||||
result = await Workflows(db).start(body, config.revision)
|
||||
from .workflows import fixed_workflow
|
||||
from .workspace_contracts import WorkflowSpec
|
||||
|
||||
graph = (
|
||||
WorkflowSpec.model_validate(
|
||||
(await Assets(db).get(body.workflow_id, body.workflow_version, "workflow"))["content"]
|
||||
)
|
||||
if body.workflow_id
|
||||
else fixed_workflow(body.budget.max_rounds)
|
||||
)
|
||||
needs_model = any(
|
||||
n.type == "generate"
|
||||
or (n.type == "feature" and not n.config.get("asset_id"))
|
||||
or (n.type == "variant" and n.config.get("method", "structure") == "structure")
|
||||
for n in graph.nodes
|
||||
)
|
||||
config = await request.app.state.ai.config(db) if needs_model else None
|
||||
result = await Workflows(db).start(body, config.revision if config else None)
|
||||
request.app.state.research.wake.set()
|
||||
return result
|
||||
|
||||
|
||||
@router.get("/flows/runs")
|
||||
async def flow_runs(request: Request, limit: int = Query(25, ge=1, le=100), offset: int = Query(0, ge=0)):
|
||||
async def flow_runs(
|
||||
request: Request,
|
||||
limit: int = Query(25, ge=1, le=100),
|
||||
offset: int = Query(0, ge=0),
|
||||
kind: str | None = None,
|
||||
):
|
||||
from .workflows import Workflows
|
||||
|
||||
async with request.app.state.sessions() as db:
|
||||
return await Workflows(db).list(limit, offset)
|
||||
if kind not in (None, "pipeline", "quantflow"):
|
||||
raise HTTPException(422, "未知研究运行类型")
|
||||
return await Workflows(db).list(limit, offset, kind)
|
||||
|
||||
|
||||
@router.get("/flows/runs/{run_id}")
|
||||
@@ -276,3 +298,17 @@ async def control_flow(run_id: str, body: FlowControl, request: Request):
|
||||
request.app.state.research.wake.set()
|
||||
request.app.state.runner.backtests.wake.set()
|
||||
return result
|
||||
|
||||
|
||||
@router.get("/flows/nodes")
|
||||
async def flow_nodes():
|
||||
from .workflows import NODE_TYPES
|
||||
|
||||
return {"items": [{"type": key, **value} for key, value in NODE_TYPES.items()]}
|
||||
|
||||
|
||||
@router.post("/flows/validate")
|
||||
async def validate_flow(body: WorkflowSpec):
|
||||
from .workflows import validate_graph
|
||||
|
||||
return {"valid": True, "order": validate_graph(body)}
|
||||
|
||||
Reference in New Issue
Block a user