Refine agent text mode workflow
This commit is contained in:
parent
ec988be30a
commit
67d834f0dd
@ -98,6 +98,11 @@ import type {
|
|||||||
} from "@/lib/ai/context-memory/types";
|
} from "@/lib/ai/context-memory/types";
|
||||||
import { ChatSDKError } from "@/lib/errors";
|
import { ChatSDKError } from "@/lib/errors";
|
||||||
import { extractImageUrlsFromText } from "@/lib/image-url";
|
import { extractImageUrlsFromText } from "@/lib/image-url";
|
||||||
|
import {
|
||||||
|
buildPromptMemoryUpdate,
|
||||||
|
extractPromptMemoryFromWorkingState,
|
||||||
|
isPromptCarryForwardRequest,
|
||||||
|
} from "@/lib/ai/prompt-memory";
|
||||||
import { uploadFile } from "@/lib/storage/service";
|
import { uploadFile } from "@/lib/storage/service";
|
||||||
import { getVideoStoryboardConfig } from "@/lib/video-agent/config";
|
import { getVideoStoryboardConfig } from "@/lib/video-agent/config";
|
||||||
import { runRuxaNineGridPipeline } from "@/lib/video-agent/pipeline/ruxa-nine-grid-pipeline";
|
import { runRuxaNineGridPipeline } from "@/lib/video-agent/pipeline/ruxa-nine-grid-pipeline";
|
||||||
@ -3059,6 +3064,7 @@ export async function POST(request: Request) {
|
|||||||
| Awaited<ReturnType<typeof getConversationWorkingStateByChatId>>
|
| Awaited<ReturnType<typeof getConversationWorkingStateByChatId>>
|
||||||
| null = null;
|
| null = null;
|
||||||
let storyboardPreferenceMemory = null;
|
let storyboardPreferenceMemory = null;
|
||||||
|
let reusablePromptMemory = null;
|
||||||
let smartAutoHistoryMessagesFromDb: DBMessage[] = [];
|
let smartAutoHistoryMessagesFromDb: DBMessage[] = [];
|
||||||
let preferredAgentModelId: string | undefined;
|
let preferredAgentModelId: string | undefined;
|
||||||
let pendingGridConfirmation:
|
let pendingGridConfirmation:
|
||||||
@ -3186,6 +3192,7 @@ export async function POST(request: Request) {
|
|||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
storyboardPreferenceMemory = extractStoryboardPreferenceMemory(requestWorkingState);
|
storyboardPreferenceMemory = extractStoryboardPreferenceMemory(requestWorkingState);
|
||||||
|
reusablePromptMemory = extractPromptMemoryFromWorkingState(requestWorkingState);
|
||||||
pendingGridConfirmation =
|
pendingGridConfirmation =
|
||||||
extractPendingGridConfirmationFromWorkingState(requestWorkingState);
|
extractPendingGridConfirmationFromWorkingState(requestWorkingState);
|
||||||
|
|
||||||
@ -3234,9 +3241,22 @@ export async function POST(request: Request) {
|
|||||||
chatId: id,
|
chatId: id,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
confirmedPromptForGeneration = extractConfirmedPromptFromWorkingState(requestWorkingState);
|
confirmedPromptForGeneration =
|
||||||
|
extractConfirmedPromptFromWorkingState(requestWorkingState) ||
|
||||||
|
reusablePromptMemory?.optimizedPrompt;
|
||||||
|
const hasImageInputForPromptCarryForward =
|
||||||
|
message.parts.some((part: any) =>
|
||||||
|
part?.type === "file" || part?.type === "image" || part?.type === "image_url"
|
||||||
|
);
|
||||||
|
const isPromptCarryForwardExecution =
|
||||||
|
Boolean(confirmedPromptForGeneration) &&
|
||||||
|
isPromptCarryForwardRequest({
|
||||||
|
text: requestTextContent,
|
||||||
|
hasImage: hasImageInputForPromptCarryForward,
|
||||||
|
});
|
||||||
forcePromptDrivenImageGeneration =
|
forcePromptDrivenImageGeneration =
|
||||||
isConfirmedPromptGenerationRequest(requestTextContent) &&
|
(isConfirmedPromptGenerationRequest(requestTextContent) ||
|
||||||
|
isPromptCarryForwardExecution) &&
|
||||||
Boolean(confirmedPromptForGeneration);
|
Boolean(confirmedPromptForGeneration);
|
||||||
if (!requestResolvedMediaInput) {
|
if (!requestResolvedMediaInput) {
|
||||||
requestResolvedMediaInput = resolveChatMediaInput({
|
requestResolvedMediaInput = resolveChatMediaInput({
|
||||||
@ -3457,7 +3477,10 @@ export async function POST(request: Request) {
|
|||||||
availableTools: [],
|
availableTools: [],
|
||||||
};
|
};
|
||||||
smartAutoFriendlyMessage =
|
smartAutoFriendlyMessage =
|
||||||
smartAutoFriendlyMessage || "收到,我会按你刚确认的提示词直接生图。";
|
smartAutoFriendlyMessage ||
|
||||||
|
(isPromptCarryForwardExecution
|
||||||
|
? "收到,我会使用上一轮优化后的提示词,结合你这轮图片继续执行。"
|
||||||
|
: "收到,我会按你刚确认的提示词直接生图。");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (smartAutoPlan) {
|
if (smartAutoPlan) {
|
||||||
@ -4689,6 +4712,12 @@ export async function POST(request: Request) {
|
|||||||
resolutionMode: "prompt_only",
|
resolutionMode: "prompt_only",
|
||||||
confidence: 90,
|
confidence: 90,
|
||||||
optimizedPrompt: promptOnlyOptimizedPrompt.slice(0, 1000),
|
optimizedPrompt: promptOnlyOptimizedPrompt.slice(0, 1000),
|
||||||
|
promptMemory: buildPromptMemoryUpdate({
|
||||||
|
optimizedPrompt: promptOnlyOptimizedPrompt.slice(0, 1000),
|
||||||
|
sourceIntent: "image_gen",
|
||||||
|
sourceText: requestTextContent.slice(0, 500),
|
||||||
|
reusable: true,
|
||||||
|
}),
|
||||||
imageSummary: promptOnlyImageSummary.slice(0, 1200),
|
imageSummary: promptOnlyImageSummary.slice(0, 1200),
|
||||||
sourceImageUrls: promptOnlySourceImageUrls,
|
sourceImageUrls: promptOnlySourceImageUrls,
|
||||||
},
|
},
|
||||||
|
|||||||
92
lib/ai/prompt-memory.ts
Normal file
92
lib/ai/prompt-memory.ts
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
import "server-only";
|
||||||
|
|
||||||
|
export interface PromptMemoryEntry {
|
||||||
|
optimizedPrompt: string;
|
||||||
|
sourceIntent?: string;
|
||||||
|
sourceText?: string;
|
||||||
|
reusable?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeText(value: unknown, max = 2000): string | undefined {
|
||||||
|
const normalized = String(value || "").trim();
|
||||||
|
if (!normalized) return undefined;
|
||||||
|
return normalized.slice(0, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function extractPromptMemoryFromWorkingState(
|
||||||
|
workingState?: {
|
||||||
|
lastTurnSummary?: unknown;
|
||||||
|
} | null,
|
||||||
|
): PromptMemoryEntry | null {
|
||||||
|
const summary = workingState?.lastTurnSummary;
|
||||||
|
if (!summary || typeof summary !== "object") return null;
|
||||||
|
const summaryRecord = summary as Record<string, unknown>;
|
||||||
|
const memory = summaryRecord.promptMemory;
|
||||||
|
if (memory && typeof memory === "object") {
|
||||||
|
const memoryRecord = memory as Record<string, unknown>;
|
||||||
|
const optimizedPrompt = normalizeText(memoryRecord.optimizedPrompt, 4000);
|
||||||
|
if (!optimizedPrompt) return null;
|
||||||
|
return {
|
||||||
|
optimizedPrompt,
|
||||||
|
sourceIntent: normalizeText(memoryRecord.sourceIntent, 64),
|
||||||
|
sourceText: normalizeText(memoryRecord.sourceText, 500),
|
||||||
|
reusable:
|
||||||
|
typeof memoryRecord.reusable === "boolean" ? memoryRecord.reusable : true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const resolutionMode = normalizeText(summaryRecord.resolutionMode, 64);
|
||||||
|
const optimizedPrompt = normalizeText(summaryRecord.optimizedPrompt, 4000);
|
||||||
|
if (resolutionMode === "prompt_only" && optimizedPrompt) {
|
||||||
|
return {
|
||||||
|
optimizedPrompt,
|
||||||
|
sourceIntent: "image_gen",
|
||||||
|
sourceText: normalizeText(summaryRecord.text, 500),
|
||||||
|
reusable: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildPromptMemoryUpdate(params: {
|
||||||
|
optimizedPrompt: string;
|
||||||
|
sourceIntent?: string;
|
||||||
|
sourceText?: string;
|
||||||
|
reusable?: boolean;
|
||||||
|
}): PromptMemoryEntry {
|
||||||
|
return {
|
||||||
|
optimizedPrompt: normalizeText(params.optimizedPrompt, 4000) || "",
|
||||||
|
sourceIntent: normalizeText(params.sourceIntent, 64),
|
||||||
|
sourceText: normalizeText(params.sourceText, 500),
|
||||||
|
reusable: params.reusable !== false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isPromptCarryForwardRequest(params: {
|
||||||
|
text: string;
|
||||||
|
hasImage: boolean;
|
||||||
|
}): boolean {
|
||||||
|
const normalized = String(params.text || "").toLowerCase().replace(/\s+/g, "");
|
||||||
|
if (!normalized) return false;
|
||||||
|
|
||||||
|
const refersPreviousPrompt =
|
||||||
|
/根据(上一个|上一句|刚才|上面|之前|那个)?提示词|按(上一个|上一句|刚才|上面|之前|那个)?提示词|用(上一个|上一句|刚才|上面|之前|那个)?提示词|用刚才输出的提示词|按刚才输出的提示词|按上面的提示词|沿用上个提示词|继续用那个提示词/.test(
|
||||||
|
normalized,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!refersPreviousPrompt) return false;
|
||||||
|
|
||||||
|
const wantsExecution =
|
||||||
|
/生图|生成图片|出图|画出来|做图|继续生成|继续做|重新做|重绘|优化这张图|优化这个图|处理这张图|处理这个图|按这个做|照这个做|按此生成/.test(
|
||||||
|
normalized,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (wantsExecution) return true;
|
||||||
|
|
||||||
|
if (params.hasImage) {
|
||||||
|
return /优化|处理|重绘|参考这张图|结合这张图|基于这张图/.test(normalized);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@ -2517,7 +2517,12 @@ export async function createAgentPreset(params: {
|
|||||||
slots: params.slots,
|
slots: params.slots,
|
||||||
});
|
});
|
||||||
|
|
||||||
const requiredUploadCount = validatedSlots.some((slot) => slot.requireUpload !== false) ? 3 : 0;
|
const requiredUploadCount =
|
||||||
|
params.type === "text"
|
||||||
|
? 0
|
||||||
|
: validatedSlots.some((slot) => slot.requireUpload !== false)
|
||||||
|
? 3
|
||||||
|
: 0;
|
||||||
const avatarAssetId = String(params.avatarAssetId || "").trim() || null;
|
const avatarAssetId = String(params.avatarAssetId || "").trim() || null;
|
||||||
if (avatarAssetId) {
|
if (avatarAssetId) {
|
||||||
await validateOwnedReferenceAssets({
|
await validateOwnedReferenceAssets({
|
||||||
@ -2705,7 +2710,12 @@ export async function updateAgentPreset(params: {
|
|||||||
userId: params.userId,
|
userId: params.userId,
|
||||||
slots: normalizedSlotsInput,
|
slots: normalizedSlotsInput,
|
||||||
});
|
});
|
||||||
const requiredUploadCount = validatedSlots.some((slot) => slot.requireUpload !== false) ? 3 : 0;
|
const requiredUploadCount =
|
||||||
|
nextType === "text"
|
||||||
|
? 0
|
||||||
|
: validatedSlots.some((slot) => slot.requireUpload !== false)
|
||||||
|
? 3
|
||||||
|
: 0;
|
||||||
const nextAvatarAssetId =
|
const nextAvatarAssetId =
|
||||||
params.avatarAssetId !== undefined
|
params.avatarAssetId !== undefined
|
||||||
? String(params.avatarAssetId || "").trim() || null
|
? String(params.avatarAssetId || "").trim() || null
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user