|
|
@@ -512,7 +512,9 @@ function useScrollToBottom(
|
|
|
}
|
|
|
|
|
|
export function ChatActions(props: {
|
|
|
+ isClickStop: boolean,
|
|
|
sendStatus: boolean,
|
|
|
+ setSendStatus: (status: boolean) => void;
|
|
|
setUserInput: (value: string) => void;
|
|
|
doSubmit: (userInput: string) => void;
|
|
|
uploadImage: () => void;
|
|
|
@@ -640,6 +642,13 @@ export function ChatActions(props: {
|
|
|
}
|
|
|
}, [chatStore.message]);
|
|
|
|
|
|
+ useEffect(() => {
|
|
|
+ if (props.isClickStop) {
|
|
|
+ props.setSendStatus(false);
|
|
|
+ setGuessList([]);
|
|
|
+ }
|
|
|
+ }, [props.isClickStop])
|
|
|
+
|
|
|
return (
|
|
|
<div className={styles["chat-input-actions"]}>
|
|
|
{
|
|
|
@@ -939,6 +948,7 @@ function _Chat() {
|
|
|
const chatStore = useChatStore();
|
|
|
const session = chatStore.currentSession();
|
|
|
const config = useAppConfig();
|
|
|
+ config.sendPreviewBubble = false;
|
|
|
const fontSize = config.fontSize;
|
|
|
const fontFamily = config.fontFamily;
|
|
|
|
|
|
@@ -1024,8 +1034,10 @@ function _Chat() {
|
|
|
setAppList(list);
|
|
|
let appValue = '';
|
|
|
const search = location.search;
|
|
|
- if (search.startsWith('?appId=')) {
|
|
|
- const value = search.slice(7);
|
|
|
+ const params = new URLSearchParams(search);
|
|
|
+ const appId = params.get('appId');
|
|
|
+ if (appId) {
|
|
|
+ const value = appId;
|
|
|
if (list.find((item: any) => item.value === value)) {
|
|
|
appValue = value;
|
|
|
} else {
|
|
|
@@ -1591,102 +1603,112 @@ function _Chat() {
|
|
|
|
|
|
const stopAll = () => ChatControllerPool.stopAll();
|
|
|
|
|
|
+ const [isClickStop, setIsClickStop] = useState(false);
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ if (!couldStop) {
|
|
|
+ setIsClickStop(false)
|
|
|
+ }
|
|
|
+ }, [couldStop])
|
|
|
+
|
|
|
return (
|
|
|
<div className={styles.chat} key={session.id}>
|
|
|
- <div className="window-header" data-tauri-drag-region>
|
|
|
- <div style={{ display: 'flex', alignItems: 'center' }}
|
|
|
- className={`window-header-title ${styles["chat-body-title"]}`}>
|
|
|
- <div>
|
|
|
- {
|
|
|
- isMobileScreen &&
|
|
|
- <IconButton
|
|
|
- style={{ padding: 0, marginRight: 20 }}
|
|
|
- icon={<LeftIcon />}
|
|
|
- text={Locale.NewChat.Return}
|
|
|
- onClick={() => navigate('/knowledgeChat')}
|
|
|
- />
|
|
|
- }
|
|
|
- </div>
|
|
|
- <div>
|
|
|
-
|
|
|
- <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
|
|
|
- <Select
|
|
|
- style={{ width: '100%', height: 38, marginRight: 5 }}
|
|
|
- value={selectedFruit}
|
|
|
- onChange={(value: "ONLINE" | "LOCAL") => {
|
|
|
- chatStore.clearSessions();
|
|
|
- chatStore.updateCurrentSession((values) => {
|
|
|
- values.appId = globalStore.selectedAppId;
|
|
|
- });
|
|
|
- navigate({ pathname: '/newChat' });
|
|
|
- setSelectedFruit(value);
|
|
|
- chatStore.setChatMode(value);
|
|
|
- }}
|
|
|
- >
|
|
|
- {fruits.map(fruit => (
|
|
|
- <Select.Option key={fruit.id} value={fruit.id}>
|
|
|
- {fruit.name}
|
|
|
- </Select.Option>
|
|
|
- ))}
|
|
|
- </Select>
|
|
|
+ {
|
|
|
+ !location.search.includes('showMenu=false') &&
|
|
|
+ <div className="window-header" data-tauri-drag-region>
|
|
|
+ <div style={{ display: 'flex', alignItems: 'center' }}
|
|
|
+ className={`window-header-title ${styles["chat-body-title"]}`}>
|
|
|
+ <div>
|
|
|
{
|
|
|
- appList.length > 0 ?
|
|
|
- <Select
|
|
|
- style={{ width: '100%', height: 38, marginRight: 5 }}
|
|
|
- placeholder='请选择'
|
|
|
- options={appList}
|
|
|
- value={appValue}
|
|
|
- onChange={(value) => {
|
|
|
- setAppValue(value);
|
|
|
- globalStore.setSelectedAppId(value);
|
|
|
- chatStore.clearSessions();
|
|
|
- chatStore.updateCurrentSession((values) => {
|
|
|
- values.appId = value;
|
|
|
- });
|
|
|
- useChatStore.setState({
|
|
|
- message: {
|
|
|
- content: '',
|
|
|
- role: 'assistant',
|
|
|
- }
|
|
|
- });
|
|
|
- setSendStatus(false);
|
|
|
- }}
|
|
|
- />
|
|
|
- :
|
|
|
- null
|
|
|
+ isMobileScreen &&
|
|
|
+ <IconButton
|
|
|
+ style={{ padding: 0, marginRight: 20 }}
|
|
|
+ icon={<LeftIcon />}
|
|
|
+ text={Locale.NewChat.Return}
|
|
|
+ onClick={() => navigate('/knowledgeChat')}
|
|
|
+ />
|
|
|
}
|
|
|
</div>
|
|
|
+ <div>
|
|
|
+
|
|
|
+ <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
|
|
|
+ <Select
|
|
|
+ style={{ width: '100%', height: 38, marginRight: 5 }}
|
|
|
+ value={selectedFruit}
|
|
|
+ onChange={(value: "ONLINE" | "LOCAL") => {
|
|
|
+ chatStore.clearSessions();
|
|
|
+ chatStore.updateCurrentSession((values) => {
|
|
|
+ values.appId = globalStore.selectedAppId;
|
|
|
+ });
|
|
|
+ navigate({ pathname: '/newChat' });
|
|
|
+ setSelectedFruit(value);
|
|
|
+ chatStore.setChatMode(value);
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ {fruits.map(fruit => (
|
|
|
+ <Select.Option key={fruit.id} value={fruit.id}>
|
|
|
+ {fruit.name}
|
|
|
+ </Select.Option>
|
|
|
+ ))}
|
|
|
+ </Select>
|
|
|
+ {
|
|
|
+ appList.length > 0 ?
|
|
|
+ <Select
|
|
|
+ style={{ width: '100%', height: 38, marginRight: 5 }}
|
|
|
+ placeholder='请选择'
|
|
|
+ options={appList}
|
|
|
+ value={appValue}
|
|
|
+ onChange={(value) => {
|
|
|
+ setAppValue(value);
|
|
|
+ globalStore.setSelectedAppId(value);
|
|
|
+ chatStore.clearSessions();
|
|
|
+ chatStore.updateCurrentSession((values) => {
|
|
|
+ values.appId = value;
|
|
|
+ });
|
|
|
+ useChatStore.setState({
|
|
|
+ message: {
|
|
|
+ content: '',
|
|
|
+ role: 'assistant',
|
|
|
+ }
|
|
|
+ });
|
|
|
+ setSendStatus(false);
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ :
|
|
|
+ null
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
|
|
|
- <div className="window-actions">
|
|
|
- <div className="window-action-button">
|
|
|
- <Popover
|
|
|
- trigger="click"
|
|
|
- title="分享"
|
|
|
- content={() => {
|
|
|
- const url = `${window.location.origin}/#/knowledgeChat?appId=${appValue}`
|
|
|
- return <div>
|
|
|
- <div style={{ marginBottom: 10 }}>
|
|
|
- {url}
|
|
|
+ <div className="window-actions">
|
|
|
+ <div className="window-action-button">
|
|
|
+ <Popover
|
|
|
+ trigger="click"
|
|
|
+ title="分享该应用"
|
|
|
+ content={() => {
|
|
|
+ const url = `${window.location.origin}/#/knowledgeChat?showMenu=false&appId=${appValue}`
|
|
|
+ return <div>
|
|
|
+ <div style={{ marginBottom: 10 }}>
|
|
|
+ {url}
|
|
|
+ </div>
|
|
|
+ <Button onClick={() => {
|
|
|
+ navigator.clipboard.writeText(url);
|
|
|
+ message.success('分享链接已复制到剪贴板');
|
|
|
+ }}>
|
|
|
+ 复制
|
|
|
+ </Button>
|
|
|
</div>
|
|
|
- <Button onClick={() => {
|
|
|
- navigator.clipboard.writeText(url);
|
|
|
- message.success('分享链接已复制到剪贴板');
|
|
|
- }}>
|
|
|
- 复制
|
|
|
- </Button>
|
|
|
- </div>
|
|
|
- }
|
|
|
- }>
|
|
|
- <IconButton
|
|
|
- icon={<ExportIcon />}
|
|
|
- bordered
|
|
|
- title={Locale.Chat.Actions.Export}
|
|
|
- />
|
|
|
- </Popover>
|
|
|
- </div>
|
|
|
- {/* {showMaxIcon && (
|
|
|
+ }
|
|
|
+ }>
|
|
|
+ <IconButton
|
|
|
+ icon={<ExportIcon />}
|
|
|
+ bordered
|
|
|
+ title={Locale.Chat.Actions.Export}
|
|
|
+ />
|
|
|
+ </Popover>
|
|
|
+ </div>
|
|
|
+ {/* {showMaxIcon && (
|
|
|
<div className="window-action-button">
|
|
|
<IconButton
|
|
|
icon={config.tightBorder ? <MinIcon /> : <MaxIcon />}
|
|
|
@@ -1701,13 +1723,14 @@ function _Chat() {
|
|
|
/>
|
|
|
</div>
|
|
|
)} */}
|
|
|
- </div>
|
|
|
- {/* <PromptToast
|
|
|
+ </div>
|
|
|
+ {/* <PromptToast
|
|
|
showToast={!hitBottom}
|
|
|
showModal={showPromptModal}
|
|
|
setShowModal={setShowPromptModal}
|
|
|
/> */}
|
|
|
- </div>
|
|
|
+ </div>
|
|
|
+ }
|
|
|
<div
|
|
|
className={styles["chat-body"]}
|
|
|
ref={scrollRef}
|
|
|
@@ -1742,58 +1765,9 @@ function _Chat() {
|
|
|
<div className={styles["chat-message-container"]}>
|
|
|
<div className={styles["chat-message-header"]}>
|
|
|
<div className={styles["chat-message-avatar"]}>
|
|
|
- {/* <div className={styles["chat-message-edit"]}>
|
|
|
- <IconButton
|
|
|
- icon={<EditIcon />}
|
|
|
- aria={Locale.Chat.Actions.Edit}
|
|
|
- onClick={async () => {
|
|
|
- const newMessage = await showPrompt(
|
|
|
- Locale.Chat.Actions.Edit,
|
|
|
- getMessageTextContent(message),
|
|
|
- 10,
|
|
|
- );
|
|
|
- let newContent: string | MultimodalContent[] =
|
|
|
- newMessage;
|
|
|
- const images = getMessageImages(message);
|
|
|
- if (images.length > 0) {
|
|
|
- newContent = [{ type: "text", text: newMessage }];
|
|
|
- for (let i = 0; i < images.length; i++) {
|
|
|
- newContent.push({
|
|
|
- type: "image_url",
|
|
|
- image_url: {
|
|
|
- url: images[i],
|
|
|
- },
|
|
|
- });
|
|
|
- }
|
|
|
- }
|
|
|
- chatStore.updateCurrentSession((session) => {
|
|
|
- const m = session.mask.context
|
|
|
- .concat(session.messages)
|
|
|
- .find((m) => m.id === message.id);
|
|
|
- if (m) {
|
|
|
- m.content = newContent;
|
|
|
- }
|
|
|
- });
|
|
|
- }}
|
|
|
- ></IconButton>
|
|
|
- </div> */}
|
|
|
{isUser ? (
|
|
|
// 在这里换头像
|
|
|
<div style={{ position: 'relative' }}>
|
|
|
- {/* <MaskAvatar */}
|
|
|
- {/* avatar={session.mask.avatar} */}
|
|
|
- {/* /> */}
|
|
|
- {/* <div */}
|
|
|
- {/* style={{ */}
|
|
|
- {/* position: 'absolute', */}
|
|
|
- {/* zIndex: 2, */}
|
|
|
- {/* top: '50%', */}
|
|
|
- {/* left: '50%', */}
|
|
|
- {/* transform: ' translate(-50%, -50%)', */}
|
|
|
- {/* fontSize: 14, */}
|
|
|
- {/* }}> */}
|
|
|
- {/* 我 */}
|
|
|
- {/* </div> */}
|
|
|
<div
|
|
|
style={{
|
|
|
position: 'absolute',
|
|
|
@@ -1867,7 +1841,7 @@ function _Chat() {
|
|
|
{
|
|
|
showTyping ?
|
|
|
<div className={styles["chat-message-status"]}>
|
|
|
- {isUser ? '正在输入…' : '正在查询文档…'}
|
|
|
+ {isUser ? '' : '正在查询文档…'}
|
|
|
</div>
|
|
|
:
|
|
|
<div className={styles["chat-message-status"]}>
|
|
|
@@ -1994,7 +1968,9 @@ function _Chat() {
|
|
|
<div className={styles["chat-input-panel"]}>
|
|
|
{/* <PromptHints prompts={promptHints} onPromptSelect={onPromptSelect} /> */}
|
|
|
<ChatActions
|
|
|
+ isClickStop={isClickStop}
|
|
|
sendStatus={sendStatus}
|
|
|
+ setSendStatus={setSendStatus}
|
|
|
setUserInput={setUserInput}
|
|
|
doSubmit={doSubmit}
|
|
|
uploadImage={uploadImage}
|
|
|
@@ -2072,6 +2048,7 @@ function _Chat() {
|
|
|
onClick={() => {
|
|
|
if (couldStop) {
|
|
|
stopAll();
|
|
|
+ setIsClickStop(true);
|
|
|
} else {
|
|
|
doSubmit(userInput);
|
|
|
}
|