mirror of
https://github.com/tencentmusic/supersonic.git
synced 2025-12-10 19:18:23 +00:00
[feature](webapp) add mobile agents drawer (#64)
This commit is contained in:
@@ -192,6 +192,6 @@
|
||||
]
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.18.0"
|
||||
"node": ">=16"
|
||||
}
|
||||
}
|
||||
@@ -248,6 +248,8 @@
|
||||
&-entity-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
row-gap: 6px;
|
||||
column-gap: 12px;
|
||||
margin-top: 4px;
|
||||
color: var(--text-color-third);
|
||||
@@ -257,6 +259,8 @@
|
||||
&-dimension-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
row-gap: 6px;
|
||||
}
|
||||
|
||||
&-dimension-name {
|
||||
|
||||
@@ -34,7 +34,7 @@ const ROUTES = [
|
||||
component: './Agent',
|
||||
envEnableList: [ENV_KEY.CHAT],
|
||||
},
|
||||
{
|
||||
{
|
||||
path: '/model',
|
||||
name: 'semanticModel',
|
||||
envEnableList: [ENV_KEY.SEMANTIC],
|
||||
@@ -53,7 +53,6 @@ const ROUTES = [
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
path: '/database',
|
||||
name: 'database',
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
"react-split-pane": "^2.0.3",
|
||||
"react-syntax-highlighter": "^15.4.3",
|
||||
"sql-formatter": "^2.3.3",
|
||||
"supersonic-chat-sdk": "^0.5.29",
|
||||
"supersonic-chat-sdk": "0.0.0",
|
||||
"umi": "3.5",
|
||||
"umi-request": "^1.0.8"
|
||||
},
|
||||
@@ -147,4 +147,4 @@
|
||||
"@types/react": "17.0.0"
|
||||
},
|
||||
"__npminstall_done": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,20 +4,7 @@ import styles from './style.less';
|
||||
import classNames from 'classnames';
|
||||
import { message } from 'antd';
|
||||
import IconFont from '@/components/IconFont';
|
||||
|
||||
const agents = [
|
||||
'icon-fukuanbaobiaochaxun',
|
||||
'icon-hangweifenxi1',
|
||||
'icon-xiaofeifenxi',
|
||||
'icon-renwuchaxun',
|
||||
'icon-liushuichaxun',
|
||||
'icon-baobiao',
|
||||
'icon-cangkuchaxun',
|
||||
'icon-xiaoshoushuju',
|
||||
'icon-tongji',
|
||||
'icon-shujutongji',
|
||||
'icon-mendiankanban',
|
||||
];
|
||||
import { AGENT_ICONS } from '../constants';
|
||||
|
||||
type Props = {
|
||||
agentList: AgentType[];
|
||||
@@ -49,8 +36,7 @@ const AgentList: React.FC<Props> = ({ agentList, currentAgent, onSelectAgent })
|
||||
onSelectAgent(agent);
|
||||
}}
|
||||
>
|
||||
{/* <img src={agents[index % agents.length]} alt="avatar" className={styles.avatar} /> */}
|
||||
<IconFont type={agents[index % agents.length]} className={styles.avatar} />
|
||||
<IconFont type={AGENT_ICONS[index % AGENT_ICONS.length]} className={styles.avatar} />
|
||||
<div className={styles.agentInfo}>
|
||||
<div className={styles.agentName}>{agent.name}</div>
|
||||
<div className={styles.agentDesc}>{agent.description}</div>
|
||||
|
||||
@@ -66,10 +66,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
&:hover, &.active {
|
||||
&:hover,
|
||||
&.active {
|
||||
background: #22a5f7;
|
||||
|
||||
.agentName, .agentDesc {
|
||||
.agentName,
|
||||
.agentDesc {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ type Props = {
|
||||
currentAgent?: AgentType;
|
||||
agentList: AgentType[];
|
||||
onToggleHistoryVisible: () => void;
|
||||
onOpenMobileAgents: () => void;
|
||||
onInputMsgChange: (value: string) => void;
|
||||
onSendMsg: (msg: string, modelId?: number) => void;
|
||||
onAddConversation: (agent?: AgentType) => void;
|
||||
@@ -41,6 +42,7 @@ const ChatFooter: ForwardRefRenderFunction<any, Props> = (
|
||||
currentAgent,
|
||||
agentList,
|
||||
onToggleHistoryVisible,
|
||||
onOpenMobileAgents,
|
||||
onInputMsgChange,
|
||||
onSendMsg,
|
||||
onAddConversation,
|
||||
@@ -310,6 +312,12 @@ const ChatFooter: ForwardRefRenderFunction<any, Props> = (
|
||||
<div>历史对话</div>
|
||||
</div>
|
||||
)}
|
||||
{isMobile && (
|
||||
<div className={styles.toolItem} onClick={onOpenMobileAgents}>
|
||||
<IconFont type="icon-zhinengzhuli" className={styles.toolIcon} />
|
||||
<div>智能助理</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className={styles.composer}>
|
||||
<div className={styles.composerInputWrapper}>
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
import IconFont from '@/components/IconFont';
|
||||
import { Drawer } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import { AGENT_ICONS } from '../constants';
|
||||
import { AgentType } from '../type';
|
||||
import styles from './style.less';
|
||||
|
||||
type Props = {
|
||||
open: boolean;
|
||||
agentList: AgentType[];
|
||||
currentAgent?: AgentType;
|
||||
onSelectAgent: (agent: AgentType) => void;
|
||||
onClose: () => void;
|
||||
};
|
||||
|
||||
const MobileAgents: React.FC<Props> = ({
|
||||
open,
|
||||
agentList,
|
||||
currentAgent,
|
||||
onSelectAgent,
|
||||
onClose,
|
||||
}) => {
|
||||
return (
|
||||
<Drawer
|
||||
title="智能助理"
|
||||
placement="bottom"
|
||||
open={open}
|
||||
height="85%"
|
||||
className={styles.mobileAgents}
|
||||
onClose={onClose}
|
||||
>
|
||||
<div className={styles.agentListContent}>
|
||||
{agentList.map((agent, index) => {
|
||||
const agentItemClass = classNames(styles.agentItem, {
|
||||
[styles.active]: currentAgent?.id === agent.id,
|
||||
});
|
||||
return (
|
||||
<div
|
||||
key={agent.id}
|
||||
className={agentItemClass}
|
||||
onClick={() => {
|
||||
onSelectAgent(agent);
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
<div className={styles.agentTitleBar}>
|
||||
<IconFont
|
||||
type={AGENT_ICONS[index % AGENT_ICONS.length]}
|
||||
className={styles.avatar}
|
||||
/>
|
||||
<div className={styles.agentName}>{agent.name}</div>
|
||||
</div>
|
||||
<div className={styles.agentDesc}>{agent.description}</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</Drawer>
|
||||
);
|
||||
};
|
||||
|
||||
export default MobileAgents;
|
||||
@@ -0,0 +1,55 @@
|
||||
.mobileAgents {
|
||||
:global {
|
||||
.ant-drawer-content {
|
||||
border-top-left-radius: 12px;
|
||||
border-top-right-radius: 12px;
|
||||
|
||||
.ant-drawer-header {
|
||||
padding: 16px 12px;
|
||||
}
|
||||
|
||||
.ant-drawer-body {
|
||||
padding: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.agentListContent {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 12px;
|
||||
|
||||
.agentItem {
|
||||
padding: 12px 16px;
|
||||
background-color: #f5f7f9;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 10px;
|
||||
|
||||
&.active {
|
||||
border: 1px solid var(--chat-blue);
|
||||
}
|
||||
|
||||
.agentTitleBar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
column-gap: 6px;
|
||||
|
||||
.avatar {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.agentName {
|
||||
color: var(--text-color);
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.agentDesc {
|
||||
margin-top: 8px;
|
||||
color: var(--text-color-third);
|
||||
font-size: 13px;
|
||||
line-height: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,20 @@ export const SEMANTIC_TYPE_MAP = {
|
||||
[SemanticTypeEnum.VALUE]: '维度值',
|
||||
};
|
||||
|
||||
export const AGENT_ICONS = [
|
||||
'icon-fukuanbaobiaochaxun',
|
||||
'icon-hangweifenxi1',
|
||||
'icon-xiaofeifenxi',
|
||||
'icon-renwuchaxun',
|
||||
'icon-baobiao',
|
||||
'icon-liushuichaxun',
|
||||
'icon-cangkuchaxun',
|
||||
'icon-xiaoshoushuju',
|
||||
'icon-tongji',
|
||||
'icon-shujutongji',
|
||||
'icon-mendiankanban',
|
||||
];
|
||||
|
||||
export const CHAT_TITLE = '';
|
||||
|
||||
export const DEFAULT_CONVERSATION_NAME = '新问答对话';
|
||||
|
||||
@@ -23,6 +23,7 @@ import 'supersonic-chat-sdk/dist/index.css';
|
||||
import { setToken as setChatSdkToken } from 'supersonic-chat-sdk';
|
||||
import AgentList from './AgentList';
|
||||
import { AUTH_TOKEN_KEY } from '@/common/constants';
|
||||
import MobileAgents from './MobileAgents';
|
||||
|
||||
type Props = {
|
||||
isCopilotMode?: boolean;
|
||||
@@ -58,6 +59,7 @@ const Chat: React.FC<Props> = ({
|
||||
const [defaultEntity, setDefaultEntity] = useState<DefaultEntityType>();
|
||||
const [agentList, setAgentList] = useState<AgentType[]>([]);
|
||||
const [currentAgent, setCurrentAgent] = useState<AgentType>();
|
||||
const [mobileAgentsVisible, setMobileAgentsVisible] = useState(false);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const conversationRef = useRef<any>();
|
||||
@@ -403,6 +405,9 @@ const Chat: React.FC<Props> = ({
|
||||
onSendMsg={sendMsg}
|
||||
onAddConversation={onAddConversation}
|
||||
onSelectAgent={onSelectAgent}
|
||||
onOpenMobileAgents={() => {
|
||||
setMobileAgentsVisible(true);
|
||||
}}
|
||||
ref={chatFooterRef}
|
||||
/>
|
||||
</div>
|
||||
@@ -423,6 +428,15 @@ const Chat: React.FC<Props> = ({
|
||||
ref={conversationRef}
|
||||
/>
|
||||
</div>
|
||||
<MobileAgents
|
||||
open={mobileAgentsVisible}
|
||||
agentList={agentList}
|
||||
currentAgent={currentAgent}
|
||||
onSelectAgent={onSelectAgent}
|
||||
onClose={() => {
|
||||
setMobileAgentsVisible(false);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -243,7 +243,7 @@ const DetailModal: React.FC<Props> = ({ detail, onSubmit, onCancel }) => {
|
||||
<FormItem name="pattern" label="函数描述">
|
||||
<TextArea placeholder="请输入函数描述,多个描述换行分隔" allowClear />
|
||||
</FormItem>
|
||||
<FormItem name="params" label="函数参数" hidden={pluginType === PluginTypeEnum.DSL}>
|
||||
{/* <FormItem name="params" label="函数参数" hidden={pluginType === PluginTypeEnum.DSL}>
|
||||
<div className={styles.paramsSection}>
|
||||
{functionParams.map((functionParam: FunctionParamFormItemType) => {
|
||||
const { id, name, type, description } = functionParam;
|
||||
@@ -300,7 +300,7 @@ const DetailModal: React.FC<Props> = ({ detail, onSubmit, onCancel }) => {
|
||||
新增函数参数
|
||||
</Button>
|
||||
</div>
|
||||
</FormItem>
|
||||
</FormItem> */}
|
||||
<FormItem name="exampleQuestions" label="示例问题">
|
||||
<div className={styles.paramsSection}>
|
||||
{examples.map((example) => {
|
||||
@@ -340,7 +340,7 @@ const DetailModal: React.FC<Props> = ({ detail, onSubmit, onCancel }) => {
|
||||
<FormItem name="url" label="地址" rules={[{ required: true, message: '请输入地址' }]}>
|
||||
<Input placeholder="请输入地址" allowClear />
|
||||
</FormItem>
|
||||
<FormItem name="params" label="参数">
|
||||
<FormItem name="params" label="函数参数">
|
||||
<div className={styles.paramsSection}>
|
||||
{filters.map((filter: any) => {
|
||||
return (
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"experimentalDecorators": true,
|
||||
"suppressImplicitAnyIndexErrors": true,
|
||||
"ignoreDeprecations": "5.0",
|
||||
"strict": true,
|
||||
"paths": {
|
||||
|
||||
Reference in New Issue
Block a user