直接上效果图:
页面分上下两部分,上面是会话界面,底部是提交框。
直接上代码:
解决步骤1:引入vue+elementUi
<head>
<meta charset="UTF-8" />
<title>Fetch Stream Example</title>
</head>
<script src="./vue.js"></script>
<!-- 引入样式 -->
<link
rel="stylesheet"
href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"
/>
<!-- 引入组件库 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
解决步骤2:搭建静态页面——使用vue
<div id="bodyWrap">
<div class="wrapCon">
<div class="wrapCls" v-for="(item,index) in historyList" :key="index">
<div class="questionWrap">
<img
src="https://img2.baidu.com/it/u=2125727497,3458875842&fm=253&fmt=auto&app=138&f=JPEG"
alt=""
/>
<div class="question">{{item.message}}</div>
</div>
<div class="output">{{item.content}}</div>
</div>
</div>
<div id="footerId">
<el-input
type="textarea"
:rows="3"
ref="textearaRef"
placeholder="请输入内容"
v-model="textarea"
>
</el-input>
<el-button size="small" type="primary" @click="handleSubmit"
>提交</el-button
>
</div>
</div>
解决步骤3:css部分
<style>
* {
margin: 0;
padding: 0;
}
body {
font-size: 14px;
padding: 10px;
}
#bodyWrap {
height: 100vh;
border: 1px solid #efefef;
border-radius: 10px;
padding: 10px;
}
.wrapCon {
height: calc(100vh - 60px);
overflow: auto;
}
#footerId {
position: fixed;
bottom: 10px;
display: flex;
left: 30px;
right: 30px;
}
#footerId .el-textarea {
margin-right: 10px;
flex: 1;
}
.wrapCls {
margin: 10px;
padding: 10px;
border: 1px solid #efefef;
border-radius: 5px;
}
.questionWrap {
display: flex;
width: 60%;
}
.questionWrap img {
border-radius: 50%;
margin-right: 10px;
width: 40px;
height: 40px;
}
.output {
margin-top: 10px;
background-color: #d9ecff;
border: 1px solid #409eff;
padding: 10px;
border-radius: 4px;
margin-left: 50px;
min-height: 20px;
}
.question {
background-color: #f0f9eb;
border: 1px solid #67c23a;
padding: 10px;
border-radius: 4px;
}
</style>
解决步骤4:js部分
<script>
new Vue({
el: '#bodyWrap',
data() {
return {
textarea:
'我的元器件参数是: 100Ω±1%-1/10W 帮我选择一个国巨型号,精简一下话术20字之内,只要给我一个型号就可以',
historyList: [],
};
},
mounted() {
this.$refs.textearaRef.focus();
},
methods: {
handleSubmit() {
if (!this.textarea) {
return;
}
this.render();
},
render() {
let that = this;
let params = {
message: that.textarea,
content: '',
};
that.historyList.push(params);
// 假设你要获取的数据是一个文本流
//下面的接口地址是我局域网后端同事提供的,需要换成你们自己的才可以
fetch('http://192.168.35.3:11434/api/chat', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
model: 'llama3.1',
messages: [
{
role: 'user',
content: this.textarea,
},
],
stream: true,
}),
dataType: 'text/event-stream',
})
.then((response) => response.body) // 获取响应体
.then((body) => {
// 创建一个读取流
const reader = body.getReader();
// 使用循环来读取数据流
const p = document.createElement('p');
const output = document.createElement('div');
(function read() {
reader.read().then(({ done, value }) => {
let con = '';
if (done) {
return;
}
let json = new TextDecoder('utf-8').decode(value);
if (json) {
let obj = JSON.parse(json);
p.appendChild(
document.createTextNode(obj.message.content)
);
output.appendChild(p);
that.historyList[that.historyList.length - 1].content +=
obj.message.content;
}
// 递归调用read函数以继续读取数据流
read();
});
})();
});
},
},
});
</script>
最开始其实是想用eventSource
的方式来处理的。但是onMessage
一直收不到后端的数据,所以后面就放弃了,转而用了fetch
。下面也记录一下eventSource
的用法:
下面使用eventSource
来处理,但是效果没有实现
解决步骤1:在h5中使用fetchEventSource
,需要用到webpack
1.初始化包管理文件
npm install
2.安装webpack
和webpack-cli
编译器
npm install webpack --save-dev
npm install webpack-cli --save-dev
3.新建webpack.config.js
文件,文件内容如下:
const path = require('path');
module.exports = {
entry: './test.js', //打包入口
output: {
//打包文件输出路径
path: path.resolve(__dirname, 'dist'),
filename: 'index.js',
},
};
4.新建test.js文件,文件内容如下:
import { fetchEventSource } from '@microsoft/fetch-event-source';
fetchEventSource('http://192.168.35.3:11434/api/chat', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
model: 'llama3.1',
messages: [{ role: 'user', content: '你好啊' }],
stream: true,
}),
onmessage: (ev) => {
console.log('ev', ev, JSON.parse(ev.data));
// document.getElementById('output').textContent += ev.data;
console.log(111);
},
onopen() {
console.log('Connection opened');
},
onclose() {
console.log('Connection closed');
},
onerror(err) {
console.error('Error:', err);
},
});
感觉上面的代码没问题,但是onmessage
方法中就是收不到ev的内容,所以没有实现最终的效果。