Makelore 2.0 initial clean snapshot
This commit is contained in:
119
src/lib/works-image.ts
Normal file
119
src/lib/works-image.ts
Normal file
@@ -0,0 +1,119 @@
|
||||
import { hostApiFetch } from '@/lib/host-api';
|
||||
|
||||
export type WorksImageAspectRatio = '1:1' | '4:3' | '16:9' | '9:16';
|
||||
|
||||
export type WorksImageQuality = 'standard' | 'high';
|
||||
|
||||
export type WorksImageJobStatus =
|
||||
| 'queued'
|
||||
| 'running'
|
||||
| 'succeeded'
|
||||
| 'failed'
|
||||
| 'expired'
|
||||
| 'cancelled'
|
||||
| string;
|
||||
|
||||
export type WorksImageJob = {
|
||||
id: string;
|
||||
status: WorksImageJobStatus;
|
||||
prompt?: string;
|
||||
outputUrls?: string[];
|
||||
error?: string | { message?: string } | null;
|
||||
createdAt?: string;
|
||||
updatedAt?: string;
|
||||
};
|
||||
|
||||
export type WorksImageGenerationInput = {
|
||||
accessToken: string;
|
||||
prompt: string;
|
||||
aspectRatio: WorksImageAspectRatio;
|
||||
quality: WorksImageQuality;
|
||||
};
|
||||
|
||||
type WorksImageResponse<TField extends string, TValue> = {
|
||||
success: boolean;
|
||||
status?: number;
|
||||
error?: string;
|
||||
} & {
|
||||
[key in TField]?: TValue;
|
||||
};
|
||||
|
||||
export class WorksImageApiError extends Error {
|
||||
readonly statusCode?: number;
|
||||
|
||||
constructor(message: string, statusCode?: number) {
|
||||
super(message);
|
||||
this.name = 'WorksImageApiError';
|
||||
this.statusCode = statusCode;
|
||||
}
|
||||
}
|
||||
|
||||
function assertSuccess<TField extends string, TValue>(
|
||||
response: WorksImageResponse<TField, TValue>,
|
||||
field: TField,
|
||||
fallback: string,
|
||||
): TValue {
|
||||
if (!response.success || response[field] === undefined) {
|
||||
throw new WorksImageApiError(response.error || fallback, response.status);
|
||||
}
|
||||
return response[field] as TValue;
|
||||
}
|
||||
|
||||
function authHeaders(accessToken: string): Record<string, string> {
|
||||
return {
|
||||
'X-NianCode-Access-Token': accessToken,
|
||||
};
|
||||
}
|
||||
|
||||
function mapQuality(quality: WorksImageQuality): string {
|
||||
return quality === 'high' ? 'high' : 'medium';
|
||||
}
|
||||
|
||||
function normalizeJob(payload: unknown, fallbackPrompt?: string): WorksImageJob {
|
||||
const record = payload && typeof payload === 'object'
|
||||
? payload as Record<string, unknown>
|
||||
: {};
|
||||
const taskId = record.task_id ?? record.taskId ?? record.id;
|
||||
const resultUrls = record.result_urls ?? record.resultUrls ?? record.outputUrls;
|
||||
return {
|
||||
id: typeof taskId === 'string' && taskId ? taskId : 'image-task',
|
||||
status: typeof record.status === 'string' ? record.status : 'queued',
|
||||
prompt: typeof record.prompt === 'string' ? record.prompt : fallbackPrompt,
|
||||
outputUrls: Array.isArray(resultUrls)
|
||||
? resultUrls.filter((url): url is string => typeof url === 'string' && Boolean(url.trim()))
|
||||
: [],
|
||||
error: typeof record.error === 'string' || (record.error && typeof record.error === 'object')
|
||||
? record.error as WorksImageJob['error']
|
||||
: null,
|
||||
createdAt: typeof record.created_at === 'string' ? record.created_at : undefined,
|
||||
updatedAt: typeof record.updated_at === 'string' ? record.updated_at : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
export async function fetchWorksImageTask(accessToken: string, taskId: string): Promise<WorksImageJob> {
|
||||
const response = await hostApiFetch<WorksImageResponse<'job', unknown>>(
|
||||
`/api/works/ai-gateway/images/tasks/${encodeURIComponent(taskId)}`,
|
||||
{
|
||||
headers: authHeaders(accessToken),
|
||||
},
|
||||
);
|
||||
return normalizeJob(assertSuccess(response, 'job', 'Failed to load image generation task'));
|
||||
}
|
||||
|
||||
export async function submitWorksImageGeneration(input: WorksImageGenerationInput): Promise<WorksImageJob> {
|
||||
const response = await hostApiFetch<WorksImageResponse<'job', unknown>>(
|
||||
'/api/works/ai-gateway/images/generations',
|
||||
{
|
||||
method: 'POST',
|
||||
headers: authHeaders(input.accessToken),
|
||||
body: JSON.stringify({
|
||||
prompt: input.prompt,
|
||||
image_urls: [],
|
||||
size: input.aspectRatio,
|
||||
quality: mapQuality(input.quality),
|
||||
resolution: '2K',
|
||||
}),
|
||||
},
|
||||
);
|
||||
return normalizeJob(assertSuccess(response, 'job', 'Failed to submit image generation'), input.prompt);
|
||||
}
|
||||
Reference in New Issue
Block a user