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

三视图优化为一张

parent a6819dfe
......@@ -76,7 +76,13 @@ function getCharacterViewUrl(character: Partial<Character>, viewType: CharacterV
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));
}
......@@ -120,7 +126,7 @@ export function CharacterGeneration() {
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 statusBadge = (status: string) => {
......@@ -395,7 +401,7 @@ export function CharacterGeneration() {
<div className="flex items-center justify-between mb-3">
<div>
<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>
<button
onClick={() => handleGenerateImage(character)}
......@@ -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"
>
{isGenerating ? <Loader2 className="w-3 h-3 animate-spin" /> : <RefreshCw className="w-3 h-3" />}
{hasCompleteThreeViews(character) ? "重新生成三视图" : "AI生成三视图"}
{hasCharacterImage(character) ? "重新生成三视图" : "AI生成三视图"}
</button>
</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">
{CHARACTER_VIEWS.map((view) => {
const imageUrl = getCharacterViewUrl(character, view.type);
......@@ -436,10 +456,9 @@ export function CharacterGeneration() {
);
})}
</div>
);
})()}
{character.imagePrompt && (
<p className="mt-3 text-xs text-muted-foreground line-clamp-3">{character.imagePrompt}</p>
)}
</div>
</div>
);
......
......@@ -10,6 +10,11 @@ public interface SeedreamService {
*/
String generateImage(String prompt);
/**
* 文生图:自定义画布尺寸(如 "2048x1152" 用于 16:9 横版角色三视图)
*/
String generateImage(String prompt, String size);
/** 当前使用的 Seedream 模型 ID,用于计费明细 */
String getModelId();
......
......@@ -36,11 +36,16 @@ public class SeedreamServiceImpl implements SeedreamService {
@Override
public String generateImage(String prompt) {
return generateImage(prompt, "2048x2048");
}
@Override
public String generateImage(String prompt, String size) {
Map<String, Object> body = Map.of(
"model", properties.getImageModel(),
"prompt", prompt,
"n", 1,
"size", "2048x2048",
"size", size,
"response_format", "url"
);
......
......@@ -42,9 +42,12 @@ public class VideoTaskController {
}
List<String> characterKeys = req.getCharacterImageKeys();
if ((characterKeys == null || characterKeys.isEmpty())
&& (req.getCharacterImageKey() == null || req.getCharacterImageKey().isBlank())) {
throw new BizException(ErrorCode.INVALID_PARAM, "请至少选择一个出镜角色");
boolean hasCharacter = (characterKeys != null && !characterKeys.isEmpty())
|| (req.getCharacterImageKey() != null && !req.getCharacterImageKey().isBlank());
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();
......
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