API
This commit is contained in:
96
app/routers/proactive.py
Normal file
96
app/routers/proactive.py
Normal file
@@ -0,0 +1,96 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
|
||||
from app.middleware.auth import get_current_user_id
|
||||
from app.models import (
|
||||
ProactiveExecuteRequest,
|
||||
ProactiveExecuteResponse,
|
||||
ProactivePreference,
|
||||
ProactivePreferencesResponse,
|
||||
ProactiveRespondRequest,
|
||||
ProactiveRespondResponse,
|
||||
)
|
||||
from app.services.db import get_pool
|
||||
|
||||
router = APIRouter(prefix="/proactive", tags=["proactive"])
|
||||
|
||||
|
||||
@router.post("/respond", response_model=ProactiveRespondResponse)
|
||||
async def respond_to_action(req: ProactiveRespondRequest, user_id: str = Depends(get_current_user_id)):
|
||||
pool = await get_pool()
|
||||
|
||||
row = await pool.fetchrow(
|
||||
"SELECT id, user_id FROM proactive_actions WHERE id = $1 AND user_id = $2::uuid",
|
||||
req.proactive_action_id,
|
||||
user_id,
|
||||
)
|
||||
if not row:
|
||||
raise HTTPException(status_code=404, detail="Proactive action not found")
|
||||
|
||||
await pool.execute(
|
||||
"UPDATE proactive_actions SET user_choice = $1, chosen_action = $2, responded_at = now() WHERE id = $3",
|
||||
req.user_choice,
|
||||
req.chosen_action,
|
||||
req.proactive_action_id,
|
||||
)
|
||||
|
||||
return ProactiveRespondResponse(
|
||||
logged=True,
|
||||
should_execute=req.user_choice == "accepted",
|
||||
)
|
||||
|
||||
|
||||
@router.post("/execute", response_model=ProactiveExecuteResponse)
|
||||
async def execute_action(req: ProactiveExecuteRequest, user_id: str = Depends(get_current_user_id)):
|
||||
pool = await get_pool()
|
||||
|
||||
row = await pool.fetchrow(
|
||||
"SELECT id, user_choice FROM proactive_actions WHERE id = $1 AND user_id = $2::uuid",
|
||||
req.proactive_action_id,
|
||||
user_id,
|
||||
)
|
||||
if not row:
|
||||
raise HTTPException(status_code=404, detail="Proactive action not found")
|
||||
|
||||
# Mark as executed — actual execution happens device-side (AppleScript/Computer Use)
|
||||
# This endpoint logs that it was executed and can store results
|
||||
await pool.execute(
|
||||
"UPDATE proactive_actions SET executed = true WHERE id = $1",
|
||||
req.proactive_action_id,
|
||||
)
|
||||
|
||||
return ProactiveExecuteResponse(
|
||||
executed=True,
|
||||
result=f"Action {req.action_type} marked as executed. Device-side execution handles the actual work.",
|
||||
)
|
||||
|
||||
|
||||
@router.get("/preferences", response_model=ProactivePreferencesResponse)
|
||||
async def get_preferences(user_id: str = Depends(get_current_user_id)):
|
||||
pool = await get_pool()
|
||||
|
||||
rows = await pool.fetch(
|
||||
"""SELECT
|
||||
friction_type,
|
||||
COUNT(*) as total,
|
||||
COUNT(*) FILTER (WHERE user_choice = 'accepted') as accepted,
|
||||
(SELECT chosen_action FROM proactive_actions pa2
|
||||
WHERE pa2.user_id = $1::uuid AND pa2.friction_type = pa.friction_type
|
||||
AND pa2.user_choice = 'accepted'
|
||||
GROUP BY chosen_action ORDER BY COUNT(*) DESC LIMIT 1) as top_action
|
||||
FROM proactive_actions pa
|
||||
WHERE user_id = $1::uuid AND user_choice IS NOT NULL
|
||||
GROUP BY friction_type""",
|
||||
user_id,
|
||||
)
|
||||
|
||||
preferences = {}
|
||||
for r in rows:
|
||||
total = r["total"]
|
||||
accepted = r["accepted"]
|
||||
preferences[r["friction_type"]] = ProactivePreference(
|
||||
preferred_action=r["top_action"],
|
||||
total_choices=total,
|
||||
acceptance_rate=accepted / total if total > 0 else 0.0,
|
||||
)
|
||||
|
||||
return ProactivePreferencesResponse(preferences=preferences)
|
||||
Reference in New Issue
Block a user