|
|
import apiClient from "./client"; |
|
|
import type { |
|
|
GenerateResponse, |
|
|
BatchResponse, |
|
|
MatrixGenerateResponse, |
|
|
TestingMatrixResponse, |
|
|
AnglesResponse, |
|
|
ConceptsResponse, |
|
|
CompatibleConceptsResponse, |
|
|
AngleInfo, |
|
|
ConceptInfo, |
|
|
DbStatsResponse, |
|
|
AdsListResponse, |
|
|
AdCreativeDB, |
|
|
HealthResponse, |
|
|
ApiRootResponse, |
|
|
ImageCorrectResponse, |
|
|
ImageRegenerateResponse, |
|
|
ModelsListResponse, |
|
|
LoginResponse, |
|
|
Niche, |
|
|
CreativeAnalysisResponse, |
|
|
CreativeModifyResponse, |
|
|
FileUploadResponse, |
|
|
ModificationMode, |
|
|
CreativeAnalysisData, |
|
|
MotivatorGenerateRequest, |
|
|
MotivatorGenerateResponse, |
|
|
} from "../../types/api"; |
|
|
|
|
|
|
|
|
export const getHealth = async (): Promise<HealthResponse> => { |
|
|
const response = await apiClient.get<HealthResponse>("/health"); |
|
|
return response.data; |
|
|
}; |
|
|
|
|
|
export const getApiInfo = async (): Promise<ApiRootResponse> => { |
|
|
const response = await apiClient.get<ApiRootResponse>("/"); |
|
|
return response.data; |
|
|
}; |
|
|
|
|
|
|
|
|
export const generateAd = async (params: { |
|
|
niche: Niche; |
|
|
num_images: number; |
|
|
image_model?: string | null; |
|
|
target_audience?: string | null; |
|
|
offer?: string | null; |
|
|
use_trending?: boolean; |
|
|
trending_context?: string | null; |
|
|
}): Promise<GenerateResponse> => { |
|
|
const response = await apiClient.post<GenerateResponse>("/generate", params); |
|
|
return response.data; |
|
|
}; |
|
|
|
|
|
export const generateBatch = async (params: { |
|
|
niche: Niche; |
|
|
count: number; |
|
|
image_model?: string | null; |
|
|
method?: "standard" | "matrix" | null; |
|
|
target_audience?: string | null; |
|
|
offer?: string | null; |
|
|
}): Promise<BatchResponse> => { |
|
|
const response = await apiClient.post<BatchResponse>("/generate/batch", params); |
|
|
return response.data; |
|
|
}; |
|
|
|
|
|
|
|
|
export const generateMatrixAd = async (params: { |
|
|
niche: Niche; |
|
|
angle_key?: string | null; |
|
|
concept_key?: string | null; |
|
|
custom_angle?: string | null; |
|
|
custom_concept?: string | null; |
|
|
num_images: number; |
|
|
image_model?: string | null; |
|
|
target_audience?: string | null; |
|
|
offer?: string | null; |
|
|
core_motivator?: string; |
|
|
}): Promise<MatrixGenerateResponse> => { |
|
|
const response = await apiClient.post<MatrixGenerateResponse>("/matrix/generate", params); |
|
|
return response.data; |
|
|
}; |
|
|
|
|
|
export const generateMotivators = async ( |
|
|
params: MotivatorGenerateRequest |
|
|
): Promise<MotivatorGenerateResponse> => { |
|
|
const response = await apiClient.post<MotivatorGenerateResponse>( |
|
|
"/api/motivator/generate", |
|
|
{ ...params, count: params.count ?? 6 } |
|
|
); |
|
|
return response.data; |
|
|
}; |
|
|
|
|
|
|
|
|
const EXTENSIVE_POLL_INTERVAL_MS = 5500; |
|
|
const EXTENSIVE_POLL_TIMEOUT_MS = 20 * 60 * 1000; |
|
|
|
|
|
export const getExtensiveJobStatus = async (jobId: string): Promise<{ job_id: string; status: "running" | "completed" | "failed"; error?: string }> => { |
|
|
const response = await apiClient.get(`/extensive/status/${jobId}`); |
|
|
return response.data; |
|
|
}; |
|
|
|
|
|
export const getExtensiveJobResult = async (jobId: string): Promise<BatchResponse> => { |
|
|
const response = await apiClient.get<BatchResponse>(`/extensive/result/${jobId}`); |
|
|
return response.data; |
|
|
}; |
|
|
|
|
|
export const generateExtensiveAd = async (params: { |
|
|
niche: Niche; |
|
|
custom_niche?: string | null; |
|
|
target_audience?: string | null; |
|
|
offer?: string | null; |
|
|
num_images: number; |
|
|
image_model?: string | null; |
|
|
num_strategies: number; |
|
|
}): Promise<BatchResponse> => { |
|
|
const requestParams = { |
|
|
niche: params.niche, |
|
|
num_images: params.num_images || 1, |
|
|
num_strategies: params.num_strategies || 1, |
|
|
...(params.custom_niche && { custom_niche: params.custom_niche }), |
|
|
...(params.target_audience && { target_audience: params.target_audience }), |
|
|
...(params.offer && { offer: params.offer }), |
|
|
...(params.image_model && { image_model: params.image_model }), |
|
|
}; |
|
|
const response = await apiClient.post<{ job_id: string; message?: string }>("/extensive/generate", requestParams); |
|
|
const jobId = response.data?.job_id; |
|
|
if (!jobId) { |
|
|
throw new Error("Server did not return a job ID"); |
|
|
} |
|
|
const deadline = Date.now() + EXTENSIVE_POLL_TIMEOUT_MS; |
|
|
for (;;) { |
|
|
const status = await getExtensiveJobStatus(jobId); |
|
|
if (status.status === "completed") { |
|
|
return getExtensiveJobResult(jobId); |
|
|
} |
|
|
if (status.status === "failed") { |
|
|
throw new Error(status.error || "Extensive generation failed"); |
|
|
} |
|
|
if (Date.now() >= deadline) { |
|
|
throw new Error("Extensive generation timed out. Try fewer strategies or images."); |
|
|
} |
|
|
await new Promise((r) => setTimeout(r, EXTENSIVE_POLL_INTERVAL_MS)); |
|
|
} |
|
|
}; |
|
|
|
|
|
export const generateTestingMatrix = async (params: { |
|
|
niche: Niche; |
|
|
angle_count: number; |
|
|
concept_count: number; |
|
|
strategy: "balanced" | "top_performers" | "diverse"; |
|
|
}): Promise<TestingMatrixResponse> => { |
|
|
const response = await apiClient.post<TestingMatrixResponse>("/matrix/testing", params); |
|
|
return response.data; |
|
|
}; |
|
|
|
|
|
export const getAllAngles = async (): Promise<AnglesResponse> => { |
|
|
const response = await apiClient.get<AnglesResponse>("/matrix/angles"); |
|
|
return response.data; |
|
|
}; |
|
|
|
|
|
export const getAllConcepts = async (): Promise<ConceptsResponse> => { |
|
|
const response = await apiClient.get<ConceptsResponse>("/matrix/concepts"); |
|
|
return response.data; |
|
|
}; |
|
|
|
|
|
export const getAngle = async (angleKey: string): Promise<AngleInfo> => { |
|
|
const response = await apiClient.get<AngleInfo>(`/matrix/angle/${angleKey}`); |
|
|
return response.data; |
|
|
}; |
|
|
|
|
|
export const getConcept = async (conceptKey: string): Promise<ConceptInfo> => { |
|
|
const response = await apiClient.get<ConceptInfo>(`/matrix/concept/${conceptKey}`); |
|
|
return response.data; |
|
|
}; |
|
|
|
|
|
export const getCompatibleConcepts = async (angleKey: string): Promise<CompatibleConceptsResponse> => { |
|
|
const response = await apiClient.get<CompatibleConceptsResponse>(`/matrix/compatible/${angleKey}`); |
|
|
return response.data; |
|
|
}; |
|
|
|
|
|
|
|
|
export const refineCustomAngleOrConcept = async (params: { |
|
|
text: string; |
|
|
type: "angle" | "concept"; |
|
|
niche: Niche; |
|
|
goal?: string; |
|
|
}): Promise<{ status: string; type: "angle" | "concept"; refined?: any; error?: string }> => { |
|
|
const response = await apiClient.post("/matrix/refine-custom", params); |
|
|
return response.data; |
|
|
}; |
|
|
|
|
|
|
|
|
export const getDbStats = async (): Promise<DbStatsResponse> => { |
|
|
const response = await apiClient.get<DbStatsResponse>("/db/stats"); |
|
|
return response.data; |
|
|
}; |
|
|
|
|
|
export const listAds = async (params?: { |
|
|
niche?: string | null; |
|
|
generation_method?: string | null; |
|
|
limit?: number; |
|
|
offset?: number; |
|
|
}): Promise<AdsListResponse> => { |
|
|
const response = await apiClient.get<AdsListResponse>("/db/ads", { params }); |
|
|
return response.data; |
|
|
}; |
|
|
|
|
|
export const getAd = async (adId: string): Promise<AdCreativeDB> => { |
|
|
const response = await apiClient.get<AdCreativeDB>(`/db/ad/${adId}`); |
|
|
return response.data; |
|
|
}; |
|
|
|
|
|
export const deleteAd = async (adId: string): Promise<{ success: boolean; deleted_id: string }> => { |
|
|
const response = await apiClient.delete<{ success: boolean; deleted_id: string }>(`/db/ad/${adId}`); |
|
|
return response.data; |
|
|
}; |
|
|
|
|
|
|
|
|
export const getStrategies = async (niche: Niche): Promise<any> => { |
|
|
const response = await apiClient.get(`/strategies/${niche}`); |
|
|
return response.data; |
|
|
}; |
|
|
|
|
|
|
|
|
export const correctImage = async (params: { |
|
|
image_id: string; |
|
|
image_url?: string; |
|
|
user_instructions?: string; |
|
|
auto_analyze?: boolean; |
|
|
}): Promise<ImageCorrectResponse> => { |
|
|
const response = await apiClient.post<ImageCorrectResponse>("/api/correct", params); |
|
|
return response.data; |
|
|
}; |
|
|
|
|
|
|
|
|
export const regenerateImage = async (params: { |
|
|
image_id: string; |
|
|
image_model?: string | null; |
|
|
preview_only?: boolean; |
|
|
}): Promise<ImageRegenerateResponse> => { |
|
|
const response = await apiClient.post<ImageRegenerateResponse>("/api/regenerate", { |
|
|
...params, |
|
|
preview_only: params.preview_only ?? true, |
|
|
}); |
|
|
return response.data; |
|
|
}; |
|
|
|
|
|
|
|
|
export const confirmImageSelection = async (params: { |
|
|
image_id: string; |
|
|
selection: "new" | "original"; |
|
|
new_image_url?: string | null; |
|
|
new_r2_url?: string | null; |
|
|
new_filename?: string | null; |
|
|
new_model?: string | null; |
|
|
new_seed?: number | null; |
|
|
}): Promise<{ status: string; message: string; selection: string; new_image_url?: string }> => { |
|
|
const response = await apiClient.post("/api/regenerate/confirm", params); |
|
|
return response.data; |
|
|
}; |
|
|
|
|
|
|
|
|
export const getImageModels = async (): Promise<ModelsListResponse> => { |
|
|
const response = await apiClient.get<ModelsListResponse>("/api/models"); |
|
|
return response.data; |
|
|
}; |
|
|
|
|
|
|
|
|
export const login = async (username: string, password: string): Promise<LoginResponse> => { |
|
|
const response = await apiClient.post<LoginResponse>("/auth/login", { |
|
|
username, |
|
|
password, |
|
|
}); |
|
|
return response.data; |
|
|
}; |
|
|
|
|
|
|
|
|
export const editAdCopy = async (params: { |
|
|
ad_id: string; |
|
|
field: "title" | "headline" | "primary_text" | "description" | "body_story" | "cta"; |
|
|
value: string; |
|
|
mode: "manual" | "ai"; |
|
|
user_suggestion?: string; |
|
|
}): Promise<{ edited_value: string; success: boolean }> => { |
|
|
const response = await apiClient.post<{ edited_value: string; success: boolean }>("/db/ad/edit", params); |
|
|
return response.data; |
|
|
}; |
|
|
|
|
|
|
|
|
export const downloadImageProxy = async (params: { |
|
|
image_url?: string; |
|
|
image_id?: string; |
|
|
}): Promise<Blob> => { |
|
|
const response = await apiClient.get("/api/download-image", { |
|
|
params, |
|
|
responseType: "blob", |
|
|
}); |
|
|
return response.data as Blob; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export const uploadCreative = async (file: File): Promise<FileUploadResponse> => { |
|
|
const formData = new FormData(); |
|
|
formData.append("file", file); |
|
|
|
|
|
const response = await apiClient.post<FileUploadResponse>( |
|
|
"/api/creative/upload", |
|
|
formData, |
|
|
{ |
|
|
headers: { |
|
|
"Content-Type": "multipart/form-data", |
|
|
}, |
|
|
} |
|
|
); |
|
|
return response.data; |
|
|
}; |
|
|
|
|
|
|
|
|
export const analyzeCreativeByUrl = async (params: { |
|
|
image_url: string; |
|
|
}): Promise<CreativeAnalysisResponse> => { |
|
|
const response = await apiClient.post<CreativeAnalysisResponse>( |
|
|
"/api/creative/analyze", |
|
|
params |
|
|
); |
|
|
return response.data; |
|
|
}; |
|
|
|
|
|
|
|
|
export const analyzeCreativeByFile = async ( |
|
|
file: File |
|
|
): Promise<CreativeAnalysisResponse> => { |
|
|
const formData = new FormData(); |
|
|
formData.append("file", file); |
|
|
|
|
|
const response = await apiClient.post<CreativeAnalysisResponse>( |
|
|
"/api/creative/analyze/upload", |
|
|
formData, |
|
|
{ |
|
|
headers: { |
|
|
"Content-Type": "multipart/form-data", |
|
|
}, |
|
|
} |
|
|
); |
|
|
return response.data; |
|
|
}; |
|
|
|
|
|
|
|
|
export const modifyCreative = async (params: { |
|
|
image_url: string; |
|
|
analysis?: CreativeAnalysisData | null; |
|
|
angle?: string; |
|
|
concept?: string; |
|
|
mode: ModificationMode; |
|
|
image_model?: string | null; |
|
|
user_prompt?: string; |
|
|
}): Promise<CreativeModifyResponse> => { |
|
|
const response = await apiClient.post<CreativeModifyResponse>( |
|
|
"/api/creative/modify", |
|
|
params |
|
|
); |
|
|
return response.data; |
|
|
}; |
|
|
|
|
|
|
|
|
export const exportBulkAds = async (adIds: string[]): Promise<Blob> => { |
|
|
const response = await apiClient.post( |
|
|
"/api/export/bulk", |
|
|
{ ad_ids: adIds }, |
|
|
{ responseType: "blob" } |
|
|
); |
|
|
return response.data as Blob; |
|
|
}; |
|
|
|