Commit 7cca1b38 authored by Ylg's avatar Ylg

add request response intercept and resolve file conflict

parents 60ab9523 8b542a3f
...@@ -50,6 +50,7 @@ ...@@ -50,6 +50,7 @@
"@ant-design/icons": "^4.7.0", "@ant-design/icons": "^4.7.0",
"@ant-design/pro-components": "1.1.1", "@ant-design/pro-components": "1.1.1",
"@umijs/route-utils": "^2.0.0", "@umijs/route-utils": "^2.0.0",
"ahooks": "^3.7.6",
"antd": "^4.20.0", "antd": "^4.20.0",
"classnames": "^2.3.0", "classnames": "^2.3.0",
"lodash": "^4.17.0", "lodash": "^4.17.0",
......
...@@ -5,21 +5,17 @@ import styles from './index.less'; ...@@ -5,21 +5,17 @@ import styles from './index.less';
interface IAnswerProps { interface IAnswerProps {
answerValue: string; answerValue: string;
loading: boolean
isShowRetry?: boolean; isShowRetry?: boolean;
} }
const { useBreakpoint } = Grid; const { useBreakpoint } = Grid;
const Answer = (props: IAnswerProps) => { const Answer = (props: IAnswerProps) => {
const { answerValue, isShowRetry } = props;
const { answerValue, loading, isShowRetry } = props
const screens = useBreakpoint(); const screens = useBreakpoint();
const isMobile = screens.xs; const isMobile = screens.xs;
console.log('isMobile', isMobile)
return ( return (
<div> <div>
<p className={styles.question} style={{ marginTop: isMobile ? '20px' : '40px' }}> <p className={styles.question} style={{ marginTop: isMobile ? '20px' : '40px' }}>
...@@ -54,7 +50,11 @@ const Answer = (props: IAnswerProps) => { ...@@ -54,7 +50,11 @@ const Answer = (props: IAnswerProps) => {
<span>复制回答</span> <span>复制回答</span>
</p> </p>
} }
<p className={styles.answerValue}>{loading ? '请耐心等待3-5秒~' : answerValue}</p> {!answerValue ? (
<p className={styles.answerValue}>请耐心等待3-5秒~</p>
) : (
<p className={styles.answerValue} dangerouslySetInnerHTML={{ __html: answerValue }}></p>
)}
</div> </div>
{ {
isShowRetry && !isMobile && <Button className={styles.chat_retry}>重试</Button> isShowRetry && !isMobile && <Button className={styles.chat_retry}>重试</Button>
...@@ -67,15 +67,11 @@ const Answer = (props: IAnswerProps) => { ...@@ -67,15 +67,11 @@ const Answer = (props: IAnswerProps) => {
<img src={copySvg} alt="" /> <img src={copySvg} alt="" />
<span>复制回答</span> <span>复制回答</span>
</Button> </Button>
<Button <Button className={styles.mobile_chat_retry}>重试</Button>
className={styles.mobile_chat_retry}
>
重试
</Button>
</div> </div>
} }
</div> </div>
); );
} };
export default Answer; export default Answer;
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
.newSession { .newSession {
width: 1000px; width: 1000px;
margin-top: 40px;
.question { .question {
display: flex; display: flex;
align-items: flex-start; align-items: flex-start;
...@@ -10,10 +11,10 @@ ...@@ -10,10 +11,10 @@
height: 26px; height: 26px;
} }
.question_span { .question_span {
font-size: 20px; color: #333333;
font-weight: 600; font-weight: 600;
font-size: 20px;
line-height: 26px; line-height: 26px;
color: #333333;
} }
} }
...@@ -22,17 +23,17 @@ ...@@ -22,17 +23,17 @@
.answer { .answer {
position: relative; position: relative;
width: 900px; width: 900px;
min-height: 268px;
margin-left: 28px; margin-left: 28px;
background: #F0F3F6; color: rgba(0, 0, 0, 0.85);
border-radius: 4px;
font-size: 18px; font-size: 18px;
color: rgba(0,0,0,0.85);
line-height: 32px; line-height: 32px;
min-height: 268px; background: #f0f3f6;
border-radius: 4px;
.copyAnswer { .copyAnswer {
position: absolute; position: absolute;
bottom: 0;
right: 16px; right: 16px;
bottom: 0;
z-index: 2; z-index: 2;
cursor: pointer; cursor: pointer;
img { img {
...@@ -40,10 +41,10 @@ ...@@ -40,10 +41,10 @@
height: 24px; height: 24px;
} }
span { span {
color: #009B95;
line-height: 20px;
height: 24px; height: 24px;
color: #009b95;
font-size: 14px; font-size: 14px;
line-height: 20px;
} }
} }
...@@ -54,17 +55,17 @@ ...@@ -54,17 +55,17 @@
.chat_retry { .chat_retry {
width: 90px; width: 90px;
height: 48px; height: 48px;
background: #FFFFFF;
border-radius: 6px;
border: 1px solid #009B95;
margin-left: 10px; margin-left: 10px;
background: #ffffff;
border: 1px solid #009b95;
border-radius: 6px;
span { span {
width: 40px; width: 40px;
height: 28px; height: 28px;
color: #009b95;
font-weight: 400;
font-size: 20px; font-size: 20px;
font-family: PingFangSC-Regular, PingFang SC; font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #009B95;
line-height: 28px; line-height: 28px;
} }
} }
...@@ -77,26 +78,26 @@ ...@@ -77,26 +78,26 @@
.mobile_copyAnswer { .mobile_copyAnswer {
width: 151px; width: 151px;
height: 40px; height: 40px;
background: rgba(0,155,149,0.12); background: rgba(0, 155, 149, 0.12);
border-radius: 4px; border-radius: 4px;
img { img {
width: 24px; width: 24px;
height: 24px; height: 24px;
} }
span { span {
color: #009B95;
line-height: 20px;
height: 24px; height: 24px;
color: #009b95;
font-size: 14px; font-size: 14px;
line-height: 20px;
} }
} }
.mobile_chat_retry { .mobile_chat_retry {
width: 151px; width: 151px;
height: 40px; height: 40px;
background: #FFFFFF; color: #009b95;
background: #ffffff;
border: 1px solid #009b95;
border-radius: 4px; border-radius: 4px;
border: 1px solid #009B95;
color: #009B95;
} }
} }
} }
...@@ -11,7 +11,6 @@ interface INewSessionProps { ...@@ -11,7 +11,6 @@ interface INewSessionProps {
const { useBreakpoint } = Grid; const { useBreakpoint } = Grid;
const NewSession = (props: INewSessionProps) => { const NewSession = (props: INewSessionProps) => {
const { questionValue, answerValue } = props; const { questionValue, answerValue } = props;
const screens = useBreakpoint(); const screens = useBreakpoint();
...@@ -19,39 +18,13 @@ const NewSession = (props: INewSessionProps) => { ...@@ -19,39 +18,13 @@ const NewSession = (props: INewSessionProps) => {
return ( return (
<div className={styles.newSession} style={{ <div className={styles.newSession} style={{
padding: isMobile ? '48px 16px 16px' : '0', padding: isMobile ? '4px 16px 16px' : '0',
width: isMobile ? '100%' : '1000px' width: isMobile ? '100%' : '1000px'
}}> }}>
<Issue <Issue questionValue={questionValue} />
questionValue={questionValue} <Answer answerValue={answerValue} />
/>
<Answer
answerValue={answerValue}
loading
/>
<Issue
questionValue={questionValue}
/>
<Answer
answerValue={answerValue}
loading
/>
<Issue
questionValue={questionValue}
/>
<Answer
answerValue={answerValue}
loading
/>
<Issue
questionValue={questionValue}
/>
<Answer
answerValue={answerValue}
loading
/>
</div> </div>
); );
} };
export default NewSession; export default NewSession;
...@@ -61,3 +61,9 @@ ol { ...@@ -61,3 +61,9 @@ ol {
min-height: 100vh; min-height: 100vh;
} }
} }
::-webkit-scrollbar {
width: 2px !important;
background-color: #009b95 !important;
border-radius: 4px;
}
export default { export default {
'menu.chat': 'ChatGLM',
'menu.welcome': '欢迎', 'menu.welcome': '欢迎',
'menu.more-blocks': '更多区块', 'menu.more-blocks': '更多区块',
'menu.home': '首页', 'menu.home': '首页',
......
...@@ -72,9 +72,11 @@ ...@@ -72,9 +72,11 @@
position: fixed; position: fixed;
bottom: 0; bottom: 0;
left: 0; left: 0;
z-index: 10;
width: 100%; width: 100%;
height: 150px; height: 150px;
padding: 16px; padding: 16px;
overflow: hidden;
background-color: white; background-color: white;
box-shadow: 0 2px 8px #f0f1f2; box-shadow: 0 2px 8px #f0f1f2;
.chatWrapper { .chatWrapper {
......
/* eslint-disable @typescript-eslint/no-unused-expressions */ /* eslint-disable @typescript-eslint/no-unused-expressions */
import { Form, Button, Col, Row, Input, Typography, Grid } from 'antd'; import { Form, Button, Col, Row, Input, Typography, Grid, message } from 'antd';
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect, useRef, useMemo } from 'react';
import styles from './index.less'; import styles from './index.less';
import ChatFirstContent from './components/content'; import ChatFirstContent from './components/content';
import { import {
...@@ -15,11 +15,18 @@ import classNames from 'classnames'; ...@@ -15,11 +15,18 @@ import classNames from 'classnames';
import { history } from 'umi'; import { history } from 'umi';
import LoginModal from '@/components/loginModal'; import LoginModal from '@/components/loginModal';
import NewSession from '@/components/newSession'; import NewSession from '@/components/newSession';
import { useWebSocket, useRequest } from 'ahooks';
import { GetChatGLMToken } from '@/services/chatGLM/api';
const { useBreakpoint } = Grid; const { useBreakpoint } = Grid;
const { Title } = Typography; const { Title } = Typography;
const { Item } = Form; const { Item } = Form;
interface IHistory {
prompt: string;
answer: string;
}
const Chat: React.FC = () => { const Chat: React.FC = () => {
const screens = useBreakpoint(); const screens = useBreakpoint();
const isMobile = screens.xs; const isMobile = screens.xs;
...@@ -28,11 +35,55 @@ const Chat: React.FC = () => { ...@@ -28,11 +35,55 @@ const Chat: React.FC = () => {
const [firstChat, setFirstChat] = useState(false); const [firstChat, setFirstChat] = useState(false);
const [form] = Form.useForm(); const [form] = Form.useForm();
const [selectSiderTabs, setSelectSiderTabs] = useState(''); const [selectSiderTabs, setSelectSiderTabs] = useState('');
const { data: glmToken } = useRequest(GetChatGLMToken);
const [answer, setAnswer] = useState('');
const [loading, setLoading] = useState(true);
const messageHistory = useRef<IHistory[]>([]);
const { sendMessage } = useWebSocket('wss://glm-api.baibaomen.com/ws', {
onMessage: (event) => {
const text = event.data;
if (text == '{{BBMCPLT}}') {
setLoading(false);
} else {
setAnswer(text);
window.scrollTo(0, document.body.scrollHeight);
}
},
onOpen: () => {
console.log('连接成功!');
setLoading(false);
},
onError: () => {
setLoading(false);
message.error('连接失败了,请稍后再试!');
},
});
messageHistory.current = useMemo(() => {
if (messageHistory.current.length > 0)
messageHistory.current[messageHistory.current.length - 1].answer += answer;
return messageHistory.current;
}, [answer]);
async function handleSendMessage() {
setLoading(true);
sendMessage &&
sendMessage(
JSON.stringify({
prompt: chat,
max_length: 2048,
top_p: 0.7,
temperature: 0.95,
history: [messageHistory.current.map((h) => h.prompt)],
token: glmToken,
}),
);
messageHistory.current.push({ prompt: chat, answer: '' });
}
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const tabShow = showSider && !isMobile; const tabShow = showSider && !isMobile;
const questionValue = form.getFieldValue('chatInput'); const user = localStorage.getItem('user');
useEffect(() => { useEffect(() => {
if (!isMobile) { if (!isMobile) {
...@@ -42,7 +93,7 @@ const Chat: React.FC = () => { ...@@ -42,7 +93,7 @@ const Chat: React.FC = () => {
let token = ''; let token = '';
useEffect(() => { useEffect(() => {
if (localStorage.getItem('user')) { if (user) {
token = JSON.parse(localStorage.user)?.token; token = JSON.parse(localStorage.user)?.token;
} }
if (token) { if (token) {
...@@ -50,11 +101,12 @@ const Chat: React.FC = () => { ...@@ -50,11 +101,12 @@ const Chat: React.FC = () => {
} else { } else {
setOpen(true); setOpen(true);
} }
}, []); }, [user]);
const onSend = () => { const onSend = () => {
form.setFieldValue('chatInput', ''); form.setFieldValue('chatInput', '');
setFirstChat(true); setFirstChat(true);
handleSendMessage();
}; };
const setInput = (value: any) => { const setInput = (value: any) => {
...@@ -168,7 +220,7 @@ const Chat: React.FC = () => { ...@@ -168,7 +220,7 @@ const Chat: React.FC = () => {
xs={isMobile ? 24 : 12} xs={isMobile ? 24 : 12}
> >
{!isMobile && ( {!isMobile && (
<div className={styles.header}> <div className={styles.header} hidden={firstChat}>
<Row> <Row>
<Col span={24}> <Col span={24}>
<Title level={1}>产品名称</Title> <Title level={1}>产品名称</Title>
...@@ -189,7 +241,15 @@ const Chat: React.FC = () => { ...@@ -189,7 +241,15 @@ const Chat: React.FC = () => {
onFinish={onSend} onFinish={onSend}
> >
{firstChat ? ( {firstChat ? (
<NewSession questionValue={chat} answerValue="" /> <div style={{ overflowY: 'scroll', marginBottom: 150 }}>
{messageHistory.current.map((item, index) => (
<NewSession
key={'new' + index}
questionValue={item.prompt}
answerValue={item.answer}
/>
))}
</div>
) : ( ) : (
<div className={classNames(isMobile && styles.mobileContent)}> <div className={classNames(isMobile && styles.mobileContent)}>
<Item name="firstInput"> <Item name="firstInput">
...@@ -212,7 +272,7 @@ const Chat: React.FC = () => { ...@@ -212,7 +272,7 @@ const Chat: React.FC = () => {
<Col span={4} push={isMobile ? 0 : 4}> <Col span={4} push={isMobile ? 0 : 4}>
<div className={styles.outputButtonWrapper}> <div className={styles.outputButtonWrapper}>
<Item name="outputButton"> <Item name="outputButton">
<Button htmlType="submit" type="primary" size="large"> <Button htmlType="submit" type="primary" size="large" loading={loading}>
发送 发送
</Button> </Button>
</Item> </Item>
......
import { useWebSocket } from 'ahooks';
import { Button, Col, Row, message } from 'antd';
import Input from 'rc-input';
import { useMemo, useRef, useEffect, useState } from 'react';
enum ReadyState {
Connecting = 0,
Open = 1,
Closing = 2,
Closed = 3,
}
interface IHistory {
prompt: string;
answer: string;
}
const Test = () => {
const [prompt, setPrompt] = useState<string>('你好');
const [loading, setLoading] = useState(true);
const [answer, setAnswer] = useState('');
const messageHistory = useRef<IHistory[]>([]);
const { sendMessage } = useWebSocket('wss://glm-api.baibaomen.com/ws', {
onMessage: (event) => {
const text = event.data;
if (text == '{{BBMCPLT}}') {
} else {
setAnswer(text);
}
},
onOpen: () => {
setLoading(false);
console.log('连接成功!');
},
onError: (e) => {
message.error('连接失败了,请稍后再试!');
},
});
// useEffect(() => {
// console.log(readyState);
// if (readyState !== ReadyState.Open) {
// connect && connect();
// }
// return () => {
// disconnect && disconnect();
// };
// }, []);
messageHistory.current = useMemo(() => {
if (messageHistory.current.length > 0)
messageHistory.current[messageHistory.current.length - 1].answer += answer;
console.log(messageHistory.current);
return messageHistory.current;
}, [answer]);
function handleSendMessage() {
sendMessage &&
sendMessage(
JSON.stringify({
prompt: prompt,
max_length: 2048,
top_p: 0.7,
temperature: 0.95,
history: [messageHistory.current.map((h) => h.prompt)],
token: 'Uicm6VMjVPdzepbqnwNvpl25xJjRxFekMV8QZdeTLTwacNBl',
}),
);
messageHistory.current.push({ prompt: prompt, answer: '' });
}
return (
<>
<Input
placeholder=""
value={prompt}
onChange={(e) => {
setPrompt(e.target.value);
}}
/>
<Button onClick={handleSendMessage} loading={loading}>
发送
</Button>
{messageHistory.current.map((item, index) => (
<Row key={'message-' + index}>
<Col span={24}>{item.prompt}</Col>
<Col span={24} dangerouslySetInnerHTML={{ __html: item.answer }}></Col>
</Row>
))}
</>
);
};
export default Test;
import request from 'umi-request'; import { notification } from 'antd';
import { extend } from 'umi-request';
import { history } from 'umi';
interface ILoginParams { interface ILoginParams {
name: string; name: string;
password: string; password: string;
} }
// request.interceptors.request.use((url, options) => { const codeMessage = {
// let { token } = JSON.parse(localStorage.getItem('user') || ''); 200: '服务器成功返回请求的数据。',
// if (null === token) { 201: '新建或修改数据成功。',
// token = ''; 202: '一个请求已经进入后台排队(异步任务)。',
// } 204: '删除数据成功。',
// const authHeader = { 400: '发出的请求有错误,服务器没有进行新建或修改数据的操作。',
// Authorization: `Bearer ${token}`, 401: '用户没有权限(令牌、用户名、密码错误)。',
// 'Content-Type': 'application/json', 403: '用户得到授权,但是访问是被禁止的。',
// '__tenant': '3a0a90fe-9a0d-70f4-200d-a80a41fb6195' // 用户id 404: '发出的请求针对的是不存在的记录,服务器没有进行操作。',
// }; 406: '请求的格式不可得。',
// return { 410: '请求的资源被永久删除,且不会再得到的。',
// url: url, 422: '当创建一个对象时,发生一个验证错误。',
// options: { ...options, interceptors: true, headers: authHeader }, 500: '服务器发生错误,请检查服务器。',
// }; 502: '网关错误。',
// }); 503: '服务不可用,服务器暂时过载或维护。',
504: '网关超时。',
};
const errorHandler = (error: any) => {
const { response = {} } = error;
const errortext = codeMessage[response.status] || response.statusText;
const { status, url } = response;
notification.error({
message: `请求错误 ${status}: ${url}`,
description: errortext,
});
};
const request = extend({
errorHandler
});
request.interceptors.response.use(async (response): Promise<any> => {
console.log('response', response);
if(response.status === 401) {
localStorage.removeItem('user');
history.push('/chat');
} else if(response.status === 200) {
return response;
} else {
return Promise.reject(response.statusText);
}
})
export function loginChatGLM(options: ILoginParams) { export function loginChatGLM(options: ILoginParams) {
return request('https://glm-mangement-api.baibaomen.com/api/app/account/login', { return request('https://glm-mangement-api.baibaomen.com/api/app/account/login', {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'__tenant': '3a0a90fe-9a0d-70f4-200d-a80a41fb6195' __tenant: '3a0a90fe-9a0d-70f4-200d-a80a41fb6195',
}, },
data: options data: options,
}) });
} }
type History = [string, string]; export function GetChatGLMToken(): Promise<string> {
interface ITalkParams { return request('https://glm-mangement-api.baibaomen.com/user/token', {
prompt: string; method: 'POST',
history: History[]; headers: { Authorization: 'Bearer ' + JSON.parse(localStorage.getItem('user') || '')?.token },
max_length?: number; });
top_p?: number;
temperature?: number;
} }
// export function talkChatGLM({ prompt, history, max_length = 2000, top_p = 0.9, temperature = 0.8 }: ITalkParams) {
// return request('https://glm-mangement-api.baibaomen.com/', {
// method: 'POST',
// data: {
// prompt,
// history,
// max_length,
// top_p,
// temperature
// }
// })
// }
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment