File size: 4,887 Bytes
5c244a3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""
Chat API Endpoint - AI Orchestrator
"""
from fastapi import APIRouter, HTTPException, Depends
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from uuid import UUID, uuid4

from src.api.models import ChatCommandRequest, ChatCommandResponse
from src.models import Task
from src.services import IntentDetector, SkillDispatcher, EventPublisher
from src.utils.database import get_db_session
from src.utils.logging import get_logger

logger = get_logger(__name__)
router = APIRouter(prefix="/chat", tags=["chat"])

intent_detector = IntentDetector()
skill_dispatcher = SkillDispatcher()
event_publisher = EventPublisher()


@router.post("/command", response_model=ChatCommandResponse)
async def chat_command(
    request: ChatCommandRequest,
    db_session: AsyncSession = Depends(get_db_session),
):
    """Process chat command via AI orchestrator"""
    correlation_id = str(uuid4())

    # Detect intent
    intent_result = intent_detector.detect(request.user_input)

    if intent_result["requires_clarification"]:
        return ChatCommandResponse(
            response=f"I need more info: {', '.join(intent_result['missing_fields'])}",
            intent_detected=intent_result["intent"],
            skill_agent_used=intent_result["agent"] or "none",
            confidence_score=intent_result["confidence"],
            requires_clarification=True,
        )

    # Build context
    context = {
        "user_id": "default-user-id",
        "db_session": db_session,
        "correlation_id": correlation_id,
    }

    # Dispatch to skill agent
    await skill_dispatcher.dispatch(
        agent_name=intent_result["agent"],
        intent_data=intent_result["data"],
        context=context,
    )

    # Execute operation
    try:
        if intent_result["intent"] == "create":
            result = await _create_task(intent_result["data"], context, correlation_id)
        elif intent_result["intent"] == "complete":
            result = await _complete_task(intent_result["data"], context, correlation_id)
        elif intent_result["intent"] == "list":
            result = await _list_tasks(intent_result["data"], context)
        else:
            result = {"response": "Could you please rephrase that?"}

        return ChatCommandResponse(
            response=result["response"],
            intent_detected=intent_result["intent"],
            skill_agent_used=intent_result["agent"],
            confidence_score=intent_result["confidence"],
            requires_clarification=False,
            data=result.get("data"),
        )
    except Exception as e:
        logger.error("chat_command_failed", error=str(e))
        raise HTTPException(status_code=500, detail=str(e))


async def _create_task(data: dict, context: dict, correlation_id: str) -> dict:
    """Create a new task"""
    db_session = context["db_session"]

    task = Task(
        user_id=UUID(context["user_id"]),
        title=data["title"],
        priority=data.get("priority", "medium"),
        tags=data.get("tags", []),
        status="active",
    )

    db_session.add(task)
    await db_session.commit()
    await db_session.refresh(task)

    # Publish event
    await event_publisher.publish_task_created(
        task_id=str(task.id),
        user_id=context["user_id"],
        task_data=task.to_dict(),
        correlation_id=correlation_id,
    )

    return {
        "response": f"I've created '{task.title}' with {task.priority} priority.",
        "data": {"task_id": str(task.id)},
    }


async def _complete_task(data: dict, context: dict, correlation_id: str) -> dict:
    """Mark a task as complete"""
    db_session = context["db_session"]

    result = await db_session.execute(select(Task).where(Task.id == UUID(data["task_id"])))
    task = result.scalar_one_or_none()

    if not task:
        return {"response": "Task not found."}

    task.status = "completed"
    await db_session.commit()

    await event_publisher.publish_task_completed(
        task_id=str(task.id),
        user_id=context["user_id"],
        correlation_id=correlation_id,
    )

    return {"response": f"Marked '{task.title}' as complete!", "data": {"task_id": str(task.id)}}


async def _list_tasks(data: dict, context: dict) -> dict:
    """List user's tasks"""
    db_session = context["db_session"]

    query = select(Task).where(Task.user_id == UUID(context["user_id"]))
    filters = data.get("filters", {})
    if "status" in filters:
        query = query.where(Task.status == filters["status"])

    result = await db_session.execute(query)
    tasks = result.scalars().all()

    if not tasks:
        return {"response": "No tasks found.", "data": {"tasks": []}}

    task_list = "\n".join([f"- {t.title} ({t.status})" for t in tasks[:10]])
    return {"response": f"Your tasks:\n{task_list}", "data": {"tasks": [t.to_dict() for t in tasks]}}