mirror of
https://github.com/x1xhlol/system-prompts-and-models-of-ai-tools.git
synced 2026-06-17 23:09:35 +00:00
The missing brain that connects ALL existing services into one system:
1. full_os_orchestrator.py — Deal lifecycle state machine:
12 stages: new_lead → qualifying → qualified → nurturing →
meeting_booked → meeting_done → proposal_sent → negotiating →
payment_requested → pilot_active → closed_won/lost/opted_out.
Each stage has: auto-transitions based on intent, auto-actions
(send_whatsapp, book_meeting, sync_crm, etc.), Arabic response
templates, qualification questions.
2. full_os.py API — 4 endpoints:
- POST /os/process — classify event + determine next stage + actions
- POST /os/process-and-act — same + auto-execute (WhatsApp send
via Ultramsg if safe, or create draft if human approval needed)
- POST /os/bulk-process — batch event processing
- GET /os/stages — list all stages with transitions
3. How it works:
Inbound WhatsApp → /os/process-and-act →
classify intent → transition stage →
if auto_send_allowed: send WhatsApp response immediately
if human_approval_required: create draft for Sami to review
Always: log activity + suggest next actions
4. Safety:
- Negotiation/payment/pilot stages = human_approval_required
- Opt-out = immediate stop, no further contact
- All sends via existing Ultramsg (rate limited, logged)
- Draft queue for anything needing review
Connects to existing infrastructure:
- outreach_engine._send_via_ultramsg() for WhatsApp
- OutreachDraft model for draft queue
- Reply classifier for intent detection
https://claude.ai/code/session_01W1rJthWDkasijTdXCfxVHs
170 lines
5.9 KiB
Python
170 lines
5.9 KiB
Python
"""Full OS API — unified deal lifecycle orchestration.
|
|
|
|
Single endpoint processes any event (inbound message, reply, booking,
|
|
payment) and returns: next stage, actions to take, response message,
|
|
and whether human approval is needed.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any, Dict, List, Optional
|
|
|
|
from fastapi import APIRouter
|
|
from pydantic import BaseModel
|
|
|
|
router = APIRouter(prefix="/os", tags=["Full OS"])
|
|
|
|
|
|
class ProcessEventRequest(BaseModel):
|
|
lead_id: str = ""
|
|
phone: str = ""
|
|
email: str = ""
|
|
company: str = ""
|
|
sector: str = ""
|
|
source: str = "whatsapp_inbound"
|
|
message: str = ""
|
|
current_stage: str = "new_lead"
|
|
event_type: str = "inbound_message"
|
|
|
|
|
|
class BulkProcessRequest(BaseModel):
|
|
events: List[ProcessEventRequest]
|
|
|
|
|
|
@router.post("/process")
|
|
async def process_event(req: ProcessEventRequest) -> Dict[str, Any]:
|
|
"""Process a single event through the deal lifecycle state machine.
|
|
|
|
Returns: new_stage, actions, response_message_ar, human_approval_required.
|
|
If auto_send_allowed=True, the response can be sent automatically.
|
|
If human_approval_required=True, create a draft for Sami to review.
|
|
"""
|
|
from app.services.full_os_orchestrator import orchestrator, OrchestratorEvent
|
|
|
|
event = OrchestratorEvent(
|
|
lead_id=req.lead_id,
|
|
phone=req.phone,
|
|
email=req.email,
|
|
company=req.company,
|
|
sector=req.sector,
|
|
source=req.source,
|
|
message=req.message,
|
|
current_stage=req.current_stage,
|
|
event_type=req.event_type,
|
|
)
|
|
return orchestrator.process_event(event)
|
|
|
|
|
|
@router.post("/process-and-act")
|
|
async def process_and_act(req: ProcessEventRequest) -> Dict[str, Any]:
|
|
"""Process event AND execute the first safe action.
|
|
|
|
If auto_send_allowed: sends WhatsApp response via Ultramsg.
|
|
If human_approval_required: creates a draft for review.
|
|
Always logs the activity.
|
|
"""
|
|
from app.services.full_os_orchestrator import orchestrator, OrchestratorEvent
|
|
|
|
event = OrchestratorEvent(
|
|
lead_id=req.lead_id,
|
|
phone=req.phone,
|
|
email=req.email,
|
|
company=req.company,
|
|
sector=req.sector,
|
|
source=req.source,
|
|
message=req.message,
|
|
current_stage=req.current_stage,
|
|
event_type=req.event_type,
|
|
)
|
|
result = orchestrator.process_event(event)
|
|
|
|
execution = {"action_taken": "none", "send_result": None, "draft_created": False}
|
|
|
|
if result.get("auto_send_allowed") and result.get("response_message_ar") and req.phone:
|
|
if "send_whatsapp" in result.get("actions", []):
|
|
try:
|
|
from app.api.v1.outreach_engine import _send_via_ultramsg
|
|
send_result = await _send_via_ultramsg(req.phone, result["response_message_ar"])
|
|
execution = {
|
|
"action_taken": "whatsapp_sent",
|
|
"send_result": send_result,
|
|
"draft_created": False,
|
|
}
|
|
except Exception as exc:
|
|
execution = {
|
|
"action_taken": "whatsapp_failed",
|
|
"error": str(exc)[:200],
|
|
"draft_created": False,
|
|
}
|
|
|
|
elif result.get("human_approval_required") and result.get("response_message_ar"):
|
|
try:
|
|
from app.models.outreach_draft import OutreachDraft
|
|
from app.database import async_session
|
|
async with async_session() as session:
|
|
draft = OutreachDraft(
|
|
batch_id=f"os_{result['lead_id']}",
|
|
company=req.company,
|
|
contact_phone=req.phone,
|
|
contact_email=req.email,
|
|
channel="whatsapp" if req.phone else "email",
|
|
subject=f"[{result['new_stage']}] {req.company}",
|
|
body=result["response_message_ar"],
|
|
sector=req.sector,
|
|
status="draft",
|
|
approval_required=True,
|
|
source="full_os_orchestrator",
|
|
)
|
|
session.add(draft)
|
|
await session.commit()
|
|
execution = {
|
|
"action_taken": "draft_created",
|
|
"draft_id": str(draft.id),
|
|
"draft_created": True,
|
|
}
|
|
except Exception:
|
|
execution = {"action_taken": "draft_failed", "draft_created": False}
|
|
|
|
return {**result, "execution": execution}
|
|
|
|
|
|
@router.post("/bulk-process")
|
|
async def bulk_process(req: BulkProcessRequest) -> Dict[str, Any]:
|
|
"""Process multiple events at once (for batch imports)."""
|
|
from app.services.full_os_orchestrator import orchestrator, OrchestratorEvent
|
|
|
|
results = []
|
|
for event_req in req.events:
|
|
event = OrchestratorEvent(
|
|
lead_id=event_req.lead_id,
|
|
phone=event_req.phone,
|
|
email=event_req.email,
|
|
company=event_req.company,
|
|
sector=event_req.sector,
|
|
source=event_req.source,
|
|
message=event_req.message,
|
|
current_stage=event_req.current_stage,
|
|
event_type=event_req.event_type,
|
|
)
|
|
results.append(orchestrator.process_event(event))
|
|
|
|
return {
|
|
"processed": len(results),
|
|
"results": results,
|
|
}
|
|
|
|
|
|
@router.get("/stages")
|
|
async def list_stages() -> Dict[str, Any]:
|
|
"""List all deal lifecycle stages with their possible transitions."""
|
|
from app.services.full_os_orchestrator import STAGE_TRANSITIONS, STAGE_AUTO_ACTIONS, STAGE_MESSAGES_AR
|
|
|
|
stages = {}
|
|
for stage, transitions in STAGE_TRANSITIONS.items():
|
|
stages[stage.value] = {
|
|
"transitions": {k: v.value for k, v in transitions.items()},
|
|
"auto_actions": [a.value for a in STAGE_AUTO_ACTIONS.get(stage, [])],
|
|
"message_template": STAGE_MESSAGES_AR.get(stage, ""),
|
|
}
|
|
return {"stages": stages, "total": len(stages)}
|