fix: 完成角度编辑功能的组件传递链,使按钮正确显示
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled

This commit is contained in:
Your Name 2026-01-11 00:29:54 +08:00
parent b12dd2d77a
commit 604d7425ad
6 changed files with 98 additions and 4 deletions

View File

@ -3550,8 +3550,26 @@ export function AdminSettingsClient() {
placeholder="留空使用默认地址"
disabled={!angleEditConfig.enabled}
/>
<div className="text-xs text-muted-foreground">
默认: huggingface.co/fal/Qwen-Image-Edit-2511-Multiple-Angles-LoRA
<div className="space-y-1 text-xs text-muted-foreground">
<div>
默认地址(推荐使用,无需修改):
</div>
<div className="font-mono break-all">
huggingface.co/fal/Qwen-Image-Edit-2511-Multiple-Angles-LoRA/resolve/main/qwen-image-edit-2511-multiple-angles-lora.safetensors
</div>
<div className="mt-1 text-muted-foreground/80">
如需自定义,请访问{" "}
<a
href="https://huggingface.co/fal/Qwen-Image-Edit-2511-Multiple-Angles-LoRA"
target="_blank"
rel="noopener noreferrer"
className="text-primary underline hover:no-underline"
onClick={(e) => e.stopPropagation()}
>
Hugging Face 模型页面
</a>
{" "},找到文件并复制下载链接
</div>
</div>
</div>

View File

@ -115,6 +115,7 @@ export function Chat({
const [isProcessingEnhance, setIsProcessingEnhance] = useState(false);
const [isProcessingRmbg, setIsProcessingRmbg] = useState(false);
const [isProcessingExtend, setIsProcessingExtend] = useState(false);
const [isProcessingAngleEdit, setIsProcessingAngleEdit] = useState(false);
const currentModelIdRef = useRef(currentModelId);
// 🆕 视频参数状态
@ -951,6 +952,60 @@ export function Chat({
}
};
// 处理角度编辑完成
const handleImageAngleEdit = async (resultUrl: string) => {
const messageId = generateUUID();
// 构造图片Markdown(使用与其他处理功能相同的格式)
const imageMarkdown = `![thumb|||${resultUrl}|||2K](${resultUrl})`;
// 创建最终消息
const finalMessage: ChatMessage = {
id: messageId,
role: "assistant",
parts: [{ type: "text", text: imageMarkdown }],
metadata: {
createdAt: new Date().toISOString(),
},
} as ChatMessage;
// 添加消息
setMessages((prev) => [...prev, finalMessage]);
// 滚动到底部
setTimeout(() => {
const messagesContainer = document.querySelector('[role="log"]');
if (messagesContainer) {
messagesContainer.scrollTo({
top: messagesContainer.scrollHeight,
behavior: "smooth",
});
}
}, 100);
// 保存消息到数据库
try {
await fetch("/api/messages", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
chatId: id,
message: {
id: messageId,
role: "assistant",
parts: [{ type: "text", text: imageMarkdown }],
attachments: [],
createdAt: new Date().toISOString(),
},
}),
});
} catch (saveError) {
console.error("[Chat] Failed to save angle edit message:", saveError);
}
};
useAutoResume({
autoResume,
initialMessages,
@ -983,9 +1038,11 @@ export function Chat({
onImageEnhance={handleImageEnhance}
onImageRmbg={handleImageRmbg}
onImageExtend={handleImageExtend}
onImageAngleEdit={handleImageAngleEdit}
isProcessingEnhance={isProcessingEnhance}
isProcessingRmbg={isProcessingRmbg}
isProcessingExtend={isProcessingExtend}
isProcessingAngleEdit={isProcessingAngleEdit}
pendingGeneration={pendingGeneration}
imageCount={imageParams?.imageCount || 1}
/>

View File

@ -12,13 +12,15 @@ type ResponseProps = ComponentProps<typeof Streamdown> & {
onImageEnhance?: (imageUrl: string) => void;
onImageRmbg?: (imageUrl: string) => void;
onImageExtend?: (imageUrl: string) => void;
onImageAngleEdit?: (imageUrl: string) => void;
isProcessingEnhance?: boolean;
isProcessingRmbg?: boolean;
isProcessingExtend?: boolean;
isProcessingAngleEdit?: boolean;
};
export const Response = memo(
({ className, onImageEdit, onDrawingComplete, onImageEnhance, onImageRmbg, onImageExtend, isProcessingEnhance, isProcessingRmbg, isProcessingExtend, ...props }: ResponseProps) => (
({ className, onImageEdit, onDrawingComplete, onImageEnhance, onImageRmbg, onImageExtend, onImageAngleEdit, isProcessingEnhance, isProcessingRmbg, isProcessingExtend, isProcessingAngleEdit, ...props }: ResponseProps) => (
<Streamdown
className={cn(
"size-full [&>*:first-child]:mt-0 [&>*:last-child]:mb-0 [&_code]:whitespace-pre-wrap [&_code]:break-words [&_pre]:max-w-full [&_pre]:overflow-x-auto",
@ -37,9 +39,11 @@ export const Response = memo(
onImageEnhance={onImageEnhance}
onImageRmbg={onImageRmbg}
onImageExtend={onImageExtend}
onImageAngleEdit={onImageAngleEdit}
isProcessingEnhance={isProcessingEnhance}
isProcessingRmbg={isProcessingRmbg}
isProcessingExtend={isProcessingExtend}
isProcessingAngleEdit={isProcessingAngleEdit}
/>;
},
video: ({ src, alt }: { src?: string; alt?: string }) => {
@ -59,9 +63,11 @@ export const Response = memo(
prevProps.onImageEnhance === nextProps.onImageEnhance &&
prevProps.onImageRmbg === nextProps.onImageRmbg &&
prevProps.onImageExtend === nextProps.onImageExtend &&
prevProps.onImageAngleEdit === nextProps.onImageAngleEdit &&
prevProps.isProcessingEnhance === nextProps.isProcessingEnhance &&
prevProps.isProcessingRmbg === nextProps.isProcessingRmbg &&
prevProps.isProcessingExtend === nextProps.isProcessingExtend
prevProps.isProcessingExtend === nextProps.isProcessingExtend &&
prevProps.isProcessingAngleEdit === nextProps.isProcessingAngleEdit
);
Response.displayName = "Response";

View File

@ -151,9 +151,11 @@ const PurePreviewMessage = ({
onImageEnhance,
onImageRmbg,
onImageExtend,
onImageAngleEdit,
isProcessingEnhance,
isProcessingRmbg,
isProcessingExtend,
isProcessingAngleEdit,
}: {
chatId: string;
message: ChatMessage;
@ -169,9 +171,11 @@ const PurePreviewMessage = ({
onImageEnhance?: (imageUrl: string) => void;
onImageRmbg?: (imageUrl: string) => void;
onImageExtend?: (imageUrl: string) => void;
onImageAngleEdit?: (imageUrl: string) => void;
isProcessingEnhance?: boolean;
isProcessingRmbg?: boolean;
isProcessingExtend?: boolean;
isProcessingAngleEdit?: boolean;
}) => {
const [mode, setMode] = useState<"view" | "edit">("view");
@ -305,9 +309,11 @@ const PurePreviewMessage = ({
onImageEnhance={onImageEnhance}
onImageRmbg={onImageRmbg}
onImageExtend={onImageExtend}
onImageAngleEdit={onImageAngleEdit}
isProcessingEnhance={isProcessingEnhance}
isProcessingRmbg={isProcessingRmbg}
isProcessingExtend={isProcessingExtend}
isProcessingAngleEdit={isProcessingAngleEdit}
>
{sanitizeText(part.content)}
</Response>

View File

@ -40,9 +40,11 @@ type MessagesProps = {
onImageEnhance?: (imageUrl: string) => void;
onImageRmbg?: (imageUrl: string) => void;
onImageExtend?: (imageUrl: string) => void;
onImageAngleEdit?: (imageUrl: string) => void;
isProcessingEnhance?: boolean;
isProcessingRmbg?: boolean;
isProcessingExtend?: boolean;
isProcessingAngleEdit?: boolean;
pendingGeneration?: PendingGeneration | null; // 🆕 持久化的生成状态
imageCount?: number; // 🆕 用户选择的图片数量
};
@ -62,9 +64,11 @@ function PureMessages({
onImageEnhance,
onImageRmbg,
onImageExtend,
onImageAngleEdit,
isProcessingEnhance = false,
isProcessingRmbg = false,
isProcessingExtend = false,
isProcessingAngleEdit = false,
pendingGeneration,
imageCount = 1,
}: MessagesProps) {
@ -246,9 +250,11 @@ function PureMessages({
onImageEnhance={onImageEnhance}
onImageRmbg={onImageRmbg}
onImageExtend={onImageExtend}
onImageAngleEdit={onImageAngleEdit}
isProcessingEnhance={isProcessingEnhance}
isProcessingRmbg={isProcessingRmbg}
isProcessingExtend={isProcessingExtend}
isProcessingAngleEdit={isProcessingAngleEdit}
/>
))}

View File

@ -142,3 +142,4 @@ pmset -g