Release Candidate: Production Release with Multi-Tenant & Onboarding Enhancements

This commit is contained in:
ajaysi
2026-02-28 20:06:26 +05:30
parent 08a1f4a1d8
commit 4828274cbf
162 changed files with 19489 additions and 4300 deletions

View File

@@ -35,10 +35,93 @@ export interface StoryGenerationRequest {
audio_lang?: string;
audio_slow?: boolean;
audio_rate?: number;
anime_bible?: AnimeStoryBible | null;
}
export interface StorySetupGenerationRequest {
story_idea: string;
story_mode?: 'marketing' | 'pure';
story_template?: string | null;
brand_context?: {
brand_name?: string | null;
writing_tone?: string | null;
audience_description?: string | null;
} | null;
}
export interface StoryIdeaEnhanceRequest {
story_idea: string;
story_mode?: 'marketing' | 'pure';
story_template?: string | null;
brand_context?: {
brand_name?: string | null;
writing_tone?: string | null;
audience_description?: string | null;
} | null;
fiction_variant?: string | null;
narrative_energy?: string | null;
}
export interface StoryIdeaEnhanceSuggestion {
idea: string;
whats_missing: string;
why_choose: string;
}
export interface StoryIdeaEnhanceResponse {
suggestions: StoryIdeaEnhanceSuggestion[];
success: boolean;
}
export interface StoryContextResponse {
canonical_profile: Record<string, any> | null;
website_url?: string | null;
research_preferences?: Record<string, any> | null;
brand_context?: {
brand_name?: string | null;
writing_tone?: string | null;
audience_description?: string | null;
} | null;
brand_assets?: {
avatar_url?: string | null;
voice_preview_url?: string | null;
custom_voice_id?: string | null;
} | null;
persona_enabled?: boolean;
has_persona_context?: boolean;
}
export interface AnimeCharacter {
id: string;
name: string;
age_range: string;
role: string;
look: string;
outfit_palette: string;
personality_tags: string[];
}
export interface AnimeWorld {
setting: string;
era: string;
tech_or_magic_level: string;
core_rules: string[];
}
export interface AnimeVisualStyle {
style_preset: string;
camera_style: string;
color_mood: string;
lighting: string;
line_style: string;
extra_tags: string[];
}
export interface AnimeStoryBible {
story_id?: string;
main_cast: AnimeCharacter[];
world: AnimeWorld;
visual_style: AnimeVisualStyle;
}
export interface StorySetupOption {
@@ -96,6 +179,7 @@ export interface StoryOutlineResponse {
success: boolean;
task_id?: string;
is_structured?: boolean;
anime_bible?: AnimeStoryBible;
}
export interface StoryContentResponse {
@@ -261,6 +345,97 @@ export interface ResumeAnimateSceneRequest {
duration?: 5 | 10;
}
export interface AnimeSceneTextRequest {
scene: StoryScene;
persona: string;
story_setting: string;
character_input: string;
plot_elements: string;
writing_style: string;
story_tone: string;
narrative_pov: string;
audience_age_group: string;
content_rating: string;
anime_bible?: AnimeStoryBible | null;
}
export interface AnimeSceneTextResponse {
scene: StoryScene;
success: boolean;
}
export interface AnimeSceneGenerateRequest {
premise: string;
persona: string;
story_setting: string;
character_input: string;
plot_elements: string;
writing_style: string;
story_tone: string;
narrative_pov: string;
audience_age_group: string;
content_rating: string;
anime_bible: AnimeStoryBible;
previous_scenes?: StoryScene[] | null;
target_scene_number?: number | null;
}
export interface AnimeSceneGenerateResponse {
scene: StoryScene;
success: boolean;
}
export interface StoryProjectSummary {
id: number;
project_id: string;
user_id: string;
title?: string | null;
story_mode?: string | null;
story_template?: string | null;
setup?: Record<string, any> | null;
outline?: Record<string, any> | null;
scenes?: Record<string, any>[] | null;
story_content?: Record<string, any> | null;
anime_bible?: AnimeStoryBible | null;
media_state?: Record<string, any> | null;
current_phase?: string | null;
status: string;
is_favorite: boolean;
is_complete: boolean;
created_at: string;
updated_at: string;
}
export interface StoryProjectListResponse {
projects: StoryProjectSummary[];
total: number;
limit: number;
offset: number;
}
export interface CreateStoryProjectRequest {
project_id: string;
title?: string | null;
story_mode?: string | null;
story_template?: string | null;
setup?: Record<string, any> | null;
}
export interface UpdateStoryProjectRequest {
title?: string | null;
story_mode?: string | null;
story_template?: string | null;
setup?: Record<string, any> | null;
outline?: Record<string, any> | null;
scenes?: Record<string, any>[] | null;
story_content?: Record<string, any> | null;
anime_bible?: AnimeStoryBible | null;
media_state?: Record<string, any> | null;
current_phase?: string | null;
status?: string | null;
is_complete?: boolean | null;
}
class StoryWriterApi {
/**
* Generate 3 story setup options from a user's story idea
@@ -275,6 +450,24 @@ class StoryWriterApi {
return response.data;
}
async enhanceStoryIdea(
request: StoryIdeaEnhanceRequest
): Promise<StoryIdeaEnhanceResponse> {
const response = await aiApiClient.post<StoryIdeaEnhanceResponse>(
"/api/story/enhance-idea",
request
);
return response.data;
}
/**
* Get onboarding-based story context for Story Studio
*/
async getStoryContext(): Promise<StoryContextResponse> {
const response = await aiApiClient.get<StoryContextResponse>("/api/story/context");
return response.data;
}
/**
* Generate a story premise
*/
@@ -441,6 +634,71 @@ class StoryWriterApi {
return response.data;
}
async refineAnimeSceneText(request: AnimeSceneTextRequest): Promise<AnimeSceneTextResponse> {
const response = await aiApiClient.post<AnimeSceneTextResponse>(
"/api/story/anime/scene-text",
request
);
return response.data;
}
async generateAnimeSceneFromBible(
request: AnimeSceneGenerateRequest
): Promise<AnimeSceneGenerateResponse> {
const response = await aiApiClient.post<AnimeSceneGenerateResponse>(
"/api/story/anime/scene-generate",
request
);
return response.data;
}
async createStoryProject(
payload: CreateStoryProjectRequest
): Promise<StoryProjectSummary> {
const response = await aiApiClient.post<StoryProjectSummary>("/api/story/projects", payload);
return response.data;
}
async loadStoryProject(projectId: string): Promise<StoryProjectSummary> {
const response = await aiApiClient.get<StoryProjectSummary>(`/api/story/projects/${projectId}`);
return response.data;
}
async updateStoryProject(
projectId: string,
payload: UpdateStoryProjectRequest
): Promise<StoryProjectSummary> {
const response = await aiApiClient.put<StoryProjectSummary>(
`/api/story/projects/${projectId}`,
payload
);
return response.data;
}
async listStoryProjects(params?: {
status?: string;
favorites_only?: boolean;
limit?: number;
offset?: number;
order_by?: "updated_at" | "created_at";
}): Promise<StoryProjectListResponse> {
const response = await aiApiClient.get<StoryProjectListResponse>("/api/story/projects", {
params,
});
return response.data;
}
async deleteStoryProject(projectId: string): Promise<void> {
await aiApiClient.delete(`/api/story/projects/${projectId}`);
}
async toggleStoryProjectFavorite(projectId: string): Promise<StoryProjectSummary> {
const response = await aiApiClient.post<StoryProjectSummary>(
`/api/story/projects/${projectId}/favorite`
);
return response.data;
}
private buildAbsoluteUrl(path: string): string {
if (!path) return path;
if (path.startsWith('http://') || path.startsWith('https://')) {