(feature)(webapp) use nativeQuery field to determine whether it is a selection (#222)

This commit is contained in:
williamhliu
2023-10-14 16:37:28 +08:00
committed by GitHub
parent d9efe8f137
commit fdf48d7bfd
16 changed files with 63 additions and 38 deletions

View File

@@ -2,7 +2,6 @@ import { Form, Input, Modal } from 'antd';
import { useEffect, useRef, useState } from 'react'; import { useEffect, useRef, useState } from 'react';
import { updateConversationName } from '../../service'; import { updateConversationName } from '../../service';
import type { ConversationDetailType } from '../../type'; import type { ConversationDetailType } from '../../type';
import { CHAT_TITLE } from '../../constants';
const FormItem = Form.Item; const FormItem = Form.Item;
@@ -44,7 +43,7 @@ const ConversationModal: React.FC<Props> = ({ visible, editConversation, onClose
return ( return (
<Modal <Modal
title={`修改${CHAT_TITLE}问答名称`} title="修改问答名称"
open={visible} open={visible}
onCancel={onClose} onCancel={onClose}
onOk={onConfirm} onOk={onConfirm}
@@ -53,7 +52,7 @@ const ConversationModal: React.FC<Props> = ({ visible, editConversation, onClose
<Form {...layout} form={form}> <Form {...layout} form={form}>
<FormItem name="conversationName" label="名称" rules={[{ required: true }]}> <FormItem name="conversationName" label="名称" rules={[{ required: true }]}>
<Input <Input
placeholder={`请输入${CHAT_TITLE}问答名称`} placeholder="请输入问答名称"
ref={conversationNameInputRef} ref={conversationNameInputRef}
onPressEnter={onConfirm} onPressEnter={onConfirm}
/> />

View File

@@ -4,6 +4,7 @@ import classNames from 'classnames';
import LeftAvatar from './CopilotAvatar'; import LeftAvatar from './CopilotAvatar';
import Message from './Message'; import Message from './Message';
import styles from './style.module.less'; import styles from './style.module.less';
import { userAvatarUrl } from '../../common/env';
type Props = { type Props = {
position: 'left' | 'right'; position: 'left' | 'right';
@@ -15,6 +16,7 @@ const Text: React.FC<Props> = ({ position, data, quote }) => {
const textWrapperClass = classNames(styles.textWrapper, { const textWrapperClass = classNames(styles.textWrapper, {
[styles.rightTextWrapper]: position === 'right', [styles.rightTextWrapper]: position === 'right',
}); });
const rightAvatarUrl = userAvatarUrl;
return ( return (
<div className={textWrapperClass}> <div className={textWrapperClass}>
{!isMobile && position === 'left' && <LeftAvatar />} {!isMobile && position === 'left' && <LeftAvatar />}
@@ -22,6 +24,9 @@ const Text: React.FC<Props> = ({ position, data, quote }) => {
{position === 'right' && quote && <div className={styles.quote}>{quote}</div>} {position === 'right' && quote && <div className={styles.quote}>{quote}</div>}
<div className={styles.text}>{data}</div> <div className={styles.text}>{data}</div>
</Message> </Message>
{!isMobile && position === 'right' && rightAvatarUrl && (
<Avatar shape="circle" size={40} src={rightAvatarUrl} className={styles.rightAvatar} />
)}
</div> </div>
); );
}; };

View File

@@ -43,16 +43,8 @@ export const AGENT_ICONS = [
export const HOLDER_TAG = '@_supersonic_@'; export const HOLDER_TAG = '@_supersonic_@';
export const CHAT_TITLE = '';
export const DEFAULT_CONVERSATION_NAME = '新问答对话'; export const DEFAULT_CONVERSATION_NAME = '新问答对话';
export const PAGE_TITLE = '问答对话';
export const WEB_TITLE = '问答对话';
export const MOBILE_TITLE = '问答对话';
export const PLACE_HOLDER = '请输入您的问题,或输入“/”切换助理'; export const PLACE_HOLDER = '请输入您的问题,或输入“/”切换助理';
export const SIMPLE_PLACE_HOLDER = '请输入您的问题'; export const SIMPLE_PLACE_HOLDER = '请输入您的问题';

View File

@@ -15,7 +15,6 @@ import { useThrottleFn } from 'ahooks';
import Conversation from './Conversation'; import Conversation from './Conversation';
import ChatFooter from './ChatFooter'; import ChatFooter from './ChatFooter';
import classNames from 'classnames'; import classNames from 'classnames';
import { CHAT_TITLE } from './constants';
import { cloneDeep } from 'lodash'; import { cloneDeep } from 'lodash';
import AgentList from './AgentList'; import AgentList from './AgentList';
import MobileAgents from './MobileAgents'; import MobileAgents from './MobileAgents';
@@ -59,7 +58,7 @@ const Chat: ForwardRefRenderFunction<any, Props> = (
const [historyInited, setHistoryInited] = useState(false); const [historyInited, setHistoryInited] = useState(false);
const [currentConversation, setCurrentConversation] = useState< const [currentConversation, setCurrentConversation] = useState<
ConversationDetailType | undefined ConversationDetailType | undefined
>(isMobile ? { chatId: 0, chatName: `${CHAT_TITLE}问答` } : undefined); >(isMobile ? { chatId: 0, chatName: '问答' } : undefined);
const [historyVisible, setHistoryVisible] = useState(false); const [historyVisible, setHistoryVisible] = useState(false);
const [agentList, setAgentList] = useState<AgentType[]>([]); const [agentList, setAgentList] = useState<AgentType[]>([]);
const [currentAgent, setCurrentAgent] = useState<AgentType>(); const [currentAgent, setCurrentAgent] = useState<AgentType>();

View File

@@ -14,6 +14,7 @@ import { AgentType } from '../Chat/type';
import { setToken } from '../utils/utils'; import { setToken } from '../utils/utils';
import { SendMsgParamsType } from '../common/type'; import { SendMsgParamsType } from '../common/type';
import styles from './style.module.less'; import styles from './style.module.less';
import { copilotTitle } from '../common/env';
type Props = { type Props = {
token?: string; token?: string;
@@ -123,7 +124,7 @@ const Copilot: ForwardRefRenderFunction<any, Props> = (
/> />
)} )}
</div> </div>
<div className={styles.title}></div> <div className={styles.title}>{copilotTitle}</div>
</div> </div>
<div className={styles.chat}> <div className={styles.chat}>
<Chat <Chat

View File

@@ -0,0 +1,7 @@
export const proxyTarget = 'http://localhost:9080';
export const userAvatarUrl = '';
export const webPageHost = '';
export const copilotTitle = 'Copilot';

View File

@@ -183,7 +183,7 @@ export enum SemanticTypeEnum {
}; };
export const SEMANTIC_TYPE_MAP = { export const SEMANTIC_TYPE_MAP = {
[SemanticTypeEnum.DOMAIN]: '数据来源', [SemanticTypeEnum.DOMAIN]: '数据模型',
[SemanticTypeEnum.DIMENSION]: '维度', [SemanticTypeEnum.DIMENSION]: '维度',
[SemanticTypeEnum.METRIC]: '指标', [SemanticTypeEnum.METRIC]: '指标',
[SemanticTypeEnum.VALUE]: '维度值', [SemanticTypeEnum.VALUE]: '维度值',

View File

@@ -150,7 +150,6 @@ const FilterItem: React.FC<Props> = ({
onChange={onChange} onChange={onChange}
mode={isArray(filter.value) ? 'multiple' : undefined} mode={isArray(filter.value) ? 'multiple' : undefined}
showSearch showSearch
// allowClear
/> />
) : entityAlias && ) : entityAlias &&
['歌曲', '艺人'].includes(entityAlias) && ['歌曲', '艺人'].includes(entityAlias) &&

View File

@@ -78,7 +78,6 @@ const ParseTip: React.FC<Props> = ({
queryMode, queryMode,
properties, properties,
entity, entity,
// entityInfo,
elementMatches, elementMatches,
nativeQuery, nativeQuery,
} = currentParseInfo || {}; } = currentParseInfo || {};
@@ -198,7 +197,7 @@ const ParseTip: React.FC<Props> = ({
<div className={`${prefixCls}-tip-item-filter-content`}> <div className={`${prefixCls}-tip-item-filter-content`}>
<div className={`${prefixCls}-tip-item-option`}> <div className={`${prefixCls}-tip-item-option`}>
<span className={`${prefixCls}-tip-item-filter-name`}></span> <span className={`${prefixCls}-tip-item-filter-name`}></span>
{dimensions?.some(item => item.bizName?.includes('_id')) ? ( {nativeQuery ? (
<span className={itemValueClass}> <span className={itemValueClass}>
{startDate === endDate ? startDate : `${startDate} ~ ${endDate}`} {startDate === endDate ? startDate : `${startDate} ~ ${endDate}`}
</span> </span>

View File

@@ -61,6 +61,11 @@ const Table: React.FC<Props> = ({ data, size, onApplyAuth }) => {
return index % 2 !== 0 ? `${prefixCls}-even-row` : ''; return index % 2 !== 0 ? `${prefixCls}-even-row` : '';
}; };
const dateColumn = queryColumns.find(column => column.type === 'DATE');
const dataSource = dateColumn
? queryResults.sort((a, b) => moment(a[dateColumn.nameEn]).diff(moment(b[dateColumn.nameEn])))
: queryResults;
return ( return (
<div className={prefixCls}> <div className={prefixCls}>
<AntTable <AntTable
@@ -68,8 +73,8 @@ const Table: React.FC<Props> = ({ data, size, onApplyAuth }) => {
queryResults.length <= 10 ? false : { defaultPageSize: 10, position: ['bottomCenter'] } queryResults.length <= 10 ? false : { defaultPageSize: 10, position: ['bottomCenter'] }
} }
columns={tableColumns} columns={tableColumns}
dataSource={queryResults} dataSource={dataSource}
style={{ width: '100%', overflowX: 'auto' }} style={{ width: '100%', overflowX: 'auto', overflowY: 'hidden' }}
rowClassName={getRowClassName} rowClassName={getRowClassName}
size={size} size={size}
/> />

View File

@@ -1,6 +1,7 @@
import { useCallback, useEffect, useState } from 'react'; import { useCallback, useEffect, useState } from 'react';
import { MsgDataType } from '../../../common/type'; import { MsgDataType } from '../../../common/type';
import { getToken, isProd } from '../../../utils/utils'; import { getToken, isProd } from '../../../utils/utils';
import { webPageHost } from '../../../common/env';
type Props = { type Props = {
id: string | number; id: string | number;
@@ -88,6 +89,7 @@ const WebPage: React.FC<Props> = ({ id, data }) => {
'?', '?',
`?token=${getToken()}&miniProgram=true&reportName=${name}&filterData=${filterData}&` `?token=${getToken()}&miniProgram=true&reportName=${name}&filterData=${filterData}&`
); );
urlValue = `${webPageHost}${urlValue}`;
} else { } else {
const params = Object.keys(valueParams || {}).map(key => `${key}=${valueParams[key]}`); const params = Object.keys(valueParams || {}).map(key => `${key}=${valueParams[key]}`);
if (params.length > 0) { if (params.length > 0) {

View File

@@ -2,7 +2,7 @@ import { Input } from 'antd';
import styles from './style.module.less'; import styles from './style.module.less';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import ChatItem from '../components/ChatItem'; import ChatItem from '../components/ChatItem';
import { searchRecommend } from '../service'; import { MsgDataType } from '../common/type';
const { Search } = Input; const { Search } = Input;
@@ -10,8 +10,9 @@ const Chat = () => {
const [data, setData] = useState<any>(); const [data, setData] = useState<any>();
const [inputMsg, setInputMsg] = useState(''); const [inputMsg, setInputMsg] = useState('');
const [msg, setMsg] = useState(''); const [msg, setMsg] = useState('');
const [followQuestions, setFollowQuestions] = useState<string[]>([]);
const [triggerResize, setTriggerResize] = useState(false); const [triggerResize, setTriggerResize] = useState(false);
const [executeItemNode, setExecuteItemNode] = useState<React.ReactNode>();
const [chatItemVisible, setChatItemVisible] = useState(false);
const onWindowResize = () => { const onWindowResize = () => {
setTriggerResize(true); setTriggerResize(true);
@@ -34,14 +35,24 @@ const Chat = () => {
const onSearch = () => { const onSearch = () => {
setMsg(inputMsg); setMsg(inputMsg);
setChatItemVisible(false);
setTimeout(() => {
setChatItemVisible(true);
}, 200);
}; };
const onMsgDataLoaded = (msgData: any) => { const onMsgDataLoaded = (msgData: MsgDataType) => {
setData(msgData); setData(msgData);
setFollowQuestions(['测试1234测试', '测试1234测试', '测试1234测试']); const { queryColumns, queryResults, queryMode } = msgData;
const songIds = queryColumns.some(column => column.nameEn === 'zyqk_song_id')
? (queryResults || []).map(result => result['zyqk_song_id'])
: [];
if (queryMode === 'DSL') {
setExecuteItemNode(<>test</>);
}
}; };
// 5: 查信息6: 智能圈选 //预发环境: 5: 查信息6: 智能圈选12问指标15歌曲库16艺人库
return ( return (
<div className={styles.page}> <div className={styles.page}>
@@ -53,15 +64,19 @@ const Chat = () => {
onSearch={onSearch} onSearch={onSearch}
/> />
</div> </div>
{inputMsg && ( {msg && chatItemVisible && (
<div className={styles.chatItem}> <div className={styles.chatItem}>
<ChatItem <ChatItem
msg={msg} msg={msg}
// msgData={data} // msgData={data}
agentId={6} agentId={5}
conversationId={112211121}
onMsgDataLoaded={onMsgDataLoaded} onMsgDataLoaded={onMsgDataLoaded}
isLastMessage isLastMessage
triggerResize={triggerResize} triggerResize={triggerResize}
integrateSystem="wiki"
executeItemNode={executeItemNode}
isDeveloper
/> />
</div> </div>
)} )}

View File

@@ -35,14 +35,7 @@ const CopilotDemo = () => {
</Button> </Button>
))} ))}
</Space> </Space>
<Copilot <Copilot isDeveloper ref={copilotRef} />
// token={localStorage.getItem('SUPERSONIC_TOKEN') || ''}
// agentIds={[8]}
isDeveloper
// integrateSystem="c2"
ref={copilotRef}
// noInput
/>
</div> </div>
); );
}; };

View File

@@ -5,7 +5,7 @@ import './styles/index.less';
// import ChatDemo from './demo/ChatDemo'; // import ChatDemo from './demo/ChatDemo';
// import CopilotDemo from './demo/CopilotDemo'; // import CopilotDemo from './demo/CopilotDemo';
// const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement); // const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
// root.render(<ChatDemo />); // root.render(<Chat />);
export { default as Chat } from './Chat'; export { default as Chat } from './Chat';

View File

@@ -1,9 +1,10 @@
import axios from './axiosInstance'; import axios from './axiosInstance';
import { ChatContextType, DrillDownDimensionType, EntityInfoType, HistoryType, MsgDataType, ParseDataType, SearchRecommendItem } from '../common/type'; import { ChatContextType, DrillDownDimensionType, EntityInfoType, HistoryType, MsgDataType, ParseDataType, SearchRecommendItem } from '../common/type';
import { isMobile } from '../utils/utils';
const DEFAULT_CHAT_ID = 0; const DEFAULT_CHAT_ID = 0;
const prefix = '/api'; const prefix = isMobile ? '/openapi' : '/api';
export function searchRecommend(queryText: string, chatId?: number, modelId?: number, agentId?: number) { export function searchRecommend(queryText: string, chatId?: number, modelId?: number, agentId?: number) {
return axios.post<SearchRecommendItem[]>(`${prefix}/chat/query/search`, { return axios.post<SearchRecommendItem[]>(`${prefix}/chat/query/search`, {

View File

@@ -1,10 +1,18 @@
const { createProxyMiddleware } = require('http-proxy-middleware'); const { createProxyMiddleware } = require('http-proxy-middleware');
const { proxyTarget } = require('./common/env');
module.exports = function(app) { module.exports = function(app) {
app.use( app.use(
'/api', '/api',
createProxyMiddleware({ createProxyMiddleware({
target: 'http://localhost:9080', target: proxyTarget,
changeOrigin: true,
})
);
app.use(
'/openapi',
createProxyMiddleware({
target: proxyTarget,
changeOrigin: true, changeOrigin: true,
}) })
); );