apix/lib/providers/meta-crawl-client.ts
Khoa.vo 2a4bf8b58b
Some checks are pending
CI / build (18.x) (push) Waiting to run
CI / build (20.x) (push) Waiting to run
feat: updates before deployment
2026-01-06 13:26:11 +07:00

174 lines
4.5 KiB
TypeScript

/**
* Meta AI Crawl4AI Client
*
* TypeScript client for the Python Crawl4AI microservice
* that handles Meta AI image generation with bot detection bypass.
*/
const CRAWL4AI_URL = process.env.CRAWL4AI_URL || 'http://localhost:8000';
export interface MetaCrawlImage {
url: string;
data?: string; // base64
prompt: string;
model: string;
}
export interface MetaCrawlResponse {
success: boolean;
images: MetaCrawlImage[];
error?: string;
task_id?: string;
}
export interface TaskStatusResponse {
task_id: string;
status: 'pending' | 'processing' | 'completed' | 'failed';
images: MetaCrawlImage[];
error?: string;
progress?: number;
}
export class MetaCrawlClient {
private baseUrl: string;
constructor(baseUrl?: string) {
this.baseUrl = baseUrl || CRAWL4AI_URL;
}
/**
* Generate images synchronously (waits for completion)
*/
async generate(
prompt: string,
cookies: string,
numImages: number = 4
): Promise<MetaCrawlImage[]> {
console.log(`[MetaCrawl] Sending request to ${this.baseUrl}/generate/sync`);
const response = await fetch(`${this.baseUrl}/generate/sync`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
prompt,
cookies,
num_images: numImages
})
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`MetaCrawl service error: ${response.status} - ${errorText}`);
}
const data: MetaCrawlResponse = await response.json();
if (!data.success) {
throw new Error(data.error || 'Image generation failed');
}
return data.images;
}
/**
* Start async image generation (returns immediately with task_id)
*/
async generateAsync(
prompt: string,
cookies: string,
numImages: number = 4
): Promise<string> {
const response = await fetch(`${this.baseUrl}/generate`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
prompt,
cookies,
num_images: numImages
})
});
if (!response.ok) {
throw new Error(`MetaCrawl service error: ${response.status}`);
}
const data: MetaCrawlResponse = await response.json();
if (!data.task_id) {
throw new Error('No task_id returned from async generation');
}
return data.task_id;
}
/**
* Get status of an async generation task
*/
async getTaskStatus(taskId: string): Promise<TaskStatusResponse> {
const response = await fetch(`${this.baseUrl}/status/${taskId}`);
if (!response.ok) {
if (response.status === 404) {
throw new Error('Task not found');
}
throw new Error(`MetaCrawl service error: ${response.status}`);
}
return response.json();
}
/**
* Poll for async task completion
*/
async waitForCompletion(
taskId: string,
pollIntervalMs: number = 2000,
timeoutMs: number = 120000
): Promise<MetaCrawlImage[]> {
const startTime = Date.now();
while (Date.now() - startTime < timeoutMs) {
const status = await this.getTaskStatus(taskId);
if (status.status === 'completed') {
return status.images;
}
if (status.status === 'failed') {
throw new Error(status.error || 'Generation failed');
}
await new Promise(resolve => setTimeout(resolve, pollIntervalMs));
}
throw new Error('Task timed out');
}
/**
* Check if the Crawl4AI service is healthy
*/
async healthCheck(): Promise<boolean> {
try {
const response = await fetch(`${this.baseUrl}/health`);
return response.ok;
} catch {
return false;
}
}
/**
* Get current rate limit status
*/
async getRateLimitStatus(): Promise<{
requests_this_hour: number;
max_per_hour: number;
delay_seconds: number;
}> {
const response = await fetch(`${this.baseUrl}/rate-limit`);
return response.json();
}
}