前期回顾
两分钟学会 制作自己的浏览器 —— 并将 ChatGPT 接入_彩色之外的博客-CSDN博客自定义浏览器,并集合ChatGPT,源码已公开https://blog.csdn.net/m0_57904695/article/details/130467253?spm=1001.2014.3001.5501
目录
效果图
代码步骤:(配key)
主页面:
✅ 谢谢观看 :
已经部署上线:ChatGPT-彩色之外
效果图
代码步骤:(配key)
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
server: {
host: true
},
plugins: [vue()],
define: {
'process.env': {
INSCODE_API_KEY: process.env.INSCODE_API_KEY
}
}
})
主页面:
<template>
<div class="container ivu-p">
<!-- 聊天窗口 -->
<div class="dialog">
<!-- 使用提示 -->
<div class="dialog-item" style="display: block; text-align: center;">
<div class="dialog-item-main" style="max-width: 100%; margin-bottom: 4px; color: #61647b;">试试发送一些问题给我,比如
<br />"{{ topic }}"
</div>
<div><span
style="padding: 5px 12px; border: 1px solid #444f8a; background-color: #3a4684; color: #fff; border-radius: 8px; cursor: pointer;"
@click="rewardSupportCard = true">打赏支持 🎉</span></div>
</div>
<!-- 回答 -->
<template v-for="(item, index) in dialogs" :key="index">
<div class="dialog-item" :class="{ 'dialog-item-me': item.role === 'me', 'dialog-item-ai': item.role === 'ai' }">
<div class="dialog-item-main" v-html="highlightCode(item.text)">
</div>
</div>
</template>
</div>
<!-- 发送信息 -->
<div class="question ivu-mt">
<Input v-model.trim="question" type="textarea" :autosize="{ minRows: 4, maxRows: 6 }" placeholder="输入你的问题"
@keyup.enter="handleSend" v-focus autofocus />
<Row class="ivu-mt" style="display: flex; justify-content: right;">
<Col>
<Button type="primary" size="large" icon="md-send" style="background-color: #3a4684; border-color: #3a4684;"
:loading="loading" @click="handleSend">发送</Button>
</Col>
<Col style="display: none;">
<Button size="large" class="ivu-ml" icon="md-add" :disabled="loading" @click="handleNewChat">新对话</Button>
</Col>
</Row>
</div>
<!-- 打赏支持 -->
<div class="reward-support" v-show="rewardSupportCard">
<div class="reward-support__card">
<div class="reward-support__head">
<button type="button" :class="{ 'reward-support__btn--active': QRCodeModel == 1 }" class="reward-support__btn"
@click="QRCodeModel = 1">支付宝</button>
<button type="button" :class="{ 'reward-support__btn--active': QRCodeModel == 2 }"
:style="{ 'backgroundColor': QRCodeModel == 2 ? '#21aa38' : '' }" class="reward-support__btn"
@click="QRCodeModel = 2">微信</button>
</div>
<div class="reward-support__content">
<div class="reward-support__QRCode" style="margin-bottom: 10px;">
<img v-if="QRCodeModel == 1" src="./assets/zhifubao.jpg" alt="">
<img v-else src="./assets/weixin.jpg" alt="">
</div>
<div class="reward-support__text" style="margin-bottom: 10px; text-align: center; color: #baccbe;">
<span v-if="QRCodeModel == 1">支付宝扫一扫</span>
<span v-else>微信扫一扫</span>
</div>
<div class="reward-support__quit"><span @click="rewardSupportCard = false">下次一定</span></div>
</div>
</div>
<div class="reward-support__shadow" @click.stop="rewardSupportCard = false"></div>
</div>
<!-- 设置 -->
</div>
</template>
<script>
import { fetchEventSource } from '@microsoft/fetch-event-source';
import { apiKey, apiUrl } from './api';
import 'prismjs'
import 'prismjs/themes/prism.css'
import 'prismjs/components/prism-javascript'
export default {
mounted() {
Prism.highlightAll();
},
data() {
return {
question: '',
loading: false,
dialogs: [],
dialog: [],
rewardSupportCard: false,
QRCodeModel: 1,
gptTopic: ["彩色之外怎么这么帅、泰裤辣~", "推荐一些有趣的电影、音乐", "编写一个适合5岁小孩的睡前小故事", "怎么像喜欢的人表白"],
topic: "",
}
},
created() {
this.topic = this.gptTopic[parseInt(Math.random() * this.gptTopic.length)]
},
methods: {
highlightCode(text) {
const code = Prism.highlight(text, Prism.languages.javascript, 'javascript');
// 如果有 ``` 就换行
const codeWithNewLines = code.replace(/```[\s\S]*?```/g, (match) => {
const codeWithoutTicks = match.slice(3, -3);
return '\n' + codeWithoutTicks + '\n';
});
console.log(codeWithNewLines);
return `<code>${codeWithNewLines}</code>`;
}
,
handleSend() {
if (this.loading || this.question === '') return;
this.loading = true;
const question = this.question;
this.question = '';
// Add user dialog to the list
this.dialogs.push({
id: this.dialogs.length + 1,
role: 'me',
text: question
});
const aiDialogID = this.dialogs.length + 1;
// Add AI dialog to the list
this.dialogs.push({
id: aiDialogID,
role: 'ai',
text: '让大哥想一下 ...'
});
const dialog = this.dialogs.find(item => item.id === aiDialogID);
// Send request to GPT backend service
const body = {
messages: [
{
role: 'user',
content: "你现在是《彩色之外》的AI机器人。" + question
}
],
apikey: apiKey
}
const source = fetchEventSource(apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(body),
onopen: (response) => {
dialog.text = '';
},
onmessage: (msg) => {
if (msg.data === '[DONE]') {
this.loading = false;
return;
};
const data = JSON.parse(msg.data);
const finish_reason = data.choices[0].finish_reason;
const finish = finish_reason === 'stop' || finish_reason === 'length';
const content = data.choices[0].delta.content;
if (finish) {
this.loading = false;
} else if (content) {
const text = content;
dialog.text += text;
}
},
onerror: (err) => {
console.log("error", err);
}
});
},
handleNewChat() {
this.dialogs = [];
},
}
}
</script>
<style>
.copy-btn:hover {
border: 1px solid #ccc;
border-radius: 3px;
}
.question {
display: flex;
}
.question .ivu-mt {
margin: 0 !important;
}
.ivu-input-wrapper {
margin-right: 10px;
}
.ivu-input-wrapper textarea {
height: 40px !important;
min-height: 40px !important;
}
.ivu-input:hover {
border-color: #3a4684 !important;
}
.ivu-input:focus {
box-shadow: 0 0 0 2px rgba(58, 70, 132, .2) !important;
}
.ivu-input:focus {
border-color: #3a4684 !important;
}
.ivu-btn-primary:focus {
box-shadow: 0 0 0 2px rgba(58, 70, 132, .2) !important;
}
.ivu-btn:active,
.ivu-btn:hover {
/* color: #3a4684 !important; */
border-color: #3a4684 !important;
}
.ivu-btn:focus {
box-shadow: 0 0 0 2px rgba(58, 70, 132, .2) !important;
}
.reward-support {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.reward-support .reward-support__card {
position: absolute;
top: 10%;
left: 50%;
transform: translateX(-50%);
width: 300px;
padding: 24px;
border-radius: 12px;
background-color: #f8f8f8;
z-index: 1;
}
.reward-support .reward-support__head {
display: flex;
justify-content: center;
margin-bottom: 14px;
}
.reward-support .reward-support__btn {
width: 65px;
height: 25px;
border: 0;
margin-right: 10px;
border-radius: 6px;
font-size: 14px;
background-color: #ebebeb;
cursor: pointer;
color: #8e8e94;
}
.reward-support .reward-support__QRCode {
width: 163px;
height: 163px;
margin: 0 auto;
background-color: #fff;
}
.reward-support .reward-support__QRCode img {
width: 100%;
}
.reward-support .reward-support__quit {
text-align: center;
}
.reward-support .reward-support__quit span {
width: 120px;
height: 36px;
line-height: 36px;
display: inline-block;
border-radius: 6px;
background-color: #ffffff;
cursor: pointer;
font-size: 14px;
}
.reward-support .reward-support__quit span:hover {
background-color: #ebebeb;
}
.reward-support .reward-support__btn--active {
background-color: #1777ff;
color: #fff;
}
.reward-support .reward-support__shadow {
width: 100%;
height: 100%;
background-color: #7f7f7f;
opacity: .7;
}
.container {
height: 100%;
display: flex;
flex-direction: column;
}
.dialog {
flex: 1;
overflow: auto;
}
.dialog-item {
display: flex;
}
.dialog-item-main {
max-width: 80%;
padding: 8px;
word-wrap: break-word;
word-break: break-all;
margin-top: 16px;
border-radius: 4px;
}
.dialog-item-me {
justify-content: flex-end;
}
.dialog-item-me .dialog-item-main {
background-color: #95ec69;
}
.dialog-item-ai .dialog-item-main {
background-color: #eee;
}
</style>
✅ 谢谢观看 :
_______________________________ 期待再见 _______________________________