fix: 修复新会话重复请求并更新部署脚本默认目标
This commit is contained in:
parent
fd884bd676
commit
1243bd0aac
|
|
@ -67,10 +67,19 @@ export default function ChatPage() {
|
|||
// 新逻辑:历史渲染和新会话仅由路由 /chats/new 控制,不再读取 isnew/is_chatting 参数。
|
||||
const shouldRenderHistory = !showWelcomeStyle;
|
||||
const createNewSession = useMemo(() => isNewThread, [isNewThread]);
|
||||
const safeThreadId = useMemo(() => {
|
||||
if (!threadId || threadId === "new") {
|
||||
return undefined;
|
||||
}
|
||||
return threadId;
|
||||
}, [threadId]);
|
||||
|
||||
const streamThreadId = useMemo(() => {
|
||||
return isNewThread && createNewSession ? undefined : threadId;
|
||||
}, [createNewSession, isNewThread, threadId]);
|
||||
if (isNewThread && createNewSession) {
|
||||
return undefined;
|
||||
}
|
||||
return safeThreadId;
|
||||
}, [createNewSession, isNewThread, safeThreadId]);
|
||||
|
||||
const { showNotification } = useNotification();
|
||||
|
||||
|
|
@ -79,7 +88,7 @@ export default function ChatPage() {
|
|||
skillError: selectedSkillError,
|
||||
clearSkillError: clearSelectedSkillError,
|
||||
isBootstrapping: isSelectedSkillBootstrapping,
|
||||
} = useSelectedSkillListener({ threadId });
|
||||
} = useSelectedSkillListener({ threadId: safeThreadId ?? null });
|
||||
// 对话行为控制器
|
||||
const [thread, sendMessage, isUploading] = useThreadStream({
|
||||
threadId: streamThreadId,
|
||||
|
|
@ -495,7 +504,7 @@ export default function ChatPage() {
|
|||
if (threadId && threadId !== "new") {
|
||||
nextQuery.set("thread_id", threadId);
|
||||
}
|
||||
router.replace(`/workspace/chats/new?${nextQuery.toString()}`);
|
||||
router.replace(`/workspace/chats/${threadId}?is_chatting=false`);
|
||||
}}
|
||||
>
|
||||
确定
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
"use client";
|
||||
|
||||
import { useParams, usePathname, useSearchParams } from "next/navigation";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
|
||||
export function useThreadChat() {
|
||||
|
|
@ -26,53 +26,13 @@ export function useThreadChat() {
|
|||
const rawPathThreadId = params?.thread_id ?? threadIdFromPathname;
|
||||
|
||||
const isNewRoute = rawPathThreadId === "new";
|
||||
const threadIdFromPathOrParams:string = isNewRoute
|
||||
? threadIdFromSearchParams?? params.thread_id
|
||||
: params.thread_id;
|
||||
const threadIdFromPathOrParams = isNewRoute
|
||||
? normalizeThreadId(threadIdFromSearchParams)
|
||||
: normalizeThreadId(rawPathThreadId);
|
||||
// console.log("[useThreadChat] pathname", pathname);
|
||||
// console.log("[useThreadChat] params.thread_id", params?.thread_id);
|
||||
// console.log("[useThreadChat] threadIdFromPathname", threadIdFromPathname);
|
||||
// console.log("[useThreadChat] threadIdFromPath", threadIdFromPath);
|
||||
// 持久化兜底:用于处理首屏水合或 params 时序问题。
|
||||
const readStoredThreadId = () => {
|
||||
if (typeof window === "undefined") {
|
||||
return undefined;
|
||||
}
|
||||
const stored = window.sessionStorage.getItem("workspace.thread_id");
|
||||
return isValidThreadId(stored) ? stored : undefined;
|
||||
};
|
||||
|
||||
// 读取 query 的 thread_id(先用 hook,必要时用 window 兜底)。
|
||||
const readQueryThreadId = () => {
|
||||
const fromHook = threadIdFromSearchParams;
|
||||
if (isValidThreadId(fromHook)) {
|
||||
return fromHook;
|
||||
}
|
||||
if (typeof window === "undefined") {
|
||||
return undefined;
|
||||
}
|
||||
const fromLocation = new URLSearchParams(window.location.search).get(
|
||||
"thread_id",
|
||||
);
|
||||
if (isValidThreadId(fromLocation)) {
|
||||
return fromLocation.trim();
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
const queryThreadIdFromParams = readQueryThreadId();
|
||||
// console.log("[useThreadChat] query.thread_id", queryThreadIdFromParams);
|
||||
// 归一化:当值为 "new" 时,替换为 query 中的 thread_id(如果存在)。
|
||||
const normalizeThreadId = useCallback(
|
||||
(value?: string | null) => {
|
||||
if (!value) {
|
||||
return undefined;
|
||||
}
|
||||
return value === "new" ? queryThreadIdFromParams : value;
|
||||
},
|
||||
[queryThreadIdFromParams],
|
||||
);
|
||||
|
||||
// New session is only controlled by `/workspace/chats/new`.
|
||||
const [isNewThread, setIsNewThread] = useState(() => isNewRoute);
|
||||
|
||||
|
|
@ -82,7 +42,7 @@ export function useThreadChat() {
|
|||
// console.log("[useThreadChat] effectiveThreadIdFromPath", effectiveThreadIdFromPath);
|
||||
|
||||
const [threadId, setThreadId] = useState<string>(() => {
|
||||
return threadIdFromPathOrParams;
|
||||
return threadIdFromPathOrParams ?? "";
|
||||
});
|
||||
|
||||
|
||||
|
|
@ -93,11 +53,10 @@ export function useThreadChat() {
|
|||
}
|
||||
setIsNewThread(isNewRoute);
|
||||
// Prefer path thread id, fall back to query thread_id when path is /new.
|
||||
setThreadId(threadIdFromPathOrParams);
|
||||
setThreadId(threadIdFromPathOrParams ?? "");
|
||||
setShowWelcomeStyle(isNewRoute || !isChattingFromQuery);
|
||||
}, [
|
||||
isNewRoute,
|
||||
normalizeThreadId,
|
||||
pathname,
|
||||
searchParams,
|
||||
isChattingFromQuery,
|
||||
|
|
@ -114,6 +73,11 @@ export function useThreadChat() {
|
|||
};
|
||||
}
|
||||
|
||||
function normalizeThreadId(value?: string | null): string | undefined {
|
||||
if (!value) return undefined;
|
||||
return isValidThreadId(value) ? value.trim() : undefined;
|
||||
}
|
||||
|
||||
function isValidThreadId(value?: string | null): value is string {
|
||||
if (!value) return false;
|
||||
const normalized = value.trim().toLowerCase();
|
||||
|
|
|
|||
|
|
@ -117,31 +117,31 @@ export const zhCN: Translations = {
|
|||
prompt:
|
||||
"为[主题/产品]撰写吸引人的自媒体文案,包括标题、正文和话题标签。",
|
||||
icon: PenLineIcon,
|
||||
children: [{ id: "1245", name: "自媒体文案" }],
|
||||
children: [{ id: "1245", name: "微信文章撰写" }],
|
||||
},
|
||||
{
|
||||
suggestion: "需求文档",
|
||||
prompt: "编写[项目/功能]的需求文档,包含功能描述、用户故事和验收标准。",
|
||||
icon: CompassIcon,
|
||||
children: [{ id: "520", name: "需求文档" }],
|
||||
children: [{ id: "520", name: "分解功能产品需求文档" }],
|
||||
},
|
||||
{
|
||||
suggestion: "使用指南",
|
||||
prompt: "编写[产品/功能]的使用指南,包含操作步骤、注意事项和常见问题。",
|
||||
icon: GraduationCapIcon,
|
||||
children: [{ id: "409", name: "使用指南" }],
|
||||
children: [{ id: "409", name: "用户指南编写" }],
|
||||
},
|
||||
{
|
||||
suggestion: "Excel数据分析",
|
||||
prompt: "对[Excel文件/数据]进行分析,生成数据洞察和可视化建议。",
|
||||
icon: MicroscopeIcon,
|
||||
children: [{ id: "5", name: "Excel数据分析" }],
|
||||
children: [{ id: "5", name: "数据分析" }],
|
||||
},
|
||||
{
|
||||
suggestion: "市场调研",
|
||||
prompt: "针对[行业/产品]进行市场调研,分析市场规模、竞品和趋势。",
|
||||
icon: ShapesIcon,
|
||||
children: [{ id: "1216", name: "市场调研" }],
|
||||
children: [{ id: "1216", name: "市场研究报告" }],
|
||||
},
|
||||
],
|
||||
suggestionsCreate: [
|
||||
|
|
|
|||
|
|
@ -328,15 +328,20 @@ export function useThreadStream({
|
|||
}
|
||||
setOptimisticMessages(newOptimistic);
|
||||
|
||||
if (resolvedThreadId) {
|
||||
// For "new chat with prefilled thread_id" flows, calling onStart before
|
||||
// submit can trigger route switch too early, which causes the new page to
|
||||
// fetch history before the thread/run is actually created.
|
||||
// Let useStream.onCreated -> handleStreamStart drive onStart instead.
|
||||
if (resolvedThreadId && !createNewSession) {
|
||||
_handleOnStart(resolvedThreadId);
|
||||
}
|
||||
|
||||
let uploadedFileInfo: UploadedFileInfo[] = [];
|
||||
|
||||
try {
|
||||
// 新会话模式下,删除旧线程并创建同名新线程
|
||||
if (createNewSession && resolvedThreadId) {
|
||||
// 新会话模式下,仅在本地已有历史消息时才重置旧线程。
|
||||
// 对于全新 thread_id,避免多发一次 DELETE /threads/{id}(通常会 404)。
|
||||
if (createNewSession && resolvedThreadId && thread.messages.length > 0) {
|
||||
await apiClient.threads.delete(resolvedThreadId).catch(() => undefined);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,16 +5,21 @@ set -euo pipefail
|
|||
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$REPO_ROOT"
|
||||
|
||||
# Default deploy target (can be overridden by positional args)
|
||||
DEFAULT_REMOTE="root@111.228.39.147"
|
||||
DEFAULT_REMOTE_APP_DIR="/root/deerflow2"
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage:
|
||||
./scripts/deploy-frontend-standalone.sh <remote> <remote_app_dir>
|
||||
./scripts/deploy-frontend-standalone.sh [remote] [remote_app_dir]
|
||||
|
||||
Arguments:
|
||||
remote SSH target, e.g. user@example.com
|
||||
remote_app_dir Remote deerflow2 root dir, e.g. /home/user/deerflow2
|
||||
remote SSH target, optional. Default: root@111.228.39.147
|
||||
remote_app_dir Remote deerflow2 root dir, optional. Default: /root/deerflow2
|
||||
|
||||
Example:
|
||||
./scripts/deploy-frontend-standalone.sh
|
||||
./scripts/deploy-frontend-standalone.sh ubuntu@1.2.3.4 /opt/deerflow2
|
||||
|
||||
Notes:
|
||||
|
|
@ -31,13 +36,17 @@ if [ "${1:-}" = "-h" ] || [ "${1:-}" = "--help" ]; then
|
|||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$#" -ne 2 ]; then
|
||||
if [ "$#" -gt 2 ]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
REMOTE="$1"
|
||||
REMOTE_APP_DIR="$2"
|
||||
REMOTE="${1:-$DEFAULT_REMOTE}"
|
||||
REMOTE_APP_DIR="${2:-$DEFAULT_REMOTE_APP_DIR}"
|
||||
|
||||
echo "==> Deploy target:"
|
||||
echo " remote: $REMOTE"
|
||||
echo " app dir: $REMOTE_APP_DIR"
|
||||
|
||||
echo "==> Building frontend (standalone)..."
|
||||
pnpm -C frontend build
|
||||
|
|
|
|||
Loading…
Reference in New Issue