提交 dd36ebcc 编写于 作者: DCloud_JSON's avatar DCloud_JSON

修复 不兼容Vue3的问题,代码高亮不换行的问题,云函数超时问题

上级 c5879ea5
......@@ -12,7 +12,7 @@
},
"h5" :
{
"launchtype" : "local"
"launchtype" : "remote"
},
"mp-weixin" :
{
......
<template>
<view class="rich-text-box">
<view class="rich-text-box" :class="{'show-cursor':showCursor}">
<rich-text v-if="nodes&&nodes.length" space="nbsp" :nodes="nodes"></rich-text>
</view>
</template>
<script>
import parseHtml from './html-parser.js';
const MarkdownIt = require('markdown-it')
const hljs = require('highlight.js')
import MarkdownIt from "markdown-it";
import hljs from 'highlight.js';
const md = new MarkdownIt({
html: false,
html: true,
highlight: function(str, lang) {
if (lang && hljs.getLanguage(lang)) {
try {
return `<pre class="hljs"><code>${hljs.highlight(lang, str, true).value}</code></pre>`
return '<pre class="hljs"><code>' +
hljs.highlight(lang, str, true).value +
'</code></pre>';
} catch (__) {}
}
return '<pre class="hljs"><code>' + md.utils.escapeHtml(str) + '</code></pre>';
}
})
export default {
name: "msg",
data() {
return {
};
return {};
},
props: {
md: {
type: String,
default () {
return '# H1 \r ```js' + '\r alert(1); \r```'
return ''
}
},
showCursor: {
type: [Boolean, Number],
default () {
return false
}
}
},
computed: {
html() {
// req.body.content 代表md代码
return md.render(this.md)
// req.body.content 代表md代码
return md.render(this.md + '<span class="cursor">|</span>')
},
nodes() {
nodes() {
return parseHtml(this.html)
}
},
}
}
}
</script>
<style lang="scss">
@import "highlight.js/styles/agate.css";
@import "highlight.js/styles/a11y-dark.css";
/* #ifndef APP-NVUE */
.hljs code {
padding: 5px;
pre.hljs{
padding: 5px 8px;
margin: 5px 0;
display: flex;
overflow: scroll;
}
.cursor{
display: none;
}
.show-cursor .cursor {
display: inline-block;
color: blue;
font-weight: bold;
animation: blinking 1s infinite;
}
@keyframes blinking {
from {
opacity: 1.0;
}
to {
opacity: 0.0;
}
}
/* #endif */
......
{
"name" : "hello uni-ai",
"name" : "uni-ai-chat",
"appid" : "__UNI__8F14B14",
"description" : "",
"versionName" : "1.0.0",
......@@ -68,7 +68,7 @@
"uniStatistics" : {
"enable" : false
},
"vueVersion" : "2",
"vueVersion" : "3",
"h5" : {
"unipush" : {
"enable" : true
......
{
"hash": "2dbbc430",
"browserHash": "bb2ca09f",
"optimized": {
"markdown-it": {
"src": "../../markdown-it/index.js",
"file": "markdown-it.js",
"fileHash": "a4c68cee",
"needsInterop": true
},
"highlight.js": {
"src": "../../highlight.js/es/index.js",
"file": "highlight__js.js",
"fileHash": "7d4e05cb",
"needsInterop": false
}
},
"chunks": {
"chunk-DFKQJ226": {
"file": "chunk-DFKQJ226.js"
}
}
}
\ No newline at end of file
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __commonJS = (cb, mod) => function __require() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
export {
__commonJS,
__toESM
};
//# sourceMappingURL=chunk-DFKQJ226.js.map
{
"version": 3,
"sources": [],
"sourcesContent": [],
"mappings": "",
"names": []
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
因为 它太大了无法显示 source diff 。你可以改为 查看blob
{"type":"module"}
\ No newline at end of file
......@@ -11,9 +11,8 @@
</view>
<view style="flex-direction: column;">
<view class="content">
<uni-ai-msg :md="msg.content"></uni-ai-msg>
<uni-ai-msg :md="msg.content" :show-cursor="index == msgList.length-1 && msg.isAi && sseIndex"></uni-ai-msg>
<!-- <text :selectable="true">{{msg.content}}</text> -->
<text v-if="index == msgList.length-1 && msg.isAi && sseIndex" class="blinking-cursor">|</text>
</view>
</view>
<uni-icons v-if="index == msgList.length-1 && !msg.isAi && msg.state != 100 && msgStateIcon(msg)"
......@@ -37,8 +36,8 @@
</view>
</view>
<label class="set-stream">
<text style="font-size: 12px;">stream:</text>
<switch style="transform: scale(0.7);" checked="true" :checked="stream" @change="changeStream" />
<text style="font-size: 12px;">流式响应:</text>
<switch style="transform: scale(0.7);" :checked="stream" @change="changeStream" />
</label>
</view>
</template>
......@@ -78,9 +77,12 @@
}
}
},
watch: {
msgList(msgList) {
uni.setStorageSync('uni-ai-msg', msgList)
watch: {
msgList:{
handler(msgList) {
uni.setStorageSync('uni-ai-msg', msgList)
},
deep:true
}
},
async mounted() {
......@@ -94,8 +96,7 @@
this.msgList = uni.getStorageSync('uni-ai-msg') || []
// this.msgList.pop()
console.log('this.msgList', this.msgList);
// console.log('this.msgList', this.msgList);
this.showLastMsg()
// #ifdef H5
......@@ -124,8 +125,11 @@
// #endif
},
methods: {
// updateLastMsg(){
// },
changeStream(e){
console.log('e',e.detail.value);
// console.log('e',e.detail.value);
this.stream = e.detail.value
},
retriesSendMsg() {
......@@ -158,10 +162,10 @@
let msgs = [...this.msgList]
// 带总结的消息 index
let findIndex = [...msgs].reverse().findIndex(item => item.summarize)
console.log('findIndex', findIndex)
// console.log('findIndex', findIndex)
if (findIndex != -1) {
let aiSummaryIndex = msgs.length - findIndex - 1
console.log('aiSummaryIndex', aiSummaryIndex)
// console.log('aiSummaryIndex', aiSummaryIndex)
msgs[aiSummaryIndex].content = msgs[aiSummaryIndex].summarize
// 拿最后一条带直接的消息作为与ai对话的msg body
msgs = msgs.splice(aiSummaryIndex, msgs.length - 1)
......@@ -187,8 +191,9 @@
let SSEChannel = false;
if(this.stream){
SSEChannel = new uniCloud.SSEChannel() // 创建消息通道
// console.log('SSEChannel',SSEChannel);
SSEChannel.on('message', (message) => { // 监听message事件
console.log('on message', message);
// console.log('on message', message);
if (this.sseIndex === 0) {
this.msgList.push({
isAi: true,
......@@ -206,7 +211,7 @@
this.sseIndex++
})
SSEChannel.on('end', (e) => { // 监听end事件,如果云端执行end时传了message,会在客户端end事件内收到传递的消息
console.log('on end', e);
// console.log('on end', e);
if(e && e.summarize){
let length = this.msgList.length,
lastMsg = this.msgList[length - 1]
......@@ -234,7 +239,7 @@
this.msgList.splice(index, 1, lastItem)
if (!SSEChannel) {
console.log(res, res.reply);
// console.log(res, res.reply);
this.msgList.push({
isAi: true,
content: res.reply,
......@@ -459,7 +464,6 @@
max-width: 500rpx;
background-color: #FFF;
border-radius: 5px;
/* border-top-left-radius: 0; */
padding: 12px 10px;
margin-left: 10px;
/* #ifndef APP-NVUE */
......@@ -486,8 +490,6 @@
.reverse .content {
margin-left: 0;
margin-right: 10px;
border-top-left-radius: 15px;
// border-top-right-radius: 0;
}
.reverse-align {
......@@ -502,21 +504,6 @@
font-size: 12px;
justify-content: center;
}
.blinking-cursor {
color: blue;
font-weight: bold;
animation: blinking 1s infinite;
}
@keyframes blinking {
from {
opacity: 1.0;
}
to {
opacity: 0.0;
}
}
.set-stream{
position: fixed;
......
......@@ -4,21 +4,21 @@ uni-ai-chat是基于[uni-ai](https://uniapp.dcloud.net.cn/uniCloud/uni-ai.html)
视频效果:
<video controls src="https://web-assets.dcloud.net.cn/unidoc/zh/uni-ai-chat/uni-ai-stream.mov" style="max-width: 100%; max-height: 70vh;"></video>
包含一个前端页面(路径:`/pages/chat/chat.vue`)和一个云对象(路径:`uniCloud-aliyun/cloudfunctions/uni-ai-chat/index.obj.js`)
包含一个前端页面(路径:`/pages/chat/chat.vue`)和一个云对象(路径:`uniCloud/cloudfunctions/uni-ai-chat/index.obj.js`)
## 体验步骤
1. 如之前未使用过uni-app,那请头学起。[uni-app官网](https://uniapp.dcloud.net.cn)
1. 如之前未使用过uni-app,那请头学起。[uni-app官网](https://uniapp.dcloud.net.cn)
2. 如果你还没有开通uniCloud,需要登录[https://unicloud.dcloud.net.cn/](https://unicloud.dcloud.net.cn/),创建一个服务空间。
3. 打开`uni-ai-chat`插件下载地址:[https://ext.dcloud.net.cn/plugin?name=uni-ai-chat](https://ext.dcloud.net.cn/plugin?name=uni-ai-chat)
4. 点击`使用HBuilderX导入示例项目`
5. 对项目根目录uniCloud点右键选择“云服务空间初始化向导”界面按提示部署项目
6. 在uni-app项目点右键创建uniCloud环境,关联之前创建的服务空间。
6. 在uni-app项目点右键,关联之前创建的服务空间。
## 注意事项
uni-ai-chat支持[stream](https://uniapp.dcloud.net.cn/uniCloud/uni-ai.html#%E6%B5%81%E5%BC%8F%E5%93%8D%E5%BA%94-chat-completion-stream)
模式,该模式会接收uni-ai的流式响应的数据,再通过[sse-channel](https://uniapp.dcloud.net.cn/uniCloud/sse-channel.html)即:云函数(云对象)请求中的中间状态通知通道向客户端推送消息
uni-ai-chat支持[流式响应](https://uniapp.dcloud.net.cn/uniCloud/uni-ai.html#%E6%B5%81%E5%BC%8F%E5%93%8D%E5%BA%94-chat-completion-stream)
模式,该模式会接收uni-ai的流式响应的数据,通过sse-channel[(云函数(云对象)请求中的中间状态通知通道)](https://uniapp.dcloud.net.cn/uniCloud/sse-channel.html)向客户端推送消息,
而使用`sse-channel`需要先[开通uni-push](https://uniapp.dcloud.net.cn/unipush-v2.html#%E7%AC%AC%E4%B8%80%E6%AD%A5-%E5%BC%80%E9%80%9A)
,目前uni-push2.0不支持本地调试(后续版本会支持),需要在HBuilderX控制台,更改`连接本地云函数``连接云端云函数`
,目前uni-push2.0不支持本地调试(后续版本会支持),需要在HBuilderX控制台,更改`连接本地云函数``连接云端云函数`
......@@ -11,12 +11,6 @@ module.exports = {
*** 激励视频是造富神器。行业经常出现几个人的团队,月收入百万的奇迹。 ***
*/
},
/**
* send方法描述
* @param {messages}
* @param {SSEChannel}
* @returns {object} 返回值描述
*/
async send({messages,SSEChannel}) {
// 初次调试时,可不从客户端获取数据,直接使用下面写死在云函数里的数据
// messages = [{
......@@ -32,29 +26,36 @@ module.exports = {
// 向uni-ai发送消息
return await chatCompletion({
messages,
SSEChannel
messages, //消息内容
SSEChannel, //sse渠道对象
// 以下参数参考:https://uniapp.dcloud.net.cn/uniCloud/uni-ai.html#get-llm-manager
// provider:"minimax",//llm服务商,目前支持openai、baidu、minimax。不指定时由uni-ai自动分配
// apiKey:"",//llm服务商的apiKey,如不填则使用uni-ai的key。如指定openai和baidu则必填
// accessToken:"",//llm服务商的accessToken。目前百度文心一言是必填
// proxy:""//可有效连接openai服务器的、可被uniCloud云函数连接的代理服务器地址。格式为IP或域名,域名不包含http前缀,协议层面仅支持https。配置为openai时必填
})
async function chatCompletion({
messages,
summarize = false,
SSEChannel = false
SSEChannel = false,
provider,
apiKey,
accessToken,
proxy
}) {
const llmManager = uniCloud.ai.getLLMManager({
// provider: 'openai',
// apiKey: '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',
// proxy: 'sgoa.dcloud.io',
provider: 'minimax',
// provider: 'baidu',
// accessToken: '24.3989d9fc6f2ff40813f9f9f8b006d72b.2592000.1682688547.282335-31576157'
provider,
apiKey,
accessToken,
proxy
})
let res = await llmManager.chatCompletion({
messages,
tokensToGenerate: 3000,
tokensToGenerate: 512,
stream: SSEChannel !== false
})
......@@ -72,7 +73,7 @@ module.exports = {
// console.log('---line----', line)
})
res.on('end', async () => {
console.log('---end----',reply)
// console.log('---end----',reply)
messages.push({
"content": reply,
......@@ -80,10 +81,10 @@ module.exports = {
})
let totalTokens = messages.map(i => i.content).join('').length;
console.error('totalTokens',totalTokens);
// console.log('totalTokens',totalTokens);
if (!summarize && totalTokens > 500) {
let replySummarize = await getSummarize(messages)
console.error('replySummarize',replySummarize)
// console.log('replySummarize',replySummarize)
await channel.end({summarize:replySummarize})
}else{
await channel.end()
......
{
"name": "uni-ai-chat",
"dependencies": {},
"extensions": {
"uni-cloud-jql": {},
"uni-cloud-ai": {},
"uni-cloud-push": {}
}
{
"name": "uni-ai-chat",
"dependencies": {},
"extensions": {
"uni-cloud-jql": {},
"uni-cloud-ai": {},
"uni-cloud-push": {}
},
"cloudfunction-config": {
"timeout": 60
}
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册