144 lines
3.6 KiB
TypeScript
144 lines
3.6 KiB
TypeScript
import { fetchJson } from './apiClient';
|
|
import { getDeviceId } from '../lib/device';
|
|
|
|
export type GuestAiStyle = {
|
|
id: number;
|
|
key: string;
|
|
name: string;
|
|
category?: string | null;
|
|
description?: string | null;
|
|
provider?: string | null;
|
|
provider_model?: string | null;
|
|
requires_source_image?: boolean;
|
|
is_premium?: boolean;
|
|
metadata?: Record<string, unknown>;
|
|
};
|
|
|
|
export type GuestAiStylesMeta = {
|
|
required_feature?: string | null;
|
|
addon_keys?: string[] | null;
|
|
allow_custom_prompt?: boolean;
|
|
allowed_style_keys?: string[] | null;
|
|
policy_message?: string | null;
|
|
};
|
|
|
|
export type GuestAiEditOutput = {
|
|
id: number;
|
|
storage_disk?: string | null;
|
|
storage_path?: string | null;
|
|
provider_url?: string | null;
|
|
url?: string | null;
|
|
mime_type?: string | null;
|
|
width?: number | null;
|
|
height?: number | null;
|
|
is_primary?: boolean;
|
|
safety_state?: string | null;
|
|
safety_reasons?: string[];
|
|
generated_at?: string | null;
|
|
};
|
|
|
|
export type GuestAiEditRequest = {
|
|
id: number;
|
|
event_id: number;
|
|
photo_id: number;
|
|
style?: {
|
|
id: number;
|
|
key: string;
|
|
name: string;
|
|
} | null;
|
|
provider?: string | null;
|
|
provider_model?: string | null;
|
|
status: 'queued' | 'processing' | 'succeeded' | 'failed' | 'blocked' | 'canceled' | string;
|
|
safety_state?: string | null;
|
|
safety_reasons?: string[];
|
|
failure_code?: string | null;
|
|
failure_message?: string | null;
|
|
queued_at?: string | null;
|
|
started_at?: string | null;
|
|
completed_at?: string | null;
|
|
outputs: GuestAiEditOutput[];
|
|
};
|
|
|
|
export type GuestAiStylesResponse = {
|
|
data: GuestAiStyle[];
|
|
meta: GuestAiStylesMeta;
|
|
};
|
|
|
|
export type GuestAiEditEnvelope = {
|
|
message?: string;
|
|
duplicate?: boolean;
|
|
data: GuestAiEditRequest;
|
|
};
|
|
|
|
function deviceHeaders(): Record<string, string> {
|
|
return {
|
|
'X-Device-Id': getDeviceId(),
|
|
};
|
|
}
|
|
|
|
export async function fetchGuestAiStyles(eventToken: string): Promise<GuestAiStylesResponse> {
|
|
const response = await fetchJson<GuestAiStylesResponse>(
|
|
`/api/v1/events/${encodeURIComponent(eventToken)}/ai-styles`,
|
|
{
|
|
headers: deviceHeaders(),
|
|
noStore: true,
|
|
}
|
|
);
|
|
|
|
const payload = response.data;
|
|
|
|
return {
|
|
data: Array.isArray(payload?.data) ? payload.data : [],
|
|
meta: payload?.meta && typeof payload.meta === 'object' ? payload.meta : {},
|
|
};
|
|
}
|
|
|
|
export async function createGuestAiEdit(
|
|
eventToken: string,
|
|
photoId: number,
|
|
payload: {
|
|
style_key?: string;
|
|
prompt?: string;
|
|
negative_prompt?: string;
|
|
provider_model?: string;
|
|
idempotency_key?: string;
|
|
session_id?: string;
|
|
metadata?: Record<string, unknown>;
|
|
}
|
|
): Promise<GuestAiEditEnvelope> {
|
|
const response = await fetchJson<GuestAiEditEnvelope>(
|
|
`/api/v1/events/${encodeURIComponent(eventToken)}/photos/${photoId}/ai-edits`,
|
|
{
|
|
method: 'POST',
|
|
headers: {
|
|
...deviceHeaders(),
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(payload),
|
|
noStore: true,
|
|
}
|
|
);
|
|
|
|
if (!response.data || typeof response.data !== 'object' || !response.data.data) {
|
|
throw new Error('AI edit request response is invalid.');
|
|
}
|
|
|
|
return response.data;
|
|
}
|
|
|
|
export async function fetchGuestAiEditStatus(eventToken: string, requestId: number): Promise<{ data: GuestAiEditRequest }> {
|
|
const response = await fetchJson<{ data: GuestAiEditRequest }>(
|
|
`/api/v1/events/${encodeURIComponent(eventToken)}/ai-edits/${requestId}`,
|
|
{
|
|
headers: deviceHeaders(),
|
|
noStore: true,
|
|
}
|
|
);
|
|
|
|
if (!response.data || typeof response.data !== 'object' || !response.data.data) {
|
|
throw new Error('AI edit status response is invalid.');
|
|
}
|
|
|
|
return response.data;
|
|
}
|