feat: expand novel IP and production workflows
This commit is contained in:
@@ -1,5 +1,22 @@
|
||||
import type { ScriptStatus, StoryboardStatus } from './script.types';
|
||||
|
||||
export class GenerateEpisodeScriptDto {
|
||||
provider_code?: string;
|
||||
prompt_override?: string;
|
||||
request_params_override?: {
|
||||
max_output_tokens?: number;
|
||||
temperature?: number;
|
||||
timeout_ms?: number;
|
||||
};
|
||||
}
|
||||
|
||||
export class GenerateStoryboardDto {
|
||||
provider_code?: string;
|
||||
video_provider_code?: string;
|
||||
storyboard_mode?: 'visual_board' | 'shot_list';
|
||||
force?: boolean;
|
||||
}
|
||||
|
||||
export class UpdateEpisodeScriptDto {
|
||||
script_text?: string;
|
||||
narration_text?: string;
|
||||
@@ -21,5 +38,8 @@ export class UpdateStoryboardShotDto {
|
||||
duration?: number;
|
||||
prompt_text?: string;
|
||||
negative_prompt?: string;
|
||||
transition_to_next?: string;
|
||||
transition_to_next_duration?: number;
|
||||
transition_to_next_reason?: string;
|
||||
status?: StoryboardStatus;
|
||||
}
|
||||
|
||||
@@ -34,13 +34,85 @@ export interface SafeStoryboardShot {
|
||||
camera_motion: string | null;
|
||||
effect_type: string | null;
|
||||
duration: number | null;
|
||||
scene_type: string | null;
|
||||
importance_score: number | null;
|
||||
emotion_score: number | null;
|
||||
action_score: number | null;
|
||||
route_tier: string | null;
|
||||
prompt_text: string | null;
|
||||
negative_prompt: string | null;
|
||||
live_action_desc: string | null;
|
||||
actor_action: string | null;
|
||||
camera_instruction: string | null;
|
||||
performance_instruction: string | null;
|
||||
video_prompt: string | null;
|
||||
transition_to_next: string | null;
|
||||
transition_to_next_duration: number | null;
|
||||
transition_to_next_reason: string | null;
|
||||
keyframe_asset_id: string | null;
|
||||
video_clip_asset_id: string | null;
|
||||
video_status: string | null;
|
||||
status: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
export interface SafeStoryboardVisualBoardCell {
|
||||
shot_id: string;
|
||||
shot_no: number;
|
||||
board_no: number;
|
||||
row_no: number;
|
||||
cell_no: number;
|
||||
global_cell_no: number;
|
||||
scene_name: string | null;
|
||||
shot_type: string | null;
|
||||
visual_desc: string | null;
|
||||
action_desc: string | null;
|
||||
dialogue_text: string | null;
|
||||
duration: number | null;
|
||||
required_assets_text: string;
|
||||
}
|
||||
|
||||
export interface SafeStoryboardVisualBoardGroup {
|
||||
group_no: number;
|
||||
board_no: number;
|
||||
row_no: number;
|
||||
cell_range: string;
|
||||
shot_ids: string[];
|
||||
shot_nos: number[];
|
||||
suggested_duration: number;
|
||||
prompt_text: string;
|
||||
negative_prompt: string;
|
||||
cells: SafeStoryboardVisualBoardCell[];
|
||||
}
|
||||
|
||||
export interface SafeStoryboardVisualBoard {
|
||||
board_no: number;
|
||||
grid_mode: 25;
|
||||
title: string;
|
||||
prompt_text: string;
|
||||
negative_prompt: string;
|
||||
cells: SafeStoryboardVisualBoardCell[];
|
||||
}
|
||||
|
||||
export interface SafeStoryboardVisualBoardPlan {
|
||||
mode: 'visual_board';
|
||||
grid_mode: 25;
|
||||
group_size: 5;
|
||||
board_count: number;
|
||||
total_cells: number;
|
||||
provider_code: string | null;
|
||||
provider_label: string;
|
||||
provider_duration_range: {
|
||||
min: number;
|
||||
max: number;
|
||||
allowed: number[];
|
||||
};
|
||||
boards: SafeStoryboardVisualBoard[];
|
||||
groups: SafeStoryboardVisualBoardGroup[];
|
||||
copy_package_text: string;
|
||||
}
|
||||
|
||||
export function toSafeEpisodeScript(script: EpisodeScript): SafeEpisodeScript {
|
||||
return {
|
||||
id: script.id.toString(),
|
||||
@@ -72,8 +144,26 @@ export function toSafeStoryboardShot(shot: StoryboardShot): SafeStoryboardShot {
|
||||
camera_motion: shot.camera_motion,
|
||||
effect_type: shot.effect_type,
|
||||
duration: shot.duration ? Number(shot.duration.toString()) : null,
|
||||
scene_type: shot.scene_type,
|
||||
importance_score: shot.importance_score,
|
||||
emotion_score: shot.emotion_score,
|
||||
action_score: shot.action_score,
|
||||
route_tier: shot.route_tier,
|
||||
prompt_text: shot.prompt_text,
|
||||
negative_prompt: shot.negative_prompt,
|
||||
live_action_desc: shot.live_action_desc,
|
||||
actor_action: shot.actor_action,
|
||||
camera_instruction: shot.camera_instruction,
|
||||
performance_instruction: shot.performance_instruction,
|
||||
video_prompt: shot.video_prompt,
|
||||
transition_to_next: shot.transition_to_next,
|
||||
transition_to_next_duration: shot.transition_to_next_duration
|
||||
? Number(shot.transition_to_next_duration.toString())
|
||||
: null,
|
||||
transition_to_next_reason: shot.transition_to_next_reason,
|
||||
keyframe_asset_id: shot.keyframe_asset_id?.toString() ?? null,
|
||||
video_clip_asset_id: shot.video_clip_asset_id?.toString() ?? null,
|
||||
video_status: shot.video_status,
|
||||
status: shot.status,
|
||||
created_at: shot.created_at.toISOString(),
|
||||
updated_at: shot.updated_at.toISOString()
|
||||
|
||||
@@ -7,12 +7,18 @@ import {
|
||||
Param,
|
||||
Patch,
|
||||
Post,
|
||||
Query,
|
||||
UseGuards
|
||||
} from '@nestjs/common';
|
||||
import { CurrentUser } from '../auth/current-user.decorator';
|
||||
import type { AuthRequestUser } from '../auth/auth.types';
|
||||
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
|
||||
import { UpdateEpisodeScriptDto, UpdateStoryboardShotDto } from './script.dto';
|
||||
import {
|
||||
GenerateEpisodeScriptDto,
|
||||
GenerateStoryboardDto,
|
||||
UpdateEpisodeScriptDto,
|
||||
UpdateStoryboardShotDto
|
||||
} from './script.dto';
|
||||
import { ScriptsService } from './scripts.service';
|
||||
|
||||
@Controller()
|
||||
@@ -23,9 +29,19 @@ export class ScriptsController {
|
||||
@Post('episodes/:episodeId/script/generate')
|
||||
generateScript(
|
||||
@CurrentUser() user: AuthRequestUser,
|
||||
@Param('episodeId') episodeId: string
|
||||
@Param('episodeId') episodeId: string,
|
||||
@Body() dto: GenerateEpisodeScriptDto
|
||||
) {
|
||||
return this.scriptsService.generateScript(user, episodeId);
|
||||
return this.scriptsService.generateScript(user, episodeId, dto);
|
||||
}
|
||||
|
||||
@Post('episodes/:episodeId/script/request-preview')
|
||||
previewScriptRequest(
|
||||
@CurrentUser() user: AuthRequestUser,
|
||||
@Param('episodeId') episodeId: string,
|
||||
@Body() dto: GenerateEpisodeScriptDto
|
||||
) {
|
||||
return this.scriptsService.previewScriptRequest(user, episodeId, dto);
|
||||
}
|
||||
|
||||
@Get('episodes/:episodeId/script')
|
||||
@@ -56,9 +72,10 @@ export class ScriptsController {
|
||||
@Post('episodes/:episodeId/storyboard/generate')
|
||||
generateStoryboard(
|
||||
@CurrentUser() user: AuthRequestUser,
|
||||
@Param('episodeId') episodeId: string
|
||||
@Param('episodeId') episodeId: string,
|
||||
@Body() dto: GenerateStoryboardDto
|
||||
) {
|
||||
return this.scriptsService.generateStoryboard(user, episodeId);
|
||||
return this.scriptsService.generateStoryboard(user, episodeId, dto);
|
||||
}
|
||||
|
||||
@Get('episodes/:episodeId/storyboard')
|
||||
@@ -69,6 +86,15 @@ export class ScriptsController {
|
||||
return this.scriptsService.getStoryboard(user, episodeId);
|
||||
}
|
||||
|
||||
@Get('episodes/:episodeId/storyboard/visual-board-plan')
|
||||
getStoryboardVisualBoardPlan(
|
||||
@CurrentUser() user: AuthRequestUser,
|
||||
@Param('episodeId') episodeId: string,
|
||||
@Query('video_provider_code') videoProviderCode?: string
|
||||
) {
|
||||
return this.scriptsService.getStoryboardVisualBoardPlan(user, episodeId, videoProviderCode);
|
||||
}
|
||||
|
||||
@Patch('storyboard-shots/:shotId')
|
||||
updateStoryboardShot(
|
||||
@CurrentUser() user: AuthRequestUser,
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { AuthModule } from '../auth/auth.module';
|
||||
import { PrismaModule } from '../prisma/prisma.module';
|
||||
import { ProvidersModule } from '../providers/providers.module';
|
||||
import { ScriptsController } from './scripts.controller';
|
||||
import { ScriptsService } from './scripts.service';
|
||||
|
||||
@Module({
|
||||
imports: [AuthModule, PrismaModule],
|
||||
imports: [AuthModule, PrismaModule, ProvidersModule],
|
||||
controllers: [ScriptsController],
|
||||
providers: [ScriptsService],
|
||||
exports: [ScriptsService]
|
||||
|
||||
@@ -399,7 +399,7 @@ describe('ScriptsService', () => {
|
||||
where: { id: 10n },
|
||||
data: { status: 'storyboard_generating' }
|
||||
});
|
||||
expect(tx.storyboardShot.createMany.mock.calls[0][0].data).toHaveLength(10);
|
||||
expect(tx.storyboardShot.createMany.mock.calls[0][0].data).toHaveLength(2);
|
||||
expect(tx.storyboardShot.createMany.mock.calls[0][0].data[0]).toEqual(
|
||||
expect.objectContaining({
|
||||
project_id: 10n,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user