Update services/api.ts

#1
by Opera10 - opened
Files changed (1) hide show
  1. 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 formData = new FormData();
15
- formData.append('source_audio', sourceFile, 'source.wav');
16
- formData.append('ref_audio', refFile, 'ref.wav');
 
 
 
 
 
 
17
 
18
- const response = await fetch(`${VC_BASE_URL}/upload`, {
 
19
  method: 'POST',
20
- body: formData,
 
 
 
 
21
  });
22
 
23
  if (!response.ok) {
24
- throw new Error(`Upload failed: ${response.status}`);
 
25
  }
26
 
27
  const data = await response.json();
 
 
28
  return {
29
- ...data,
 
 
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' // Explicitly mark as standard backend
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
- const response = await fetch(`${VC_BASE_URL}/check_status`, {
119
- method: 'POST',
120
- headers: { 'Content-Type': 'application/json' },
121
- body: JSON.stringify({ job_id: job.job_id, total_chunks: job.total_chunks || 1, chunks: job.chunks || [] }),
122
- });
123
- return await response.json();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
  }
125
 
126
- // Priority 2: Fallback for jobs created before the backend flag was added
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
- const response = await fetch(`${VC_BASE_URL}/check_status`, {
140
- method: 'POST',
141
- headers: { 'Content-Type': 'application/json' },
142
- body: JSON.stringify({ job_id: job.job_id, total_chunks: job.total_chunks || 1, chunks: job.chunks || [] }),
143
- });
144
- return await response.json();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ };