taghirsado / services /legacy_api.ts
Opera10's picture
Update services/legacy_api.ts
17b29ae verified
Raw
History Blame Contribute Delete
4.36 kB
import { JobData, StatusResponse } from '../types';
const safeBase64Encode = (str: string): string => {
return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, (match, p1) => {
return String.fromCharCode(parseInt('0x' + p1));
}));
};
const uploadAudioToOrchestrator = async (file: Blob | File, runId: string, suffix: string): Promise<string> => {
const formData = new FormData();
const ext = (file as File).name?.split('.').pop()?.toLowerCase() || 'wav';
formData.append('run_id', `${runId}_${suffix}`);
formData.append('ext', ext);
formData.append('file', file);
const response = await fetch('https://opera8-action.hf.space/api/webhook/upload', {
method: 'POST',
body: formData
});
if (!response.ok) throw new Error("خطا در آپلود فایل صوتی به سرور پشتیبان.");
return ext;
};
/**
* Uploads a job to the FastAPI RVC Legacy backend via the load-balanced GitHub Actions orchestrator.
*/
export const uploadLegacyJob = async (
sourceFile: Blob | File,
modelUrl: string,
pitch: number,
modelMetadata: { name?: string, image?: string },
algo: string = "rmvpe+",
indexInf: number = 0.75
): Promise<JobData> => {
const currentRunId = "rvc" + Math.random().toString(36).substring(2, 14);
// ۱. آپلود فایل صوتی ورودی به ارکستریتور ابری
const audioExt = await uploadAudioToOrchestrator(sourceFile, currentRunId, 'rvc_audio');
// ۲. رمزگذاری آدرس‌ها و آماده‌سازی کلید پیکربندی آر‌وی‌سی
const b64ModelUrl = safeBase64Encode(modelUrl);
const b64SpaceUrl = safeBase64Encode("https://r3gm-rvc-zero.hf.space");
const rvcPayload = `RVCCONFIG_userRunId_${currentRunId}_audioExt_${audioExt}_pitchAlgo_${algo}_pitchLvl_${pitch}_indexInf_${indexInf}_denoise_false_reverb_false_modelUrl_${b64ModelUrl}_spaceUrl_${b64SpaceUrl}`;
// ۳. ارسال درخواست به بک‌اند ابری جهت توزیع در صف گیت‌هاب
const response = await fetch('https://opera8-action.hf.space/api/generate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
prompt: rvcPayload,
action_name: 'rvc-voice'
})
});
if (!response.ok) {
const errData = await response.json().catch(() => ({}));
throw new Error(errData.message || `خطا در تخصیص صف گیت‌هاب: ${response.status}`);
}
const data = await response.json();
const finalRunId = data.run_id || currentRunId;
return {
job_id: finalRunId,
status: 'started',
progress: 10,
statusMessage: 'در صف انتظار سرورهای موازی ...',
total_chunks: 1,
chunks: [],
date: new Date().toLocaleString('fa-IR'),
timestamp: Date.now(),
type: 'model',
modelName: modelMetadata.name,
modelImage: modelMetadata.image,
retryCount: 0,
backend: 'legacy'
};
};
/**
* Checks the status of a legacy job on the orchestrator.
*/
export const checkLegacyStatus = async (jobId: string): Promise<StatusResponse> => {
try {
const response = await fetch(`/api/status/${jobId}`);
if (!response.ok) throw new Error(`بررسی وضعیت با خطا مواجه شد: ${response.status}`);
const data = await response.json();
let status: 'processing' | 'completed' | 'failed' | 'error' = 'processing';
if (data.status === 'ready') status = 'completed';
else if (data.status === 'failed') status = 'failed';
else if (data.status === 'not_found' || data.status === 'error') status = 'error';
return {
status,
progress: data.status === 'ready' ? 100 : (data.status === 'processing' ? 50 : 10),
filename: data.url ? data.url.split('/').pop() : undefined,
detail: data.message || (data.status === 'ready' ? 'تکمیل شد' : 'در حال پردازش در سرور ابری...'),
downloadUrl: data.url ? data.url : undefined
};
} catch (e) {
return { status: 'processing', progress: 10, detail: 'درحال تلاش برای برقراری ارتباط با سرور...' };
}
};