Merge branch 'zhangyuankun-main-patch-48108' into 'zhangyuankun-main-patch-41282'
Zhangyuankun main patch 48108 See merge request line-group/dify-conversation!1
This commit is contained in:
commit
fe1b17c408
@ -6,7 +6,7 @@ import { API_KEY, API_URL } from '@/config'
|
||||
export const getInfo = (request: NextRequest) => {
|
||||
const username = request.cookies.get('username')?.value || 'no-user'
|
||||
const sessionId = request.cookies.get('session_id')?.value || v4()
|
||||
const user = `user_${username}:${sessionId}`
|
||||
const user = `${username}`
|
||||
return {
|
||||
sessionId,
|
||||
user,
|
||||
|
||||
55
app/components/chat-with-history/FeedbackModal.tsx
Normal file
55
app/components/chat-with-history/FeedbackModal.tsx
Normal file
@ -0,0 +1,55 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Modal, Checkbox, Input, message } from 'antd';
|
||||
|
||||
const { TextArea } = Input;
|
||||
|
||||
interface FeedbackModalProps {
|
||||
open: boolean;
|
||||
onOk: (selectedOption: number | null, feedbackText: string) => void;
|
||||
onCancel: () => void;
|
||||
}
|
||||
|
||||
const FeedbackModal: React.FC<FeedbackModalProps> = ({ open, onOk, onCancel }) => {
|
||||
const [selectedOption, setSelectedOption] = useState<number | null>(null);
|
||||
const [feedbackText, setFeedbackText] = useState<string>('');
|
||||
|
||||
const handleOk = () => {
|
||||
if (selectedOption === null || !feedbackText) {
|
||||
message.warning('请选择操作类型并填写反馈建议');
|
||||
return;
|
||||
}
|
||||
onOk(selectedOption, feedbackText);
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title="反馈"
|
||||
open={open}
|
||||
onOk={handleOk}
|
||||
onCancel={onCancel}
|
||||
>
|
||||
<div>
|
||||
<Checkbox
|
||||
checked={selectedOption === 0}
|
||||
onChange={() => setSelectedOption(0)}
|
||||
>
|
||||
新增
|
||||
</Checkbox>
|
||||
<Checkbox
|
||||
checked={selectedOption === 1}
|
||||
onChange={() => setSelectedOption(1)}
|
||||
>
|
||||
修改
|
||||
</Checkbox>
|
||||
</div>
|
||||
<TextArea
|
||||
rows={4}
|
||||
placeholder="请输入您的反馈建议"
|
||||
value={feedbackText}
|
||||
onChange={(e) => setFeedbackText(e.target.value)}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default FeedbackModal;
|
||||
@ -1,25 +1,15 @@
|
||||
import {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import useSWR from 'swr'
|
||||
import { useLocalStorageState } from 'ahooks'
|
||||
import { produce } from 'immer'
|
||||
import type {
|
||||
Callback,
|
||||
ChatConfig,
|
||||
ChatItem,
|
||||
Feedback,
|
||||
} from '../types'
|
||||
import { CONVERSATION_ID_INFO } from '../constants'
|
||||
import { buildChatItemTree } from '../utils'
|
||||
import { addFileInfos, sortAgentSorts } from '@/app/components/tools/utils'
|
||||
import { getProcessedFilesFromResponse } from '@/app/components/base/file-uploader/utils'
|
||||
// TODO mars
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import useSWR from "swr";
|
||||
import { useLocalStorageState } from "ahooks";
|
||||
import { produce } from "immer";
|
||||
import { message } from "antd";
|
||||
import { client, getInfo } from "@/app/api/utils/common";
|
||||
import type { Callback, ChatConfig, ChatItem, Feedback } from "../types";
|
||||
import { CONVERSATION_ID_INFO } from "../constants";
|
||||
import { buildChatItemTree } from "../utils";
|
||||
import { addFileInfos, sortAgentSorts } from "@/app/components/tools/utils";
|
||||
import { getProcessedFilesFromResponse } from "@/app/components/base/file-uploader/utils";
|
||||
import {
|
||||
delConversation,
|
||||
fetchAppInfo,
|
||||
@ -32,50 +22,66 @@ import {
|
||||
renameConversation,
|
||||
unpinConversation,
|
||||
updateFeedback,
|
||||
} from '@/service/index'
|
||||
import type { InstalledApp } from '@/models/explore'
|
||||
import type {
|
||||
AppData,
|
||||
ConversationItem,
|
||||
} from '@/models/share'
|
||||
import { useToastContext } from '@/app/components/base/toast'
|
||||
import { changeLanguage } from '@/i18n/i18next-config'
|
||||
import { useAppFavicon } from '@/hooks/use-app-favicon'
|
||||
import { InputVarType } from '@/app/components/workflow/types'
|
||||
import { TransferMethod } from '@/types/app'
|
||||
} from "@/service/index";
|
||||
import type { InstalledApp } from "@/models/explore";
|
||||
import type { AppData, ConversationItem } from "@/models/share";
|
||||
import { useToastContext } from "@/app/components/base/toast";
|
||||
import { changeLanguage } from "@/i18n/i18next-config";
|
||||
import { useAppFavicon } from "@/hooks/use-app-favicon";
|
||||
import { InputVarType } from "@/app/components/workflow/types";
|
||||
import { TransferMethod } from "@/types/app";
|
||||
import FeedbackModal from "@/app/components/chat-with-history/FeedbackModal"; // 引入 FeedbackModal 组件
|
||||
|
||||
function getFormattedChatList(messages: any[]) {
|
||||
const newChatList: ChatItem[] = []
|
||||
const newChatList: ChatItem[] = [];
|
||||
messages.forEach((item) => {
|
||||
const questionFiles = item.message_files?.filter((file: any) => file.belongs_to === 'user') || []
|
||||
const questionFiles =
|
||||
item.message_files?.filter((file: any) => file.belongs_to === "user") ||
|
||||
[];
|
||||
newChatList.push({
|
||||
id: `question-${item.id}`,
|
||||
content: item.query,
|
||||
isAnswer: false,
|
||||
message_files: getProcessedFilesFromResponse(questionFiles.map((item: any) => ({ ...item, related_id: item.id }))),
|
||||
message_files: getProcessedFilesFromResponse(
|
||||
questionFiles.map((item: any) => ({ ...item, related_id: item.id }))
|
||||
),
|
||||
parentMessageId: item.parent_message_id || undefined,
|
||||
})
|
||||
const answerFiles = item.message_files?.filter((file: any) => file.belongs_to === 'assistant') || []
|
||||
});
|
||||
const answerFiles =
|
||||
item.message_files?.filter(
|
||||
(file: any) => file.belongs_to === "assistant"
|
||||
) || [];
|
||||
if (answerFiles.length > 0 && questionFiles.length > 0)
|
||||
// 获取本地文件名
|
||||
answerFiles[0].filename = questionFiles[0]?.filename
|
||||
answerFiles[0].filename = questionFiles[0]?.filename;
|
||||
newChatList.push({
|
||||
id: item.id,
|
||||
content: item.answer,
|
||||
agent_thoughts: addFileInfos(item.agent_thoughts ? sortAgentSorts(item.agent_thoughts) : item.agent_thoughts, item.message_files),
|
||||
agent_thoughts: addFileInfos(
|
||||
item.agent_thoughts
|
||||
? sortAgentSorts(item.agent_thoughts)
|
||||
: item.agent_thoughts,
|
||||
item.message_files
|
||||
),
|
||||
feedback: item.feedback,
|
||||
isAnswer: true,
|
||||
citation: item.retriever_resources,
|
||||
message_files: getProcessedFilesFromResponse(answerFiles.map((item: any) => ({ ...item, related_id: item.id }))),
|
||||
message_files: getProcessedFilesFromResponse(
|
||||
answerFiles.map((item: any) => ({ ...item, related_id: item.id }))
|
||||
),
|
||||
parentMessageId: `question-${item.id}`,
|
||||
})
|
||||
})
|
||||
return newChatList
|
||||
});
|
||||
});
|
||||
return newChatList;
|
||||
}
|
||||
|
||||
export const useChatWithHistory = (installedAppInfo?: InstalledApp) => {
|
||||
const isInstalledApp = useMemo(() => !!installedAppInfo, [installedAppInfo])
|
||||
const { data: appInfo, isLoading: appInfoLoading, error: appInfoError } = useSWR(installedAppInfo ? null : 'appInfo', fetchAppInfo)
|
||||
const isInstalledApp = useMemo(() => !!installedAppInfo, [installedAppInfo]);
|
||||
const {
|
||||
data: appInfo,
|
||||
isLoading: appInfoLoading,
|
||||
error: appInfoError,
|
||||
} = useSWR(installedAppInfo ? null : "appInfo", fetchAppInfo);
|
||||
|
||||
useAppFavicon({
|
||||
enable: !installedAppInfo,
|
||||
@ -83,11 +89,11 @@ export const useChatWithHistory = (installedAppInfo?: InstalledApp) => {
|
||||
icon: appInfo?.site?.icon,
|
||||
icon_background: appInfo?.site?.icon_background,
|
||||
icon_url: appInfo?.site?.icon_url,
|
||||
})
|
||||
});
|
||||
|
||||
const appData = useMemo(() => {
|
||||
if (isInstalledApp) {
|
||||
const { id, app } = installedAppInfo!
|
||||
const { id, app } = installedAppInfo!;
|
||||
return {
|
||||
app_id: id,
|
||||
site: {
|
||||
@ -97,326 +103,507 @@ export const useChatWithHistory = (installedAppInfo?: InstalledApp) => {
|
||||
icon_background: app.icon_background,
|
||||
icon_url: app.icon_url,
|
||||
prompt_public: false,
|
||||
copyright: '',
|
||||
copyright: "",
|
||||
show_workflow_steps: true,
|
||||
use_icon_as_answer_icon: app.use_icon_as_answer_icon,
|
||||
},
|
||||
plan: 'basic',
|
||||
} as AppData
|
||||
plan: "basic",
|
||||
} as AppData;
|
||||
}
|
||||
|
||||
return appInfo
|
||||
}, [isInstalledApp, installedAppInfo, appInfo])
|
||||
const appId = useMemo(() => appData?.app_id, [appData])
|
||||
return appInfo;
|
||||
}, [isInstalledApp, installedAppInfo, appInfo]);
|
||||
const appId = useMemo(() => appData?.app_id, [appData]);
|
||||
|
||||
useEffect(() => {
|
||||
if (appData?.site?.default_language)
|
||||
changeLanguage(appData.site?.default_language)
|
||||
}, [appData])
|
||||
changeLanguage(appData.site?.default_language);
|
||||
}, [appData]);
|
||||
|
||||
const [conversationIdInfo, setConversationIdInfo] = useLocalStorageState<Record<string, string>>(CONVERSATION_ID_INFO, {
|
||||
const [conversationIdInfo, setConversationIdInfo] = useLocalStorageState<
|
||||
Record<string, string>
|
||||
>(CONVERSATION_ID_INFO, {
|
||||
defaultValue: {},
|
||||
})
|
||||
const currentConversationId = useMemo(() => conversationIdInfo?.[appId || ''] || '', [appId, conversationIdInfo])
|
||||
const handleConversationIdInfoChange = useCallback((changeConversationId: string) => {
|
||||
if (appId) {
|
||||
setConversationIdInfo({
|
||||
...conversationIdInfo,
|
||||
[appId || '']: changeConversationId,
|
||||
})
|
||||
}
|
||||
}, [appId, conversationIdInfo, setConversationIdInfo])
|
||||
const [showConfigPanelBeforeChat, setShowConfigPanelBeforeChat] = useState(true)
|
||||
const [newConversationId, setNewConversationId] = useState('')
|
||||
});
|
||||
const currentConversationId = useMemo(
|
||||
() => conversationIdInfo?.[appId || ""] || "",
|
||||
[appId, conversationIdInfo]
|
||||
);
|
||||
const handleConversationIdInfoChange = useCallback(
|
||||
(changeConversationId: string) => {
|
||||
if (appId) {
|
||||
setConversationIdInfo({
|
||||
...conversationIdInfo,
|
||||
[appId || ""]: changeConversationId,
|
||||
});
|
||||
}
|
||||
},
|
||||
[appId, conversationIdInfo, setConversationIdInfo]
|
||||
);
|
||||
const [showConfigPanelBeforeChat, setShowConfigPanelBeforeChat] =
|
||||
useState(true);
|
||||
const [newConversationId, setNewConversationId] = useState("");
|
||||
const chatShouldReloadKey = useMemo(() => {
|
||||
if (currentConversationId === newConversationId)
|
||||
return ''
|
||||
if (currentConversationId === newConversationId) return "";
|
||||
|
||||
return currentConversationId
|
||||
}, [currentConversationId, newConversationId])
|
||||
const { data: appParams } = useSWR(['appParams', isInstalledApp, appId], () => fetchAppParams())
|
||||
const { data: appMeta } = useSWR(['appMeta', isInstalledApp, appId], () => fetchAppMeta())
|
||||
const { data: appPinnedConversationData, mutate: mutateAppPinnedConversationData } = useSWR(['appConversationData', isInstalledApp, appId, true], () => fetchConversations())
|
||||
const { data: appConversationData, isLoading: appConversationDataLoading, mutate: mutateAppConversationData } = useSWR(['appConversationData', isInstalledApp, appId, false], () => fetchConversations())
|
||||
const { data: appChatListData, isLoading: appChatListDataLoading } = useSWR(chatShouldReloadKey ? ['appChatList', chatShouldReloadKey, isInstalledApp, appId] : null, () => fetchChatList(chatShouldReloadKey))
|
||||
return currentConversationId;
|
||||
}, [currentConversationId, newConversationId]);
|
||||
const { data: appParams } = useSWR(["appParams", isInstalledApp, appId], () =>
|
||||
fetchAppParams()
|
||||
);
|
||||
const { data: appMeta } = useSWR(["appMeta", isInstalledApp, appId], () =>
|
||||
fetchAppMeta()
|
||||
);
|
||||
const {
|
||||
data: appPinnedConversationData,
|
||||
mutate: mutateAppPinnedConversationData,
|
||||
} = useSWR(["appConversationData", isInstalledApp, appId, true], () =>
|
||||
fetchConversations()
|
||||
);
|
||||
const {
|
||||
data: appConversationData,
|
||||
isLoading: appConversationDataLoading,
|
||||
mutate: mutateAppConversationData,
|
||||
} = useSWR(["appConversationData", isInstalledApp, appId, false], () =>
|
||||
fetchConversations()
|
||||
);
|
||||
const { data: appChatListData, isLoading: appChatListDataLoading } = useSWR(
|
||||
chatShouldReloadKey
|
||||
? ["appChatList", chatShouldReloadKey, isInstalledApp, appId]
|
||||
: null,
|
||||
() => fetchChatList(chatShouldReloadKey)
|
||||
);
|
||||
|
||||
const appPrevChatTree = useMemo(
|
||||
() => (currentConversationId && appChatListData?.data.length)
|
||||
? buildChatItemTree(getFormattedChatList(appChatListData.data))
|
||||
: [],
|
||||
[appChatListData, currentConversationId],
|
||||
)
|
||||
() =>
|
||||
currentConversationId && appChatListData?.data.length
|
||||
? buildChatItemTree(getFormattedChatList(appChatListData.data))
|
||||
: [],
|
||||
[appChatListData, currentConversationId]
|
||||
);
|
||||
|
||||
const [showNewConversationItemInList, setShowNewConversationItemInList] = useState(false)
|
||||
const [showNewConversationItemInList, setShowNewConversationItemInList] =
|
||||
useState(false);
|
||||
|
||||
const pinnedConversationList = useMemo(() => {
|
||||
return appPinnedConversationData?.data || []
|
||||
}, [appPinnedConversationData])
|
||||
const { t } = useTranslation()
|
||||
const newConversationInputsRef = useRef<Record<string, any>>({})
|
||||
const [newConversationInputs, setNewConversationInputs] = useState<Record<string, any>>({})
|
||||
const handleNewConversationInputsChange = useCallback((newInputs: Record<string, any>) => {
|
||||
newConversationInputsRef.current = newInputs
|
||||
setNewConversationInputs(newInputs)
|
||||
}, [])
|
||||
return appPinnedConversationData?.data || [];
|
||||
}, [appPinnedConversationData]);
|
||||
const { t } = useTranslation();
|
||||
const newConversationInputsRef = useRef<Record<string, any>>({});
|
||||
const [newConversationInputs, setNewConversationInputs] = useState<
|
||||
Record<string, any>
|
||||
>({});
|
||||
const handleNewConversationInputsChange = useCallback(
|
||||
(newInputs: Record<string, any>) => {
|
||||
newConversationInputsRef.current = newInputs;
|
||||
setNewConversationInputs(newInputs);
|
||||
},
|
||||
[]
|
||||
);
|
||||
const inputsForms = useMemo(() => {
|
||||
return (appParams?.user_input_form || []).filter((item: any) => !item.external_data_tool).map((item: any) => {
|
||||
if (item.paragraph) {
|
||||
return {
|
||||
...item.paragraph,
|
||||
type: 'paragraph',
|
||||
return (appParams?.user_input_form || [])
|
||||
.filter((item: any) => !item.external_data_tool)
|
||||
.map((item: any) => {
|
||||
if (item.paragraph) {
|
||||
return {
|
||||
...item.paragraph,
|
||||
type: "paragraph",
|
||||
};
|
||||
}
|
||||
}
|
||||
if (item.number) {
|
||||
return {
|
||||
...item.number,
|
||||
type: 'number',
|
||||
if (item.number) {
|
||||
return {
|
||||
...item.number,
|
||||
type: "number",
|
||||
};
|
||||
}
|
||||
}
|
||||
if (item.select) {
|
||||
return {
|
||||
...item.select,
|
||||
type: 'select',
|
||||
if (item.select) {
|
||||
return {
|
||||
...item.select,
|
||||
type: "select",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (item['file-list']) {
|
||||
return {
|
||||
...item['file-list'],
|
||||
type: 'file-list',
|
||||
if (item["file-list"]) {
|
||||
return {
|
||||
...item["file-list"],
|
||||
type: "file-list",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (item.file) {
|
||||
return {
|
||||
...item.file,
|
||||
type: 'file',
|
||||
if (item.file) {
|
||||
return {
|
||||
...item.file,
|
||||
type: "file",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
...item['text-input'],
|
||||
type: 'text-input',
|
||||
}
|
||||
})
|
||||
}, [appParams])
|
||||
return {
|
||||
...item["text-input"],
|
||||
type: "text-input",
|
||||
};
|
||||
});
|
||||
}, [appParams]);
|
||||
useEffect(() => {
|
||||
const conversationInputs: Record<string, any> = {}
|
||||
const conversationInputs: Record<string, any> = {};
|
||||
|
||||
inputsForms.forEach((item: any) => {
|
||||
conversationInputs[item.variable] = item.default || null
|
||||
})
|
||||
handleNewConversationInputsChange(conversationInputs)
|
||||
}, [handleNewConversationInputsChange, inputsForms])
|
||||
conversationInputs[item.variable] = item.default || null;
|
||||
});
|
||||
handleNewConversationInputsChange(conversationInputs);
|
||||
}, [handleNewConversationInputsChange, inputsForms]);
|
||||
|
||||
const { data: newConversation } = useSWR(newConversationId ? [isInstalledApp, appId, newConversationId] : null, () => generationConversationName(newConversationId))
|
||||
const [originConversationList, setOriginConversationList] = useState<ConversationItem[]>([])
|
||||
const { data: newConversation } = useSWR(
|
||||
newConversationId ? [isInstalledApp, appId, newConversationId] : null,
|
||||
() => generationConversationName(newConversationId)
|
||||
);
|
||||
const [originConversationList, setOriginConversationList] = useState<
|
||||
ConversationItem[]
|
||||
>([]);
|
||||
useEffect(() => {
|
||||
if (appConversationData?.data && !appConversationDataLoading)
|
||||
setOriginConversationList(appConversationData?.data)
|
||||
}, [appConversationData, appConversationDataLoading])
|
||||
setOriginConversationList(appConversationData?.data);
|
||||
}, [appConversationData, appConversationDataLoading]);
|
||||
const conversationList = useMemo(() => {
|
||||
const data = originConversationList.slice()
|
||||
const data = originConversationList.slice();
|
||||
|
||||
if (showNewConversationItemInList && data[0]?.id !== '') {
|
||||
if (showNewConversationItemInList && data[0]?.id !== "") {
|
||||
data.unshift({
|
||||
id: '',
|
||||
name: t('share.chat.newChatDefaultName'),
|
||||
id: "",
|
||||
name: t("share.chat.newChatDefaultName"),
|
||||
inputs: {},
|
||||
introduction: '',
|
||||
})
|
||||
introduction: "",
|
||||
});
|
||||
}
|
||||
return data
|
||||
}, [originConversationList, showNewConversationItemInList, t])
|
||||
return data;
|
||||
}, [originConversationList, showNewConversationItemInList, t]);
|
||||
|
||||
useEffect(() => {
|
||||
if (newConversation) {
|
||||
setOriginConversationList(produce((draft) => {
|
||||
const index = draft.findIndex(item => item.id === newConversation.id)
|
||||
setOriginConversationList(
|
||||
produce((draft) => {
|
||||
const index = draft.findIndex(
|
||||
(item) => item.id === newConversation.id
|
||||
);
|
||||
|
||||
if (index > -1)
|
||||
draft[index] = newConversation
|
||||
else
|
||||
draft.unshift(newConversation)
|
||||
}))
|
||||
if (index > -1) draft[index] = newConversation;
|
||||
else draft.unshift(newConversation);
|
||||
})
|
||||
);
|
||||
}
|
||||
}, [newConversation])
|
||||
}, [newConversation]);
|
||||
|
||||
const currentConversationItem = useMemo(() => {
|
||||
let conversationItem = conversationList.find(item => item.id === currentConversationId)
|
||||
let conversationItem = conversationList.find(
|
||||
(item) => item.id === currentConversationId
|
||||
);
|
||||
|
||||
if (!conversationItem && pinnedConversationList.length)
|
||||
conversationItem = pinnedConversationList.find(item => item.id === currentConversationId)
|
||||
conversationItem = pinnedConversationList.find(
|
||||
(item) => item.id === currentConversationId
|
||||
);
|
||||
|
||||
return conversationItem
|
||||
}, [conversationList, currentConversationId, pinnedConversationList])
|
||||
return conversationItem;
|
||||
}, [conversationList, currentConversationId, pinnedConversationList]);
|
||||
|
||||
const { notify } = useToastContext()
|
||||
const checkInputsRequired = useCallback((silent?: boolean) => {
|
||||
let hasEmptyInput = ''
|
||||
let fileIsUploading = false
|
||||
const requiredVars = inputsForms.filter(({ required }) => required)
|
||||
if (requiredVars.length) {
|
||||
requiredVars.forEach(({ variable, label, type }) => {
|
||||
if (hasEmptyInput)
|
||||
return
|
||||
const { notify } = useToastContext();
|
||||
const checkInputsRequired = useCallback(
|
||||
(silent?: boolean) => {
|
||||
let hasEmptyInput = "";
|
||||
let fileIsUploading = false;
|
||||
const requiredVars = inputsForms.filter(({ required }) => required);
|
||||
if (requiredVars.length) {
|
||||
requiredVars.forEach(({ variable, label, type }) => {
|
||||
if (hasEmptyInput) return;
|
||||
|
||||
if (fileIsUploading)
|
||||
return
|
||||
if (fileIsUploading) return;
|
||||
|
||||
if (!newConversationInputsRef.current[variable] && !silent)
|
||||
hasEmptyInput = label as string
|
||||
if (!newConversationInputsRef.current[variable] && !silent)
|
||||
hasEmptyInput = label as string;
|
||||
|
||||
if ((type === InputVarType.singleFile || type === InputVarType.multiFiles) && newConversationInputsRef.current[variable] && !silent) {
|
||||
const files = newConversationInputsRef.current[variable]
|
||||
if (Array.isArray(files))
|
||||
fileIsUploading = files.find(item => item.transferMethod === TransferMethod.local_file && !item.uploadedId)
|
||||
else
|
||||
fileIsUploading = files.transferMethod === TransferMethod.local_file && !files.uploadedId
|
||||
}
|
||||
})
|
||||
}
|
||||
if (
|
||||
(type === InputVarType.singleFile ||
|
||||
type === InputVarType.multiFiles) &&
|
||||
newConversationInputsRef.current[variable] &&
|
||||
!silent
|
||||
) {
|
||||
const files = newConversationInputsRef.current[variable];
|
||||
if (Array.isArray(files))
|
||||
fileIsUploading = files.find(
|
||||
(item) =>
|
||||
item.transferMethod === TransferMethod.local_file &&
|
||||
!item.uploadedId
|
||||
);
|
||||
else
|
||||
fileIsUploading =
|
||||
files.transferMethod === TransferMethod.local_file &&
|
||||
!files.uploadedId;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (hasEmptyInput) {
|
||||
notify({ type: 'error', message: t('appDebug.errorMessage.valueOfVarRequired', { key: hasEmptyInput }) })
|
||||
return false
|
||||
}
|
||||
if (hasEmptyInput) {
|
||||
notify({
|
||||
type: "error",
|
||||
message: t("appDebug.errorMessage.valueOfVarRequired", {
|
||||
key: hasEmptyInput,
|
||||
}),
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fileIsUploading) {
|
||||
notify({ type: 'info', message: t('appDebug.errorMessage.waitForFileUpload') })
|
||||
return
|
||||
}
|
||||
if (fileIsUploading) {
|
||||
notify({
|
||||
type: "info",
|
||||
message: t("appDebug.errorMessage.waitForFileUpload"),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
return true
|
||||
}, [inputsForms, notify, t])
|
||||
return true;
|
||||
},
|
||||
[inputsForms, notify, t]
|
||||
);
|
||||
const handleStartChat = useCallback(() => {
|
||||
if (checkInputsRequired()) {
|
||||
setShowConfigPanelBeforeChat(false)
|
||||
setShowNewConversationItemInList(true)
|
||||
setShowConfigPanelBeforeChat(false);
|
||||
setShowNewConversationItemInList(true);
|
||||
}
|
||||
}, [setShowConfigPanelBeforeChat, setShowNewConversationItemInList, checkInputsRequired])
|
||||
const currentChatInstanceRef = useRef<{ handleStop: () => void }>({ handleStop: () => { } })
|
||||
const handleChangeConversation = useCallback((conversationId: string) => {
|
||||
currentChatInstanceRef.current.handleStop()
|
||||
setNewConversationId('')
|
||||
handleConversationIdInfoChange(conversationId)
|
||||
}, [
|
||||
setShowConfigPanelBeforeChat,
|
||||
setShowNewConversationItemInList,
|
||||
checkInputsRequired,
|
||||
]);
|
||||
const currentChatInstanceRef = useRef<{ handleStop: () => void }>({
|
||||
handleStop: () => {},
|
||||
});
|
||||
const handleChangeConversation = useCallback(
|
||||
(conversationId: string) => {
|
||||
currentChatInstanceRef.current.handleStop();
|
||||
setNewConversationId("");
|
||||
handleConversationIdInfoChange(conversationId);
|
||||
|
||||
if (conversationId === '' && !checkInputsRequired(true))
|
||||
setShowConfigPanelBeforeChat(true)
|
||||
else
|
||||
setShowConfigPanelBeforeChat(false)
|
||||
}, [handleConversationIdInfoChange, setShowConfigPanelBeforeChat, checkInputsRequired])
|
||||
if (conversationId === "" && !checkInputsRequired(true))
|
||||
setShowConfigPanelBeforeChat(true);
|
||||
else setShowConfigPanelBeforeChat(false);
|
||||
},
|
||||
[
|
||||
handleConversationIdInfoChange,
|
||||
setShowConfigPanelBeforeChat,
|
||||
checkInputsRequired,
|
||||
]
|
||||
);
|
||||
const handleNewConversation = useCallback(() => {
|
||||
currentChatInstanceRef.current.handleStop()
|
||||
setNewConversationId('')
|
||||
currentChatInstanceRef.current.handleStop();
|
||||
setNewConversationId("");
|
||||
|
||||
if (showNewConversationItemInList) {
|
||||
handleChangeConversation('')
|
||||
handleChangeConversation("");
|
||||
} else if (currentConversationId) {
|
||||
handleConversationIdInfoChange("");
|
||||
setShowConfigPanelBeforeChat(true);
|
||||
setShowNewConversationItemInList(true);
|
||||
handleNewConversationInputsChange({});
|
||||
}
|
||||
else if (currentConversationId) {
|
||||
handleConversationIdInfoChange('')
|
||||
setShowConfigPanelBeforeChat(true)
|
||||
setShowNewConversationItemInList(true)
|
||||
handleNewConversationInputsChange({})
|
||||
}
|
||||
}, [handleChangeConversation, currentConversationId, handleConversationIdInfoChange, setShowConfigPanelBeforeChat, setShowNewConversationItemInList, showNewConversationItemInList, handleNewConversationInputsChange])
|
||||
}, [
|
||||
handleChangeConversation,
|
||||
currentConversationId,
|
||||
handleConversationIdInfoChange,
|
||||
setShowConfigPanelBeforeChat,
|
||||
setShowNewConversationItemInList,
|
||||
showNewConversationItemInList,
|
||||
handleNewConversationInputsChange,
|
||||
]);
|
||||
const handleUpdateConversationList = useCallback(() => {
|
||||
mutateAppConversationData()
|
||||
mutateAppPinnedConversationData()
|
||||
}, [mutateAppConversationData, mutateAppPinnedConversationData])
|
||||
mutateAppConversationData();
|
||||
mutateAppPinnedConversationData();
|
||||
}, [mutateAppConversationData, mutateAppPinnedConversationData]);
|
||||
|
||||
const handlePinConversation = useCallback(async (conversationId: string) => {
|
||||
await pinConversation(isInstalledApp, appId, conversationId)
|
||||
notify({ type: 'success', message: t('common.api.success') })
|
||||
handleUpdateConversationList()
|
||||
}, [isInstalledApp, appId, notify, t, handleUpdateConversationList])
|
||||
const handlePinConversation = useCallback(
|
||||
async (conversationId: string) => {
|
||||
await pinConversation(isInstalledApp, appId, conversationId);
|
||||
notify({ type: "success", message: t("common.api.success") });
|
||||
handleUpdateConversationList();
|
||||
},
|
||||
[isInstalledApp, appId, notify, t, handleUpdateConversationList]
|
||||
);
|
||||
|
||||
const handleUnpinConversation = useCallback(async (conversationId: string) => {
|
||||
await unpinConversation(isInstalledApp, appId, conversationId)
|
||||
notify({ type: 'success', message: t('common.api.success') })
|
||||
handleUpdateConversationList()
|
||||
}, [isInstalledApp, appId, notify, t, handleUpdateConversationList])
|
||||
const handleUnpinConversation = useCallback(
|
||||
async (conversationId: string) => {
|
||||
await unpinConversation(isInstalledApp, appId, conversationId);
|
||||
notify({ type: "success", message: t("common.api.success") });
|
||||
handleUpdateConversationList();
|
||||
},
|
||||
[isInstalledApp, appId, notify, t, handleUpdateConversationList]
|
||||
);
|
||||
|
||||
const [conversationDeleting, setConversationDeleting] = useState(false)
|
||||
const handleDeleteConversation = useCallback(async (
|
||||
conversationId: string,
|
||||
{
|
||||
onSuccess,
|
||||
}: Callback,
|
||||
) => {
|
||||
if (conversationDeleting)
|
||||
return
|
||||
const [conversationDeleting, setConversationDeleting] = useState(false);
|
||||
const handleDeleteConversation = useCallback(
|
||||
async (conversationId: string, { onSuccess }: Callback) => {
|
||||
if (conversationDeleting) return;
|
||||
|
||||
try {
|
||||
setConversationDeleting(true)
|
||||
await delConversation(conversationId)
|
||||
notify({ type: 'success', message: t('common.api.success') })
|
||||
onSuccess()
|
||||
}
|
||||
finally {
|
||||
setConversationDeleting(false)
|
||||
}
|
||||
try {
|
||||
setConversationDeleting(true);
|
||||
await delConversation(conversationId);
|
||||
notify({ type: "success", message: t("common.api.success") });
|
||||
onSuccess();
|
||||
} finally {
|
||||
setConversationDeleting(false);
|
||||
}
|
||||
|
||||
if (conversationId === currentConversationId)
|
||||
handleNewConversation()
|
||||
if (conversationId === currentConversationId) handleNewConversation();
|
||||
|
||||
handleUpdateConversationList()
|
||||
}, [isInstalledApp, appId, notify, t, handleUpdateConversationList, handleNewConversation, currentConversationId, conversationDeleting])
|
||||
handleUpdateConversationList();
|
||||
},
|
||||
[
|
||||
isInstalledApp,
|
||||
appId,
|
||||
notify,
|
||||
t,
|
||||
handleUpdateConversationList,
|
||||
handleNewConversation,
|
||||
currentConversationId,
|
||||
conversationDeleting,
|
||||
]
|
||||
);
|
||||
|
||||
const [conversationRenaming, setConversationRenaming] = useState(false)
|
||||
const handleRenameConversation = useCallback(async (
|
||||
conversationId: string,
|
||||
newName: string,
|
||||
{
|
||||
onSuccess,
|
||||
}: Callback,
|
||||
) => {
|
||||
if (conversationRenaming)
|
||||
return
|
||||
const [conversationRenaming, setConversationRenaming] = useState(false);
|
||||
const handleRenameConversation = useCallback(
|
||||
async (
|
||||
conversationId: string,
|
||||
newName: string,
|
||||
{ onSuccess }: Callback
|
||||
) => {
|
||||
if (conversationRenaming) return;
|
||||
|
||||
if (!newName.trim()) {
|
||||
notify({
|
||||
type: 'error',
|
||||
message: t('common.chat.conversationNameCanNotEmpty'),
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!newName.trim()) {
|
||||
notify({
|
||||
type: "error",
|
||||
message: t("common.chat.conversationNameCanNotEmpty"),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
setConversationRenaming(true)
|
||||
try {
|
||||
await renameConversation(conversationId, newName)
|
||||
setConversationRenaming(true);
|
||||
try {
|
||||
await renameConversation(conversationId, newName);
|
||||
|
||||
notify({
|
||||
type: 'success',
|
||||
message: t('common.actionMsg.modifiedSuccessfully'),
|
||||
})
|
||||
setOriginConversationList(produce((draft) => {
|
||||
const index = originConversationList.findIndex(item => item.id === conversationId)
|
||||
const item = draft[index]
|
||||
notify({
|
||||
type: "success",
|
||||
message: t("common.actionMsg.modifiedSuccessfully"),
|
||||
});
|
||||
setOriginConversationList(
|
||||
produce((draft) => {
|
||||
const index = originConversationList.findIndex(
|
||||
(item) => item.id === conversationId
|
||||
);
|
||||
const item = draft[index];
|
||||
|
||||
draft[index] = {
|
||||
...item,
|
||||
name: newName,
|
||||
}
|
||||
}))
|
||||
onSuccess()
|
||||
}
|
||||
finally {
|
||||
setConversationRenaming(false)
|
||||
}
|
||||
}, [isInstalledApp, appId, notify, t, conversationRenaming, originConversationList])
|
||||
draft[index] = {
|
||||
...item,
|
||||
name: newName,
|
||||
};
|
||||
})
|
||||
);
|
||||
onSuccess();
|
||||
} finally {
|
||||
setConversationRenaming(false);
|
||||
}
|
||||
},
|
||||
[
|
||||
isInstalledApp,
|
||||
appId,
|
||||
notify,
|
||||
t,
|
||||
conversationRenaming,
|
||||
originConversationList,
|
||||
]
|
||||
);
|
||||
|
||||
const handleNewConversationCompleted = useCallback((newConversationId: string) => {
|
||||
setNewConversationId(newConversationId)
|
||||
handleConversationIdInfoChange(newConversationId)
|
||||
setShowNewConversationItemInList(false)
|
||||
mutateAppConversationData()
|
||||
}, [mutateAppConversationData, handleConversationIdInfoChange])
|
||||
const handleNewConversationCompleted = useCallback(
|
||||
(newConversationId: string) => {
|
||||
setNewConversationId(newConversationId);
|
||||
handleConversationIdInfoChange(newConversationId);
|
||||
setShowNewConversationItemInList(false);
|
||||
mutateAppConversationData();
|
||||
},
|
||||
[mutateAppConversationData, handleConversationIdInfoChange]
|
||||
);
|
||||
|
||||
const handleFeedback = useCallback(async (messageId: string, feedback: Feedback) => {
|
||||
await updateFeedback({ url: `/messages/${messageId}/feedbacks`, body: { rating: feedback.rating } }, isInstalledApp, appId)
|
||||
notify({ type: 'success', message: t('common.api.success') })
|
||||
}, [isInstalledApp, appId, t, notify])
|
||||
const [isFeedbackModalVisible, setIsFeedbackModalVisible] = useState(false);
|
||||
const [currentMessageId, setCurrentMessageId] = useState<string | null>(null);
|
||||
const [currentFeedback, setCurrentFeedback] = useState<Feedback | null>(null);
|
||||
const [
|
||||
currentConversationIdForFeedback,
|
||||
setCurrentConversationIdForFeedback,
|
||||
] = useState<string | null>(null);
|
||||
|
||||
const handleFeedback = useCallback(
|
||||
(messageId: string, feedback: Feedback, conversationId: string) => {
|
||||
setCurrentMessageId(messageId);
|
||||
setCurrentFeedback(feedback);
|
||||
setCurrentConversationIdForFeedback(conversationId);
|
||||
setIsFeedbackModalVisible(true);
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const handleFeedbackSubmit = useCallback(
|
||||
async (selectedOption: number | null, feedbackText: string) => {
|
||||
console.log(currentMessageId);
|
||||
console.log(currentFeedback);
|
||||
|
||||
try {
|
||||
// 构造请求参数
|
||||
const requestBody = {
|
||||
operationType: selectedOption, // 0 或 1
|
||||
feedbackText, // 用户反馈建议
|
||||
conversationId: '89fba8a7-e4e2-4167-8b7c-b3c103797053', // 会话 ID
|
||||
messageId: currentMessageId, // 消息 ID
|
||||
username: "user_admin", // 用户名
|
||||
};
|
||||
|
||||
// 调用 Java 接口
|
||||
const javaResponse = await fetch(
|
||||
`${process.env.NEXT_PUBLIC_BASE_API_URL}/api/conversation/feedback`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(requestBody),
|
||||
}
|
||||
);
|
||||
|
||||
// 调用原有的 updateFeedback 函数
|
||||
await updateFeedback(
|
||||
{
|
||||
url: `/messages/${currentMessageId}/feedbacks`,
|
||||
body: { rating: currentFeedback.rating },
|
||||
},
|
||||
isInstalledApp,
|
||||
appId
|
||||
);
|
||||
|
||||
// 显示成功通知
|
||||
notify({ type: "success", message: t("common.api.success") });
|
||||
|
||||
// 关闭对话框
|
||||
setIsFeedbackModalVisible(false);
|
||||
} catch (error) {
|
||||
console.error("Error:", error);
|
||||
notify({ type: "error", message: t("common.api.failed") });
|
||||
}
|
||||
},
|
||||
[
|
||||
currentMessageId,
|
||||
currentFeedback,
|
||||
currentConversationIdForFeedback,
|
||||
isInstalledApp,
|
||||
appId,
|
||||
notify,
|
||||
t,
|
||||
]
|
||||
);
|
||||
|
||||
return {
|
||||
appInfoError,
|
||||
@ -427,7 +614,7 @@ export const useChatWithHistory = (installedAppInfo?: InstalledApp) => {
|
||||
currentConversationItem,
|
||||
handleConversationIdInfoChange,
|
||||
appData,
|
||||
appParams: appParams || {} as ChatConfig,
|
||||
appParams: appParams || ({} as ChatConfig),
|
||||
appMeta,
|
||||
appPinnedConversationData,
|
||||
appConversationData,
|
||||
@ -458,5 +645,12 @@ export const useChatWithHistory = (installedAppInfo?: InstalledApp) => {
|
||||
chatShouldReloadKey,
|
||||
handleFeedback,
|
||||
currentChatInstanceRef,
|
||||
}
|
||||
}
|
||||
feedbackModal: (
|
||||
<FeedbackModal
|
||||
open={isFeedbackModalVisible}
|
||||
onOk={handleFeedbackSubmit}
|
||||
onCancel={() => setIsFeedbackModalVisible(false)}
|
||||
/>
|
||||
),
|
||||
};
|
||||
};
|
||||
|
||||
@ -1,33 +1,26 @@
|
||||
import type { FC } from 'react'
|
||||
import {
|
||||
useEffect,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { useAsyncEffect } from 'ahooks'
|
||||
import { useThemeContext } from '@/app/components/chat/embedded-chatbot/theme/theme-context'
|
||||
import {
|
||||
ChatWithHistoryContext,
|
||||
useChatWithHistoryContext,
|
||||
} from './context'
|
||||
import { useChatWithHistory } from './hooks'
|
||||
import Sidebar from './sidebar'
|
||||
import HeaderInMobile from './header-in-mobile'
|
||||
import ConfigPanel from './config-panel'
|
||||
import ChatWrapper from './chat-wrapper'
|
||||
import type { InstalledApp } from '@/models/explore'
|
||||
import Loading from '@/app/components/base/loading'
|
||||
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import AppUnavailable from '@/app/components/base/app-unavailable'
|
||||
import type { FC } from "react";
|
||||
import "antd/dist/reset.css"; // 引入 antd 的样式
|
||||
import { useEffect, useState } from "react";
|
||||
import { useAsyncEffect } from "ahooks";
|
||||
import { useThemeContext } from "@/app/components/chat/embedded-chatbot/theme/theme-context";
|
||||
import { ChatWithHistoryContext, useChatWithHistoryContext } from "./context";
|
||||
import { useChatWithHistory } from "./hooks";
|
||||
import Sidebar from "./sidebar";
|
||||
import HeaderInMobile from "./header-in-mobile";
|
||||
import ConfigPanel from "./config-panel";
|
||||
import ChatWrapper from "./chat-wrapper";
|
||||
import type { InstalledApp } from "@/models/explore";
|
||||
import Loading from "@/app/components/base/loading";
|
||||
import useBreakpoints, { MediaType } from "@/hooks/use-breakpoints";
|
||||
import { useRouter } from "next/navigation";
|
||||
import AppUnavailable from "@/app/components/base/app-unavailable";
|
||||
|
||||
type ChatWithHistoryProps = {
|
||||
className?: string
|
||||
userStr?: string
|
||||
}
|
||||
const ChatWithHistory: FC<ChatWithHistoryProps> = ({
|
||||
className,
|
||||
userStr,
|
||||
}) => {
|
||||
className?: string;
|
||||
userStr?: string;
|
||||
};
|
||||
|
||||
const ChatWithHistory: FC<ChatWithHistoryProps> = ({ className, userStr }) => {
|
||||
const {
|
||||
appInfoError,
|
||||
appData,
|
||||
@ -38,82 +31,78 @@ const ChatWithHistory: FC<ChatWithHistoryProps> = ({
|
||||
chatShouldReloadKey,
|
||||
isMobile,
|
||||
themeBuilder,
|
||||
} = useChatWithHistoryContext()
|
||||
} = useChatWithHistoryContext();
|
||||
|
||||
const chatReady = (!showConfigPanelBeforeChat || !!appPrevChatTree.length)
|
||||
const customConfig = appData?.custom_config
|
||||
const site = appData?.site
|
||||
const chatReady = !showConfigPanelBeforeChat || !!appPrevChatTree.length;
|
||||
const customConfig = appData?.custom_config;
|
||||
const site = appData?.site;
|
||||
|
||||
useEffect(() => {
|
||||
themeBuilder?.buildTheme(site?.chat_color_theme, site?.chat_color_theme_inverted)
|
||||
themeBuilder?.buildTheme(
|
||||
site?.chat_color_theme,
|
||||
site?.chat_color_theme_inverted
|
||||
);
|
||||
if (site) {
|
||||
if (customConfig)
|
||||
document.title = `${site.title}`
|
||||
else
|
||||
document.title = `${site.title} - Powered by Dify`
|
||||
if (customConfig) document.title = `${site.title}`;
|
||||
else document.title = `${site.title} - Powered by Dify`;
|
||||
}
|
||||
}, [site, customConfig, themeBuilder])
|
||||
}, [site, customConfig, themeBuilder]);
|
||||
|
||||
if (appInfoLoading) {
|
||||
return (
|
||||
<Loading type='app' />
|
||||
)
|
||||
return <Loading type="app" />;
|
||||
}
|
||||
|
||||
if (appInfoError) {
|
||||
return (
|
||||
<AppUnavailable />
|
||||
)
|
||||
return <AppUnavailable />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`h-full flex bg-white ${className} ${isMobile && 'flex-col'}`}>
|
||||
{
|
||||
!isMobile && (
|
||||
<Sidebar userStr={userStr} />
|
||||
)
|
||||
}
|
||||
{
|
||||
isMobile && (
|
||||
<HeaderInMobile />
|
||||
)
|
||||
}
|
||||
<div className={`grow overflow-hidden ${showConfigPanelBeforeChat && !appPrevChatTree.length && 'flex items-center justify-center'}`}>
|
||||
{
|
||||
showConfigPanelBeforeChat && !appChatListDataLoading && !appPrevChatTree.length && (
|
||||
<div className={`flex w-full items-center justify-center h-full ${isMobile && 'px-4'}`}>
|
||||
<div
|
||||
className={`h-full flex bg-white ${className} ${isMobile && "flex-col"}`}
|
||||
>
|
||||
{!isMobile && <Sidebar userStr={userStr} />}
|
||||
{isMobile && <HeaderInMobile />}
|
||||
<div
|
||||
className={`grow overflow-hidden ${
|
||||
showConfigPanelBeforeChat &&
|
||||
!appPrevChatTree.length &&
|
||||
"flex items-center justify-center"
|
||||
}`}
|
||||
>
|
||||
{showConfigPanelBeforeChat &&
|
||||
!appChatListDataLoading &&
|
||||
!appPrevChatTree.length && (
|
||||
<div
|
||||
className={`flex w-full items-center justify-center h-full ${
|
||||
isMobile && "px-4"
|
||||
}`}
|
||||
>
|
||||
<ConfigPanel />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
{
|
||||
appChatListDataLoading && chatReady && (
|
||||
<Loading type='app' />
|
||||
)
|
||||
}
|
||||
{
|
||||
chatReady && !appChatListDataLoading && (
|
||||
<ChatWrapper key={chatShouldReloadKey} />
|
||||
)
|
||||
}
|
||||
)}
|
||||
{appChatListDataLoading && chatReady && <Loading type="app" />}
|
||||
{chatReady && !appChatListDataLoading && (
|
||||
<ChatWrapper key={chatShouldReloadKey} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export type ChatWithHistoryWrapProps = {
|
||||
installedAppInfo?: InstalledApp
|
||||
className?: string
|
||||
userStr?: string
|
||||
}
|
||||
installedAppInfo?: InstalledApp;
|
||||
className?: string;
|
||||
userStr?: string;
|
||||
};
|
||||
|
||||
const ChatWithHistoryWrap: FC<ChatWithHistoryWrapProps> = ({
|
||||
installedAppInfo,
|
||||
className,
|
||||
userStr,
|
||||
}) => {
|
||||
const media = useBreakpoints()
|
||||
const isMobile = media === MediaType.mobile
|
||||
const themeBuilder = useThemeContext()
|
||||
const media = useBreakpoints();
|
||||
const isMobile = media === MediaType.mobile;
|
||||
const themeBuilder = useThemeContext();
|
||||
|
||||
const {
|
||||
appInfoError,
|
||||
@ -146,93 +135,99 @@ const ChatWithHistoryWrap: FC<ChatWithHistoryWrapProps> = ({
|
||||
appId,
|
||||
handleFeedback,
|
||||
currentChatInstanceRef,
|
||||
} = useChatWithHistory(installedAppInfo)
|
||||
feedbackModal,
|
||||
} = useChatWithHistory(installedAppInfo);
|
||||
|
||||
return (
|
||||
<ChatWithHistoryContext.Provider value={{
|
||||
appInfoError,
|
||||
appInfoLoading,
|
||||
appData,
|
||||
appParams,
|
||||
appMeta,
|
||||
appChatListDataLoading,
|
||||
currentConversationId,
|
||||
currentConversationItem,
|
||||
appPrevChatTree,
|
||||
pinnedConversationList,
|
||||
conversationList,
|
||||
showConfigPanelBeforeChat,
|
||||
newConversationInputs,
|
||||
newConversationInputsRef,
|
||||
handleNewConversationInputsChange,
|
||||
inputsForms,
|
||||
handleNewConversation,
|
||||
handleStartChat,
|
||||
handleChangeConversation,
|
||||
handlePinConversation,
|
||||
handleUnpinConversation,
|
||||
handleDeleteConversation,
|
||||
conversationRenaming,
|
||||
handleRenameConversation,
|
||||
handleNewConversationCompleted,
|
||||
chatShouldReloadKey,
|
||||
isMobile,
|
||||
isInstalledApp,
|
||||
appId,
|
||||
handleFeedback,
|
||||
currentChatInstanceRef,
|
||||
themeBuilder,
|
||||
}}>
|
||||
<ChatWithHistoryContext.Provider
|
||||
value={{
|
||||
appInfoError,
|
||||
appInfoLoading,
|
||||
appData,
|
||||
appParams,
|
||||
appMeta,
|
||||
appChatListDataLoading,
|
||||
currentConversationId,
|
||||
currentConversationItem,
|
||||
appPrevChatTree,
|
||||
pinnedConversationList,
|
||||
conversationList,
|
||||
showConfigPanelBeforeChat,
|
||||
newConversationInputs,
|
||||
newConversationInputsRef,
|
||||
handleNewConversationInputsChange,
|
||||
inputsForms,
|
||||
handleNewConversation,
|
||||
handleStartChat,
|
||||
handleChangeConversation,
|
||||
handlePinConversation,
|
||||
handleUnpinConversation,
|
||||
handleDeleteConversation,
|
||||
conversationRenaming,
|
||||
handleRenameConversation,
|
||||
handleNewConversationCompleted,
|
||||
chatShouldReloadKey,
|
||||
isMobile,
|
||||
isInstalledApp,
|
||||
appId,
|
||||
handleFeedback,
|
||||
currentChatInstanceRef,
|
||||
themeBuilder,
|
||||
}}
|
||||
>
|
||||
<ChatWithHistory className={className} userStr={userStr} />
|
||||
{feedbackModal} {/* 确保 feedbackModal 正确渲染 */}
|
||||
</ChatWithHistoryContext.Provider>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const ChatWithHistoryWrapWithCheckToken: FC<ChatWithHistoryWrapProps> = ({
|
||||
installedAppInfo,
|
||||
className,
|
||||
}) => {
|
||||
const [initialized, setInitialized] = useState(false)
|
||||
const [appUnavailable, setAppUnavailable] = useState<boolean>(false)
|
||||
const [resCode, setResCode] = useState<number>(200)
|
||||
const router = useRouter()
|
||||
const [userName, setUserName] = useState('')
|
||||
const [nickName, setNickName] = useState('')
|
||||
const [initialized, setInitialized] = useState(false);
|
||||
const [appUnavailable, setAppUnavailable] = useState<boolean>(false);
|
||||
const [resCode, setResCode] = useState<number>(200);
|
||||
const router = useRouter();
|
||||
const [userName, setUserName] = useState("");
|
||||
const [nickName, setNickName] = useState("");
|
||||
|
||||
useAsyncEffect(async () => {
|
||||
if (!initialized) {
|
||||
if (!installedAppInfo) {
|
||||
const accessToken = localStorage.getItem('token')
|
||||
const accessToken = localStorage.getItem("token");
|
||||
if (!accessToken) {
|
||||
router.replace('/login')
|
||||
router.replace("/login");
|
||||
} else {
|
||||
fetch(`${process.env.NEXT_PUBLIC_BASE_API_URL}/getInfo`, {
|
||||
method: 'GET',
|
||||
method: "GET",
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
}).then(res => res.json()).then(data => {
|
||||
if (data.code !== 200) {
|
||||
localStorage.removeItem('token')
|
||||
router.replace('/login')
|
||||
} else {
|
||||
setUserName(data.user.userName)
|
||||
setNickName(data.user.nickName)
|
||||
}
|
||||
}).catch(() => {
|
||||
setResCode(500)
|
||||
setAppUnavailable(true)
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((data) => {
|
||||
if (data.code !== 200) {
|
||||
localStorage.removeItem("token");
|
||||
router.replace("/login");
|
||||
} else {
|
||||
setUserName(data.user.userName);
|
||||
setNickName(data.user.nickName);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
setResCode(500);
|
||||
setAppUnavailable(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
setInitialized(true)
|
||||
setInitialized(true);
|
||||
}
|
||||
}, [])
|
||||
}, []);
|
||||
|
||||
if (!initialized)
|
||||
return null
|
||||
if (!initialized) return null;
|
||||
|
||||
if (appUnavailable)
|
||||
return <AppUnavailable code={resCode} />
|
||||
if (appUnavailable) return <AppUnavailable code={resCode} />;
|
||||
|
||||
return (
|
||||
<ChatWithHistoryWrap
|
||||
@ -240,7 +235,7 @@ const ChatWithHistoryWrapWithCheckToken: FC<ChatWithHistoryWrapProps> = ({
|
||||
className={className}
|
||||
userStr={`${nickName}[${userName}]`}
|
||||
/>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export default ChatWithHistoryWrapWithCheckToken
|
||||
export default ChatWithHistoryWrapWithCheckToken;
|
||||
|
||||
@ -1,34 +1,32 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
devIndicators: false, // show dev tools
|
||||
productionBrowserSourceMaps: false, // enable browser source map generation during the production build
|
||||
// Configure pageExtensions to include md and mdx
|
||||
pageExtensions: ['ts', 'tsx', 'js', 'jsx', 'md', 'mdx'],
|
||||
experimental: {
|
||||
// appDir: true,
|
||||
reactStrictMode: true,
|
||||
// 压缩优化(Next.js 13+默认启用SWC,无需手动配置)
|
||||
compress: true,
|
||||
|
||||
// 图片优化
|
||||
images: {
|
||||
formats: ["image/avif", "image/webp"],
|
||||
domains: ["cdn.yourdomain.com"],
|
||||
},
|
||||
// fix all before production. Now it slow the develop speed.
|
||||
eslint: {
|
||||
// Warning: This allows production builds to successfully complete even if
|
||||
// your project has ESLint errors.
|
||||
ignoreDuringBuilds: true,
|
||||
},
|
||||
typescript: {
|
||||
// https://nextjs.org/docs/api-reference/next.config.js/ignoring-typescript-errors
|
||||
ignoreBuildErrors: true,
|
||||
|
||||
// 修正后的开发指示器配置
|
||||
devIndicators: {
|
||||
position: "bottom-right", // 新版统一用position
|
||||
},
|
||||
|
||||
// 页面扩展名
|
||||
pageExtensions: ["ts", "tsx", "js", "jsx", "md", "mdx"],
|
||||
|
||||
// 路由重写
|
||||
async rewrites() {
|
||||
return [
|
||||
{
|
||||
source: '/files/:path*',
|
||||
destination: `${process.env.NEXT_PUBLIC_FILES_URL}/:path*`,
|
||||
source: "/dev-api/:path*",
|
||||
destination: "http://192.168.6.9:8085/:path*",
|
||||
},
|
||||
{
|
||||
source: '/dev-api/:path*',
|
||||
destination: 'http://192.168.6.9:8085/:path*',
|
||||
},
|
||||
]
|
||||
];
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = nextConfig
|
||||
module.exports = nextConfig;
|
||||
|
||||
@ -44,9 +44,9 @@ export const fetchConversations = async (limit = 100, last_id = null) => {
|
||||
return get('conversations', { params: { limit, last_id } })
|
||||
}
|
||||
|
||||
export const fetchChatList = async (conversationId: string, limit = 20, last_id = null) => {
|
||||
export const fetchChatList = async (conversationId: string, limit = 20) => {
|
||||
return get('messages', {
|
||||
params: { conversation_id: conversationId, limit, last_id }
|
||||
params: { conversation_id: conversationId, limit}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user