Save local changes (GSC/Bing integrations) before merging PR #354

This commit is contained in:
ajaysi
2026-02-13 13:11:27 +05:30
parent 43e66835ac
commit 08a1f4a1d8
144 changed files with 8310 additions and 2748 deletions

View File

@@ -5,6 +5,7 @@ export interface AssetResponse {
image_url?: string;
image_base64?: string;
optimized_prompt?: string;
prompt?: string;
asset_id?: number;
message?: string;
error?: string;
@@ -19,16 +20,39 @@ export interface VoiceCloneResponse {
error?: string;
}
export const getLatestBrandAvatar = async (): Promise<AssetResponse> => {
try {
const response = await apiClient.get('/onboarding/assets/latest-avatar');
return response.data;
} catch (error: any) {
// 404 is expected if no avatar exists
if (error.response?.status === 404) {
return { success: false, message: 'No avatar found' };
}
console.error('Failed to fetch latest avatar:', error);
return {
success: false,
error: error.response?.data?.detail || 'Failed to fetch latest avatar'
};
}
};
export const generateBrandAvatar = async (
prompt: string,
stylePreset?: string,
aspectRatio: string = "1:1"
aspectRatio: string = "1:1",
model?: string,
renderingSpeed?: string,
provider?: string
): Promise<AssetResponse> => {
try {
const response = await apiClient.post('/onboarding/assets/generate-avatar', {
prompt,
style_preset: stylePreset,
aspect_ratio: aspectRatio,
model,
rendering_speed: renderingSpeed,
provider,
user_id: "current_user" // Backend extracts actual user
});
return response.data;
@@ -61,24 +85,48 @@ export const createAvatarVariation = async (
prompt: string,
file: File
): Promise<AssetResponse> => {
// TODO: Implement backend endpoint for variation
// For now, return a mock error or handle as new generation
console.warn("createAvatarVariation not fully implemented in backend");
try {
const formData = new FormData();
formData.append('prompt', prompt);
formData.append('file', file);
formData.append('user_id', "current_user");
const response = await apiClient.post('/onboarding/assets/create-variation', formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
return response.data;
} catch (error: any) {
console.error('Avatar variation error:', error);
return {
success: false,
error: "Feature not available yet"
success: false,
error: error.response?.data?.detail || 'Failed to create avatar variation'
};
}
};
export const enhanceBrandAvatar = async (
file: File
): Promise<AssetResponse> => {
// TODO: Implement backend endpoint for enhancement (upscaling)
console.warn("enhanceBrandAvatar not fully implemented in backend");
try {
const formData = new FormData();
formData.append('file', file);
formData.append('user_id', "current_user");
const response = await apiClient.post('/onboarding/assets/enhance-avatar', formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
return response.data;
} catch (error: any) {
console.error('Avatar enhancement error:', error);
return {
success: false,
error: "Feature not available yet"
success: false,
error: error.response?.data?.detail || 'Failed to enhance avatar'
};
}
};
export const setBrandAvatar = async (
@@ -96,6 +144,37 @@ export const setBrandAvatar = async (
};
};
export const getLatestVoiceClone = async (): Promise<VoiceCloneResponse> => {
try {
const response = await apiClient.get('/onboarding/assets/latest-voice-clone');
return response.data;
} catch (error: any) {
if (error.response?.status === 404) {
return { success: false, message: 'No voice clone found' };
}
console.error('Failed to fetch latest voice clone:', error);
return {
success: false,
error: error.response?.data?.detail || 'Failed to fetch latest voice clone'
};
}
};
export const setBrandVoice = async (
data: {
audio_url?: string;
custom_voice_id?: string;
voice_description?: string;
}
): Promise<AssetResponse> => {
// TODO: Implement backend endpoint to set as active voice
// For now, simulate success
return {
success: true,
message: "Voice set as active brand voice"
};
};
export interface VoiceCloneParams {
audioFile: File;
engine: 'minimax' | 'qwen3';
@@ -147,3 +226,29 @@ export const createVoiceClone = async (
};
}
};
export interface VoiceDesignParams {
text: string;
voiceDescription: string;
language?: string;
}
export const createVoiceDesign = async (
params: VoiceDesignParams
): Promise<VoiceCloneResponse> => {
try {
const response = await apiClient.post('/onboarding/assets/create-voice-design', {
text: params.text,
voice_description: params.voiceDescription,
language: params.language || 'auto',
user_id: "current_user"
});
return response.data;
} catch (error: any) {
console.error('Voice design error:', error);
return {
success: false,
error: error.response?.data?.detail || 'Failed to create voice design'
};
}
};

View File

@@ -3,6 +3,8 @@
*/
import { aiApiClient } from './client';
// Import TaskStatusResponse from blogWriterApi to ensure compatibility with usePolling
import type { TaskStatusResponse } from '../services/blogWriterApi';
const API_BASE = '/api/video-studio';
@@ -18,6 +20,17 @@ export interface PromptOptimizeResponse {
success: boolean;
}
export interface CreateAvatarVideoResponse {
task_id: string;
status: string;
message: string;
error?: string;
result?: {
video_url: string;
[key: string]: any;
};
}
/**
* Optimize a prompt using WaveSpeed prompt optimizer
*/
@@ -30,3 +43,77 @@ export async function optimizePrompt(
);
return response.data;
}
/**
* Create a talking avatar video asynchronously
* Uses dedicated Video Studio endpoint for generic avatar generation
*/
export async function createAvatarVideoAsync(
imageFile: File,
audioFile: File,
resolution: '480p' | '720p' = '720p',
model: 'infinitetalk' | 'hunyuan-avatar' = 'infinitetalk'
): Promise<CreateAvatarVideoResponse> {
const formData = new FormData();
formData.append('image', imageFile);
formData.append('audio', audioFile);
formData.append('resolution', resolution);
formData.append('model', model);
try {
const response = await aiApiClient.post<CreateAvatarVideoResponse>(
`${API_BASE}/avatar/create-async`,
formData,
{
headers: {
'Content-Type': 'multipart/form-data',
},
}
);
return response.data;
} catch (error: any) {
console.error('Error creating avatar video:', error);
throw new Error(error.response?.data?.detail || 'Failed to create avatar video');
}
}
/**
* Get the status of a video generation task
*/
export async function getVideoTaskStatus(taskId: string): Promise<CreateAvatarVideoResponse> {
try {
const response = await aiApiClient.get<CreateAvatarVideoResponse>(
`${API_BASE}/task/${taskId}`
);
return response.data;
} catch (error: any) {
console.error('Error fetching video task status:', error);
throw new Error(error.response?.data?.detail || 'Failed to fetch task status');
}
}
/**
* Poll video task status compatible with usePolling hook
*/
export async function pollVideoTaskStatus(taskId: string): Promise<TaskStatusResponse<{ video_url: string; [key: string]: any }>> {
const data = await getVideoTaskStatus(taskId);
// Map CreateAvatarVideoResponse to TaskStatusResponse
// Ensure we map 'processing' to 'running' for frontend consistency
let status: 'pending' | 'running' | 'completed' | 'failed' = 'pending';
if (data.status === 'completed') status = 'completed';
else if (data.status === 'failed') status = 'failed';
else if (data.status === 'running' || data.status === 'processing') status = 'running';
else status = 'pending';
return {
task_id: data.task_id,
status: status,
progress_messages: [], // Video Studio currently doesn't return progress messages
result: data.result,
error: data.error,
// Add default values for missing fields
created_at: new Date().toISOString(),
};
}