Skip to content

Commit

Permalink
Ospp 2024/feat schema render (#780)
Browse files Browse the repository at this point in the history
* fix: Fixed AI chat function

* feat: Improve speech input function, dialogue display markdown conversion

* fix: Modified the verification rules and style adjustment of accessToken

* refactor: Refactored DesignPlugins by extracting popup components, optimizing code formatting

* fix: Modify the open token dialog logic

* fix: Optimize code details

* feat: Add a token setting entry

* fix: Fix code details

* feat: Introduce AI dialog model "Kimi"

* fix:Update session carry immediately after adding token

* fix: Modify code details

* fix: Remove redundant AI models

* fix: Remove redundant code and normalize naming

* feat: Generate the schema from the generated code

* fix: Add missing code

* fix: Add missing code
  • Loading branch information
Fleurxxx authored Oct 23, 2024
1 parent 1597244 commit f3798b4
Show file tree
Hide file tree
Showing 10 changed files with 122 additions and 34 deletions.
35 changes: 35 additions & 0 deletions packages/plugins/robot/docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# 打开 AI 聊天窗口

![robot_process1.png](image/robot_process1.png)


# 配置 AI 访问令牌

为了确保您的会话安全且有效,您需要输入属于您个人的 AI 访问令牌。请按照以下步骤操作:

1. 在聊天窗口中找到令牌输入区域。
2. 输入您从对应 AI 模型官网获取的访问令牌。
3. 确保令牌的准确性,以避免连接错误。

![robot_process2.png](image/robot_process2.png)

**如何获取 Kimi 接口访问令牌?**

- 访问令牌需要您自行前往 [Moonshot AI 开放平台](https://platform.moonshot.cn/console/api-keys) 生成并保存。
- 在左侧菜单选择 “ API Key 管理 ”,根据指引创建个人密钥。
![key_process1.png](image/key_process1.png)

- 注意密钥只会在新建后显示一次,妥善保存您所生成的密钥。如果您遗失了令牌,请登录到您的 API Key 管理页面重新生成新的令牌。
![key_process2.png](image/key_process2.png)


# 通过提问,让AI生成页面

您可以上传图片,并通过语音或手动输入需求描述生成代码。AI 生成的代码将自动渲染在画布上,实时显示页面效果。

![img_1.png](image/robot_process3.png)


# 通过继续提问,让AI修改生成的页面

如需对生成的页面进行调整,只需继续提问。AI 将根据您的新指令对页面进行迭代修改,帮助您逐步完善设计与功能。
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 17 additions & 5 deletions packages/plugins/robot/src/ContentDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -45,24 +45,36 @@ export default {
.code-block {
position: relative;
}
.code-block:hover .copy-btn {
.code-block:hover .code-block-btn {
opacity: 1;
transition: opacity 0.3s ease, transform 0.3s ease;
}
.code-container {
padding: 10px;
border-radius: 5px;
}
.generate-btn {
right: 75px;
}
.copy-btn {
width: 56px;
font-size: 12px;
right: 8px;
}
.code-block-btn {
cursor: pointer;
position: absolute;
top: 8px;
font-size: 12px;
line-height: 12px;
background-color: #ccc;
border: none;
padding: 5px 10px;
cursor: pointer;
position: absolute;
top: 5px;
right: 5px;
border-radius: 3px;
transition: all 0.3s;
opacity: 0;
Expand Down
83 changes: 60 additions & 23 deletions packages/plugins/robot/src/Main.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
:key="item.label"
:class="{ 'selected-model': currentModel === item.value }"
@click="changeModel(item)"
>{{ item.label }}</tiny-dropdown-item
>
>{{ item.label }}
</tiny-dropdown-item>
</tiny-dropdown-menu>
</template>
</tiny-dropdown>
Expand Down Expand Up @@ -115,7 +115,8 @@ import {
DropdownMenu as TinyDropdownMenu,
DropdownItem as TinyDropdownItem
} from '@opentiny/vue'
import { useCanvas, useHistory, usePage, useModal } from '@opentiny/tiny-engine-controller'
import { useCanvas, useHistory, usePage, useModal, useLayout } from '@opentiny/tiny-engine-controller'
import { iconChevronDown, iconSetting, iconPicture, iconError } from '@opentiny/vue-icon'
import { extend } from '@opentiny/vue-renderless/common/object'
import { useHttp } from '@opentiny/tiny-engine-http'
Expand Down Expand Up @@ -152,7 +153,7 @@ export default {
const activeMessages = ref([])
const connectedFailed = ref(false)
const inputContent = ref('')
const inProcesing = ref(false)
const inProcessing = ref(false)
const selectedModel = ref(AIModelOptions[0])
let currentModel = AIModelOptions[0]
const { confirm } = useModal()
Expand Down Expand Up @@ -198,20 +199,29 @@ export default {
pageSettingState.currentPageData['page_content'] = schema
pageSettingState.currentPageDataCopy = extend(true, {}, pageSettingState.currentPageData)
clearCurrentState()
// 已经创建过临时页面只更新schema
useLayout().layoutState.pageStatus = {
state: useLayout().layoutState.pageStatus.state,
data: {}
}
initData(pageSettingState.currentPageData['page_content'], pageSettingState.currentPageData)
useHistory().addHistory()
}
const codeRules = `
我想让你充当 Stackoverflow 的帖子。我将提出与编程有关的问题,你将回答答案是什么。我希望你只回答给定的答案,在没有足够的细节时写出解释。
每次回复请遵循以下准则:
1. 如果需要展示代码,确保回复中只包含一个代码块。
2. 所有代码必须基于 Vue 3 框架编写。
3. 所有使用的组件必须来自 TinyVue 组件库,严禁使用 Element UI 等其他第三方组件库或原生组件。例如,想使用输入框组件,应该使用TinyVue组件库中的 \`tiny-input\`;想使用按钮组件,应该使用 TinyVue 组件库中的 \`tiny-button\`
4. 仔细阅读并遵循 [TinyVue 组件库文档](https://opentiny.design/tiny-vue/zh-CN/os-theme/overview) 中的指导,确保代码的准确性和一致性。
请根据上述准则,使用 TinyVue 组件库生成高质量的前端代码。
`
从现在开始,请扮演一名前端专家。如果需要根据图片或者描述生成前端代码,代码中的所有组件必须使用 Vue 3 框架和 TinyVue 组件库进行编写。例如,如果你想使用按钮组件,应该使用 TinyVue 组件库中的 \`TinyButton\`
以下是 TinyVue 组件库的文档,请通读并遵循其中的指导来生成代码:[TinyVue 组件库文档](https://opentiny.design/tiny-vue/zh-CN/os-theme/overview)
生成代码时遵从以下几条要求:
###
1. 回复中只能有一个代码块
2. 所有生成的代码都是基于 Vue 3 框架
3. 所有组件都来自 TinyVue 组件库,避免使用原生组件或其他第三方库
4. 参考并遵循 TinyVue 文档中的组件使用方式
5. 所有的组件都遵循了首字母大写的命名约定,例如用TinyForm、TinyFormItem、Text等。
###
`
// 在每一次发送请求之前,都把引入区块的内容,给放到第一条消息中
// 为了不污染存储在localstorage里的用户的原始消息,这里进行了简单的对象拷贝
// 引入区块不存放在localstorage的原因:因为区块是可以变化的,用户可能在同一个会话中,对区块进行了删除和创建。那么存放的数据就不是即时数据了。
Expand All @@ -238,7 +248,7 @@ export default {
http
.post('/app-center/api/ai/chat', getSendSeesionProcess(), { timeout: 600000 })
.then((res) => {
const { originalResponse } = res
const { originalResponse, schema } = res
const responseMessage = getAiRespMessage(
originalResponse.choices?.[0]?.message.role,
originalResponse.choices?.[0]?.message.content
Expand All @@ -247,15 +257,15 @@ export default {
originalResponse.choices?.[0]?.message.role,
originalResponse.choices?.[0]?.message.content
)
sessionProcess.messages.push(responseMessage)
sessionProcess.displayMessages.push(respDisplayMessage)
messages.value[messages.value.length - 1].content = originalResponse.choices?.[0]?.message.content
setContextSession()
// TODO:返回schema格式的代码
// if (schema?.schema) {
// createNewPage(schema.schema)
// }
inProcesing.value = false
if (schema?.schema) {
createNewPage(schema.schema)
}
inProcessing.value = false
connectedFailed.value = false
})
.catch((error) => {
Expand All @@ -269,7 +279,7 @@ export default {
}
messages.value[messages.value.length - 1].content = '连接失败'
localStorage.removeItem('aiChat')
inProcesing.value = false
inProcessing.value = false
connectedFailed.value = false
})
}
Expand Down Expand Up @@ -391,7 +401,7 @@ export default {
})
return
}
if (inProcesing.value) {
if (inProcessing.value) {
Notify({
type: 'error',
message: '请等待当前会话完成后再试!',
Expand All @@ -406,7 +416,7 @@ export default {
await resizeChatWindow()
}
const message = getMessage(realContent, 'user')
inProcesing.value = true
inProcessing.value = true
messages.value.push(message)
sessionProcess?.messages.push(message)
sessionProcess?.displayMessages.push(message)
Expand All @@ -418,6 +428,7 @@ export default {
if (!isModel) {
inputContent.value = ''
imageUrl.value = ''
imageContent.value = ''
}
await scrollContent()
await sleep(1000)
Expand Down Expand Up @@ -558,11 +569,12 @@ export default {
margin-top: -10px;
max-width: 100%;
border-radius: 5px;
border: 1px solid var(--ti-lowcode-chat-model-user-text-border);
.image {
width: 100px;
height: 70px;
height: 100%;
border-radius: 5px;
border: 1px solid var(--ti-lowcode-chat-model-user-text-border);
}
}
Expand Down Expand Up @@ -621,15 +633,18 @@ export default {
.chat-title-icons {
font-size: 16px;
height: 16px;
svg {
float: right;
margin: 0 4px;
cursor: pointer;
&:hover {
opacity: 0.8;
}
}
}
.chat-title {
font-weight: bold;
font-size: 14px;
Expand All @@ -643,11 +658,14 @@ export default {
.tiny-dropdown .tiny-dropdown__trigger:not(.tiny-button) .tiny-svg {
vertical-align: middle;
}
.chat-window {
max-height: 400px;
overflow: scroll;
.chat-avatar-wrap {
width: 46px;
.chat-avatar {
width: 28px;
height: 28px;
Expand All @@ -656,10 +674,12 @@ export default {
border: 1px solid var(--ti-lowcode-chat-model-avatar-border);
border-radius: 50px;
}
.chat-avatar-ai {
border: none;
}
}
.chat-content {
max-width: 568px;
border-radius: 8px;
Expand All @@ -674,6 +694,7 @@ export default {
color: var(--ti-lowcode-chat-model-user-text);
}
}
.chat-message-row {
margin-bottom: 20px;
}
Expand All @@ -696,6 +717,7 @@ export default {
font-size: 12px;
margin-top: 10px;
color: var(--ti-lowcode-chat-model-text);
span {
display: inline-block;
line-height: 32px;
Expand All @@ -704,35 +726,43 @@ export default {
border: 1px solid var(--ti-lowcode-chat-model-text-border);
border-radius: 20px;
cursor: pointer;
&:hover {
border-color: var(--ti-lowcode-chat-model-text);
}
}
}
.chat-submit {
margin-top: 14px;
font-size: 14px;
.tiny-input {
width: calc(100% - 236px);
.tiny-input__inner {
height: 40px;
background-color: var(--ti-lowcode-chat-model-input-bg);
border: none;
}
svg {
font-size: 16px;
color: var(--ti-lowcode-chat-model-input-icon);
}
.upload-image {
margin-right: 7px;
}
.microphone {
font-size: 18px;
}
.microphone-svg {
color: var(--ti-lowcode-base-blue-6);
}
}
.tiny-button {
background-color: var(--ti-lowcode-chat-model-button-bg) !important;
border: 1px solid var(--ti-lowcode-chat-model-button-border) !important;
Expand All @@ -742,11 +772,13 @@ export default {
border-radius: 12px !important;
float: right;
margin-right: 5px;
&:hover {
opacity: 0.8;
}
}
}
.hidden-text {
white-space: nowrap;
text-overflow: ellipsis;
Expand All @@ -756,18 +788,23 @@ export default {
.chat-loading .tiny-loading__spinner svg {
fill: var(--ti-lowcode-chat-loading-svg-color);
}
.chat-loading .tiny-loading__spinner .tiny-loading__text {
color: var(--ti-lowcode-chat-loading-text-color);
}
.chat-model-popover {
background-color: var(--ti-lowcode-chat-model-popover-bg);
.tiny-dropdown-item {
color: var(--ti-lowcode-chat-model-popover-color);
&:hover {
color: var(--ti-lowcode-chat-model-popover-active-color);
background-color: var(--ti-lowcode-chat-model-popover-active-bg);
}
}
.selected-model {
color: var(--ti-lowcode-chat-model-popover-active-color);
background-color: var(--ti-lowcode-chat-model-popover-active-bg);
Expand Down
12 changes: 8 additions & 4 deletions packages/plugins/robot/src/TokenDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,13 @@ export default {
const submitKeyForm = () => {
keyFormRef.value.validate((valid) => {
if (valid) {
localStorage.setItem(props.currentModel.modelKey, keyForm.value.token)
emit('token-status', true)
closeKeyFormDialog()
try {
localStorage.setItem(props.currentModel.modelKey, keyForm.value.token)
emit('token-status', true)
closeKeyFormDialog()
} catch (error) {
emit('token-status', false)
}
}
})
}
Expand Down Expand Up @@ -96,7 +100,7 @@ export default {
<tiny-alert
:icon="TinyIconCommission"
:closable="false"
:description="`尝试用自己的 ${model.modelKey} 开启AI对话功能吧!`"
:description="`尝试用自己的 ${model.modelKey} 开启 AI 对话功能吧!`"
></tiny-alert>
<tiny-form-item label="" prop="token">
<tiny-input
Expand Down
Loading

0 comments on commit f3798b4

Please sign in to comment.