File size: 6,964 Bytes
12b9f26
 
83fe4f9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b032b2d
 
83fe4f9
 
 
 
 
 
12b9f26
83fe4f9
 
 
 
12b9f26
 
 
 
 
83fe4f9
 
 
 
 
 
 
 
 
f0c7697
 
 
 
12b9f26
 
 
 
 
 
 
 
 
83fe4f9
 
 
 
f0c7697
 
 
 
12b9f26
 
 
 
 
 
 
 
 
 
 
83fe4f9
 
 
 
f0c7697
 
 
 
12b9f26
 
 
 
 
 
83fe4f9
 
 
 
 
f0c7697
 
 
 
83fe4f9
 
 
 
 
 
 
 
 
 
 
 
 
 
b032b2d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83fe4f9
 
 
 
 
 
 
426e9e3
 
 
 
 
 
83fe4f9
 
f0c7697
 
 
 
83fe4f9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12b9f26
 
fb38df2
 
 
12b9f26
 
fb38df2
12b9f26
 
fb38df2
 
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
import logging

from fastapi import APIRouter, HTTPException

from backend.ai.analyzer import analyze_business_description, analyze_custom_task
from backend.ai.workflow_builder import build_workflow_definition
from backend.ai.workflow_suggester import suggest_workflow_options
from backend.engine.compiler import compile_workflow
from backend.engine.executor import WorkflowExecutor
from backend.integrations.file_parser import parse_uploaded_payload
from backend.models.schemas import (
    AnalyzeRequest,
    BuildWorkflowRequest,
    BuildWorkflowResponse,
    CustomTaskRequest,
    DeployRequest,
    DeploymentResponse,
    EscalationReplyRequest,
    EscalationResponse,
    FileUploadRequest,
    FileUploadResponse,
    OwnerStatusResponse,
    StopAutomationRequest,
    StopAutomationResponse,
    WorkflowSuggestionRequest,
)
from backend.storage.database import db

router = APIRouter()
executor = WorkflowExecutor()
logger = logging.getLogger(__name__)


@router.post("/analyze")
def analyze(request: AnalyzeRequest) -> dict:
    try:
        analysis = analyze_business_description(request.description)
    except Exception as exc:
        logger.exception("Analyze request failed")
        raise HTTPException(status_code=500, detail=f"Analyze failed: {exc}") from exc
    owner = db.ensure_owner(request.owner_id, request.owner_email)
    owner["business_description"] = request.description
    owner["business_analysis"] = analysis
    db.save_owner(owner)
    return analysis


@router.post("/custom-task")
def custom_task(request: CustomTaskRequest) -> dict:
    try:
        owner = db.get_owner(request.owner_id)
    except KeyError as exc:
        raise HTTPException(status_code=404, detail=str(exc)) from exc
    try:
        return analyze_custom_task(
            business_description=owner.get("business_description", ""),
            existing_workflows=db.list_workflows(request.owner_id),
            custom_task=request.custom_task,
        )
    except Exception as exc:
        logger.exception("Custom task analysis failed")
        raise HTTPException(status_code=500, detail=f"Custom task analysis failed: {exc}") from exc


@router.post("/suggest-workflows")
def suggest_workflows(request: WorkflowSuggestionRequest) -> dict:
    try:
        owner = db.get_owner(request.owner_id)
    except KeyError as exc:
        raise HTTPException(status_code=404, detail=str(exc)) from exc
    try:
        return suggest_workflow_options(
            task_name=request.task_name,
            task_description=request.task_description,
            category=request.category,
            spreadsheet_info=owner.get("spreadsheet_config", {"connected": False}),
            uploaded_files=db.list_data_files(request.owner_id),
        )
    except Exception as exc:
        logger.exception("Workflow suggestion failed")
        raise HTTPException(status_code=500, detail=f"Workflow suggestion failed: {exc}") from exc


@router.post("/build-workflow", response_model=BuildWorkflowResponse)
def build_workflow(request: BuildWorkflowRequest) -> BuildWorkflowResponse:
    try:
        owner = db.get_owner(request.owner_id)
    except KeyError as exc:
        raise HTTPException(status_code=404, detail=str(exc)) from exc
    try:
        workflow_json = build_workflow_definition(request=request, owner=owner)
        compiled = compile_workflow(workflow_json)
    except Exception as exc:
        logger.exception("Workflow build failed")
        raise HTTPException(status_code=500, detail=f"Workflow build failed: {exc}") from exc
    return BuildWorkflowResponse(workflow=compiled)


@router.post("/deploy", response_model=DeploymentResponse)
def deploy_workflow(request: DeployRequest) -> DeploymentResponse:
    try:
        owner = db.get_owner(request.owner_id)
    except KeyError as exc:
        raise HTTPException(status_code=404, detail=str(exc)) from exc
    deployments = []
    for workflow in request.workflows:
        compiled = compile_workflow(workflow.model_dump())
        saved = db.save_workflow(request.owner_id, compiled)
        deployments.append(saved)
    owner["state"] = "live"
    db.save_owner(owner)
    return DeploymentResponse(
        status="deployed",
        workflows=deployments,
        message="All workflows are live.",
    )


@router.post("/stop", response_model=StopAutomationResponse)
def stop_automation(request: StopAutomationRequest) -> StopAutomationResponse:
    try:
        owner = db.get_owner(request.owner_id)
    except KeyError as exc:
        raise HTTPException(status_code=404, detail=str(exc)) from exc
    workflows = db.deactivate_workflows(request.owner_id)
    owner["state"] = "paused"
    db.save_owner(owner)
    return StopAutomationResponse(
        status="stopped",
        workflows=workflows,
        message="Automation stopped.",
    )


@router.post("/upload-data", response_model=FileUploadResponse)
def upload_data(request: FileUploadRequest) -> FileUploadResponse:
    parsed = parse_uploaded_payload(request.filename, request.content, request.purpose)
    record = db.save_data_file(request.owner_id, request.filename, request.file_type, request.purpose, parsed)
    return FileUploadResponse(file=record)


@router.post("/reset")
def reset_data() -> dict[str, str]:
    db.reset()
    return {"status": "ok", "message": "In-memory data reset."}


@router.get("/status", response_model=OwnerStatusResponse)
def status(owner_id: str) -> OwnerStatusResponse:
    try:
        owner = db.get_owner(owner_id)
    except KeyError as exc:
        raise HTTPException(status_code=404, detail=str(exc)) from exc
    return OwnerStatusResponse(
        owner=owner,
        workflows=db.list_workflows(owner_id),
        recent_executions=db.list_execution_logs(owner_id),
    )


@router.get("/escalations")
def escalations(owner_id: str) -> dict:
    return {"items": db.list_escalations(owner_id)}


@router.post("/escalation-reply", response_model=EscalationResponse)
def escalation_reply(request: EscalationReplyRequest) -> EscalationResponse:
    escalation = db.resolve_escalation(request.escalation_id, request.response)
    return EscalationResponse(escalation=escalation)


@router.post("/simulate-run")
def simulate_run(owner_id: str, workflow_id: str, trigger: dict) -> dict:
    workflow = db.get_workflow(owner_id, workflow_id)
    result = executor.execute(workflow, trigger, db=db, owner_id=owner_id)
    db.save_execution_log(owner_id, workflow_id, trigger, result["steps"], result["outcome"], result.get("error"))
    return result


@router.get("/debug/groq")
def debug_groq() -> dict:
    from backend.ai.client import llm_client

    try:
        text = llm_client.generate_text("Reply with exactly: Groq debug ok")
        return {"status": "ok", "response": text}
    except Exception as exc:
        logger.exception("Groq debug call failed")
        raise HTTPException(status_code=500, detail=f"Groq debug failed: {exc}") from exc