1、提示
- 由于国内注册 https://api.openai.com 比较麻烦,直接购买的第三方接口和key
- 淘宝购买,几块钱1个月
3、自己娱乐够用
2、前端框架
- Vant 移动端使用
- axios
3、创建拦截器,api/request.js
/*
* @Descripttion: 文件说明
* @version: 0.0.1
* @Author: pengshuai
* @Date: 2023-11-01 10:39:22
* @LastEditors: PengShuai
* @LastEditTime: 2023-11-02 10:33:28
*/
import axios from 'axios'
// 创建axios实例
const service = axios.create({
timeout: 300 * 1000,// ms请求超时时间
})
// request拦截器
service.interceptors.request.use(
(config) => {
return config
},(error) => {
// Do something with request error
Promise.reject(error)
}
)
// respone拦截器
service.interceptors.response.use(
(response) => {
const res = response
if (res.status !== 200) {
return Promise.reject(response)
} else {
if (res.status === 200) {
return res.data
} else {
return Promise.reject(res.data.message)
}
}
},(error) => {
return Promise.reject(error)
}
)
export default service
4、创建接口 api/index.js
import service from './request'
// 访问接口地址
const baseUrl = window.configUrl.openApi
const openAi = (data) =>
service({
url: baseUrl + '/v1/chat/completions',method: 'post',headers: {
'content-type': 'application/json',Authorization:
'Bearer YOU-KEY-63D8A64444655655C56a0838490e',},data,})
export default { openAi }
5、完整代码
<!--
* @Descripttion: 人工智障
* @version: 0.0.1
* @Author: PengShuai
* @Date: 2023-11-10 10:22:33
* @LastEditors: PengShuai
* @LastEditTime: 2023-11-10 16:02:25
-->
<template>
<div class="page">
<div class="header">
<nav-bar
title="人工智障"
right-text="清空"
@click-right="onClickRight"
></nav-bar>
</div>
<div class="main" ref="mainScroll">
<div
class="list"
v-for="(item,index) in params.messages"
:key="index"
:class="item.role + 'tr'"
>
<div :class="item.role">{{ item.content }}</div>
<base-loading
v-if="
item.role === 'user' &&
index === params.messages.length - 1 &&
loading
"
></base-loading>
</div>
</div>
<div class="footer">
<van-field placeholder="请输入..." v-model="messages.content">
<template #button>
<van-button
size="small"
icon="guide-o"
type="primary"
@click="onSend"
@keyup.enter="onSend"
></van-button>
</template>
</van-field>
</div>
<div class="popup" v-if="loading"></div>
</div>
</template>
<script>
import api from '@/api'
import { NavBar,Field,Button,Notify } from 'vant'
import baseLoading from '@/components/baseLoading'
export default {
name: 'HomePage',components: {
baseLoading,NavBar,[Notify.name]: Notify,[Field.name]: Field,[Button.name]: Button,data() {
return {
// 参数
params: {
messages: [
{
role: 'system',content: '你好,我是彭帅的人工智障,有什么可以帮您?',],stream: true,model: 'gpt-3.5-turbo',temperature: 0.5,presence_penalty: 0,frequency_penalty: 0,top_p: 1,// 消息列表
infoList: [],// 消息
messages: {
role: 'user',content: '',loading: false,}
},methods: {
/**
*@Descripttion:点击右侧清空
*@Author: PengShuai
*@Date: 2023-11-10 13:13:51
*/
onClickRight() {
this.params = {
messages: [
{
role: 'system',}
this.messages.content = ''
},/**
*@Descripttion:点击发送
*@Author: PengShuai
*@Date: 2023-11-10 13:34:06
*/
onSend() {
this.loading = true
this.params.messages.push(JSON.parse(JSON.stringify(this.messages)))
let obj = {
role: '',}
this.messages.content = ''
this.onBottomScrollClick()
api
.openAi(this.params)
.then((res) => {
if (res) {
let info = null
info = res.split('\n\n')
info = info.map((obj) => obj.substring(5))
info.splice(-2)
info = info.map((obj) => JSON.parse(obj))
if (info.length > 0) {
info.forEach((item) => {
if (item.choices.length > 0) {
item.choices.forEach((o) => {
if (o.delta.role) {
obj.role = o.delta.role
} else if (o.delta.content) {
obj.content += o.delta.content
}
})
}
})
this.infoList.push(obj)
}
this.params.messages.push(this.infoList[this.infoList.length - 1])
this.loading = false
this.onBottomScrollClick()
}
})
.catch((err) => {
this.loading = false
Notify({ type: 'danger',message: err })
})
},/**
*@Descripttion:滚动条到底部
*@Author: PengShuai
*@Date: 2023-11-10 15:38:21
*/
onBottomScrollClick() {
this.$nextTick(() => {
let scroll = this.$refs.mainScroll
scroll.scrollTo({ top: scroll.scrollHeight,behavior: 'smooth' })
})
},}
</script>
<style lang="less" scoped>
.page {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
.header {
border-bottom: 1px solid #ddd;
}
.footer {
border: 1px solid #ddd;
}
.main {
flex: 1;
margin: 10px 0;
border: 1px solid #ddd;
overflow: auto;
}
.usertr {
text-align: right;
}
.list {
.system,.assistant {
margin: 10px 10px 10px 35px;
text-align: left;
position: relative;
padding: 5px 0;
color: #878787;
border-bottom: 1px solid #ddd;
display: inline-block;
&::after {
content: '智';
position: absolute;
left: -25px;
top: 5px;
background: #07c160;
border-radius: 50%;
width: 22px;
height: 22px;
line-height: 22px;
text-align: center;
color: #fff;
font-size: 12px;
}
}
.user {
margin: 10px 40px 10px 10px;
text-align: right;
position: relative;
padding: 5px 0;
color: #505050;
border-bottom: 1px solid #ddd;
display: inline-block;
&::after {
content: '帅';
position: absolute;
right: -25px;
top: 5px;
background: #07c160;
border-radius: 50%;
width: 22px;
height: 22px;
line-height: 22px;
text-align: center;
color: #fff;
font-size: 12px;
}
}
}
.popup {
width: 100%;
height: 100%;
position: fixed;
top: 0;
left: 0;
z-index: 99;
display: flex;
justify-content: center;
align-items: center;
}
}
</style>
6、提示 baseLoading 请求loading 组件 可删除自己写
<template>
<div class="baseLoading">
<div class="loading">
<span style="--time: 1">智</span>
<span style="--time: 2">障</span>
<span style="--time: 3">正</span>
<span style="--time: 4">在</span>
<span style="--time: 5">思</span>
<span style="--time: 6">考</span>
<span style="--time: 7">中</span>
<span style="--time: 8">.</span>
<span style="--time: 9">.</span>
<span style="--time: 10">.</span>
</div>
</div>
</template>
<script>
export default {
name: 'baseLoading',}
</script>
<style lang="less" scoped>
.loading {
text-align: center;
}
.loading span {
display: inline-block;
font-size: 12px;
font-weight: bold;
font-family: 'Courier New',Courier,monospace;
animation: loading 1s ease-in-out infinite;
animation-delay: calc(0.1s * var(--time));
color: #919191;
}
@keyframes loading {
0% {
transform: translateY(0px);
}
25% {
transform: translateY(-20px);
}
50%,100% {
transform: translateY(0px);
}
}
</style>
7、示例
8、注意
Tips: 请求返回的数据格式为数组,一个字一个数组,需要自己进行数据整理和拼接。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件举报,一经查实,本站将立刻删除。