Files
ai-contract-platform/backend/app/api/prompt_assets.py
T

312 lines
12 KiB
Python

from typing import Optional
from fastapi import APIRouter, Depends, Form, Header
from sqlalchemy.orm import Session
from app.core.response import success_response
from app.db import get_db_session
from app.services.audit_log_service import AuditLogService
from app.services.auth_service import AuthService
from app.services.prompt_asset_service import PromptAssetService
router = APIRouter(prefix="/prompt-assets", tags=["prompt-assets"])
ROUTE_PERMISSION_SCOPE = "prompt_asset_management"
ROUTE_PERMISSION_ACTIONS = {
"list": "prompt_assets:list",
"detail": "prompt_assets:detail",
"create": "prompt_assets:create",
"create_version": "prompt_assets:versions:create",
"evaluate": "prompt_assets:evaluations:run",
"publish": "prompt_assets:publish",
"unpublish": "prompt_assets:unpublish",
"rollback": "prompt_assets:rollback",
"record_run_link": "prompt_assets:run_links:create",
}
def get_prompt_asset_service(db: Session = Depends(get_db_session)) -> PromptAssetService:
return PromptAssetService(db)
def get_audit_log_service(db: Session = Depends(get_db_session)) -> AuditLogService:
return AuditLogService(db)
def require_current_user(
authorization: Optional[str] = Header(default=None),
db: Session = Depends(get_db_session),
):
return AuthService(db).require_current_user(authorization)
@router.get("")
def list_prompt_assets(
page: int = 1,
page_size: int = 20,
prompt_type: Optional[str] = None,
status_filter: Optional[str] = None,
prompt_asset_service: PromptAssetService = Depends(get_prompt_asset_service),
current_user: dict = Depends(require_current_user),
):
return success_response(prompt_asset_service.list_prompt_assets(current_user, page, page_size, prompt_type, status_filter))
@router.get("/{asset_id}")
def get_prompt_asset_detail(
asset_id: str,
prompt_asset_service: PromptAssetService = Depends(get_prompt_asset_service),
current_user: dict = Depends(require_current_user),
):
return success_response(prompt_asset_service.get_prompt_asset_detail(current_user, asset_id))
@router.post("")
def create_prompt_asset(
prompt_key: str = Form(...),
prompt_type: str = Form(...),
name: str = Form(...),
prompt_content: str = Form(...),
description: Optional[str] = Form(default=None),
target_scene: Optional[str] = Form(default=None),
system_prompt: Optional[str] = Form(default=None),
variables_json: Optional[str] = Form(default=None),
output_schema_json: Optional[str] = Form(default=None),
model_config_json: Optional[str] = Form(default=None),
evaluation_report_json: Optional[str] = Form(default=None),
evaluation_status: Optional[str] = Form(default=None),
evaluation_score: Optional[float] = Form(default=None),
change_summary: Optional[str] = Form(default=None),
prompt_asset_service: PromptAssetService = Depends(get_prompt_asset_service),
audit_log_service: AuditLogService = Depends(get_audit_log_service),
current_user: dict = Depends(require_current_user),
):
result = prompt_asset_service.create_prompt_asset(
current_user,
prompt_key,
prompt_type,
name,
prompt_content,
description=description,
target_scene=target_scene,
system_prompt=system_prompt,
variables_json=variables_json,
output_schema_json=output_schema_json,
model_config_json=model_config_json,
evaluation_report_json=evaluation_report_json,
evaluation_status=evaluation_status,
evaluation_score=evaluation_score,
change_summary=change_summary,
)
audit_log_service.record_event(
tenant_id=current_user.get("tenant_id"),
user_id=current_user.get("id"),
action="create_prompt_asset",
resource_type="prompt_asset",
resource_id=result["id"],
detail_json={
"prompt_key": result["prompt_key"],
"prompt_type": result["prompt_type"],
"current_version_label": result["current_version_label"],
"evaluation_status": result.get("latest_evaluation_status"),
},
)
return success_response(result)
@router.post("/{asset_id}/versions")
def create_prompt_asset_version(
asset_id: str,
prompt_content: str = Form(...),
system_prompt: Optional[str] = Form(default=None),
variables_json: Optional[str] = Form(default=None),
output_schema_json: Optional[str] = Form(default=None),
model_config_json: Optional[str] = Form(default=None),
evaluation_report_json: Optional[str] = Form(default=None),
evaluation_status: Optional[str] = Form(default=None),
evaluation_score: Optional[float] = Form(default=None),
change_summary: Optional[str] = Form(default=None),
prompt_asset_service: PromptAssetService = Depends(get_prompt_asset_service),
audit_log_service: AuditLogService = Depends(get_audit_log_service),
current_user: dict = Depends(require_current_user),
):
result = prompt_asset_service.create_prompt_asset_version(
current_user,
asset_id,
prompt_content,
system_prompt=system_prompt,
variables_json=variables_json,
output_schema_json=output_schema_json,
model_config_json=model_config_json,
evaluation_report_json=evaluation_report_json,
evaluation_status=evaluation_status,
evaluation_score=evaluation_score,
change_summary=change_summary,
)
audit_log_service.record_event(
tenant_id=current_user.get("tenant_id"),
user_id=current_user.get("id"),
action="create_prompt_asset_version",
resource_type="prompt_asset",
resource_id=result["id"],
detail_json={
"prompt_key": result["prompt_key"],
"current_version_label": result["current_version_label"],
"evaluation_status": result.get("latest_evaluation_status"),
},
)
return success_response(result)
@router.post("/{asset_id}/evaluations/run")
def run_prompt_asset_evaluation(
asset_id: str,
prompt_asset_service: PromptAssetService = Depends(get_prompt_asset_service),
audit_log_service: AuditLogService = Depends(get_audit_log_service),
current_user: dict = Depends(require_current_user),
):
result = prompt_asset_service.evaluate_current_prompt_asset(current_user, asset_id)
audit_log_service.record_event(
tenant_id=current_user.get("tenant_id"),
user_id=current_user.get("id"),
action="run_prompt_asset_evaluation",
resource_type="prompt_asset",
resource_id=result["asset"]["id"],
detail_json={
"prompt_key": result["asset"]["prompt_key"],
"prompt_type": result["asset"]["prompt_type"],
"version_label": result["version"]["version_label"],
"evaluation_status": result["version"]["evaluation_status"],
"evaluation_score": result["version"]["evaluation_score"],
"suite_key": result["evaluation_report"].get("suite_key"),
"evaluation_mode": result["evaluation_report"].get("evaluation_mode"),
"sample_count": result["evaluation_report"].get("sample_count"),
"passed_samples": result["evaluation_report"].get("passed_samples"),
"failed_samples": result["evaluation_report"].get("failed_samples"),
},
)
return success_response(result)
@router.post("/{asset_id}/publish")
def publish_prompt_asset(
asset_id: str,
evaluation_report_json: Optional[str] = Form(default=None),
evaluation_status: Optional[str] = Form(default=None),
evaluation_score: Optional[float] = Form(default=None),
prompt_asset_service: PromptAssetService = Depends(get_prompt_asset_service),
audit_log_service: AuditLogService = Depends(get_audit_log_service),
current_user: dict = Depends(require_current_user),
):
result = prompt_asset_service.publish_prompt_asset(
current_user,
asset_id,
evaluation_report_json=evaluation_report_json,
evaluation_status=evaluation_status,
evaluation_score=evaluation_score,
)
audit_log_service.record_event(
tenant_id=current_user.get("tenant_id"),
user_id=current_user.get("id"),
action="publish_prompt_asset",
resource_type="prompt_asset",
resource_id=result["id"],
detail_json={
"prompt_key": result["prompt_key"],
"published_version_id": result["published_version_id"],
"published_at": result["published_at"],
"evaluation_status": result.get("latest_evaluation_status"),
"evaluation_score": result.get("latest_evaluation_score"),
},
)
return success_response(result)
@router.post("/{asset_id}/unpublish")
def unpublish_prompt_asset(
asset_id: str,
prompt_asset_service: PromptAssetService = Depends(get_prompt_asset_service),
audit_log_service: AuditLogService = Depends(get_audit_log_service),
current_user: dict = Depends(require_current_user),
):
result = prompt_asset_service.unpublish_prompt_asset(current_user, asset_id)
audit_log_service.record_event(
tenant_id=current_user.get("tenant_id"),
user_id=current_user.get("id"),
action="unpublish_prompt_asset",
resource_type="prompt_asset",
resource_id=result["id"],
detail_json={
"prompt_key": result["prompt_key"],
"status": result["status"],
},
)
return success_response(result)
@router.post("/{asset_id}/rollback")
def rollback_prompt_asset(
asset_id: str,
target_version_label: str = Form(...),
change_summary: Optional[str] = Form(default=None),
prompt_asset_service: PromptAssetService = Depends(get_prompt_asset_service),
audit_log_service: AuditLogService = Depends(get_audit_log_service),
current_user: dict = Depends(require_current_user),
):
result = prompt_asset_service.rollback_prompt_asset(current_user, asset_id, target_version_label, change_summary)
audit_log_service.record_event(
tenant_id=current_user.get("tenant_id"),
user_id=current_user.get("id"),
action="rollback_prompt_asset",
resource_type="prompt_asset",
resource_id=result["id"],
detail_json={
"prompt_key": result["prompt_key"],
"target_version_label": target_version_label,
"current_version_label": result["current_version_label"],
"status": result["status"],
},
)
return success_response(result)
@router.post("/{asset_id}/run-links")
def record_prompt_run_link(
asset_id: str,
run_type: str = Form(default="ai_run"),
run_id: Optional[str] = Form(default=None),
resource_type: Optional[str] = Form(default=None),
resource_id: Optional[str] = Form(default=None),
workflow_run_id: Optional[str] = Form(default=None),
task_run_id: Optional[str] = Form(default=None),
trace_json: Optional[str] = Form(default=None),
prompt_asset_service: PromptAssetService = Depends(get_prompt_asset_service),
audit_log_service: AuditLogService = Depends(get_audit_log_service),
current_user: dict = Depends(require_current_user),
):
result = prompt_asset_service.record_prompt_run_link(
current_user,
asset_id,
run_type,
run_id=run_id,
resource_type=resource_type,
resource_id=resource_id,
workflow_run_id=workflow_run_id,
task_run_id=task_run_id,
trace_json=trace_json,
)
audit_log_service.record_event(
tenant_id=current_user.get("tenant_id"),
user_id=current_user.get("id"),
action="record_prompt_asset_run_link",
resource_type="prompt_asset_run_link",
resource_id=result["id"],
detail_json={
"prompt_asset_id": result["prompt_asset_id"],
"prompt_asset_version_id": result["prompt_asset_version_id"],
"run_id": result["run_id"],
"resource_type": result["resource_type"],
"resource_id": result["resource_id"],
},
)
return success_response(result)