全能创作:换款双形态与素材闸门防跳过

本地上传优先于商品库推荐;点击换款支持只出手/角色日常;角色未锁定禁止进核心卖点,「你来推荐」空库不再假完成。
This commit is contained in:
Azmat@qq.com
2026-09-20 09:28:31 +08:00
parent b5d970a4b5
commit f2e8a5f3c1
5 changed files with 638 additions and 67 deletions
+50 -3
View File
@@ -1153,6 +1153,7 @@ function ElicitCard({
onChatAnswer,
onPersonSourceAction,
onUpload,
sessionProductRefs = [],
}: {
message: CreationMessage;
disabled: boolean;
@@ -1167,6 +1168,8 @@ function ElicitCard({
personPrompt?: string,
) => void;
onUpload?: () => void;
/** 会话里已上传/已选的商品图。点「你来推荐」时一并回传,避免后端盲取库里最新商品。 */
sessionProductRefs?: CreationRef[];
}) {
const fields = ((message.payload.fields as CreationField[] | undefined) || []).filter(Boolean);
const submitted = Boolean(message.payload.submitted);
@@ -1504,7 +1507,12 @@ function ElicitCard({
return;
}
if (!gateField?.key) return;
onSubmit({ [gateField.key]: option.value }, []);
// 「你来推荐」必须带上本会话已上传的商品图,否则后端会盲取商品库最新一条。
const attachRefs =
option.value === "auto" || /推荐/.test(option.label)
? sessionProductRefs
: [];
onSubmit({ [gateField.key]: option.value }, attachRefs);
}}
>
{option.label}
@@ -2358,6 +2366,8 @@ export function OmniSessionPage({
messageId: string;
source: "local_upload" | "model_library";
} | null>(null);
/** 商品闸门点「上传商品图」后,上传完成要回填 elicit_answer,而不是只塞进输入框。 */
const productGateMessageIdRef = useRef<string | null>(null);
const composerRef = useRef<RichMentionEditorHandle>(null);
const [streaming, setStreaming] = useState(false);
const [liveText, setLiveText] = useState("");
@@ -2582,6 +2592,25 @@ export function OmniSessionPage({
() => collectSessionAssets(messages, conversation?.pinned_refs || [], sessionUploads),
[messages, conversation?.pinned_refs, sessionUploads],
);
/** 商品闸门回传用的结构化 Ref(不是资源栏 SessionAsset)。 */
const sessionProductRefs = useMemo(() => {
const out: CreationRef[] = [];
const seen = new Set<string>();
const add = (ref?: CreationRef | null) => {
if (!ref?.id) return;
if (ref.type !== "product" && ref.type !== "asset") return;
const key = `${ref.type}:${ref.id}`;
if (seen.has(key)) return;
seen.add(key);
out.push(ref);
};
for (const ref of conversation?.pinned_refs || []) add(ref);
for (const ref of sessionUploads) add(ref);
for (const message of messages) {
for (const ref of message.refs || []) add(ref);
}
return out;
}, [messages, conversation?.pinned_refs, sessionUploads]);
const sessionAssetGroups = useMemo(() => {
const groups: Array<{ key: SessionAssetKind; label: string; items: SessionAsset[] }> = [
{ key: "image", label: "图片", items: [] },
@@ -3178,7 +3207,14 @@ export function OmniSessionPage({
}
void submitPersonSourceChoice(message.id, source, [], personPrompt);
}}
onUpload={() => fileInputRef.current?.click()}
sessionProductRefs={sessionProductRefs}
onUpload={() => {
productGateMessageIdRef.current = message.id;
quickUploadReplyRef.current = null;
setMentionMenuOpen(false);
setUploadMenuOpen(false);
fileInputRef.current?.click();
}}
/>
);
case "strategy":
@@ -3520,13 +3556,24 @@ export function OmniSessionPage({
}
}
notify("success", "素材已上传并通过审核");
if (quickReply && uploadedRefs.length) {
const gateMessageId = productGateMessageIdRef.current;
if (gateMessageId && uploadedRefs.length) {
productGateMessageIdRef.current = null;
quickUploadReplyRef.current = null;
void send({
kind: "elicit_answer",
reply_to: gateMessageId,
answers: { _asset_gate: "upload" },
refs: uploadedRefs,
});
} else if (quickReply && uploadedRefs.length) {
quickUploadReplyRef.current = null;
void send({ kind: "text", text: uploadReplyText(quickReply), refs: uploadedRefs });
}
} catch (error) {
notify("error", (error as Error).message);
quickUploadReplyRef.current = null;
productGateMessageIdRef.current = null;
} finally {
setUploading(false);
}