Initial AI manga platform
This commit is contained in:
@@ -0,0 +1,629 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE `users` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`email` VARCHAR(191) NULL,
|
||||
`phone` VARCHAR(50) NULL,
|
||||
`password_hash` VARCHAR(255) NOT NULL,
|
||||
`nickname` VARCHAR(100) NULL,
|
||||
`avatar_url` VARCHAR(500) NULL,
|
||||
`role` VARCHAR(50) NOT NULL DEFAULT 'user',
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'active',
|
||||
`wechat_openid` VARCHAR(191) NULL,
|
||||
`last_login_at` DATETIME(3) NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `users_email_key`(`email`),
|
||||
UNIQUE INDEX `users_phone_key`(`phone`),
|
||||
UNIQUE INDEX `users_wechat_openid_key`(`wechat_openid`),
|
||||
INDEX `users_role_status_idx`(`role`, `status`),
|
||||
INDEX `users_created_at_idx`(`created_at`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `projects` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`user_id` BIGINT NOT NULL,
|
||||
`title` VARCHAR(255) NULL,
|
||||
`input_mode` VARCHAR(50) NOT NULL,
|
||||
`genre` VARCHAR(100) NULL,
|
||||
`style_code` VARCHAR(100) NULL,
|
||||
`output_type` VARCHAR(50) NULL,
|
||||
`target_episode_count` INTEGER NULL,
|
||||
`episode_duration` INTEGER NULL,
|
||||
`status` VARCHAR(80) NOT NULL DEFAULT 'draft',
|
||||
`copyright_status` VARCHAR(80) NOT NULL DEFAULT 'pending',
|
||||
`payment_status` VARCHAR(80) NOT NULL DEFAULT 'unpaid',
|
||||
`quality_level` VARCHAR(50) NULL,
|
||||
`is_long_series` BOOLEAN NOT NULL DEFAULT false,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
`completed_at` DATETIME(3) NULL,
|
||||
|
||||
INDEX `projects_user_id_status_idx`(`user_id`, `status`),
|
||||
INDEX `projects_genre_status_idx`(`genre`, `status`),
|
||||
INDEX `projects_created_at_idx`(`created_at`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `novel_sources` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`source_type` VARCHAR(50) NOT NULL,
|
||||
`title` VARCHAR(255) NULL,
|
||||
`author_name` VARCHAR(100) NULL,
|
||||
`raw_asset_id` BIGINT NULL,
|
||||
`raw_text` LONGTEXT NULL,
|
||||
`clean_text` LONGTEXT NULL,
|
||||
`word_count` INTEGER NULL,
|
||||
`chapter_count` INTEGER NULL,
|
||||
`parse_status` VARCHAR(50) NOT NULL DEFAULT 'pending',
|
||||
`parse_report` JSON NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
|
||||
INDEX `novel_sources_project_id_idx`(`project_id`),
|
||||
INDEX `novel_sources_parse_status_idx`(`parse_status`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `novel_chapters` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`novel_source_id` BIGINT NULL,
|
||||
`chapter_no` INTEGER NOT NULL,
|
||||
`title` VARCHAR(255) NULL,
|
||||
`content` LONGTEXT NOT NULL,
|
||||
`summary` TEXT NULL,
|
||||
`visual_summary` TEXT NULL,
|
||||
`word_count` INTEGER NULL,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'draft',
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
|
||||
INDEX `novel_chapters_project_id_chapter_no_idx`(`project_id`, `chapter_no`),
|
||||
INDEX `novel_chapters_project_id_status_idx`(`project_id`, `status`),
|
||||
UNIQUE INDEX `novel_chapters_novel_source_id_chapter_no_key`(`novel_source_id`, `chapter_no`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `copyright_records` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`user_id` BIGINT NOT NULL,
|
||||
`authorization_type` VARCHAR(50) NOT NULL,
|
||||
`statement_text` TEXT NOT NULL,
|
||||
`ip` VARCHAR(80) NULL,
|
||||
`user_agent` TEXT NULL,
|
||||
`confirmed_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
|
||||
INDEX `copyright_records_project_id_idx`(`project_id`),
|
||||
INDEX `copyright_records_user_id_idx`(`user_id`),
|
||||
INDEX `copyright_records_authorization_type_idx`(`authorization_type`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `story_bibles` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`title` VARCHAR(255) NULL,
|
||||
`logline` TEXT NULL,
|
||||
`main_plot` TEXT NULL,
|
||||
`core_conflict` TEXT NULL,
|
||||
`selling_points` TEXT NULL,
|
||||
`tone` VARCHAR(100) NULL,
|
||||
`world_summary` TEXT NULL,
|
||||
`ending_direction` TEXT NULL,
|
||||
`taboo_rules` TEXT NULL,
|
||||
`version` INTEGER NOT NULL DEFAULT 1,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'draft',
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
|
||||
INDEX `story_bibles_project_id_status_idx`(`project_id`, `status`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `world_bibles` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`world_type` VARCHAR(100) NULL,
|
||||
`setting_text` TEXT NULL,
|
||||
`rules_text` TEXT NULL,
|
||||
`power_system` TEXT NULL,
|
||||
`social_structure` TEXT NULL,
|
||||
`time_period` TEXT NULL,
|
||||
`visual_rules` TEXT NULL,
|
||||
`forbidden_rules` TEXT NULL,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'draft',
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
|
||||
INDEX `world_bibles_project_id_status_idx`(`project_id`, `status`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `characters` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`name` VARCHAR(100) NOT NULL,
|
||||
`alias_names` JSON NULL,
|
||||
`role_type` VARCHAR(50) NOT NULL,
|
||||
`gender_label` VARCHAR(50) NULL,
|
||||
`age_group` VARCHAR(50) NULL,
|
||||
`identity_desc` TEXT NULL,
|
||||
`appearance_desc` TEXT NULL,
|
||||
`face_desc` TEXT NULL,
|
||||
`hair_desc` TEXT NULL,
|
||||
`eye_desc` TEXT NULL,
|
||||
`body_desc` TEXT NULL,
|
||||
`costume_rules` TEXT NULL,
|
||||
`special_props` TEXT NULL,
|
||||
`personality_desc` TEXT NULL,
|
||||
`speech_style` TEXT NULL,
|
||||
`relationship_desc` TEXT NULL,
|
||||
`character_arc` TEXT NULL,
|
||||
`negative_rules` TEXT NULL,
|
||||
`anchor_asset_id` BIGINT NULL,
|
||||
`importance_level` INTEGER NOT NULL DEFAULT 0,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'draft',
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
|
||||
INDEX `characters_project_id_role_type_idx`(`project_id`, `role_type`),
|
||||
INDEX `characters_project_id_status_idx`(`project_id`, `status`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `character_images` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`character_id` BIGINT NOT NULL,
|
||||
`asset_id` BIGINT NULL,
|
||||
`image_type` VARCHAR(50) NOT NULL,
|
||||
`prompt_text` TEXT NULL,
|
||||
`negative_prompt` TEXT NULL,
|
||||
`is_anchor` BOOLEAN NOT NULL DEFAULT false,
|
||||
`quality_score` DECIMAL(5, 2) NULL,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'pending',
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
|
||||
INDEX `character_images_project_id_idx`(`project_id`),
|
||||
INDEX `character_images_character_id_image_type_idx`(`character_id`, `image_type`),
|
||||
INDEX `character_images_character_id_is_anchor_idx`(`character_id`, `is_anchor`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `character_memories` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`character_id` BIGINT NOT NULL,
|
||||
`episode_id` BIGINT NULL,
|
||||
`memory_type` VARCHAR(50) NOT NULL,
|
||||
`content` TEXT NOT NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
|
||||
INDEX `character_memories_project_id_character_id_idx`(`project_id`, `character_id`),
|
||||
INDEX `character_memories_project_id_episode_id_idx`(`project_id`, `episode_id`),
|
||||
INDEX `character_memories_memory_type_idx`(`memory_type`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `episodes` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`episode_no` INTEGER NOT NULL,
|
||||
`source_chapter_ids` JSON NULL,
|
||||
`title` VARCHAR(255) NULL,
|
||||
`summary` TEXT NULL,
|
||||
`opening_hook` TEXT NULL,
|
||||
`middle_conflict` TEXT NULL,
|
||||
`ending_hook` TEXT NULL,
|
||||
`target_duration` INTEGER NULL,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'draft',
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
|
||||
INDEX `episodes_project_id_status_idx`(`project_id`, `status`),
|
||||
UNIQUE INDEX `episodes_project_id_episode_no_key`(`project_id`, `episode_no`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `episode_scripts` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`episode_id` BIGINT NOT NULL,
|
||||
`script_text` LONGTEXT NULL,
|
||||
`narration_text` LONGTEXT NULL,
|
||||
`dialogue_json` JSON NULL,
|
||||
`version` INTEGER NOT NULL DEFAULT 1,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'draft',
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
|
||||
INDEX `episode_scripts_project_id_idx`(`project_id`),
|
||||
INDEX `episode_scripts_episode_id_version_idx`(`episode_id`, `version`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `storyboard_shots` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`episode_id` BIGINT NOT NULL,
|
||||
`shot_no` INTEGER NOT NULL,
|
||||
`scene_name` VARCHAR(255) NULL,
|
||||
`location_desc` TEXT NULL,
|
||||
`characters_json` JSON NULL,
|
||||
`visual_desc` TEXT NULL,
|
||||
`action_desc` TEXT NULL,
|
||||
`dialogue_text` TEXT NULL,
|
||||
`narration_text` TEXT NULL,
|
||||
`camera_motion` VARCHAR(100) NULL,
|
||||
`effect_type` VARCHAR(100) NULL,
|
||||
`duration` DECIMAL(6, 2) NULL,
|
||||
`prompt_text` TEXT NULL,
|
||||
`negative_prompt` TEXT NULL,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'draft',
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
|
||||
INDEX `storyboard_shots_project_id_episode_id_shot_no_idx`(`project_id`, `episode_id`, `shot_no`),
|
||||
INDEX `storyboard_shots_project_id_status_idx`(`project_id`, `status`),
|
||||
UNIQUE INDEX `storyboard_shots_episode_id_shot_no_key`(`episode_id`, `shot_no`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `shot_images` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`episode_id` BIGINT NULL,
|
||||
`shot_id` BIGINT NOT NULL,
|
||||
`asset_id` BIGINT NULL,
|
||||
`image_type` VARCHAR(50) NOT NULL DEFAULT 'preview',
|
||||
`prompt_text` TEXT NULL,
|
||||
`negative_prompt` TEXT NULL,
|
||||
`quality_score` DECIMAL(5, 2) NULL,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'pending',
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
|
||||
INDEX `shot_images_project_id_episode_id_idx`(`project_id`, `episode_id`),
|
||||
INDEX `shot_images_shot_id_image_type_idx`(`shot_id`, `image_type`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `plot_memories` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`episode_id` BIGINT NULL,
|
||||
`chapter_id` BIGINT NULL,
|
||||
`memory_type` VARCHAR(50) NOT NULL,
|
||||
`content` TEXT NOT NULL,
|
||||
`importance_level` INTEGER NOT NULL DEFAULT 0,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'active',
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
|
||||
INDEX `plot_memories_project_id_episode_id_idx`(`project_id`, `episode_id`),
|
||||
INDEX `plot_memories_project_id_memory_type_idx`(`project_id`, `memory_type`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `plot_threads` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`thread_name` VARCHAR(255) NOT NULL,
|
||||
`thread_type` VARCHAR(80) NOT NULL,
|
||||
`description` TEXT NULL,
|
||||
`start_episode_no` INTEGER NULL,
|
||||
`expected_resolve_episode_no` INTEGER NULL,
|
||||
`resolved_episode_no` INTEGER NULL,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'open',
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
|
||||
INDEX `plot_threads_project_id_status_idx`(`project_id`, `status`),
|
||||
INDEX `plot_threads_project_id_thread_type_idx`(`project_id`, `thread_type`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `continuity_checks` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`episode_id` BIGINT NULL,
|
||||
`check_type` VARCHAR(80) NOT NULL,
|
||||
`result_status` VARCHAR(50) NOT NULL,
|
||||
`issue_text` TEXT NULL,
|
||||
`suggestion_text` TEXT NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
|
||||
INDEX `continuity_checks_project_id_episode_id_idx`(`project_id`, `episode_id`),
|
||||
INDEX `continuity_checks_result_status_idx`(`result_status`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `assets` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`user_id` BIGINT NULL,
|
||||
`project_id` BIGINT NULL,
|
||||
`asset_type` VARCHAR(50) NOT NULL,
|
||||
`file_path` VARCHAR(500) NOT NULL,
|
||||
`file_url` VARCHAR(500) NULL,
|
||||
`mime_type` VARCHAR(100) NULL,
|
||||
`width` INTEGER NULL,
|
||||
`height` INTEGER NULL,
|
||||
`duration` DECIMAL(10, 2) NULL,
|
||||
`size` BIGINT NULL,
|
||||
`hash` VARCHAR(128) NULL,
|
||||
`visibility` VARCHAR(30) NOT NULL DEFAULT 'private',
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'active',
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
|
||||
INDEX `assets_project_id_asset_type_idx`(`project_id`, `asset_type`),
|
||||
INDEX `assets_user_id_asset_type_idx`(`user_id`, `asset_type`),
|
||||
INDEX `assets_hash_idx`(`hash`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `render_tasks` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`episode_id` BIGINT NULL,
|
||||
`shot_id` BIGINT NULL,
|
||||
`task_type` VARCHAR(80) NOT NULL,
|
||||
`provider_id` BIGINT NULL,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'pending',
|
||||
`input_json` JSON NULL,
|
||||
`input_hash` VARCHAR(128) NULL,
|
||||
`idempotency_key` VARCHAR(191) NULL,
|
||||
`output_asset_id` BIGINT NULL,
|
||||
`provider_request_id` VARCHAR(255) NULL,
|
||||
`retry_count` INTEGER NOT NULL DEFAULT 0,
|
||||
`max_retry` INTEGER NOT NULL DEFAULT 0,
|
||||
`cost_estimate` DECIMAL(12, 4) NULL,
|
||||
`cost_actual` DECIMAL(12, 4) NULL,
|
||||
`error_code` VARCHAR(100) NULL,
|
||||
`error_message` TEXT NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`started_at` DATETIME(3) NULL,
|
||||
`finished_at` DATETIME(3) NULL,
|
||||
|
||||
UNIQUE INDEX `render_tasks_idempotency_key_key`(`idempotency_key`),
|
||||
INDEX `render_tasks_project_id_status_idx`(`project_id`, `status`),
|
||||
INDEX `render_tasks_task_type_status_idx`(`task_type`, `status`),
|
||||
INDEX `render_tasks_project_id_episode_id_idx`(`project_id`, `episode_id`),
|
||||
INDEX `render_tasks_input_hash_idx`(`input_hash`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `provider_configs` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`provider_type` VARCHAR(80) NOT NULL,
|
||||
`provider_code` VARCHAR(100) NOT NULL,
|
||||
`display_name` VARCHAR(100) NULL,
|
||||
`mode` VARCHAR(50) NOT NULL DEFAULT 'mock',
|
||||
`model_name` VARCHAR(100) NULL,
|
||||
`config_json` JSON NULL,
|
||||
`fallback_provider_id` BIGINT NULL,
|
||||
`is_enabled` BOOLEAN NOT NULL DEFAULT true,
|
||||
`priority` INTEGER NOT NULL DEFAULT 0,
|
||||
`rate_limit_json` JSON NULL,
|
||||
`cost_rule_json` JSON NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
|
||||
INDEX `provider_configs_provider_type_is_enabled_idx`(`provider_type`, `is_enabled`),
|
||||
UNIQUE INDEX `provider_configs_provider_type_provider_code_key`(`provider_type`, `provider_code`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `provider_logs` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`provider_id` BIGINT NULL,
|
||||
`task_id` BIGINT NULL,
|
||||
`project_id` BIGINT NULL,
|
||||
`provider_type` VARCHAR(80) NOT NULL,
|
||||
`provider_code` VARCHAR(100) NULL,
|
||||
`model_name` VARCHAR(100) NULL,
|
||||
`request_json` JSON NULL,
|
||||
`response_json` JSON NULL,
|
||||
`input_size` INTEGER NULL,
|
||||
`output_size` INTEGER NULL,
|
||||
`cost_estimate` DECIMAL(12, 4) NULL,
|
||||
`cost_actual` DECIMAL(12, 4) NULL,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'success',
|
||||
`error_code` VARCHAR(100) NULL,
|
||||
`error_message` TEXT NULL,
|
||||
`started_at` DATETIME(3) NULL,
|
||||
`finished_at` DATETIME(3) NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
|
||||
INDEX `provider_logs_provider_type_status_idx`(`provider_type`, `status`),
|
||||
INDEX `provider_logs_project_id_idx`(`project_id`),
|
||||
INDEX `provider_logs_task_id_idx`(`task_id`),
|
||||
INDEX `provider_logs_created_at_idx`(`created_at`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `orders` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`user_id` BIGINT NOT NULL,
|
||||
`project_id` BIGINT NULL,
|
||||
`order_no` VARCHAR(100) NOT NULL,
|
||||
`package_code` VARCHAR(100) NULL,
|
||||
`amount` DECIMAL(12, 2) NOT NULL DEFAULT 0,
|
||||
`currency` VARCHAR(20) NOT NULL DEFAULT 'CNY',
|
||||
`payment_method` VARCHAR(50) NULL,
|
||||
`payment_status` VARCHAR(50) NOT NULL DEFAULT 'pending',
|
||||
`paid_at` DATETIME(3) NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `orders_order_no_key`(`order_no`),
|
||||
INDEX `orders_user_id_payment_status_idx`(`user_id`, `payment_status`),
|
||||
INDEX `orders_project_id_idx`(`project_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `quota_accounts` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`user_id` BIGINT NOT NULL,
|
||||
`total_quota` DECIMAL(12, 2) NOT NULL DEFAULT 0,
|
||||
`available_quota` DECIMAL(12, 2) NOT NULL DEFAULT 0,
|
||||
`frozen_quota` DECIMAL(12, 2) NOT NULL DEFAULT 0,
|
||||
`used_quota` DECIMAL(12, 2) NOT NULL DEFAULT 0,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'active',
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `quota_accounts_user_id_key`(`user_id`),
|
||||
INDEX `quota_accounts_status_idx`(`status`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `quota_logs` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`user_id` BIGINT NOT NULL,
|
||||
`project_id` BIGINT NULL,
|
||||
`task_id` BIGINT NULL,
|
||||
`change_type` VARCHAR(50) NOT NULL,
|
||||
`amount` DECIMAL(12, 2) NOT NULL,
|
||||
`balance_after` DECIMAL(12, 2) NULL,
|
||||
`reason` VARCHAR(255) NULL,
|
||||
`metadata_json` JSON NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
|
||||
INDEX `quota_logs_user_id_created_at_idx`(`user_id`, `created_at`),
|
||||
INDEX `quota_logs_project_id_idx`(`project_id`),
|
||||
INDEX `quota_logs_task_id_idx`(`task_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `revision_requests` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`user_id` BIGINT NOT NULL,
|
||||
`revision_type` VARCHAR(50) NOT NULL,
|
||||
`target_type` VARCHAR(80) NULL,
|
||||
`target_id` BIGINT NULL,
|
||||
`description` TEXT NOT NULL,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'pending',
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
|
||||
INDEX `revision_requests_project_id_status_idx`(`project_id`, `status`),
|
||||
INDEX `revision_requests_user_id_status_idx`(`user_id`, `status`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `content_reviews` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NULL,
|
||||
`user_id` BIGINT NULL,
|
||||
`target_type` VARCHAR(80) NOT NULL,
|
||||
`target_id` BIGINT NULL,
|
||||
`review_type` VARCHAR(80) NOT NULL,
|
||||
`result_status` VARCHAR(50) NOT NULL DEFAULT 'pending',
|
||||
`risk_level` VARCHAR(50) NULL,
|
||||
`issue_text` TEXT NULL,
|
||||
`suggestion_text` TEXT NULL,
|
||||
`reviewer_id` BIGINT NULL,
|
||||
`reviewed_at` DATETIME(3) NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
|
||||
INDEX `content_reviews_project_id_result_status_idx`(`project_id`, `result_status`),
|
||||
INDEX `content_reviews_target_type_target_id_idx`(`target_type`, `target_id`),
|
||||
INDEX `content_reviews_review_type_result_status_idx`(`review_type`, `result_status`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `case_showcases` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`user_id` BIGINT NULL,
|
||||
`title` VARCHAR(255) NOT NULL,
|
||||
`cover_asset_id` BIGINT NULL,
|
||||
`video_asset_id` BIGINT NULL,
|
||||
`authorization_status` VARCHAR(50) NOT NULL DEFAULT 'pending',
|
||||
`visibility` VARCHAR(30) NOT NULL DEFAULT 'private',
|
||||
`sort_order` INTEGER NOT NULL DEFAULT 0,
|
||||
`published_at` DATETIME(3) NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
|
||||
INDEX `case_showcases_visibility_sort_order_idx`(`visibility`, `sort_order`),
|
||||
INDEX `case_showcases_project_id_idx`(`project_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `analytics_events` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`episode_id` BIGINT NULL,
|
||||
`event_type` VARCHAR(80) NOT NULL,
|
||||
`platform` VARCHAR(80) NULL,
|
||||
`metric_json` JSON NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
|
||||
INDEX `analytics_events_project_id_idx`(`project_id`),
|
||||
INDEX `analytics_events_episode_id_idx`(`episode_id`),
|
||||
INDEX `analytics_events_event_type_created_at_idx`(`event_type`, `created_at`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `system_configs` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`config_key` VARCHAR(191) NOT NULL,
|
||||
`config_value` JSON NULL,
|
||||
`description` TEXT NULL,
|
||||
`is_public` BOOLEAN NOT NULL DEFAULT false,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `system_configs_config_key_key`(`config_key`),
|
||||
INDEX `system_configs_is_public_idx`(`is_public`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `operation_logs` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`user_id` BIGINT NULL,
|
||||
`operator_role` VARCHAR(50) NULL,
|
||||
`action` VARCHAR(100) NOT NULL,
|
||||
`target_type` VARCHAR(80) NULL,
|
||||
`target_id` BIGINT NULL,
|
||||
`ip` VARCHAR(80) NULL,
|
||||
`user_agent` TEXT NULL,
|
||||
`metadata_json` JSON NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
|
||||
INDEX `operation_logs_user_id_created_at_idx`(`user_id`, `created_at`),
|
||||
INDEX `operation_logs_target_type_target_id_idx`(`target_type`, `target_id`),
|
||||
INDEX `operation_logs_action_created_at_idx`(`action`, `created_at`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
@@ -0,0 +1,55 @@
|
||||
ALTER TABLE `projects`
|
||||
ADD COLUMN `output_mode` VARCHAR(50) NOT NULL DEFAULT 'image_manga' AFTER `output_type`,
|
||||
ADD COLUMN `visual_mode` VARCHAR(100) NULL AFTER `output_mode`,
|
||||
ADD COLUMN `video_generation_level` VARCHAR(50) NULL AFTER `visual_mode`;
|
||||
|
||||
ALTER TABLE `storyboard_shots`
|
||||
ADD COLUMN `live_action_desc` TEXT NULL AFTER `negative_prompt`,
|
||||
ADD COLUMN `actor_action` TEXT NULL AFTER `live_action_desc`,
|
||||
ADD COLUMN `camera_instruction` TEXT NULL AFTER `actor_action`,
|
||||
ADD COLUMN `performance_instruction` TEXT NULL AFTER `camera_instruction`,
|
||||
ADD COLUMN `video_prompt` TEXT NULL AFTER `performance_instruction`,
|
||||
ADD COLUMN `keyframe_asset_id` BIGINT NULL AFTER `video_prompt`,
|
||||
ADD COLUMN `video_clip_asset_id` BIGINT NULL AFTER `keyframe_asset_id`,
|
||||
ADD COLUMN `video_status` VARCHAR(50) NULL AFTER `video_clip_asset_id`;
|
||||
|
||||
CREATE TABLE `actor_profiles` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`character_id` BIGINT NOT NULL,
|
||||
`actor_desc` TEXT NULL,
|
||||
`appearance_rules` TEXT NULL,
|
||||
`wardrobe_rules` TEXT NULL,
|
||||
`performance_style` TEXT NULL,
|
||||
`voice_style` TEXT NULL,
|
||||
`reference_asset_ids` JSON NULL,
|
||||
`anchor_asset_id` BIGINT NULL,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'draft',
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
UNIQUE INDEX `actor_profiles_project_id_character_id_key`(`project_id`, `character_id`),
|
||||
INDEX `actor_profiles_project_id_status_idx`(`project_id`, `status`),
|
||||
INDEX `actor_profiles_character_id_idx`(`character_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `video_clips` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`episode_id` BIGINT NOT NULL,
|
||||
`shot_id` BIGINT NOT NULL,
|
||||
`provider_id` BIGINT NULL,
|
||||
`input_asset_id` BIGINT NULL,
|
||||
`output_asset_id` BIGINT NULL,
|
||||
`duration` DECIMAL(6, 2) NULL,
|
||||
`prompt_text` TEXT NULL,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'pending',
|
||||
`cost_actual` DECIMAL(12, 4) NULL,
|
||||
`retry_count` INTEGER NOT NULL DEFAULT 0,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
INDEX `video_clips_project_id_episode_id_idx`(`project_id`, `episode_id`),
|
||||
INDEX `video_clips_shot_id_status_idx`(`shot_id`, `status`),
|
||||
INDEX `video_clips_provider_id_idx`(`provider_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
@@ -0,0 +1,88 @@
|
||||
ALTER TABLE `video_clips`
|
||||
ADD COLUMN `quality_status` VARCHAR(50) NULL AFTER `retry_count`,
|
||||
ADD COLUMN `quality_score` DECIMAL(5, 2) NULL AFTER `quality_status`,
|
||||
ADD COLUMN `quality_issues` JSON NULL AFTER `quality_score`;
|
||||
|
||||
INSERT INTO `provider_configs`
|
||||
(`provider_type`, `provider_code`, `display_name`, `mode`, `model_name`, `config_json`, `is_enabled`, `priority`, `rate_limit_json`, `cost_rule_json`, `created_at`, `updated_at`)
|
||||
VALUES
|
||||
(
|
||||
'VideoProvider',
|
||||
'runway-image-to-video',
|
||||
'Runway Image-to-Video',
|
||||
'real',
|
||||
'gen4.5',
|
||||
JSON_OBJECT(
|
||||
'driver', 'runway_image_to_video',
|
||||
'api_key_env', 'RUNWAYML_API_SECRET',
|
||||
'base_url', 'https://api.dev.runwayml.com',
|
||||
'api_version', '2024-11-06',
|
||||
'timeout_ms', 180000,
|
||||
'create_endpoint', '/v1/image_to_video',
|
||||
'task_endpoint_template', '/v1/tasks/{task_id}',
|
||||
'poll_interval_ms', 10000,
|
||||
'max_poll_attempts', 90,
|
||||
'ratio', '720:1280',
|
||||
'duration', 5,
|
||||
'note', '默认禁用。启用后必须在业务侧显式确认真实视频生成,避免误扣费。'
|
||||
),
|
||||
false,
|
||||
40,
|
||||
JSON_OBJECT('rpm', 5, 'concurrency', 1),
|
||||
JSON_OBJECT(
|
||||
'flat_cost', 0,
|
||||
'unit', 'video_seconds',
|
||||
'price_per_second', 0,
|
||||
'currency', 'USD',
|
||||
'max_cost_per_call', 0,
|
||||
'daily_cost_limit', 0,
|
||||
'note', '请按 Runway 实际账单填写 price_per_second 或单次/每日成本上限。'
|
||||
),
|
||||
NOW(3),
|
||||
NOW(3)
|
||||
),
|
||||
(
|
||||
'VideoProvider',
|
||||
'kling-image-to-video',
|
||||
'Kling Image-to-Video',
|
||||
'real',
|
||||
'kling-v3',
|
||||
JSON_OBJECT(
|
||||
'driver', 'kling_image_to_video',
|
||||
'api_key_env', 'KLING_API_KEY',
|
||||
'base_url', 'https://api-singapore.klingai.com',
|
||||
'timeout_ms', 180000,
|
||||
'create_endpoint', '/v1/videos/image2video',
|
||||
'task_endpoint_template', '/v1/videos/image2video/{task_id}',
|
||||
'poll_interval_ms', 10000,
|
||||
'max_poll_attempts', 90,
|
||||
'image_field', 'image',
|
||||
'prompt_field', 'prompt',
|
||||
'duration_field', 'duration',
|
||||
'aspect_ratio_field', 'aspect_ratio',
|
||||
'aspect_ratio', '9:16',
|
||||
'duration', 5,
|
||||
'note', '默认禁用。不同 Kling 官方/网关接口字段可能不同,可在高级配置里调整字段名和 Base URL。'
|
||||
),
|
||||
false,
|
||||
40,
|
||||
JSON_OBJECT('rpm', 5, 'concurrency', 1),
|
||||
JSON_OBJECT(
|
||||
'flat_cost', 0,
|
||||
'unit', 'video_seconds',
|
||||
'price_per_second', 0,
|
||||
'currency', 'USD',
|
||||
'max_cost_per_call', 0,
|
||||
'daily_cost_limit', 0,
|
||||
'note', '请按 Kling 实际账单填写 price_per_second 或单次/每日成本上限。'
|
||||
),
|
||||
NOW(3),
|
||||
NOW(3)
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
`display_name` = VALUES(`display_name`),
|
||||
`mode` = VALUES(`mode`),
|
||||
`model_name` = VALUES(`model_name`),
|
||||
`priority` = VALUES(`priority`),
|
||||
`rate_limit_json` = VALUES(`rate_limit_json`),
|
||||
`updated_at` = NOW(3);
|
||||
@@ -0,0 +1,108 @@
|
||||
INSERT INTO `provider_configs`
|
||||
(`provider_type`, `provider_code`, `display_name`, `mode`, `model_name`, `config_json`, `is_enabled`, `priority`, `rate_limit_json`, `cost_rule_json`, `created_at`, `updated_at`)
|
||||
VALUES
|
||||
(
|
||||
'VideoProvider',
|
||||
'minimax_hailuo_23_fast',
|
||||
'MiniMax Hailuo 2.3 Fast 图生视频',
|
||||
'real',
|
||||
'MiniMax-Hailuo-2.3-Fast',
|
||||
'{"driver":"configurable_image_to_video","error_prefix":"MINIMAX_VIDEO","api_key_env":"MINIMAX_API_KEY","base_url":"https://api.minimax.io","timeout_ms":300000,"create_endpoint":"/v1/video_generation","task_endpoint_template":"/v1/query/video_generation?task_id={task_id}","output_url_endpoint_template":"/v1/files/retrieve?file_id={file_id}","poll_interval_ms":10000,"max_poll_attempts":120,"image_field":"first_frame_image","prompt_field":"prompt","model_field":"model","duration_field":"duration","resolution_field":"resolution","duration":6,"resolution":"768P","extra_body_json":{"prompt_optimizer":true},"supports_reference_image":true,"supports_start_end_frame":false,"supports_audio":false,"supports_lipsync":false,"supports_character_reference":false,"note":"默认禁用。优先用于低成本快速验证真人短剧动效;成功后 MiniMax 返回 file_id,系统会再取 download_url 落库。"}',
|
||||
false,
|
||||
80,
|
||||
'{"rpm":5,"concurrency":1,"retry_limit":2}',
|
||||
'{"flat_cost":0,"unit":"video_seconds","price_per_second":0.0317,"currency":"USD","max_cost_per_call":1,"daily_cost_limit":10,"estimated_seconds":6,"note":"预估价仅用于后台试算,请按 MiniMax 控制台实时价格和账单调整。"}',
|
||||
NOW(3),
|
||||
NOW(3)
|
||||
),
|
||||
(
|
||||
'VideoProvider',
|
||||
'minimax_hailuo_23',
|
||||
'MiniMax Hailuo 2.3 图生视频',
|
||||
'real',
|
||||
'MiniMax-Hailuo-2.3',
|
||||
'{"driver":"configurable_image_to_video","error_prefix":"MINIMAX_VIDEO","api_key_env":"MINIMAX_API_KEY","base_url":"https://api.minimax.io","timeout_ms":300000,"create_endpoint":"/v1/video_generation","task_endpoint_template":"/v1/query/video_generation?task_id={task_id}","output_url_endpoint_template":"/v1/files/retrieve?file_id={file_id}","poll_interval_ms":10000,"max_poll_attempts":120,"image_field":"first_frame_image","prompt_field":"prompt","model_field":"model","duration_field":"duration","resolution_field":"resolution","duration":6,"resolution":"1080P","extra_body_json":{"prompt_optimizer":true},"supports_reference_image":true,"supports_start_end_frame":false,"supports_audio":false,"supports_lipsync":false,"supports_character_reference":false,"note":"默认禁用。质量优先于 Fast,适合正式样片对比;真实调用前必须在业务侧确认成本。"}',
|
||||
false,
|
||||
78,
|
||||
'{"rpm":5,"concurrency":1,"retry_limit":2}',
|
||||
'{"flat_cost":0,"unit":"video_seconds","price_per_second":0.0467,"currency":"USD","max_cost_per_call":1.5,"daily_cost_limit":15,"estimated_seconds":6,"note":"预估价仅用于后台试算,请按 MiniMax 控制台实时价格和账单调整。"}',
|
||||
NOW(3),
|
||||
NOW(3)
|
||||
),
|
||||
(
|
||||
'VideoProvider',
|
||||
'alibaba_wan26_i2v_flash',
|
||||
'阿里 Wan2.6 I2V Flash',
|
||||
'real',
|
||||
'wan2.6-i2v-flash',
|
||||
'{"driver":"configurable_image_to_video","error_prefix":"DASHSCOPE_VIDEO","api_key_env":"ALIBABA_DASHSCOPE_API_KEY","base_url":"https://dashscope.aliyuncs.com","timeout_ms":300000,"create_endpoint":"/api/v1/services/aigc/video-generation/video-synthesis","task_endpoint_template":"/api/v1/tasks/{task_id}","poll_interval_ms":10000,"max_poll_attempts":120,"body_style":"dashscope_legacy_i2v","headers":{"X-DashScope-Async":"enable"},"duration":5,"resolution":"720P","prompt_extend":true,"watermark":false,"supports_reference_image":true,"supports_start_end_frame":false,"supports_audio":true,"supports_lipsync":false,"supports_character_reference":false,"note":"默认禁用。阿里/百炼不同模型版本字段可能变化,必要时在高级配置中调整 endpoint、body_style 或 extra_body_json。"}',
|
||||
false,
|
||||
74,
|
||||
'{"rpm":5,"concurrency":1,"retry_limit":2}',
|
||||
'{"flat_cost":0,"unit":"video_seconds","price_per_second":0.0215,"currency":"USD","max_cost_per_call":1,"daily_cost_limit":10,"estimated_seconds":5,"note":"Flash 预估价仅用于试算,请按阿里云/百炼实际账单调整。"}',
|
||||
NOW(3),
|
||||
NOW(3)
|
||||
),
|
||||
(
|
||||
'VideoProvider',
|
||||
'alibaba_wan26_i2v',
|
||||
'阿里 Wan2.6 I2V 标准',
|
||||
'real',
|
||||
'wan2.6-i2v',
|
||||
'{"driver":"configurable_image_to_video","error_prefix":"DASHSCOPE_VIDEO","api_key_env":"ALIBABA_DASHSCOPE_API_KEY","base_url":"https://dashscope.aliyuncs.com","timeout_ms":300000,"create_endpoint":"/api/v1/services/aigc/video-generation/video-synthesis","task_endpoint_template":"/api/v1/tasks/{task_id}","poll_interval_ms":10000,"max_poll_attempts":120,"body_style":"dashscope_legacy_i2v","headers":{"X-DashScope-Async":"enable"},"duration":5,"resolution":"1080P","prompt_extend":true,"watermark":false,"supports_reference_image":true,"supports_start_end_frame":false,"supports_audio":true,"supports_lipsync":false,"supports_character_reference":false,"note":"默认禁用。标准模式适合正式出片对比;真实启用前请先小样本验证字段、速度和账单。"}',
|
||||
false,
|
||||
72,
|
||||
'{"rpm":5,"concurrency":1,"retry_limit":2}',
|
||||
'{"flat_cost":0,"unit":"video_seconds","price_per_second":0.086,"currency":"USD","max_cost_per_call":2,"daily_cost_limit":20,"estimated_seconds":5,"note":"标准模式预估价仅用于试算,请按阿里云/百炼实际账单调整。"}',
|
||||
NOW(3),
|
||||
NOW(3)
|
||||
),
|
||||
(
|
||||
'VideoProvider',
|
||||
'vidu_q3_turbo_reference',
|
||||
'Vidu Q3 Turbo 参考图生视频',
|
||||
'real',
|
||||
'viduq3-turbo',
|
||||
'{"driver":"configurable_image_to_video","error_prefix":"VIDU_VIDEO","api_key_env":"VIDU_API_KEY","base_url":"https://api.vidu.com","auth_scheme":"Token","timeout_ms":300000,"create_endpoint":"/ent/v2/reference2video","task_endpoint_template":"/ent/v2/tasks/{task_id}/creations","poll_interval_ms":10000,"max_poll_attempts":120,"body_style":"vidu_reference","duration":5,"resolution":"720p","aspect_ratio":"9:16","extra_body_json":{"audio":true,"movement_amplitude":"auto"},"supports_reference_image":true,"supports_start_end_frame":true,"supports_audio":true,"supports_lipsync":true,"supports_character_reference":true,"note":"默认禁用。适合做人物一致性和中文短剧感对比,参考图需要外部可访问 URL。"}',
|
||||
false,
|
||||
70,
|
||||
'{"rpm":5,"concurrency":1,"retry_limit":2}',
|
||||
'{"flat_cost":0,"unit":"video_seconds","price_per_second":0.05,"currency":"USD","max_cost_per_call":1.5,"daily_cost_limit":15,"estimated_seconds":5,"note":"Vidu Q3 Turbo 预估价仅用于试算,请按 Vidu 控制台实时价格和 credits 消耗调整。"}',
|
||||
NOW(3),
|
||||
NOW(3)
|
||||
),
|
||||
(
|
||||
'VideoProvider',
|
||||
'vidu_q3_pro',
|
||||
'Vidu Q3 Pro 参考图生视频',
|
||||
'real',
|
||||
'viduq3',
|
||||
'{"driver":"configurable_image_to_video","error_prefix":"VIDU_VIDEO","api_key_env":"VIDU_API_KEY","base_url":"https://api.vidu.com","auth_scheme":"Token","timeout_ms":300000,"create_endpoint":"/ent/v2/reference2video","task_endpoint_template":"/ent/v2/tasks/{task_id}/creations","poll_interval_ms":10000,"max_poll_attempts":120,"body_style":"vidu_reference","duration":5,"resolution":"1080p","aspect_ratio":"9:16","extra_body_json":{"audio":true,"movement_amplitude":"auto"},"supports_reference_image":true,"supports_start_end_frame":true,"supports_audio":true,"supports_lipsync":true,"supports_character_reference":true,"note":"默认禁用。质量优先,适合正式样片;真实启用前请先限制单次成本。"}',
|
||||
false,
|
||||
68,
|
||||
'{"rpm":5,"concurrency":1,"retry_limit":2}',
|
||||
'{"flat_cost":0,"unit":"video_seconds","price_per_second":0.12,"currency":"USD","max_cost_per_call":3,"daily_cost_limit":30,"estimated_seconds":5,"note":"Vidu Q3 Pro 预估价仅用于试算,请按 Vidu 控制台实时价格和 credits 消耗调整。"}',
|
||||
NOW(3),
|
||||
NOW(3)
|
||||
),
|
||||
(
|
||||
'VideoProvider',
|
||||
'jimeng_seedance',
|
||||
'即梦/Seedance 图生视频',
|
||||
'real',
|
||||
'doubao-seedance-1-5-pro-251215',
|
||||
'{"driver":"configurable_image_to_video","error_prefix":"SEEDANCE_VIDEO","api_key_env":"VOLCENGINE_API_KEY","base_url":"https://ark.cn-beijing.volces.com/api/v3","timeout_ms":300000,"create_endpoint":"/videos/generations","task_endpoint_template":"/videos/generations/{task_id}","poll_interval_ms":10000,"max_poll_attempts":120,"image_field":"image_url","prompt_field":"prompt","model_field":"model","duration_field":"duration","resolution_field":"resolution","aspect_ratio_field":"ratio","duration":5,"resolution":"720p","aspect_ratio":"9:16","extra_body_json":{"fps":24,"watermark":false,"camerafixed":false},"supports_reference_image":true,"supports_start_end_frame":true,"supports_audio":true,"supports_lipsync":true,"supports_character_reference":true,"note":"默认禁用。不同火山/即梦/网关 API 字段差异较大,此配置作为可改模板,正式接入前必须用小样本验证。"}',
|
||||
false,
|
||||
66,
|
||||
'{"rpm":5,"concurrency":1,"retry_limit":2}',
|
||||
'{"flat_cost":0,"unit":"video_seconds","price_per_second":0,"currency":"USD","max_cost_per_call":0,"daily_cost_limit":0,"estimated_seconds":5,"note":"Seedance/即梦价格按具体开通渠道差异较大,启用前请手动填写 price_per_second 和成本上限。"}',
|
||||
NOW(3),
|
||||
NOW(3)
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
`display_name` = VALUES(`display_name`),
|
||||
`mode` = VALUES(`mode`),
|
||||
`model_name` = VALUES(`model_name`),
|
||||
`priority` = VALUES(`priority`),
|
||||
`rate_limit_json` = VALUES(`rate_limit_json`),
|
||||
`updated_at` = NOW(3);
|
||||
@@ -0,0 +1,62 @@
|
||||
CREATE TABLE `global_characters` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`name` VARCHAR(100) NOT NULL,
|
||||
`display_name` VARCHAR(100) NULL,
|
||||
`role_archetype` VARCHAR(50) NOT NULL DEFAULT 'lead',
|
||||
`gender_label` VARCHAR(50) NULL,
|
||||
`age_group` VARCHAR(50) NULL,
|
||||
`identity_desc` TEXT NULL,
|
||||
`appearance_desc` TEXT NULL,
|
||||
`face_desc` TEXT NULL,
|
||||
`hair_desc` TEXT NULL,
|
||||
`eye_desc` TEXT NULL,
|
||||
`body_desc` TEXT NULL,
|
||||
`default_costume_rules` TEXT NULL,
|
||||
`wardrobe_json` JSON NULL,
|
||||
`special_props` TEXT NULL,
|
||||
`personality_desc` TEXT NULL,
|
||||
`speech_style` TEXT NULL,
|
||||
`voice_provider_code` VARCHAR(100) NULL,
|
||||
`voice_model` VARCHAR(100) NULL,
|
||||
`voice_id` VARCHAR(100) NULL,
|
||||
`voice_style` TEXT NULL,
|
||||
`performance_style` TEXT NULL,
|
||||
`negative_rules` TEXT NULL,
|
||||
`anchor_asset_id` BIGINT NULL,
|
||||
`voice_sample_asset_id` BIGINT NULL,
|
||||
`commercial_status` VARCHAR(50) NOT NULL DEFAULT 'internal_test',
|
||||
`usage_scope` VARCHAR(50) NOT NULL DEFAULT 'internal',
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'active',
|
||||
`created_by_user_id` BIGINT NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||||
INDEX `global_characters_status_role_archetype_idx`(`status`, `role_archetype`),
|
||||
INDEX `global_characters_commercial_status_idx`(`commercial_status`),
|
||||
INDEX `global_characters_created_by_user_id_idx`(`created_by_user_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `global_character_assets` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`global_character_id` BIGINT NOT NULL,
|
||||
`asset_id` BIGINT NULL,
|
||||
`asset_type` VARCHAR(50) NOT NULL,
|
||||
`label` VARCHAR(100) NULL,
|
||||
`prompt_text` TEXT NULL,
|
||||
`is_primary` BOOLEAN NOT NULL DEFAULT false,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'active',
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
INDEX `global_character_assets_global_character_id_asset_type_idx`(`global_character_id`, `asset_type`),
|
||||
INDEX `global_character_assets_asset_id_idx`(`asset_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
ALTER TABLE `characters`
|
||||
ADD COLUMN `global_character_id` BIGINT NULL,
|
||||
ADD COLUMN `wardrobe_variant` VARCHAR(100) NULL,
|
||||
ADD COLUMN `voice_provider_code` VARCHAR(100) NULL,
|
||||
ADD COLUMN `voice_model` VARCHAR(100) NULL,
|
||||
ADD COLUMN `voice_id` VARCHAR(100) NULL,
|
||||
ADD COLUMN `voice_style` TEXT NULL,
|
||||
ADD COLUMN `performance_style` TEXT NULL,
|
||||
ADD INDEX `characters_global_character_id_idx`(`global_character_id`);
|
||||
@@ -0,0 +1,8 @@
|
||||
ALTER TABLE `storyboard_shots`
|
||||
ADD COLUMN `scene_type` VARCHAR(50) NULL AFTER `duration`,
|
||||
ADD COLUMN `importance_score` INT NULL AFTER `scene_type`,
|
||||
ADD COLUMN `emotion_score` INT NULL AFTER `importance_score`,
|
||||
ADD COLUMN `action_score` INT NULL AFTER `emotion_score`,
|
||||
ADD COLUMN `route_tier` VARCHAR(50) NULL AFTER `action_score`,
|
||||
ADD INDEX `storyboard_shots_scene_type_idx`(`scene_type`),
|
||||
ADD INDEX `storyboard_shots_route_tier_idx`(`route_tier`);
|
||||
@@ -0,0 +1,79 @@
|
||||
CREATE TABLE `hit_analysis_cases` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`title` VARCHAR(255) NOT NULL,
|
||||
`source_platform` VARCHAR(100) NULL,
|
||||
`source_url` VARCHAR(500) NULL,
|
||||
`content_type` VARCHAR(80) NOT NULL DEFAULT 'short_drama',
|
||||
`genre` VARCHAR(100) NULL,
|
||||
`language` VARCHAR(30) NOT NULL DEFAULT 'zh-CN',
|
||||
`target_audience` VARCHAR(255) NULL,
|
||||
`duration_seconds` INT NULL,
|
||||
`episode_count` INT NULL,
|
||||
`tags_json` JSON NULL,
|
||||
`metrics_json` JSON NULL,
|
||||
`transcript_text` LONGTEXT NULL,
|
||||
`summary_text` TEXT NULL,
|
||||
`analysis_json` JSON NULL,
|
||||
`diagnosis_score` DECIMAL(5, 2) NULL,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'draft',
|
||||
`created_by_user_id` BIGINT NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `hit_analysis_cases_source_platform_idx`(`source_platform`),
|
||||
INDEX `hit_analysis_cases_genre_status_idx`(`genre`, `status`),
|
||||
INDEX `hit_analysis_cases_status_diagnosis_score_idx`(`status`, `diagnosis_score`),
|
||||
INDEX `hit_analysis_cases_created_at_idx`(`created_at`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `hit_analysis_segments` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`case_id` BIGINT NOT NULL,
|
||||
`segment_no` INT NOT NULL,
|
||||
`start_second` INT NULL,
|
||||
`end_second` INT NULL,
|
||||
`scene_type` VARCHAR(80) NULL,
|
||||
`hook_type` VARCHAR(100) NULL,
|
||||
`emotion` VARCHAR(80) NULL,
|
||||
`conflict_type` VARCHAR(100) NULL,
|
||||
`plot_function` VARCHAR(120) NULL,
|
||||
`visual_strategy` VARCHAR(120) NULL,
|
||||
`dialogue_pattern` VARCHAR(120) NULL,
|
||||
`camera_notes` TEXT NULL,
|
||||
`importance_score` INT NULL,
|
||||
`emotion_score` INT NULL,
|
||||
`action_score` INT NULL,
|
||||
`tags_json` JSON NULL,
|
||||
`summary_text` TEXT NULL,
|
||||
`prompt_seed` TEXT NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE INDEX `hit_analysis_segments_case_id_segment_no_key`(`case_id`, `segment_no`),
|
||||
INDEX `hit_analysis_segments_case_id_idx`(`case_id`),
|
||||
INDEX `hit_analysis_segments_scene_type_idx`(`scene_type`),
|
||||
INDEX `hit_analysis_segments_hook_type_idx`(`hook_type`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `creative_patterns` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`source_case_id` BIGINT NULL,
|
||||
`pattern_type` VARCHAR(80) NOT NULL,
|
||||
`title` VARCHAR(255) NOT NULL,
|
||||
`genre` VARCHAR(100) NULL,
|
||||
`language` VARCHAR(30) NOT NULL DEFAULT 'zh-CN',
|
||||
`description` TEXT NULL,
|
||||
`structure_json` JSON NULL,
|
||||
`prompt_template` TEXT NULL,
|
||||
`negative_prompt` TEXT NULL,
|
||||
`tags_json` JSON NULL,
|
||||
`usage_count` INT NOT NULL DEFAULT 0,
|
||||
`effectiveness_score` DECIMAL(5, 2) NULL,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'active',
|
||||
`created_by_user_id` BIGINT NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `creative_patterns_pattern_type_status_idx`(`pattern_type`, `status`),
|
||||
INDEX `creative_patterns_genre_status_idx`(`genre`, `status`),
|
||||
INDEX `creative_patterns_source_case_id_idx`(`source_case_id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
@@ -0,0 +1,13 @@
|
||||
CREATE TABLE `project_creative_patterns` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT NOT NULL,
|
||||
`creative_pattern_id` BIGINT NOT NULL,
|
||||
`source` VARCHAR(50) NOT NULL DEFAULT 'user_selected',
|
||||
`snapshot_json` JSON NULL,
|
||||
`sort_order` INT NOT NULL DEFAULT 0,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE INDEX `project_creative_patterns_project_id_creative_pattern_id_key`(`project_id`, `creative_pattern_id`),
|
||||
INDEX `project_creative_patterns_project_id_sort_order_idx`(`project_id`, `sort_order`),
|
||||
INDEX `project_creative_patterns_creative_pattern_id_idx`(`creative_pattern_id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
@@ -0,0 +1,826 @@
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "mysql"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
model User {
|
||||
id BigInt @id @default(autoincrement())
|
||||
email String? @unique @db.VarChar(191)
|
||||
phone String? @unique @db.VarChar(50)
|
||||
password_hash String @db.VarChar(255)
|
||||
nickname String? @db.VarChar(100)
|
||||
avatar_url String? @db.VarChar(500)
|
||||
role String @default("user") @db.VarChar(50)
|
||||
status String @default("active") @db.VarChar(50)
|
||||
wechat_openid String? @unique @db.VarChar(191)
|
||||
last_login_at DateTime?
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
|
||||
@@index([role, status])
|
||||
@@index([created_at])
|
||||
@@map("users")
|
||||
}
|
||||
|
||||
model Project {
|
||||
id BigInt @id @default(autoincrement())
|
||||
user_id BigInt
|
||||
title String? @db.VarChar(255)
|
||||
input_mode String @db.VarChar(50)
|
||||
genre String? @db.VarChar(100)
|
||||
style_code String? @db.VarChar(100)
|
||||
output_type String? @db.VarChar(50)
|
||||
output_mode String @default("image_manga") @db.VarChar(50)
|
||||
visual_mode String? @db.VarChar(100)
|
||||
video_generation_level String? @db.VarChar(50)
|
||||
target_episode_count Int?
|
||||
episode_duration Int?
|
||||
status String @default("draft") @db.VarChar(80)
|
||||
copyright_status String @default("pending") @db.VarChar(80)
|
||||
payment_status String @default("unpaid") @db.VarChar(80)
|
||||
quality_level String? @db.VarChar(50)
|
||||
is_long_series Boolean @default(false)
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
completed_at DateTime?
|
||||
|
||||
@@index([user_id, status])
|
||||
@@index([genre, status])
|
||||
@@index([created_at])
|
||||
@@map("projects")
|
||||
}
|
||||
|
||||
model NovelSource {
|
||||
id BigInt @id @default(autoincrement())
|
||||
project_id BigInt
|
||||
source_type String @db.VarChar(50)
|
||||
title String? @db.VarChar(255)
|
||||
author_name String? @db.VarChar(100)
|
||||
raw_asset_id BigInt?
|
||||
raw_text String? @db.LongText
|
||||
clean_text String? @db.LongText
|
||||
word_count Int?
|
||||
chapter_count Int?
|
||||
parse_status String @default("pending") @db.VarChar(50)
|
||||
parse_report Json?
|
||||
created_at DateTime @default(now())
|
||||
|
||||
@@index([project_id])
|
||||
@@index([parse_status])
|
||||
@@map("novel_sources")
|
||||
}
|
||||
|
||||
model NovelChapter {
|
||||
id BigInt @id @default(autoincrement())
|
||||
project_id BigInt
|
||||
novel_source_id BigInt?
|
||||
chapter_no Int
|
||||
title String? @db.VarChar(255)
|
||||
content String @db.LongText
|
||||
summary String? @db.Text
|
||||
visual_summary String? @db.Text
|
||||
word_count Int?
|
||||
status String @default("draft") @db.VarChar(50)
|
||||
created_at DateTime @default(now())
|
||||
|
||||
@@unique([novel_source_id, chapter_no])
|
||||
@@index([project_id, chapter_no])
|
||||
@@index([project_id, status])
|
||||
@@map("novel_chapters")
|
||||
}
|
||||
|
||||
model CopyrightRecord {
|
||||
id BigInt @id @default(autoincrement())
|
||||
project_id BigInt
|
||||
user_id BigInt
|
||||
authorization_type String @db.VarChar(50)
|
||||
statement_text String @db.Text
|
||||
ip String? @db.VarChar(80)
|
||||
user_agent String? @db.Text
|
||||
confirmed_at DateTime @default(now())
|
||||
|
||||
@@index([project_id])
|
||||
@@index([user_id])
|
||||
@@index([authorization_type])
|
||||
@@map("copyright_records")
|
||||
}
|
||||
|
||||
model StoryBible {
|
||||
id BigInt @id @default(autoincrement())
|
||||
project_id BigInt
|
||||
title String? @db.VarChar(255)
|
||||
logline String? @db.Text
|
||||
main_plot String? @db.Text
|
||||
core_conflict String? @db.Text
|
||||
selling_points String? @db.Text
|
||||
tone String? @db.VarChar(100)
|
||||
world_summary String? @db.Text
|
||||
ending_direction String? @db.Text
|
||||
taboo_rules String? @db.Text
|
||||
version Int @default(1)
|
||||
status String @default("draft") @db.VarChar(50)
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
|
||||
@@index([project_id, status])
|
||||
@@map("story_bibles")
|
||||
}
|
||||
|
||||
model WorldBible {
|
||||
id BigInt @id @default(autoincrement())
|
||||
project_id BigInt
|
||||
world_type String? @db.VarChar(100)
|
||||
setting_text String? @db.Text
|
||||
rules_text String? @db.Text
|
||||
power_system String? @db.Text
|
||||
social_structure String? @db.Text
|
||||
time_period String? @db.Text
|
||||
visual_rules String? @db.Text
|
||||
forbidden_rules String? @db.Text
|
||||
status String @default("draft") @db.VarChar(50)
|
||||
created_at DateTime @default(now())
|
||||
|
||||
@@index([project_id, status])
|
||||
@@map("world_bibles")
|
||||
}
|
||||
|
||||
model Character {
|
||||
id BigInt @id @default(autoincrement())
|
||||
project_id BigInt
|
||||
global_character_id BigInt?
|
||||
name String @db.VarChar(100)
|
||||
alias_names Json?
|
||||
role_type String @db.VarChar(50)
|
||||
gender_label String? @db.VarChar(50)
|
||||
age_group String? @db.VarChar(50)
|
||||
identity_desc String? @db.Text
|
||||
appearance_desc String? @db.Text
|
||||
face_desc String? @db.Text
|
||||
hair_desc String? @db.Text
|
||||
eye_desc String? @db.Text
|
||||
body_desc String? @db.Text
|
||||
costume_rules String? @db.Text
|
||||
special_props String? @db.Text
|
||||
personality_desc String? @db.Text
|
||||
speech_style String? @db.Text
|
||||
relationship_desc String? @db.Text
|
||||
character_arc String? @db.Text
|
||||
negative_rules String? @db.Text
|
||||
anchor_asset_id BigInt?
|
||||
wardrobe_variant String? @db.VarChar(100)
|
||||
voice_provider_code String? @db.VarChar(100)
|
||||
voice_model String? @db.VarChar(100)
|
||||
voice_id String? @db.VarChar(100)
|
||||
voice_style String? @db.Text
|
||||
performance_style String? @db.Text
|
||||
importance_level Int @default(0)
|
||||
status String @default("draft") @db.VarChar(50)
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
|
||||
@@index([project_id, role_type])
|
||||
@@index([project_id, status])
|
||||
@@index([global_character_id])
|
||||
@@map("characters")
|
||||
}
|
||||
|
||||
model GlobalCharacter {
|
||||
id BigInt @id @default(autoincrement())
|
||||
name String @db.VarChar(100)
|
||||
display_name String? @db.VarChar(100)
|
||||
role_archetype String @default("lead") @db.VarChar(50)
|
||||
gender_label String? @db.VarChar(50)
|
||||
age_group String? @db.VarChar(50)
|
||||
identity_desc String? @db.Text
|
||||
appearance_desc String? @db.Text
|
||||
face_desc String? @db.Text
|
||||
hair_desc String? @db.Text
|
||||
eye_desc String? @db.Text
|
||||
body_desc String? @db.Text
|
||||
default_costume_rules String? @db.Text
|
||||
wardrobe_json Json?
|
||||
special_props String? @db.Text
|
||||
personality_desc String? @db.Text
|
||||
speech_style String? @db.Text
|
||||
voice_provider_code String? @db.VarChar(100)
|
||||
voice_model String? @db.VarChar(100)
|
||||
voice_id String? @db.VarChar(100)
|
||||
voice_style String? @db.Text
|
||||
performance_style String? @db.Text
|
||||
negative_rules String? @db.Text
|
||||
anchor_asset_id BigInt?
|
||||
voice_sample_asset_id BigInt?
|
||||
commercial_status String @default("internal_test") @db.VarChar(50)
|
||||
usage_scope String @default("internal") @db.VarChar(50)
|
||||
status String @default("active") @db.VarChar(50)
|
||||
created_by_user_id BigInt?
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
|
||||
@@index([status, role_archetype])
|
||||
@@index([commercial_status])
|
||||
@@index([created_by_user_id])
|
||||
@@map("global_characters")
|
||||
}
|
||||
|
||||
model GlobalCharacterAsset {
|
||||
id BigInt @id @default(autoincrement())
|
||||
global_character_id BigInt
|
||||
asset_id BigInt?
|
||||
asset_type String @db.VarChar(50)
|
||||
label String? @db.VarChar(100)
|
||||
prompt_text String? @db.Text
|
||||
is_primary Boolean @default(false)
|
||||
status String @default("active") @db.VarChar(50)
|
||||
created_at DateTime @default(now())
|
||||
|
||||
@@index([global_character_id, asset_type])
|
||||
@@index([asset_id])
|
||||
@@map("global_character_assets")
|
||||
}
|
||||
|
||||
model CharacterImage {
|
||||
id BigInt @id @default(autoincrement())
|
||||
project_id BigInt
|
||||
character_id BigInt
|
||||
asset_id BigInt?
|
||||
image_type String @db.VarChar(50)
|
||||
prompt_text String? @db.Text
|
||||
negative_prompt String? @db.Text
|
||||
is_anchor Boolean @default(false)
|
||||
quality_score Decimal? @db.Decimal(5, 2)
|
||||
status String @default("pending") @db.VarChar(50)
|
||||
created_at DateTime @default(now())
|
||||
|
||||
@@index([project_id])
|
||||
@@index([character_id, image_type])
|
||||
@@index([character_id, is_anchor])
|
||||
@@map("character_images")
|
||||
}
|
||||
|
||||
model CharacterMemory {
|
||||
id BigInt @id @default(autoincrement())
|
||||
project_id BigInt
|
||||
character_id BigInt
|
||||
episode_id BigInt?
|
||||
memory_type String @db.VarChar(50)
|
||||
content String @db.Text
|
||||
created_at DateTime @default(now())
|
||||
|
||||
@@index([project_id, character_id])
|
||||
@@index([project_id, episode_id])
|
||||
@@index([memory_type])
|
||||
@@map("character_memories")
|
||||
}
|
||||
|
||||
model Episode {
|
||||
id BigInt @id @default(autoincrement())
|
||||
project_id BigInt
|
||||
episode_no Int
|
||||
source_chapter_ids Json?
|
||||
title String? @db.VarChar(255)
|
||||
summary String? @db.Text
|
||||
opening_hook String? @db.Text
|
||||
middle_conflict String? @db.Text
|
||||
ending_hook String? @db.Text
|
||||
target_duration Int?
|
||||
status String @default("draft") @db.VarChar(50)
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
|
||||
@@unique([project_id, episode_no])
|
||||
@@index([project_id, status])
|
||||
@@map("episodes")
|
||||
}
|
||||
|
||||
model EpisodeScript {
|
||||
id BigInt @id @default(autoincrement())
|
||||
project_id BigInt
|
||||
episode_id BigInt
|
||||
script_text String? @db.LongText
|
||||
narration_text String? @db.LongText
|
||||
dialogue_json Json?
|
||||
version Int @default(1)
|
||||
status String @default("draft") @db.VarChar(50)
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
|
||||
@@index([project_id])
|
||||
@@index([episode_id, version])
|
||||
@@map("episode_scripts")
|
||||
}
|
||||
|
||||
model StoryboardShot {
|
||||
id BigInt @id @default(autoincrement())
|
||||
project_id BigInt
|
||||
episode_id BigInt
|
||||
shot_no Int
|
||||
scene_name String? @db.VarChar(255)
|
||||
location_desc String? @db.Text
|
||||
characters_json Json?
|
||||
visual_desc String? @db.Text
|
||||
action_desc String? @db.Text
|
||||
dialogue_text String? @db.Text
|
||||
narration_text String? @db.Text
|
||||
camera_motion String? @db.VarChar(100)
|
||||
effect_type String? @db.VarChar(100)
|
||||
duration Decimal? @db.Decimal(6, 2)
|
||||
scene_type String? @db.VarChar(50)
|
||||
importance_score Int?
|
||||
emotion_score Int?
|
||||
action_score Int?
|
||||
route_tier String? @db.VarChar(50)
|
||||
prompt_text String? @db.Text
|
||||
negative_prompt String? @db.Text
|
||||
live_action_desc String? @db.Text
|
||||
actor_action String? @db.Text
|
||||
camera_instruction String? @db.Text
|
||||
performance_instruction String? @db.Text
|
||||
video_prompt String? @db.Text
|
||||
keyframe_asset_id BigInt?
|
||||
video_clip_asset_id BigInt?
|
||||
video_status String? @db.VarChar(50)
|
||||
status String @default("draft") @db.VarChar(50)
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
|
||||
@@unique([episode_id, shot_no])
|
||||
@@index([project_id, episode_id, shot_no])
|
||||
@@index([project_id, status])
|
||||
@@index([scene_type])
|
||||
@@index([route_tier])
|
||||
@@map("storyboard_shots")
|
||||
}
|
||||
|
||||
model ShotImage {
|
||||
id BigInt @id @default(autoincrement())
|
||||
project_id BigInt
|
||||
episode_id BigInt?
|
||||
shot_id BigInt
|
||||
asset_id BigInt?
|
||||
image_type String @default("preview") @db.VarChar(50)
|
||||
prompt_text String? @db.Text
|
||||
negative_prompt String? @db.Text
|
||||
quality_score Decimal? @db.Decimal(5, 2)
|
||||
status String @default("pending") @db.VarChar(50)
|
||||
created_at DateTime @default(now())
|
||||
|
||||
@@index([project_id, episode_id])
|
||||
@@index([shot_id, image_type])
|
||||
@@map("shot_images")
|
||||
}
|
||||
|
||||
model ActorProfile {
|
||||
id BigInt @id @default(autoincrement())
|
||||
project_id BigInt
|
||||
character_id BigInt
|
||||
actor_desc String? @db.Text
|
||||
appearance_rules String? @db.Text
|
||||
wardrobe_rules String? @db.Text
|
||||
performance_style String? @db.Text
|
||||
voice_style String? @db.Text
|
||||
reference_asset_ids Json?
|
||||
anchor_asset_id BigInt?
|
||||
status String @default("draft") @db.VarChar(50)
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
|
||||
@@unique([project_id, character_id])
|
||||
@@index([project_id, status])
|
||||
@@index([character_id])
|
||||
@@map("actor_profiles")
|
||||
}
|
||||
|
||||
model VideoClip {
|
||||
id BigInt @id @default(autoincrement())
|
||||
project_id BigInt
|
||||
episode_id BigInt
|
||||
shot_id BigInt
|
||||
provider_id BigInt?
|
||||
input_asset_id BigInt?
|
||||
output_asset_id BigInt?
|
||||
duration Decimal? @db.Decimal(6, 2)
|
||||
prompt_text String? @db.Text
|
||||
status String @default("pending") @db.VarChar(50)
|
||||
cost_actual Decimal? @db.Decimal(12, 4)
|
||||
retry_count Int @default(0)
|
||||
quality_status String? @db.VarChar(50)
|
||||
quality_score Decimal? @db.Decimal(5, 2)
|
||||
quality_issues Json?
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
|
||||
@@index([project_id, episode_id])
|
||||
@@index([shot_id, status])
|
||||
@@index([provider_id])
|
||||
@@map("video_clips")
|
||||
}
|
||||
|
||||
model PlotMemory {
|
||||
id BigInt @id @default(autoincrement())
|
||||
project_id BigInt
|
||||
episode_id BigInt?
|
||||
chapter_id BigInt?
|
||||
memory_type String @db.VarChar(50)
|
||||
content String @db.Text
|
||||
importance_level Int @default(0)
|
||||
status String @default("active") @db.VarChar(50)
|
||||
created_at DateTime @default(now())
|
||||
|
||||
@@index([project_id, episode_id])
|
||||
@@index([project_id, memory_type])
|
||||
@@map("plot_memories")
|
||||
}
|
||||
|
||||
model PlotThread {
|
||||
id BigInt @id @default(autoincrement())
|
||||
project_id BigInt
|
||||
thread_name String @db.VarChar(255)
|
||||
thread_type String @db.VarChar(80)
|
||||
description String? @db.Text
|
||||
start_episode_no Int?
|
||||
expected_resolve_episode_no Int?
|
||||
resolved_episode_no Int?
|
||||
status String @default("open") @db.VarChar(50)
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
|
||||
@@index([project_id, status])
|
||||
@@index([project_id, thread_type])
|
||||
@@map("plot_threads")
|
||||
}
|
||||
|
||||
model ContinuityCheck {
|
||||
id BigInt @id @default(autoincrement())
|
||||
project_id BigInt
|
||||
episode_id BigInt?
|
||||
check_type String @db.VarChar(80)
|
||||
result_status String @db.VarChar(50)
|
||||
issue_text String? @db.Text
|
||||
suggestion_text String? @db.Text
|
||||
created_at DateTime @default(now())
|
||||
|
||||
@@index([project_id, episode_id])
|
||||
@@index([result_status])
|
||||
@@map("continuity_checks")
|
||||
}
|
||||
|
||||
model Asset {
|
||||
id BigInt @id @default(autoincrement())
|
||||
user_id BigInt?
|
||||
project_id BigInt?
|
||||
asset_type String @db.VarChar(50)
|
||||
file_path String @db.VarChar(500)
|
||||
file_url String? @db.VarChar(500)
|
||||
mime_type String? @db.VarChar(100)
|
||||
width Int?
|
||||
height Int?
|
||||
duration Decimal? @db.Decimal(10, 2)
|
||||
size BigInt?
|
||||
hash String? @db.VarChar(128)
|
||||
visibility String @default("private") @db.VarChar(30)
|
||||
status String @default("active") @db.VarChar(50)
|
||||
created_at DateTime @default(now())
|
||||
|
||||
@@index([project_id, asset_type])
|
||||
@@index([user_id, asset_type])
|
||||
@@index([hash])
|
||||
@@map("assets")
|
||||
}
|
||||
|
||||
model RenderTask {
|
||||
id BigInt @id @default(autoincrement())
|
||||
project_id BigInt
|
||||
episode_id BigInt?
|
||||
shot_id BigInt?
|
||||
task_type String @db.VarChar(80)
|
||||
provider_id BigInt?
|
||||
status String @default("pending") @db.VarChar(50)
|
||||
input_json Json?
|
||||
input_hash String? @db.VarChar(128)
|
||||
idempotency_key String? @unique @db.VarChar(191)
|
||||
output_asset_id BigInt?
|
||||
provider_request_id String? @db.VarChar(255)
|
||||
retry_count Int @default(0)
|
||||
max_retry Int @default(0)
|
||||
cost_estimate Decimal? @db.Decimal(12, 4)
|
||||
cost_actual Decimal? @db.Decimal(12, 4)
|
||||
error_code String? @db.VarChar(100)
|
||||
error_message String? @db.Text
|
||||
created_at DateTime @default(now())
|
||||
started_at DateTime?
|
||||
finished_at DateTime?
|
||||
|
||||
@@index([project_id, status])
|
||||
@@index([task_type, status])
|
||||
@@index([project_id, episode_id])
|
||||
@@index([input_hash])
|
||||
@@map("render_tasks")
|
||||
}
|
||||
|
||||
model ProviderConfig {
|
||||
id BigInt @id @default(autoincrement())
|
||||
provider_type String @db.VarChar(80)
|
||||
provider_code String @db.VarChar(100)
|
||||
display_name String? @db.VarChar(100)
|
||||
mode String @default("mock") @db.VarChar(50)
|
||||
model_name String? @db.VarChar(100)
|
||||
config_json Json?
|
||||
fallback_provider_id BigInt?
|
||||
is_enabled Boolean @default(true)
|
||||
priority Int @default(0)
|
||||
rate_limit_json Json?
|
||||
cost_rule_json Json?
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
|
||||
@@unique([provider_type, provider_code])
|
||||
@@index([provider_type, is_enabled])
|
||||
@@map("provider_configs")
|
||||
}
|
||||
|
||||
model ProviderLog {
|
||||
id BigInt @id @default(autoincrement())
|
||||
provider_id BigInt?
|
||||
task_id BigInt?
|
||||
project_id BigInt?
|
||||
provider_type String @db.VarChar(80)
|
||||
provider_code String? @db.VarChar(100)
|
||||
model_name String? @db.VarChar(100)
|
||||
request_json Json?
|
||||
response_json Json?
|
||||
input_size Int?
|
||||
output_size Int?
|
||||
cost_estimate Decimal? @db.Decimal(12, 4)
|
||||
cost_actual Decimal? @db.Decimal(12, 4)
|
||||
status String @default("success") @db.VarChar(50)
|
||||
error_code String? @db.VarChar(100)
|
||||
error_message String? @db.Text
|
||||
started_at DateTime?
|
||||
finished_at DateTime?
|
||||
created_at DateTime @default(now())
|
||||
|
||||
@@index([provider_type, status])
|
||||
@@index([project_id])
|
||||
@@index([task_id])
|
||||
@@index([created_at])
|
||||
@@map("provider_logs")
|
||||
}
|
||||
|
||||
model Order {
|
||||
id BigInt @id @default(autoincrement())
|
||||
user_id BigInt
|
||||
project_id BigInt?
|
||||
order_no String @unique @db.VarChar(100)
|
||||
package_code String? @db.VarChar(100)
|
||||
amount Decimal @default(0) @db.Decimal(12, 2)
|
||||
currency String @default("CNY") @db.VarChar(20)
|
||||
payment_method String? @db.VarChar(50)
|
||||
payment_status String @default("pending") @db.VarChar(50)
|
||||
paid_at DateTime?
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
|
||||
@@index([user_id, payment_status])
|
||||
@@index([project_id])
|
||||
@@map("orders")
|
||||
}
|
||||
|
||||
model QuotaAccount {
|
||||
id BigInt @id @default(autoincrement())
|
||||
user_id BigInt @unique
|
||||
total_quota Decimal @default(0) @db.Decimal(12, 2)
|
||||
available_quota Decimal @default(0) @db.Decimal(12, 2)
|
||||
frozen_quota Decimal @default(0) @db.Decimal(12, 2)
|
||||
used_quota Decimal @default(0) @db.Decimal(12, 2)
|
||||
status String @default("active") @db.VarChar(50)
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
|
||||
@@index([status])
|
||||
@@map("quota_accounts")
|
||||
}
|
||||
|
||||
model QuotaLog {
|
||||
id BigInt @id @default(autoincrement())
|
||||
user_id BigInt
|
||||
project_id BigInt?
|
||||
task_id BigInt?
|
||||
change_type String @db.VarChar(50)
|
||||
amount Decimal @db.Decimal(12, 2)
|
||||
balance_after Decimal? @db.Decimal(12, 2)
|
||||
reason String? @db.VarChar(255)
|
||||
metadata_json Json?
|
||||
created_at DateTime @default(now())
|
||||
|
||||
@@index([user_id, created_at])
|
||||
@@index([project_id])
|
||||
@@index([task_id])
|
||||
@@map("quota_logs")
|
||||
}
|
||||
|
||||
model RevisionRequest {
|
||||
id BigInt @id @default(autoincrement())
|
||||
project_id BigInt
|
||||
user_id BigInt
|
||||
revision_type String @db.VarChar(50)
|
||||
target_type String? @db.VarChar(80)
|
||||
target_id BigInt?
|
||||
description String @db.Text
|
||||
status String @default("pending") @db.VarChar(50)
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
|
||||
@@index([project_id, status])
|
||||
@@index([user_id, status])
|
||||
@@map("revision_requests")
|
||||
}
|
||||
|
||||
model ContentReview {
|
||||
id BigInt @id @default(autoincrement())
|
||||
project_id BigInt?
|
||||
user_id BigInt?
|
||||
target_type String @db.VarChar(80)
|
||||
target_id BigInt?
|
||||
review_type String @db.VarChar(80)
|
||||
result_status String @default("pending") @db.VarChar(50)
|
||||
risk_level String? @db.VarChar(50)
|
||||
issue_text String? @db.Text
|
||||
suggestion_text String? @db.Text
|
||||
reviewer_id BigInt?
|
||||
reviewed_at DateTime?
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
|
||||
@@index([project_id, result_status])
|
||||
@@index([target_type, target_id])
|
||||
@@index([review_type, result_status])
|
||||
@@map("content_reviews")
|
||||
}
|
||||
|
||||
model CaseShowcase {
|
||||
id BigInt @id @default(autoincrement())
|
||||
project_id BigInt
|
||||
user_id BigInt?
|
||||
title String @db.VarChar(255)
|
||||
cover_asset_id BigInt?
|
||||
video_asset_id BigInt?
|
||||
authorization_status String @default("pending") @db.VarChar(50)
|
||||
visibility String @default("private") @db.VarChar(30)
|
||||
sort_order Int @default(0)
|
||||
published_at DateTime?
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
|
||||
@@index([visibility, sort_order])
|
||||
@@index([project_id])
|
||||
@@map("case_showcases")
|
||||
}
|
||||
|
||||
model HitAnalysisCase {
|
||||
id BigInt @id @default(autoincrement())
|
||||
title String @db.VarChar(255)
|
||||
source_platform String? @db.VarChar(100)
|
||||
source_url String? @db.VarChar(500)
|
||||
content_type String @default("short_drama") @db.VarChar(80)
|
||||
genre String? @db.VarChar(100)
|
||||
language String @default("zh-CN") @db.VarChar(30)
|
||||
target_audience String? @db.VarChar(255)
|
||||
duration_seconds Int?
|
||||
episode_count Int?
|
||||
tags_json Json?
|
||||
metrics_json Json?
|
||||
transcript_text String? @db.LongText
|
||||
summary_text String? @db.Text
|
||||
analysis_json Json?
|
||||
diagnosis_score Decimal? @db.Decimal(5, 2)
|
||||
status String @default("draft") @db.VarChar(50)
|
||||
created_by_user_id BigInt?
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
|
||||
@@index([source_platform])
|
||||
@@index([genre, status])
|
||||
@@index([status, diagnosis_score])
|
||||
@@index([created_at])
|
||||
@@map("hit_analysis_cases")
|
||||
}
|
||||
|
||||
model HitAnalysisSegment {
|
||||
id BigInt @id @default(autoincrement())
|
||||
case_id BigInt
|
||||
segment_no Int
|
||||
start_second Int?
|
||||
end_second Int?
|
||||
scene_type String? @db.VarChar(80)
|
||||
hook_type String? @db.VarChar(100)
|
||||
emotion String? @db.VarChar(80)
|
||||
conflict_type String? @db.VarChar(100)
|
||||
plot_function String? @db.VarChar(120)
|
||||
visual_strategy String? @db.VarChar(120)
|
||||
dialogue_pattern String? @db.VarChar(120)
|
||||
camera_notes String? @db.Text
|
||||
importance_score Int?
|
||||
emotion_score Int?
|
||||
action_score Int?
|
||||
tags_json Json?
|
||||
summary_text String? @db.Text
|
||||
prompt_seed String? @db.Text
|
||||
created_at DateTime @default(now())
|
||||
|
||||
@@unique([case_id, segment_no])
|
||||
@@index([case_id])
|
||||
@@index([scene_type])
|
||||
@@index([hook_type])
|
||||
@@map("hit_analysis_segments")
|
||||
}
|
||||
|
||||
model CreativePattern {
|
||||
id BigInt @id @default(autoincrement())
|
||||
source_case_id BigInt?
|
||||
pattern_type String @db.VarChar(80)
|
||||
title String @db.VarChar(255)
|
||||
genre String? @db.VarChar(100)
|
||||
language String @default("zh-CN") @db.VarChar(30)
|
||||
description String? @db.Text
|
||||
structure_json Json?
|
||||
prompt_template String? @db.Text
|
||||
negative_prompt String? @db.Text
|
||||
tags_json Json?
|
||||
usage_count Int @default(0)
|
||||
effectiveness_score Decimal? @db.Decimal(5, 2)
|
||||
status String @default("active") @db.VarChar(50)
|
||||
created_by_user_id BigInt?
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
|
||||
@@index([pattern_type, status])
|
||||
@@index([genre, status])
|
||||
@@index([source_case_id])
|
||||
@@map("creative_patterns")
|
||||
}
|
||||
|
||||
model ProjectCreativePattern {
|
||||
id BigInt @id @default(autoincrement())
|
||||
project_id BigInt
|
||||
creative_pattern_id BigInt
|
||||
source String @default("user_selected") @db.VarChar(50)
|
||||
snapshot_json Json?
|
||||
sort_order Int @default(0)
|
||||
created_at DateTime @default(now())
|
||||
|
||||
@@unique([project_id, creative_pattern_id])
|
||||
@@index([project_id, sort_order])
|
||||
@@index([creative_pattern_id])
|
||||
@@map("project_creative_patterns")
|
||||
}
|
||||
|
||||
model AnalyticsEvent {
|
||||
id BigInt @id @default(autoincrement())
|
||||
project_id BigInt
|
||||
episode_id BigInt?
|
||||
event_type String @db.VarChar(80)
|
||||
platform String? @db.VarChar(80)
|
||||
metric_json Json?
|
||||
created_at DateTime @default(now())
|
||||
|
||||
@@index([project_id])
|
||||
@@index([episode_id])
|
||||
@@index([event_type, created_at])
|
||||
@@map("analytics_events")
|
||||
}
|
||||
|
||||
model SystemConfig {
|
||||
id BigInt @id @default(autoincrement())
|
||||
config_key String @unique @db.VarChar(191)
|
||||
config_value Json?
|
||||
description String? @db.Text
|
||||
is_public Boolean @default(false)
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
|
||||
@@index([is_public])
|
||||
@@map("system_configs")
|
||||
}
|
||||
|
||||
model OperationLog {
|
||||
id BigInt @id @default(autoincrement())
|
||||
user_id BigInt?
|
||||
operator_role String? @db.VarChar(50)
|
||||
action String @db.VarChar(100)
|
||||
target_type String? @db.VarChar(80)
|
||||
target_id BigInt?
|
||||
ip String? @db.VarChar(80)
|
||||
user_agent String? @db.Text
|
||||
metadata_json Json?
|
||||
created_at DateTime @default(now())
|
||||
|
||||
@@index([user_id, created_at])
|
||||
@@index([target_type, target_id])
|
||||
@@index([action, created_at])
|
||||
@@map("operation_logs")
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import { hash } from 'bcryptjs';
|
||||
import { DEFAULT_AI_ROUTER_CONFIG } from '../src/ai-router/ai-router.types';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
const mockProviders = [
|
||||
['TextProvider', 'mock-text', 'Mock Text Provider', 'mock-text-v1'],
|
||||
['NovelProvider', 'mock-novel', 'Mock Novel Provider', 'mock-novel-v1'],
|
||||
['ImageProvider', 'mock-image', 'Mock Image Provider', 'mock-image-v1'],
|
||||
['VideoProvider', 'mock-video', 'Mock Video Provider', 'mock-video-v1'],
|
||||
['VoiceProvider', 'mock-voice', 'Mock Voice Provider', 'mock-voice-v1'],
|
||||
['LipSyncProvider', 'mock-lipsync', 'Mock Lip Sync Provider', 'mock-lipsync-v1'],
|
||||
['ModerationProvider', 'mock-moderation', 'Mock Moderation Provider', 'mock-moderation-v1'],
|
||||
['QualityCheckProvider', 'mock-qc', 'Mock Quality Check Provider', 'mock-qc-v1'],
|
||||
['FileParseProvider', 'mock-file-parse', 'Mock File Parse Provider', 'mock-file-parse-v1'],
|
||||
['EmbeddingProvider', 'mock-embedding', 'Mock Embedding Provider', 'mock-embedding-v1']
|
||||
] as const;
|
||||
|
||||
async function main() {
|
||||
const adminPassword = process.env.SEED_ADMIN_PASSWORD || 'Admin123!';
|
||||
const adminPasswordHash = await hash(adminPassword, 12);
|
||||
const admin = await prisma.user.upsert({
|
||||
where: { email: 'admin@example.com' },
|
||||
update: {
|
||||
password_hash: adminPasswordHash,
|
||||
role: 'admin',
|
||||
status: 'active'
|
||||
},
|
||||
create: {
|
||||
email: 'admin@example.com',
|
||||
password_hash: adminPasswordHash,
|
||||
nickname: 'System Admin',
|
||||
role: 'admin',
|
||||
status: 'active'
|
||||
}
|
||||
});
|
||||
|
||||
for (const [providerType, providerCode, displayName, modelName] of mockProviders) {
|
||||
const isEnabled = providerCode !== 'mock-lipsync';
|
||||
|
||||
await prisma.providerConfig.upsert({
|
||||
where: {
|
||||
provider_type_provider_code: {
|
||||
provider_type: providerType,
|
||||
provider_code: providerCode
|
||||
}
|
||||
},
|
||||
update: {
|
||||
display_name: displayName,
|
||||
mode: 'mock',
|
||||
model_name: modelName,
|
||||
is_enabled: isEnabled,
|
||||
priority: 100,
|
||||
rate_limit_json: {
|
||||
rpm: 120,
|
||||
concurrency: 8
|
||||
},
|
||||
cost_rule_json: {
|
||||
flat_cost: 0,
|
||||
unit: 'mock'
|
||||
}
|
||||
},
|
||||
create: {
|
||||
provider_type: providerType,
|
||||
provider_code: providerCode,
|
||||
display_name: displayName,
|
||||
mode: 'mock',
|
||||
model_name: modelName,
|
||||
is_enabled: isEnabled,
|
||||
priority: 100,
|
||||
config_json: {
|
||||
note: 'Used until the MVP flow is complete.'
|
||||
},
|
||||
rate_limit_json: {
|
||||
rpm: 120,
|
||||
concurrency: 8
|
||||
},
|
||||
cost_rule_json: {
|
||||
flat_cost: 0,
|
||||
unit: 'mock'
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
await prisma.systemConfig.upsert({
|
||||
where: { config_key: 'system_a.current_stage' },
|
||||
update: {
|
||||
config_value: {
|
||||
stage: 'stage-02-database-schema'
|
||||
}
|
||||
},
|
||||
create: {
|
||||
config_key: 'system_a.current_stage',
|
||||
config_value: {
|
||||
stage: 'stage-02-database-schema'
|
||||
},
|
||||
description: 'Tracks current System A development stage.'
|
||||
}
|
||||
});
|
||||
|
||||
await prisma.systemConfig.upsert({
|
||||
where: { config_key: 'security.api_crypto_enabled' },
|
||||
update: {},
|
||||
create: {
|
||||
config_key: 'security.api_crypto_enabled',
|
||||
config_value: {
|
||||
enabled: false
|
||||
},
|
||||
description: 'Controls frontend/backend API payload encryption. Default off for testing; enable manually in production.',
|
||||
is_public: true
|
||||
}
|
||||
});
|
||||
|
||||
await prisma.systemConfig.upsert({
|
||||
where: { config_key: 'ai.router.v1' },
|
||||
update: {},
|
||||
create: {
|
||||
config_key: 'ai.router.v1',
|
||||
config_value: DEFAULT_AI_ROUTER_CONFIG,
|
||||
description: 'AI Router V1 route config for automatic provider selection by language, shot score and budget.',
|
||||
is_public: false
|
||||
}
|
||||
});
|
||||
|
||||
await prisma.quotaAccount.upsert({
|
||||
where: { user_id: admin.id },
|
||||
update: {},
|
||||
create: {
|
||||
user_id: admin.id,
|
||||
total_quota: 100,
|
||||
available_quota: 100,
|
||||
status: 'active'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
main()
|
||||
.then(async () => {
|
||||
await prisma.$disconnect();
|
||||
})
|
||||
.catch(async (error) => {
|
||||
console.error(error);
|
||||
await prisma.$disconnect();
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user