Commit 3b6236dd authored by yaoke.yk's avatar yaoke.yk

Update comic studio project and asset generation flow

parent 16da3a9f
...@@ -30,6 +30,11 @@ export default defineConfig({ ...@@ -30,6 +30,11 @@ export default defineConfig({
'@': path.resolve(__dirname, './src'), '@': path.resolve(__dirname, './src'),
}, },
}, },
server: {
host: true,
port: 5173,
allowedHosts: true
},
// File types to support raw imports. Never add .css, .tsx, or .ts files to this. // File types to support raw imports. Never add .css, .tsx, or .ts files to this.
assetsInclude: ['**/*.svg', '**/*.csv'], assetsInclude: ['**/*.svg', '**/*.csv'],
......
version: "3.9"
services: services:
mysql: mysql:
image: mysql:8.0 image: mysql:8.0
......
...@@ -11,7 +11,6 @@ import org.springframework.web.bind.annotation.*; ...@@ -11,7 +11,6 @@ import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@Tag(name = "角色管理") @Tag(name = "角色管理")
...@@ -22,7 +21,7 @@ public class CharacterController { ...@@ -22,7 +21,7 @@ public class CharacterController {
private final AssetGenPipelineService assetService; private final AssetGenPipelineService assetService;
@Operation(summary = "AI 提取角色列表(从大纲+分集)") @Operation(summary = "AI 提取角色列表")
@PostMapping("/extract") @PostMapping("/extract")
public ApiResponse<List<Character>> extract(@PathVariable Long projectId) { public ApiResponse<List<Character>> extract(@PathVariable Long projectId) {
return ApiResponse.success(assetService.extractCharacters(projectId, TenantContext.get())); return ApiResponse.success(assetService.extractCharacters(projectId, TenantContext.get()));
...@@ -34,7 +33,7 @@ public class CharacterController { ...@@ -34,7 +33,7 @@ public class CharacterController {
return ApiResponse.success(assetService.listCharacters(projectId, TenantContext.get())); return ApiResponse.success(assetService.listCharacters(projectId, TenantContext.get()));
} }
@Operation(summary = "新建/更新角色") @Operation(summary = "新建更新角色")
@PostMapping @PostMapping
public ApiResponse<Character> save(@PathVariable Long projectId, @RequestBody Character req) { public ApiResponse<Character> save(@PathVariable Long projectId, @RequestBody Character req) {
req.setProjectId(projectId); req.setProjectId(projectId);
...@@ -42,23 +41,29 @@ public class CharacterController { ...@@ -42,23 +41,29 @@ public class CharacterController {
return ApiResponse.success(assetService.saveCharacter(req)); return ApiResponse.success(assetService.saveCharacter(req));
} }
@Operation(summary = "为角色生成形象图(Seedream)") @Operation(summary = "AI 生成角色三视图")
@PostMapping("/{characterId}/generate-image") @PostMapping("/{characterId}/generate-image")
public ApiResponse<Character> generateImage(@PathVariable Long projectId, public ApiResponse<Character> generateImage(@PathVariable Long projectId,
@PathVariable Long characterId) { @PathVariable Long characterId) {
return ApiResponse.success(assetService.generateCharacterImage(characterId, TenantContext.get())); return ApiResponse.success(assetService.generateCharacterImage(characterId, TenantContext.get()));
} }
@Operation(summary = "上传角色图片(手动)") @Operation(summary = "上传角色视图图片")
@PostMapping(value = "/{characterId}/upload-image", consumes = "multipart/form-data") @PostMapping(value = "/{characterId}/upload-image", consumes = "multipart/form-data")
public ApiResponse<Character> uploadImage(@PathVariable Long projectId, public ApiResponse<Character> uploadImage(@PathVariable Long projectId,
@PathVariable Long characterId, @PathVariable Long characterId,
@RequestParam(defaultValue = "front") String viewType,
@RequestPart("file") MultipartFile file) throws IOException { @RequestPart("file") MultipartFile file) throws IOException {
String originalName = file.getOriginalFilename() != null ? file.getOriginalFilename() : "image.jpg"; String originalName = file.getOriginalFilename() != null ? file.getOriginalFilename() : "image.jpg";
String ext = originalName.contains(".") ? originalName.substring(originalName.lastIndexOf('.') + 1) : "jpg"; String ext = originalName.contains(".") ? originalName.substring(originalName.lastIndexOf('.') + 1) : "jpg";
return ApiResponse.success(assetService.uploadCharacterImage( return ApiResponse.success(assetService.uploadCharacterImage(
characterId, TenantContext.get(), characterId,
file.getInputStream(), file.getSize(), file.getContentType(), ext)); TenantContext.get(),
viewType,
file.getInputStream(),
file.getSize(),
file.getContentType(),
ext));
} }
@Operation(summary = "删除角色") @Operation(summary = "删除角色")
......
...@@ -13,4 +13,10 @@ public class ProjectCreateRequest { ...@@ -13,4 +13,10 @@ public class ProjectCreateRequest {
@Size(max = 2000, message = "描述最长 2000 字符") @Size(max = 2000, message = "描述最长 2000 字符")
private String description; private String description;
private String style;
private String aspectRatio;
private String resolution;
} }
...@@ -13,6 +13,8 @@ public class ProjectDTO { ...@@ -13,6 +13,8 @@ public class ProjectDTO {
private String description; private String description;
private String status; private String status;
private String style; private String style;
private String aspectRatio;
private String resolution;
private String coverUrl; private String coverUrl;
private long assetCount; private long assetCount;
private LocalDateTime createdAt; private LocalDateTime createdAt;
...@@ -25,6 +27,8 @@ public class ProjectDTO { ...@@ -25,6 +27,8 @@ public class ProjectDTO {
dto.setDescription(p.getDescription()); dto.setDescription(p.getDescription());
dto.setStatus(p.getStatus()); dto.setStatus(p.getStatus());
dto.setStyle(p.getStyle()); dto.setStyle(p.getStyle());
dto.setAspectRatio(p.getAspectRatio());
dto.setResolution(p.getResolution());
dto.setCoverUrl(coverUrl); dto.setCoverUrl(coverUrl);
dto.setAssetCount(assetCount); dto.setAssetCount(assetCount);
dto.setCreatedAt(p.getCreatedAt()); dto.setCreatedAt(p.getCreatedAt());
......
...@@ -13,4 +13,8 @@ public class ProjectUpdateRequest { ...@@ -13,4 +13,8 @@ public class ProjectUpdateRequest {
private String description; private String description;
private String style; private String style;
private String aspectRatio;
private String resolution;
} }
...@@ -40,6 +40,9 @@ public class ProjectServiceImpl implements ProjectService { ...@@ -40,6 +40,9 @@ public class ProjectServiceImpl implements ProjectService {
project.setName(req.getName()); project.setName(req.getName());
project.setDescription(req.getDescription()); project.setDescription(req.getDescription());
project.setStatus("draft"); project.setStatus("draft");
project.setStyle(req.getStyle());
project.setAspectRatio(req.getAspectRatio());
project.setResolution(req.getResolution());
projectMapper.insert(project); projectMapper.insert(project);
return toDTO(project); return toDTO(project);
...@@ -75,6 +78,8 @@ public class ProjectServiceImpl implements ProjectService { ...@@ -75,6 +78,8 @@ public class ProjectServiceImpl implements ProjectService {
if (req.getName() != null) project.setName(req.getName()); if (req.getName() != null) project.setName(req.getName());
if (req.getDescription() != null) project.setDescription(req.getDescription()); if (req.getDescription() != null) project.setDescription(req.getDescription());
if (req.getStyle() != null) project.setStyle(req.getStyle()); if (req.getStyle() != null) project.setStyle(req.getStyle());
if (req.getAspectRatio() != null) project.setAspectRatio(req.getAspectRatio());
if (req.getResolution() != null) project.setResolution(req.getResolution());
projectMapper.updateById(project); projectMapper.updateById(project);
return toDTO(project); return toDTO(project);
......
...@@ -12,4 +12,5 @@ public class YaoAiApplication { ...@@ -12,4 +12,5 @@ public class YaoAiApplication {
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.run(YaoAiApplication.class, args); SpringApplication.run(YaoAiApplication.class, args);
} }
} }
ALTER TABLE characters
ADD COLUMN front_image_url VARCHAR(1024) NULL AFTER image_url,
ADD COLUMN front_image_tos_key VARCHAR(512) NULL AFTER image_tos_key,
ADD COLUMN side_image_url VARCHAR(1024) NULL AFTER front_image_url,
ADD COLUMN side_image_tos_key VARCHAR(512) NULL AFTER front_image_tos_key,
ADD COLUMN back_image_url VARCHAR(1024) NULL AFTER side_image_url,
ADD COLUMN back_image_tos_key VARCHAR(512) NULL AFTER side_image_tos_key;
UPDATE characters
SET front_image_url = image_url,
front_image_tos_key = image_tos_key
WHERE image_url IS NOT NULL
AND (front_image_url IS NULL OR front_image_url = '');
ALTER TABLE projects
ADD COLUMN aspect_ratio VARCHAR(20) DEFAULT NULL COMMENT '画幅比例' AFTER style,
ADD COLUMN resolution VARCHAR(20) DEFAULT NULL COMMENT '清晰度' AFTER aspect_ratio;
...@@ -28,13 +28,19 @@ public class Character { ...@@ -28,13 +28,19 @@ public class Character {
private String costume; private String costume;
private String visualHint; private String visualHint;
/** 供 Seedream 文生图使用的英文 Prompt */ /** Base prompt for standardized character image generation. */
private String imagePrompt; private String imagePrompt;
/** Seedream 生成的临时 URL(仅展示) */ /** Keep the primary image for backward compatibility; this points to the front view. */
private String imageUrl; private String imageUrl;
/** 已存入 TOS 的 key */
private String imageTosKey; private String imageTosKey;
private String frontImageUrl;
private String frontImageTosKey;
private String sideImageUrl;
private String sideImageTosKey;
private String backImageUrl;
private String backImageTosKey;
/** draft / generating / ready / failed */ /** draft / generating / ready / failed */
private String status; private String status;
......
...@@ -27,6 +27,10 @@ public class Project { ...@@ -27,6 +27,10 @@ public class Project {
private String style; private String style;
private String aspectRatio;
private String resolution;
private String coverKey; private String coverKey;
private LocalDateTime createdAt; private LocalDateTime createdAt;
......
...@@ -8,16 +8,13 @@ import java.util.List; ...@@ -8,16 +8,13 @@ import java.util.List;
public interface AssetGenPipelineService { public interface AssetGenPipelineService {
/** 根据大纲 + 分集内容,AI 提取角色列表并保存(不含生图) */
List<Character> extractCharacters(Long projectId, Long tenantId); List<Character> extractCharacters(Long projectId, Long tenantId);
/** 根据大纲 + 分集内容,AI 提取场景列表并保存(不含生图) */
List<Scene> extractScenes(Long projectId, Long tenantId); List<Scene> extractScenes(Long projectId, Long tenantId);
/** 为指定角色调用 Seedream 生图并存 TOS */ /** Generate three standardized character turnaround views: front, side, and back. */
Character generateCharacterImage(Long characterId, Long tenantId); Character generateCharacterImage(Long characterId, Long tenantId);
/** 为指定场景调用 Seedream 生图并存 TOS */
Scene generateSceneImage(Long sceneId, Long tenantId); Scene generateSceneImage(Long sceneId, Long tenantId);
List<Character> listCharacters(Long projectId, Long tenantId); List<Character> listCharacters(Long projectId, Long tenantId);
...@@ -32,9 +29,8 @@ public interface AssetGenPipelineService { ...@@ -32,9 +29,8 @@ public interface AssetGenPipelineService {
void deleteScene(Long id, Long tenantId); void deleteScene(Long id, Long tenantId);
/** 上传用户自定义角色图,存 TOS 并更新 imageUrl */ Character uploadCharacterImage(Long characterId, Long tenantId, String viewType,
Character uploadCharacterImage(Long characterId, Long tenantId, InputStream stream, long size, String contentType, String ext); InputStream stream, long size, String contentType, String ext);
/** 上传用户自定义场景图,存 TOS 并更新 imageUrl */
Scene uploadSceneImage(Long sceneId, Long tenantId, InputStream stream, long size, String contentType, String ext); Scene uploadSceneImage(Long sceneId, Long tenantId, InputStream stream, long size, String contentType, String ext);
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment