File size: 5,658 Bytes
d4a4da7 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
"""Angle × Concept matrix endpoints."""
from fastapi import APIRouter, HTTPException, Depends
from api.schemas import (
MatrixGenerateRequest,
MatrixGenerateResponse,
MatrixBatchRequest,
TestingMatrixResponse,
RefineCustomRequest,
RefineCustomResponse,
)
from services.generator import ad_generator
from services.matrix import matrix_service
from services.auth_dependency import get_current_user
router = APIRouter(tags=["matrix"])
@router.post("/matrix/generate", response_model=MatrixGenerateResponse)
async def generate_with_matrix(
request: MatrixGenerateRequest,
username: str = Depends(get_current_user),
):
"""
Generate ad using the Angle × Concept matrix approach.
Requires authentication. Supports custom angle/concept when key is 'custom'.
"""
try:
return await ad_generator.generate_ad_with_matrix(
niche=request.niche,
angle_key=request.angle_key,
concept_key=request.concept_key,
custom_angle=request.custom_angle,
custom_concept=request.custom_concept,
num_images=request.num_images,
image_model=request.image_model,
username=username,
core_motivator=request.core_motivator,
target_audience=request.target_audience,
offer=request.offer,
)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.post("/matrix/testing", response_model=TestingMatrixResponse)
async def generate_testing_matrix(request: MatrixBatchRequest):
"""
Generate a testing matrix (combinations without images).
Strategies: balanced, top_performers, diverse.
"""
try:
combinations = matrix_service.generate_testing_matrix(
niche=request.niche,
angle_count=request.angle_count,
concept_count=request.concept_count,
strategy=request.strategy,
)
summary = matrix_service.get_matrix_summary(combinations)
return {
"niche": request.niche,
"strategy": request.strategy,
"summary": summary,
"combinations": combinations,
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/matrix/angles")
async def list_angles():
"""List all available angles (100 total, 10 categories)."""
from data.angles import ANGLES, get_all_angles
categories = {}
for cat_key, cat_data in ANGLES.items():
categories[cat_key.value] = {
"name": cat_data["name"],
"angle_count": len(cat_data["angles"]),
"angles": [
{"key": a["key"], "name": a["name"], "trigger": a["trigger"], "example": a["example"]}
for a in cat_data["angles"]
],
}
return {"total_angles": len(get_all_angles()), "categories": categories}
@router.get("/matrix/concepts")
async def list_concepts():
"""List all available concepts (100 total, 10 categories)."""
from data.concepts import CONCEPTS, get_all_concepts
categories = {}
for cat_key, cat_data in CONCEPTS.items():
categories[cat_key.value] = {
"name": cat_data["name"],
"concept_count": len(cat_data["concepts"]),
"concepts": [
{"key": c["key"], "name": c["name"], "structure": c["structure"], "visual": c["visual"]}
for c in cat_data["concepts"]
],
}
return {"total_concepts": len(get_all_concepts()), "categories": categories}
@router.get("/matrix/angle/{angle_key}")
async def get_angle(angle_key: str):
"""Get details for a specific angle by key."""
from data.angles import get_angle_by_key
angle = get_angle_by_key(angle_key)
if not angle:
raise HTTPException(status_code=404, detail=f"Angle '{angle_key}' not found")
return angle
@router.get("/matrix/concept/{concept_key}")
async def get_concept(concept_key: str):
"""Get details for a specific concept by key."""
from data.concepts import get_concept_by_key
concept = get_concept_by_key(concept_key)
if not concept:
raise HTTPException(status_code=404, detail=f"Concept '{concept_key}' not found")
return concept
@router.get("/matrix/compatible/{angle_key}")
async def get_compatible_concepts(angle_key: str):
"""Get concepts compatible with a specific angle."""
from data.angles import get_angle_by_key
from data.concepts import get_compatible_concepts as get_compatible
angle = get_angle_by_key(angle_key)
if not angle:
raise HTTPException(status_code=404, detail=f"Angle '{angle_key}' not found")
compatible = get_compatible(angle.get("trigger", ""))
return {
"angle": {"key": angle["key"], "name": angle["name"], "trigger": angle["trigger"]},
"compatible_concepts": [
{"key": c["key"], "name": c["name"], "structure": c["structure"]}
for c in compatible
],
}
@router.post("/matrix/refine-custom", response_model=RefineCustomResponse)
async def refine_custom_angle_or_concept(request: RefineCustomRequest):
"""Refine a custom angle or concept text using AI."""
try:
result = await ad_generator.refine_custom_angle_or_concept(
text=request.text,
type=request.type,
niche=request.niche,
goal=request.goal,
)
return {"status": "success", "type": request.type, "refined": result}
except Exception as e:
return {"status": "error", "type": request.type, "refined": None, "error": str(e)}
|