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)}