mirror of
https://github.com/sstent/AICyclingCoach.git
synced 2026-01-25 16:41:58 +00:00
122 lines
3.9 KiB
Python
122 lines
3.9 KiB
Python
from fastapi import APIRouter, Depends, HTTPException
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from sqlalchemy import select
|
|
from backend.app.database import get_db
|
|
from backend.app.models.rule import Rule
|
|
from backend.app.schemas.rule import RuleCreate, Rule as RuleSchema, NaturalLanguageRuleRequest, ParsedRuleResponse
|
|
from backend.app.dependencies import get_ai_service
|
|
from backend.app.services.ai_service import AIService
|
|
from uuid import UUID
|
|
from typing import List
|
|
|
|
router = APIRouter(prefix="/rules", tags=["Rules"])
|
|
|
|
@router.post("/", response_model=RuleSchema)
|
|
async def create_rule(
|
|
rule: RuleCreate,
|
|
db: AsyncSession = Depends(get_db)
|
|
):
|
|
"""Create new rule set (plaintext) as per design specification."""
|
|
db_rule = Rule(**rule.model_dump())
|
|
db.add(db_rule)
|
|
await db.commit()
|
|
await db.refresh(db_rule)
|
|
return db_rule
|
|
|
|
@router.get("/", response_model=List[RuleSchema])
|
|
async def list_rules(
|
|
active_only: bool = True,
|
|
db: AsyncSession = Depends(get_db)
|
|
):
|
|
"""List rule sets as specified in design document."""
|
|
query = select(Rule)
|
|
if active_only:
|
|
# For now, return all rules. Later we can add an 'active' field
|
|
pass
|
|
result = await db.execute(query)
|
|
return result.scalars().all()
|
|
|
|
@router.get("/{rule_id}", response_model=RuleSchema)
|
|
async def get_rule(
|
|
rule_id: UUID,
|
|
db: AsyncSession = Depends(get_db)
|
|
):
|
|
"""Get specific rule set."""
|
|
rule = await db.get(Rule, rule_id)
|
|
if not rule:
|
|
raise HTTPException(status_code=404, detail="Rule not found")
|
|
return rule
|
|
|
|
@router.put("/{rule_id}", response_model=RuleSchema)
|
|
async def update_rule(
|
|
rule_id: UUID,
|
|
rule: RuleCreate,
|
|
db: AsyncSession = Depends(get_db)
|
|
):
|
|
"""Update rule set - creates new version as per design spec."""
|
|
db_rule = await db.get(Rule, rule_id)
|
|
if not db_rule:
|
|
raise HTTPException(status_code=404, detail="Rule not found")
|
|
|
|
# Create new version instead of updating in place
|
|
new_version = Rule(
|
|
name=rule.name,
|
|
description=rule.description,
|
|
user_defined=rule.user_defined,
|
|
rule_text=rule.rule_text,
|
|
version=db_rule.version + 1,
|
|
parent_rule_id=db_rule.id
|
|
)
|
|
|
|
db.add(new_version)
|
|
await db.commit()
|
|
await db.refresh(new_version)
|
|
return new_version
|
|
|
|
@router.delete("/{rule_id}")
|
|
async def delete_rule(
|
|
rule_id: UUID,
|
|
db: AsyncSession = Depends(get_db)
|
|
):
|
|
"""Delete rule set."""
|
|
rule = await db.get(Rule, rule_id)
|
|
if not rule:
|
|
raise HTTPException(status_code=404, detail="Rule not found")
|
|
|
|
await db.delete(rule)
|
|
await db.commit()
|
|
return {"detail": "Rule deleted"}
|
|
|
|
@router.post("/parse-natural-language", response_model=ParsedRuleResponse)
|
|
async def parse_natural_language_rules(
|
|
request: NaturalLanguageRuleRequest,
|
|
ai_service: AIService = Depends(get_ai_service)
|
|
):
|
|
"""
|
|
Parse natural language training rules into structured format using AI.
|
|
This helps users create rules but the final rule_text is stored as plaintext.
|
|
"""
|
|
try:
|
|
# Parse rules using AI service - this creates structured data for validation
|
|
parsed_rules = await ai_service.parse_rules_from_natural_language(request.natural_language_text)
|
|
|
|
# Simple validation - just check for basic completeness
|
|
suggestions = []
|
|
if len(request.natural_language_text.split()) < 10:
|
|
suggestions.append("Consider providing more detailed rules")
|
|
|
|
response = ParsedRuleResponse(
|
|
parsed_rules=parsed_rules,
|
|
confidence_score=0.8, # Simplified confidence
|
|
suggestions=suggestions,
|
|
validation_errors=[], # Simplified - no complex validation
|
|
rule_name=request.rule_name
|
|
)
|
|
|
|
return response
|
|
|
|
except Exception as e:
|
|
raise HTTPException(
|
|
status_code=500,
|
|
detail=f"Failed to parse natural language rules: {str(e)}"
|
|
) |