Spaces:
Running
Running
Update services/api.ts
#1
by Opera10 - opened
- services/api.ts +87 -24
services/api.ts
CHANGED
|
@@ -1,32 +1,67 @@
|
|
| 1 |
-
|
| 2 |
import { JobData, StatusResponse, Model } from '../types';
|
| 3 |
import * as legacyApi from './legacy_api';
|
| 4 |
|
| 5 |
-
const VC_BASE_URL = 'https://sada8888-sada.hf.space';
|
| 6 |
const TTS_BASE_URL = 'https://hamed744-ttsp3.hf.space';
|
| 7 |
const ENHANCE_BASE_URL = 'https://ezmarynoori-taqviat-sada.hf.space';
|
| 8 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
export const uploadJob = async (
|
| 10 |
sourceFile: File | Blob,
|
| 11 |
refFile: File | Blob,
|
| 12 |
metadata: { type?: 'custom' | 'model', modelName?: string, modelImage?: string }
|
| 13 |
): Promise<JobData> => {
|
| 14 |
-
const
|
| 15 |
-
|
| 16 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
|
| 18 |
-
|
|
|
|
| 19 |
method: 'POST',
|
| 20 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
});
|
| 22 |
|
| 23 |
if (!response.ok) {
|
| 24 |
-
|
|
|
|
| 25 |
}
|
| 26 |
|
| 27 |
const data = await response.json();
|
|
|
|
|
|
|
| 28 |
return {
|
| 29 |
-
|
|
|
|
|
|
|
| 30 |
date: new Date().toLocaleString('fa-IR'),
|
| 31 |
timestamp: Date.now(),
|
| 32 |
progress: 0,
|
|
@@ -34,7 +69,7 @@ export const uploadJob = async (
|
|
| 34 |
type: metadata.type,
|
| 35 |
modelName: metadata.modelName,
|
| 36 |
modelImage: metadata.modelImage,
|
| 37 |
-
backend: 'standard'
|
| 38 |
};
|
| 39 |
};
|
| 40 |
|
|
@@ -115,15 +150,29 @@ export const checkJobStatus = async (job: JobData): Promise<StatusResponse> => {
|
|
| 115 |
// Priority 1: Use the explicit backend flag if available
|
| 116 |
if (job.backend === 'legacy') return await legacyApi.checkLegacyStatus(job.job_id);
|
| 117 |
if (job.backend === 'standard') {
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 124 |
}
|
| 125 |
|
| 126 |
-
//
|
| 127 |
const legacyNames = [
|
| 128 |
'shadmehr', 'moein', 'billie', 'chavoshi', 'ghomayshi', 'yas', 'ferdosipour', 'khiabani', 'jalilvand', 'tahmasb', 'pourang', 'sponge', 'jenab', 'yousef', 'jomeong', 'musk',
|
| 129 |
'شادمهر عقیلی', 'معین', 'بیلی آیلیش', 'محسن چاوشی', 'سیاوش قمیشی', 'یاس',
|
|
@@ -136,12 +185,26 @@ export const checkJobStatus = async (job: JobData): Promise<StatusResponse> => {
|
|
| 136 |
|
| 137 |
if (isLegacy) return await legacyApi.checkLegacyStatus(job.job_id);
|
| 138 |
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 145 |
};
|
| 146 |
|
| 147 |
export const processUnifiedJob = async (
|
|
@@ -175,4 +238,4 @@ export const processUnifiedJob = async (
|
|
| 175 |
onProgress("ارسال به سرور تغییر صدا...", 20);
|
| 176 |
return await uploadJob(actualSource, refFile, metadata);
|
| 177 |
}
|
| 178 |
-
};
|
|
|
|
|
|
|
| 1 |
import { JobData, StatusResponse, Model } from '../types';
|
| 2 |
import * as legacyApi from './legacy_api';
|
| 3 |
|
|
|
|
| 4 |
const TTS_BASE_URL = 'https://hamed744-ttsp3.hf.space';
|
| 5 |
const ENHANCE_BASE_URL = 'https://ezmarynoori-taqviat-sada.hf.space';
|
| 6 |
|
| 7 |
+
const safeBase64Encode = (str: string): string => {
|
| 8 |
+
return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, (match, p1) => {
|
| 9 |
+
return String.fromCharCode(parseInt('0x' + p1));
|
| 10 |
+
}));
|
| 11 |
+
};
|
| 12 |
+
|
| 13 |
+
const uploadAudioToOrchestrator = async (file: Blob | File, runId: string, suffix: string): Promise<string> => {
|
| 14 |
+
const formData = new FormData();
|
| 15 |
+
const ext = (file as File).name?.split('.').pop()?.toLowerCase() || 'wav';
|
| 16 |
+
formData.append('run_id', `${runId}_${suffix}`);
|
| 17 |
+
formData.append('ext', ext);
|
| 18 |
+
formData.append('file', file);
|
| 19 |
+
|
| 20 |
+
const response = await fetch('/api/webhook/upload', {
|
| 21 |
+
method: 'POST',
|
| 22 |
+
body: formData
|
| 23 |
+
});
|
| 24 |
+
if (!response.ok) throw new Error("خطا در آپلود فایل صوتی به سرور پشتیبان.");
|
| 25 |
+
return ext;
|
| 26 |
+
};
|
| 27 |
+
|
| 28 |
export const uploadJob = async (
|
| 29 |
sourceFile: File | Blob,
|
| 30 |
refFile: File | Blob,
|
| 31 |
metadata: { type?: 'custom' | 'model', modelName?: string, modelImage?: string }
|
| 32 |
): Promise<JobData> => {
|
| 33 |
+
const currentRunId = "vev" + Math.random().toString(36).substring(2, 14);
|
| 34 |
+
|
| 35 |
+
// ۱. آپلود صوتیهای مبدا و مرجع به ارکستریتور
|
| 36 |
+
const sourceExt = await uploadAudioToOrchestrator(sourceFile, currentRunId, 'vevo_source');
|
| 37 |
+
const refExt = await uploadAudioToOrchestrator(refFile, currentRunId, 'vevo_ref');
|
| 38 |
+
|
| 39 |
+
// ۲. رمزگذاری آدرس فضای پردازش و ساخت کلید تنظیمات Vevo
|
| 40 |
+
const b64SpaceUrl = safeBase64Encode("https://opera8-sada.hf.space");
|
| 41 |
+
const vevoPayload = `VEVOCONFIG_userRunId_${currentRunId}_sourceExt_${sourceExt}_refExt_${refExt}_spaceUrl_${b64SpaceUrl}`;
|
| 42 |
|
| 43 |
+
// ۳. ارسال دستور کار به سیستم دیسپچ گیتهاب اکشنز
|
| 44 |
+
const response = await fetch('/api/generate', {
|
| 45 |
method: 'POST',
|
| 46 |
+
headers: { 'Content-Type': 'application/json' },
|
| 47 |
+
body: JSON.stringify({
|
| 48 |
+
prompt: vevoPayload,
|
| 49 |
+
action_name: 'vevo-voice'
|
| 50 |
+
}),
|
| 51 |
});
|
| 52 |
|
| 53 |
if (!response.ok) {
|
| 54 |
+
const errData = await response.json().catch(() => ({}));
|
| 55 |
+
throw new Error(errData.message || `خطا در تخصیص صف گیتهاب: ${response.status}`);
|
| 56 |
}
|
| 57 |
|
| 58 |
const data = await response.json();
|
| 59 |
+
const finalRunId = data.run_id || currentRunId;
|
| 60 |
+
|
| 61 |
return {
|
| 62 |
+
job_id: finalRunId,
|
| 63 |
+
total_chunks: 1,
|
| 64 |
+
chunks: [],
|
| 65 |
date: new Date().toLocaleString('fa-IR'),
|
| 66 |
timestamp: Date.now(),
|
| 67 |
progress: 0,
|
|
|
|
| 69 |
type: metadata.type,
|
| 70 |
modelName: metadata.modelName,
|
| 71 |
modelImage: metadata.modelImage,
|
| 72 |
+
backend: 'standard'
|
| 73 |
};
|
| 74 |
};
|
| 75 |
|
|
|
|
| 150 |
// Priority 1: Use the explicit backend flag if available
|
| 151 |
if (job.backend === 'legacy') return await legacyApi.checkLegacyStatus(job.job_id);
|
| 152 |
if (job.backend === 'standard') {
|
| 153 |
+
try {
|
| 154 |
+
const response = await fetch(`/api/status/${job.job_id}`);
|
| 155 |
+
if (!response.ok) throw new Error(`بررسی وضعیت با خطا مواجه شد: ${response.status}`);
|
| 156 |
+
const data = await response.json();
|
| 157 |
+
|
| 158 |
+
let status: 'processing' | 'completed' | 'failed' | 'error' = 'processing';
|
| 159 |
+
if (data.status === 'ready') status = 'completed';
|
| 160 |
+
else if (data.status === 'failed') status = 'failed';
|
| 161 |
+
else if (data.status === 'not_found' || data.status === 'error') status = 'error';
|
| 162 |
+
|
| 163 |
+
return {
|
| 164 |
+
status,
|
| 165 |
+
progress: data.status === 'ready' ? 100 : (data.status === 'processing' ? 50 : 10),
|
| 166 |
+
filename: data.url ? data.url.split('/').pop() : undefined,
|
| 167 |
+
detail: data.message || (data.status === 'ready' ? 'تکمیل شد' : 'در حال پردازش در سرور ابری...'),
|
| 168 |
+
downloadUrl: data.url ? data.url : undefined
|
| 169 |
+
};
|
| 170 |
+
} catch (e) {
|
| 171 |
+
return { status: 'processing', progress: 10, detail: 'درحال تلاش برای برقراری ارتباط با سرور...' };
|
| 172 |
+
}
|
| 173 |
}
|
| 174 |
|
| 175 |
+
// Fallback for legacy models tracking
|
| 176 |
const legacyNames = [
|
| 177 |
'shadmehr', 'moein', 'billie', 'chavoshi', 'ghomayshi', 'yas', 'ferdosipour', 'khiabani', 'jalilvand', 'tahmasb', 'pourang', 'sponge', 'jenab', 'yousef', 'jomeong', 'musk',
|
| 178 |
'شادمهر عقیلی', 'معین', 'بیلی آیلیش', 'محسن چاوشی', 'سیاوش قمیشی', 'یاس',
|
|
|
|
| 185 |
|
| 186 |
if (isLegacy) return await legacyApi.checkLegacyStatus(job.job_id);
|
| 187 |
|
| 188 |
+
try {
|
| 189 |
+
const response = await fetch(`/api/status/${job.job_id}`);
|
| 190 |
+
if (!response.ok) throw new Error(`بررسی وضعیت با خطا مواجه شد: ${response.status}`);
|
| 191 |
+
const data = await response.json();
|
| 192 |
+
|
| 193 |
+
let status: 'processing' | 'completed' | 'failed' | 'error' = 'processing';
|
| 194 |
+
if (data.status === 'ready') status = 'completed';
|
| 195 |
+
else if (data.status === 'failed') status = 'failed';
|
| 196 |
+
else if (data.status === 'not_found' || data.status === 'error') status = 'error';
|
| 197 |
+
|
| 198 |
+
return {
|
| 199 |
+
status,
|
| 200 |
+
progress: data.status === 'ready' ? 100 : (data.status === 'processing' ? 50 : 10),
|
| 201 |
+
filename: data.url ? data.url.split('/').pop() : undefined,
|
| 202 |
+
detail: data.message || (data.status === 'ready' ? 'تکمیل شد' : 'در حال پردازش در سرور ابری...'),
|
| 203 |
+
downloadUrl: data.url ? data.url : undefined
|
| 204 |
+
};
|
| 205 |
+
} catch (e) {
|
| 206 |
+
return { status: 'processing', progress: 10, detail: 'درحال تلاش برای برقراری ارتباط با سرور...' };
|
| 207 |
+
}
|
| 208 |
};
|
| 209 |
|
| 210 |
export const processUnifiedJob = async (
|
|
|
|
| 238 |
onProgress("ارسال به سرور تغییر صدا...", 20);
|
| 239 |
return await uploadJob(actualSource, refFile, metadata);
|
| 240 |
}
|
| 241 |
+
};
|