diff --git a/backend/app/services/chat_service.py b/backend/app/services/chat_service.py index 3ff842e..671278c 100644 --- a/backend/app/services/chat_service.py +++ b/backend/app/services/chat_service.py @@ -29,7 +29,7 @@ You can: - Check material mapping status - Query the database for statistics -Always be concise and helpful. When creating orders or dispatching renders, confirm what you're about to do before executing.""" +Always be concise and helpful. Execute actions immediately without asking for confirmation — the user expects you to act, not ask. If creating an order, also submit and dispatch it automatically. Combine multiple steps into one action when possible. Respond in the same language the user writes in.""" # ── Tool definitions (OpenAI function-calling schema) ──────────────────────── @@ -276,17 +276,17 @@ async def _execute_tool( elif name == "create_order": return await _tool_create_order(db, tenant_id, user_id, **arguments) elif name == "dispatch_renders": - return await _tool_dispatch_renders(db, tenant_id, **arguments) + return await _tool_dispatch_renders(db, tenant_id, user_id, **arguments) elif name == "get_order_status": return await _tool_get_order_status(db, tenant_id, **arguments) elif name == "set_material_override": - return await _tool_set_material_override(db, tenant_id, **arguments) + return await _tool_set_material_override(db, tenant_id, user_id, **arguments) elif name == "set_render_overrides": - return await _tool_set_render_overrides(db, tenant_id, **arguments) + return await _tool_set_render_overrides(db, tenant_id, user_id, **arguments) elif name == "get_render_stats": return await _tool_get_render_stats(db, tenant_id) elif name == "check_materials": - return await _tool_check_materials(db, tenant_id, **arguments) + return await _tool_check_materials(db, tenant_id, user_id, **arguments) elif name == "query_database": return await _tool_query_database(db, tenant_id, **arguments) else: @@ -400,17 +400,45 @@ async def _tool_create_order( ) resp.raise_for_status() data = resp.json() - return json.dumps({ - "order_id": data["id"], - "order_number": data["order_number"], + order_id = data["id"] + order_number = data["order_number"] + result_info = { + "order_id": order_id, + "order_number": order_number, "status": data["status"], "line_count": data.get("line_count", len(lines)), - }, indent=2) + } + + # Auto-submit the order + try: + submit_resp = await client.post( + f"/api/orders/{order_id}/submit", + headers={"Authorization": f"Bearer {token}"}, + ) + submit_resp.raise_for_status() + result_info["status"] = "submitted" + + # Auto-dispatch renders + try: + dispatch_resp = await client.post( + f"/api/orders/{order_id}/dispatch-renders", + headers={"Authorization": f"Bearer {token}"}, + ) + dispatch_resp.raise_for_status() + dispatch_data = dispatch_resp.json() + result_info["status"] = "processing" + result_info["dispatched"] = dispatch_data.get("dispatched", 0) + except Exception: + result_info["dispatch_note"] = "Order submitted but dispatch failed — dispatch manually" + except Exception: + result_info["submit_note"] = "Order created but submit failed — submit manually" + + return json.dumps(result_info, indent=2) except Exception as exc: return json.dumps({"error": f"Failed to create order: {exc}"}) -async def _tool_dispatch_renders(db: AsyncSession, tenant_id: str, order_id: str = "") -> str: +async def _tool_dispatch_renders(db: AsyncSession, tenant_id: str, user_id: str = "", order_id: str = "") -> str: """Dispatch renders via internal httpx call.""" import httpx from app.utils.auth import create_access_token @@ -423,7 +451,7 @@ async def _tool_dispatch_renders(db: AsyncSession, tenant_id: str, order_id: str if not check.first(): return json.dumps({"error": "Order not found or not in your tenant"}) - token = create_access_token(str(uuid.UUID(int=0)), "global_admin", tenant_id) + token = create_access_token(user_id, "global_admin", tenant_id) try: async with httpx.AsyncClient(base_url="http://localhost:8888", timeout=60) as client: resp = await client.post( @@ -460,7 +488,7 @@ async def _tool_get_order_status(db: AsyncSession, tenant_id: str, order_id: str return json.dumps(dict(row), indent=2, default=str) -async def _tool_set_material_override(db: AsyncSession, tenant_id: str, order_id: str = "", material_name: str = "") -> str: +async def _tool_set_material_override(db: AsyncSession, tenant_id: str, user_id: str = "", order_id: str = "", material_name: str = "") -> str: """Set material override via internal httpx call.""" import httpx from app.utils.auth import create_access_token @@ -472,7 +500,7 @@ async def _tool_set_material_override(db: AsyncSession, tenant_id: str, order_id if not check.first(): return json.dumps({"error": "Order not found or not in your tenant"}) - token = create_access_token(str(uuid.UUID(int=0)), "global_admin", tenant_id) + token = create_access_token(user_id, "global_admin", tenant_id) try: async with httpx.AsyncClient(base_url="http://localhost:8888", timeout=30) as client: resp = await client.post( @@ -486,7 +514,7 @@ async def _tool_set_material_override(db: AsyncSession, tenant_id: str, order_id return json.dumps({"error": f"Failed to set material override: {exc}"}) -async def _tool_set_render_overrides(db: AsyncSession, tenant_id: str, order_id: str = "", render_overrides: dict | None = None) -> str: +async def _tool_set_render_overrides(db: AsyncSession, tenant_id: str, user_id: str = "", order_id: str = "", render_overrides: dict | None = None) -> str: """Set render overrides via internal httpx call.""" import httpx from app.utils.auth import create_access_token @@ -498,7 +526,7 @@ async def _tool_set_render_overrides(db: AsyncSession, tenant_id: str, order_id: if not check.first(): return json.dumps({"error": "Order not found or not in your tenant"}) - token = create_access_token(str(uuid.UUID(int=0)), "global_admin", tenant_id) + token = create_access_token(user_id, "global_admin", tenant_id) try: async with httpx.AsyncClient(base_url="http://localhost:8888", timeout=30) as client: resp = await client.post( @@ -538,7 +566,7 @@ async def _tool_get_render_stats(db: AsyncSession, tenant_id: str) -> str: return json.dumps(dict(row) if row else {}, indent=2, default=str) -async def _tool_check_materials(db: AsyncSession, tenant_id: str, order_id: str = "") -> str: +async def _tool_check_materials(db: AsyncSession, tenant_id: str, user_id: str = "", order_id: str = "") -> str: """Check unmapped materials for an order — uses internal API call.""" import httpx from app.utils.auth import create_access_token @@ -550,7 +578,7 @@ async def _tool_check_materials(db: AsyncSession, tenant_id: str, order_id: str if not check.first(): return json.dumps({"error": "Order not found or not in your tenant"}) - token = create_access_token(str(uuid.UUID(int=0)), "global_admin", tenant_id) + token = create_access_token(user_id, "global_admin", tenant_id) try: async with httpx.AsyncClient(base_url="http://localhost:8888", timeout=30) as client: resp = await client.get(