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

三视图优化为一张

parent a6819dfe
...@@ -76,7 +76,13 @@ function getCharacterViewUrl(character: Partial<Character>, viewType: CharacterV ...@@ -76,7 +76,13 @@ function getCharacterViewUrl(character: Partial<Character>, viewType: CharacterV
return character.backImageUrl ?? null; return character.backImageUrl ?? null;
} }
function hasCompleteThreeViews(character: Partial<Character>) { /** AI 生成的角色三视图是单张拼图,存在 imageUrl 上 */
function getCharacterSheetUrl(character: Partial<Character>): string | null {
return character.imageUrl ?? null;
}
function hasCharacterImage(character: Partial<Character>) {
if (getCharacterSheetUrl(character)) return true;
return CHARACTER_VIEWS.every((view) => !!getCharacterViewUrl(character, view.type)); return CHARACTER_VIEWS.every((view) => !!getCharacterViewUrl(character, view.type));
} }
...@@ -120,7 +126,7 @@ export function CharacterGeneration() { ...@@ -120,7 +126,7 @@ export function CharacterGeneration() {
supporting: "配角", supporting: "配角",
}; };
const generatedCount = characters.filter((character) => hasCompleteThreeViews(character)).length; const generatedCount = characters.filter((character) => hasCharacterImage(character)).length;
const generatingCount = characters.filter((character) => character.status === "generating").length; const generatingCount = characters.filter((character) => character.status === "generating").length;
const statusBadge = (status: string) => { const statusBadge = (status: string) => {
...@@ -395,7 +401,7 @@ export function CharacterGeneration() { ...@@ -395,7 +401,7 @@ export function CharacterGeneration() {
<div className="flex items-center justify-between mb-3"> <div className="flex items-center justify-between mb-3">
<div> <div>
<span className="text-xs text-muted-foreground font-medium">角色三视图</span> <span className="text-xs text-muted-foreground font-medium">角色三视图</span>
<p className="text-[11px] text-muted-foreground mt-0.5">正面 + 侧面 + 背面,用于完整展示角色造型</p> <p className="text-[11px] text-muted-foreground mt-0.5">大头像 + 正/侧/背全身拼图,用于角色一致性参考</p>
</div> </div>
<button <button
onClick={() => handleGenerateImage(character)} onClick={() => handleGenerateImage(character)}
...@@ -403,10 +409,24 @@ export function CharacterGeneration() { ...@@ -403,10 +409,24 @@ export function CharacterGeneration() {
className="px-3 py-1.5 rounded-md border border-border bg-card text-foreground hover:bg-muted transition-colors text-xs flex items-center gap-1.5 disabled:opacity-50" className="px-3 py-1.5 rounded-md border border-border bg-card text-foreground hover:bg-muted transition-colors text-xs flex items-center gap-1.5 disabled:opacity-50"
> >
{isGenerating ? <Loader2 className="w-3 h-3 animate-spin" /> : <RefreshCw className="w-3 h-3" />} {isGenerating ? <Loader2 className="w-3 h-3 animate-spin" /> : <RefreshCw className="w-3 h-3" />}
{hasCompleteThreeViews(character) ? "重新生成三视图" : "AI生成三视图"} {hasCharacterImage(character) ? "重新生成三视图" : "AI生成三视图"}
</button> </button>
</div> </div>
{(() => {
const sheetUrl = getCharacterSheetUrl(character);
if (sheetUrl) {
return (
<div className="rounded-lg overflow-hidden bg-white border border-border">
<img
src={sheetUrl}
alt={`${character.name}-角色三视图`}
className="w-full h-auto object-contain"
/>
</div>
);
}
return (
<div className="grid grid-cols-3 gap-3"> <div className="grid grid-cols-3 gap-3">
{CHARACTER_VIEWS.map((view) => { {CHARACTER_VIEWS.map((view) => {
const imageUrl = getCharacterViewUrl(character, view.type); const imageUrl = getCharacterViewUrl(character, view.type);
...@@ -436,10 +456,9 @@ export function CharacterGeneration() { ...@@ -436,10 +456,9 @@ export function CharacterGeneration() {
); );
})} })}
</div> </div>
);
})()}
{character.imagePrompt && (
<p className="mt-3 text-xs text-muted-foreground line-clamp-3">{character.imagePrompt}</p>
)}
</div> </div>
</div> </div>
); );
......
...@@ -10,6 +10,11 @@ public interface SeedreamService { ...@@ -10,6 +10,11 @@ public interface SeedreamService {
*/ */
String generateImage(String prompt); String generateImage(String prompt);
/**
* 文生图:自定义画布尺寸(如 "2048x1152" 用于 16:9 横版角色三视图)
*/
String generateImage(String prompt, String size);
/** 当前使用的 Seedream 模型 ID,用于计费明细 */ /** 当前使用的 Seedream 模型 ID,用于计费明细 */
String getModelId(); String getModelId();
......
...@@ -36,11 +36,16 @@ public class SeedreamServiceImpl implements SeedreamService { ...@@ -36,11 +36,16 @@ public class SeedreamServiceImpl implements SeedreamService {
@Override @Override
public String generateImage(String prompt) { public String generateImage(String prompt) {
return generateImage(prompt, "2048x2048");
}
@Override
public String generateImage(String prompt, String size) {
Map<String, Object> body = Map.of( Map<String, Object> body = Map.of(
"model", properties.getImageModel(), "model", properties.getImageModel(),
"prompt", prompt, "prompt", prompt,
"n", 1, "n", 1,
"size", "2048x2048", "size", size,
"response_format", "url" "response_format", "url"
); );
......
...@@ -42,9 +42,12 @@ public class VideoTaskController { ...@@ -42,9 +42,12 @@ public class VideoTaskController {
} }
List<String> characterKeys = req.getCharacterImageKeys(); List<String> characterKeys = req.getCharacterImageKeys();
if ((characterKeys == null || characterKeys.isEmpty()) boolean hasCharacter = (characterKeys != null && !characterKeys.isEmpty())
&& (req.getCharacterImageKey() == null || req.getCharacterImageKey().isBlank())) { || (req.getCharacterImageKey() != null && !req.getCharacterImageKey().isBlank());
throw new BizException(ErrorCode.INVALID_PARAM, "请至少选择一个出镜角色"); boolean hasScene = req.getSceneImageKey() != null && !req.getSceneImageKey().isBlank();
boolean hasProp = req.getPropImageKeys() != null && !req.getPropImageKeys().isEmpty();
if (!hasCharacter && !hasScene && !hasProp) {
throw new BizException(ErrorCode.INVALID_PARAM, "请至少选择一张参考图(角色/场景/道具任一)");
} }
Long tenantId = TenantContext.get(); Long tenantId = TenantContext.get();
......
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