Browse Source

node x修改

TEST-s
TianYun 2 months ago
parent
commit
b03ceabc63
  1. 10
      src/components/__tests__/GenerationComposer.test.tsx
  2. 44
      src/components/composer/GenerationComposer.tsx
  3. 8
      src/components/nodes/PromptNode.tsx

10
src/components/__tests__/GenerationComposer.test.tsx

@ -1010,13 +1010,19 @@ describe("GenerationComposer", () => {
expect(data.durationSeconds).toBe(4);
});
it("shows custom selected video duration in quick settings", () => {
it("defaults gateway video dimension quick settings to the first schema option", async () => {
useWorkflowStore.setState({
nodes: [videoNode("vid-1", true, { durationSeconds: 6 })],
});
render(<GenerationComposer />);
expect(screen.getByLabelText("Duration")).toHaveValue("6");
expect(screen.getByLabelText("Duration")).toHaveValue("4");
await waitFor(() => {
expect((useWorkflowStore.getState().nodes[0].data as GenerateVideoNodeData).parameters).toMatchObject({
duration: "4",
resolution: "720p",
});
});
});
it("uses the audio model filter and reruns the selected audio node", async () => {

44
src/components/composer/GenerationComposer.tsx

@ -196,10 +196,6 @@ function buildGatewayDimensionSelects(
.map((parameter) => {
const options = getSchemaSelectOptions(parameter);
const value = draft.parameters?.[parameter.name]
?? (parameter.name === "ratio" ? draft.aspectRatio : undefined)
?? (parameter.name === "resolution" ? draft.resolution : undefined)
?? (parameter.name === "duration" ? draft.durationSeconds : undefined)
?? parameter.default
?? options[0]?.value;
return {
parameter,
@ -209,6 +205,24 @@ function buildGatewayDimensionSelects(
});
}
function applyGatewayDimensionParameterDefaults(
schema: ModelParameter[] | undefined,
parameters: Record<string, unknown> | undefined
): { parameters: Record<string, unknown>; changed: boolean } {
const next = { ...(parameters ?? {}) };
let changed = false;
const nameSet = new Set(GATEWAY_DIMENSION_PARAMETER_NAMES);
for (const parameter of schema ?? []) {
if (!nameSet.has(parameter.name) || !parameter.options || parameter.options.length === 0) continue;
if (next[parameter.name] !== undefined && next[parameter.name] !== null && next[parameter.name] !== "") continue;
next[parameter.name] = parameter.options[0]?.value;
changed = true;
}
return { parameters: next, changed };
}
function getImageCountOptions(schema: ModelParameter[] | undefined): ImageGenerationCount[] {
return getSchemaOptionValues(schema, IMAGE_COUNT_PARAMETER_NAMES)
.map((value) => Number(value))
@ -876,7 +890,7 @@ function buildInitialDataForNode(nodeType: NodeType, draft: ComposerDraft): Part
model: getLegacyImageModel(draft.selectedModel),
selectedModel: draft.selectedModel,
imageCount: draft.imageCount,
parameters: {},
parameters: draft.parameters ?? {},
inputSchema: undefined,
useGoogleSearch: false,
useImageSearch: false,
@ -892,7 +906,7 @@ function buildInitialDataForNode(nodeType: NodeType, draft: ComposerDraft): Part
resolution: draft.resolution,
durationSeconds: normalizeVideoDurationSeconds(draft.durationSeconds),
soundEnabled: modelSupportsVideoSound(draft.selectedModel) ? draft.soundEnabled ?? true : undefined,
parameters: {},
parameters: draft.parameters ?? {},
inputSchema: undefined,
status: "idle",
error: null,
@ -903,7 +917,7 @@ function buildInitialDataForNode(nodeType: NodeType, draft: ComposerDraft): Part
inputImages: draft.inputImages,
inputPrompt: draft.prompt.trim(),
selectedModel: draft.selectedModel,
parameters: {},
parameters: draft.parameters ?? {},
inputSchema: undefined,
status: "idle",
error: null,
@ -913,7 +927,7 @@ function buildInitialDataForNode(nodeType: NodeType, draft: ComposerDraft): Part
return {
inputPrompt: draft.prompt.trim(),
selectedModel: draft.selectedModel,
parameters: {},
parameters: draft.parameters ?? {},
inputSchema: undefined,
status: "idle",
error: null,
@ -1403,6 +1417,20 @@ export function GenerationComposer() {
? context.node?.data as NanoBananaNodeData | GenerateVideoNodeData | GenerateAudioNodeData | undefined
: undefined;
const activeParameterSchema = generationNodeData?.parameterSchema ?? [];
useEffect(() => {
if (context.mode !== "node-edit" || !context.node || activeParameterSchema.length === 0) return;
const normalized = applyGatewayDimensionParameterDefaults(activeParameterSchema, draftRef.current.parameters);
if (!normalized.changed) return;
setDraft((current) => {
const currentNormalized = applyGatewayDimensionParameterDefaults(activeParameterSchema, current.parameters);
if (!currentNormalized.changed) return current;
const next = { ...current, parameters: currentNormalized.parameters };
draftRef.current = next;
return next;
});
updateNodeData(context.node.id, { parameters: normalized.parameters });
}, [activeParameterSchema, context, updateNodeData]);
const gatewayDimensionSelects = buildGatewayDimensionSelects(activeParameterSchema, draft);
const imageCountOptions = getImageCountOptions(activeParameterSchema);
const visibleImageCountOptions = imageCountOptions.length > 0

8
src/components/nodes/PromptNode.tsx

@ -235,10 +235,14 @@ export function PromptNode({ id, data, selected }: NodeProps<PromptNodeType>) {
setIsEditing(true);
}
}}
className="flex h-full w-full cursor-text items-center justify-center rounded-lg bg-neutral-800 p-8 text-center outline-none"
className={`nodrag nopan nowheel flex h-full w-full cursor-text rounded-lg bg-neutral-800 p-8 outline-none ${
promptText
? "items-start justify-start overflow-auto text-left select-text"
: "items-center justify-center text-center"
}`}
>
{promptText ? (
<div className="w-full whitespace-pre-wrap text-left text-lg leading-relaxed text-neutral-100">
<div className="w-full whitespace-pre-wrap break-words text-lg leading-relaxed text-neutral-100 select-text">
{localPrompt}
</div>
) : (

Loading…
Cancel
Save