Skip to content

Commit 57ac995

Browse files
committed
feat(robot): code refactor
1 parent ea39870 commit 57ac995

File tree

16 files changed

+1281
-15
lines changed

16 files changed

+1281
-15
lines changed

packages/layout/src/DesignSettings.vue

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,6 @@ export default {
201201
display: flex;
202202
flex-direction: column;
203203
position: absolute;
204-
top: var(--base-top-panel-height);
205204
right: var(--base-nav-panel-width);
206205
z-index: 999;
207206

packages/layout/src/Main.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ export default {
154154
display: flex;
155155
flex-flow: row nowrap;
156156
z-index: 4;
157+
position: relative;
157158
}
158159
:deep(.monaco-editor .suggest-widget) {
159160
border-width: 0;

packages/plugins/robot/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
*
1111
*/
1212

13-
import entry from './src/Main.vue'
13+
// import entry from './src/Main.vue'
14+
import entry from './src/Home.vue'
1415
import metaData from './meta'
1516
import './src/styles/vars.less'
1617
import '@opentiny/tiny-robot/dist/style.css'

packages/plugins/robot/mock/test.ts

Whitespace-only changes.
Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
<template>
2+
<div class="robot">
3+
<toolbar-base
4+
content="AI对话框"
5+
:icon="options.icon?.default || options?.icon"
6+
:options="options"
7+
@click-api="openAIRobot"
8+
>
9+
</toolbar-base>
10+
<Teleport v-if="showTeleport" defer :to="fullscreen ? 'body' : '.tiny-engine-right-robot'">
11+
<div class="robot-chat-container" :class="{ 'robot-chat-container-fullscreen': fullscreen }">
12+
<robot-chat
13+
:ref="robotChatRef"
14+
:prompt-items="promptItems"
15+
:allowFiles="isVisualModel() && aiType === AI_MODES.Agent"
16+
@fileSelected="handleFileSelected"
17+
>
18+
<template #operations>
19+
<tiny-popover
20+
width="290"
21+
trigger="manual"
22+
v-model="showSettingPopover"
23+
:visible-arrow="false"
24+
popper-class="setting-popover"
25+
>
26+
<robot-setting-popover
27+
v-if="showSettingPopover"
28+
@changeType="changeModel"
29+
@close="closePanel"
30+
></robot-setting-popover>
31+
<template #reference>
32+
<span class="chat-title-dropdown" @click.stop="showSettingPopover = true">
33+
<svg-icon name="setting" class="operations-setting ml8"> </svg-icon>
34+
</span>
35+
</template>
36+
</tiny-popover>
37+
</template>
38+
<template #footer-left>
39+
<robot-type-select :aiType="aiType" @typeChange="typeChange"></robot-type-select>
40+
<mcp-server :position="mcpDrawerPosition" v-if="aiType === AI_MODES.Chat"></mcp-server>
41+
</template>
42+
</robot-chat>
43+
<tiny-dialog-box v-model:visible="showPreview" title="当前AI渲染效果" width="80%">
44+
<schema-renderer v-if="showPreview" :schema="currentSchema"></schema-renderer>
45+
</tiny-dialog-box>
46+
</div>
47+
</Teleport>
48+
</div>
49+
</template>
50+
51+
<script setup lang="ts">
52+
import { computed, h, onMounted, ref } from 'vue'
53+
import { ToolbarBase } from '@opentiny/tiny-engine-common'
54+
import RobotChat from './components/RobotChat.vue'
55+
import RobotSettingPopover from './components/RobotSettingPopover.vue'
56+
import { TinyPopover, TinyDialogBox } from '@opentiny/vue'
57+
import { useRobot, getMetaApi, META_SERVICE } from '@opentiny/tiny-engine-meta-register'
58+
import McpIconComponent from './icons/mcp-icon.vue'
59+
import PageIconComponent from './icons/page-icon.vue'
60+
import StudyIconComponent from './icons/study-icon.vue'
61+
import type { PromptProps } from '@opentiny/tiny-robot'
62+
import SchemaRenderer from '@opentiny/tiny-schema-renderer'
63+
import RobotTypeSelect from './components/RobotTypeSelect.vue'
64+
import McpServer from './mcp/McpServer.vue'
65+
import { updateLLMConfig } from './client'
66+
67+
const { options } = defineProps({
68+
options: {
69+
type: Object,
70+
default: () => ({})
71+
}
72+
})
73+
74+
const robotChatRef = ref('robotChatRef')
75+
76+
const fullscreen = computed(() => {
77+
return robotChatRef.value?.fullscreen
78+
})
79+
80+
const mcpDrawerPosition = computed(() => {
81+
return {
82+
type: 'fixed',
83+
position: {
84+
top: 'var(--base-top-panel-height)',
85+
bottom: 0,
86+
...(fullscreen.value ? { left: 0 } : { right: 'var(--tr-container-width)' })
87+
}
88+
}
89+
})
90+
91+
const promptItems: PromptProps[] = [
92+
{
93+
label: 'MCP工具',
94+
description: '帮我查询当前的页面列表',
95+
icon: h(McpIconComponent),
96+
badge: 'NEW'
97+
},
98+
{
99+
label: '页面搭建场景',
100+
description: '给当前页面中添加一个问卷调查表单',
101+
icon: h(PageIconComponent)
102+
},
103+
{
104+
label: '学习/知识型场景',
105+
description: 'Vue3 和 React 有什么区别?',
106+
icon: h(StudyIconComponent)
107+
}
108+
]
109+
110+
const showPreview = ref(false)
111+
const currentSchema = ref(null)
112+
const showTeleport = ref(false)
113+
const showSettingPopover = ref(false)
114+
115+
const { robotSettingState, AI_MODES, AIModelOptions } = useRobot()
116+
117+
const isVisualModel = () => {
118+
const platform = AIModelOptions.find((option) => option.value === robotSettingState.selectedModel.baseUrl)
119+
const modelAbility = platform.model.find((item) => item.value === robotSettingState.selectedModel.model)
120+
return modelAbility?.ability?.includes('visual') || false
121+
}
122+
123+
const aiType = ref(AI_MODES.Agent)
124+
125+
const typeChange = (type: string) => {
126+
aiType.value = type
127+
robotChatRef.value?.createConversation()
128+
updateLLMConfig({
129+
apiUrl: type === AI_MODES.Agent ? '/app-center/api/ai/chat' : '/app-center/api/chat/completions'
130+
})
131+
}
132+
133+
const changeApiKey = () => {
134+
localStorage.removeItem('aiChat')
135+
}
136+
137+
const changeModel = (model) => {
138+
robotSettingState.selectedModel = {
139+
label: model.label || model.model,
140+
activeName: model.activeName,
141+
baseUrl: model.baseUrl,
142+
model: model.model,
143+
completeModel: model.completeModel,
144+
apiKey: model.apiKey
145+
}
146+
// singleAttachmentItems.value = []
147+
// imageUrl.value = ''
148+
// endContent()
149+
150+
if (
151+
robotSettingState.selectedModel.apiKey !== model.apiKey &&
152+
robotSettingState.selectedModel.baseUrl === model.baseUrl &&
153+
robotSettingState.selectedModel.model === model.model
154+
) {
155+
robotSettingState.selectedModel.apiKey = model.apiKey
156+
changeApiKey()
157+
}
158+
}
159+
160+
const closePanel = () => {
161+
showSettingPopover.value = false
162+
}
163+
164+
const openAIRobot = () => {
165+
robotChatRef.value?.openAIRobot()
166+
}
167+
168+
const handleFileSelected = (formData: unknown, updateAttachment: (resourceUrl: string) => void) => {
169+
try {
170+
getMetaApi(META_SERVICE.Http)
171+
.post('/material-center/api/resource/upload', formData, {
172+
headers: {
173+
'Content-Type': 'multipart/form-data'
174+
}
175+
})
176+
.then((res: any) => {
177+
updateAttachment(res?.resourceUrl)
178+
})
179+
} catch (error) {
180+
// eslint-disable-next-line no-console
181+
console.error('上传失败', error)
182+
updateAttachment('')
183+
}
184+
}
185+
186+
onMounted(async () => {
187+
setTimeout(() => {
188+
showTeleport.value = true
189+
}, 1000)
190+
})
191+
</script>
192+
193+
<style scoped lang="less">
194+
.robot {
195+
margin-right: 8px;
196+
}
197+
.robot-chat-container {
198+
height: 100%;
199+
}
200+
.setting-popover {
201+
.robot-setting .bottom-buttons .tiny-button {
202+
margin-left: 10px;
203+
}
204+
}
205+
206+
.operations-setting {
207+
font-size: 28px;
208+
padding: 4px;
209+
}
210+
211+
.robot-chat-container-fullscreen {
212+
:deep(.tiny-container) {
213+
container-type: inline-size;
214+
215+
&.tr-container.tr-container {
216+
top: var(--base-top-panel-height);
217+
position: fixed;
218+
height: auto;
219+
}
220+
}
221+
.operations-setting {
222+
font-size: 20px;
223+
}
224+
@media (min-width: 1280px) {
225+
:deep(.robot-chat-container-content) {
226+
width: 1280px;
227+
margin: 0 auto;
228+
}
229+
:deep(.footer-sender) {
230+
width: 1280px;
231+
margin: 0 auto;
232+
padding: 20px 15px;
233+
}
234+
}
235+
}
236+
</style>

packages/plugins/robot/src/Main.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,17 +130,17 @@ import type { BubbleRoleConfig, PromptProps } from '@opentiny/tiny-robot'
130130
import { IconNewSession } from '@opentiny/tiny-robot-svgs'
131131
import SchemaRenderer from '@opentiny/tiny-schema-renderer'
132132
import { utils } from '@opentiny/tiny-engine-utils'
133-
import RobotSettingPopover from './RobotSettingPopover.vue'
133+
import RobotSettingPopover from './components/RobotSettingPopover.vue'
134134
import { PROMPTS } from './js/prompts'
135135
import * as jsonpatch from 'fast-json-patch'
136136
import { chatStream, checkComponentNameExists } from './js/utils'
137137
import McpServer from './mcp/McpServer.vue'
138-
import useMcpServer from './mcp/useMcp'
138+
import useMcpServer from './composables/useMcp'
139139
import MarkdownRenderer from './mcp/MarkdownRenderer.vue'
140140
import LoadingRenderer from './mcp/LoadingRenderer.vue'
141141
import { sendMcpRequest, serializeError } from './mcp/utils'
142142
import type { RobotMessage } from './mcp/types'
143-
import RobotTypeSelect from './RobotTypeSelect.vue'
143+
import RobotTypeSelect from './components/RobotTypeSelect.vue'
144144
import McpIconComponent from './icons/mcp-icon.vue'
145145
import PageIconComponent from './icons/page-icon.vue'
146146
import StudyIconComponent from './icons/study-icon.vue'

0 commit comments

Comments
 (0)