Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xqx_12138
AI女友
提交
df81033b
A
AI女友
项目概览
xqx_12138
/
AI女友
与 Fork 源项目一致
Fork自
inscode / ChatGPT Template With Vue
通知
1
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
A
AI女友
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
df81033b
编写于
9月 14, 2024
作者:
X
xqx_12138
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Auto Commit
上级
29e92c29
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
119 addition
and
80 deletion
+119
-80
src/App.vue
src/App.vue
+119
-80
未找到文件。
src/App.vue
浏览文件 @
df81033b
<
template
>
<
template
>
<div
class=
"container ivu-p"
>
<div
class=
"container"
>
<div
class=
"header"
>
<h2>
AI 女友陪聊助手
</h2>
<Button
type=
"primary"
@
click=
"handleNewChat"
>
开始新对话
</Button>
</div>
<div
class=
"dialog"
>
<div
class=
"dialog"
>
<template
v-for=
"(item, index) in dialogs"
:key=
"index"
>
<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"
:class=
"
{'dialog-item-me': item.role === 'me', 'dialog-item-ai': item.role === 'ai'}">
<img
:src=
"item.avatar"
:class=
"
{'avatar-me': item.role === 'me', 'avatar-ai': item.role === 'ai'}" />
<div
class=
"dialog-item-main"
>
{{
item
.
text
}}
</div>
<div
class=
"dialog-item-main"
>
{{
item
.
text
}}
</div>
</div>
</div>
</
template
>
</
template
>
</div>
</div>
<div
class=
"question ivu-mt"
>
<div
class=
"input-area"
>
<Input
v-model=
"question"
type=
"textarea"
:autosize=
"{ minRows: 4, maxRows: 6 }"
placeholder=
"输入你的问题"
/>
<Input
v-model=
"question"
type=
"textarea"
:autosize=
"{ minRows: 3, maxRows: 5 }"
placeholder=
"看看今天聊什么吧"
/>
<Row
class=
"ivu-mt"
>
<Button
type=
"primary"
@
click=
"handleSend"
>
发送
</Button>
<Col>
<Button
type=
"primary"
size=
"large"
icon=
"md-send"
:loading=
"loading"
@
click=
"handleSend"
>
发送
</Button>
</Col>
<Col>
<Button
size=
"large"
class=
"ivu-ml"
icon=
"md-add"
:disabled=
"loading"
@
click=
"handleNewChat"
>
新对话
</Button>
</Col>
</Row>
<Typography
class=
"ivu-text-center ivu-m"
>
Powered By
<img
src=
"./assets/logo.png"
class=
"logo"
>
<a
href=
"https://inscode.net"
target=
"_blank"
>
InsCode.net
</a>
</Typography>
</div>
</div>
</div>
</div>
</template>
</template>
<
script
>
<
script
>
import
{
fetchEventSource
}
from
'
@microsoft/fetch-event-source
'
;
import
{
fetchEventSource
}
from
'
@microsoft/fetch-event-source
'
;
import
{
apiKey
,
apiUrl
}
from
'
./api
'
;
import
{
apiKey
,
apiUrl
}
from
'
./api
'
;
// 引入 GPT API 地址和密钥
export
default
{
export
default
{
data
()
{
data
()
{
return
{
return
{
question
:
''
,
question
:
''
,
dialogs
:
[],
loading
:
false
,
loading
:
false
,
dialogs
:
[]
userName
:
'
小美
'
,
// 默认的AI女友名字
}
userMood
:
'
温柔
'
,
// 默认的AI女友个性
userAvatar
:
'
https://c-ssl.duitang.com/uploads/item/201702/07/20170207205844_G54rE.jpeg
'
,
// 你可以使用自己的头像 URL
aiAvatar
:
'
https://img.wxcha.com/m00/17/af/718aa0fd75674e749c8f4ab9875b8d78.jpg?down
'
,
// AI 女友的头像
aiTopics
:
[
// 随机话题列表
"
你今天过得怎么样?
"
,
"
最近有看什么好看的电影吗?
"
,
"
我学到了一些新知识,你想听听吗?
"
,
"
你喜欢什么类型的音乐?
"
,
"
有什么让我帮忙的事情吗?
"
]
};
},
mounted
()
{
// 页面加载时 AI 女友主动发送第一条随机话题
this
.
startConversation
();
},
},
methods
:
{
methods
:
{
handleSend
()
{
handleSend
()
{
...
@@ -43,115 +54,143 @@ export default {
...
@@ -43,115 +54,143 @@ export default {
const
question
=
this
.
question
;
const
question
=
this
.
question
;
this
.
question
=
''
;
this
.
question
=
''
;
// 添加用户问题到对话框
this
.
dialogs
.
push
({
this
.
dialogs
.
push
({
id
:
this
.
dialogs
.
length
+
1
,
role
:
'
me
'
,
role
:
'
me
'
,
text
:
question
text
:
question
,
avatar
:
this
.
userAvatar
// 使用用户的头像
});
});
const
aiDialogID
=
this
.
dialogs
.
length
+
1
;
// AI 思考中
const
aiDialogID
=
this
.
dialogs
.
length
;
this
.
dialogs
.
push
({
this
.
dialogs
.
push
({
id
:
aiDialogID
,
role
:
'
ai
'
,
role
:
'
ai
'
,
text
:
'
AI 思考中...
'
text
:
`
${
this
.
userName
}
正在思考...`
,
avatar
:
this
.
aiAvatar
});
});
const
dialog
=
this
.
dialogs
.
find
(
item
=>
item
.
id
===
aiDialogID
);
/**
* 发送请求,InsCode 已经集成了 GPT 能力
* 在 vite.config.js 中已通过环境变量写入了 apiKey(该 key 是动态写入使用者的,在 IDE 中是作者,发布到社区是运行该作品的用户)
* 发布到社区后,将消耗运行者的额度
* 注意:如果部署应用,任何人通过部署后的域名访问应用时,都将消耗部署者的额度
*/
const
body
=
{
const
body
=
{
messages
:
[
messages
:
[
{
{
role
:
'
system
'
,
content
:
`你现在是一个温柔的虚拟女友,你的名字是
${
this
.
userName
}
。`
},
role
:
'
user
'
,
{
role
:
'
user
'
,
content
:
question
}
content
:
question
}
],
],
apikey
:
apiKey
apikey
:
apiKey
}
}
;
const
source
=
fetchEventSource
(
apiUrl
,
{
const
dialog
=
this
.
dialogs
[
aiDialogID
];
// 请求 GPT API
fetchEventSource
(
apiUrl
,
{
method
:
'
POST
'
,
method
:
'
POST
'
,
headers
:
{
headers
:
{
'
Content-Type
'
:
'
application/json
'
},
'
Content-Type
'
:
'
application/json
'
},
body
:
JSON
.
stringify
(
body
),
body
:
JSON
.
stringify
(
body
),
onopen
:
(
response
)
=>
{
onopen
:
()
=>
{
dialog
.
text
=
''
;
dialog
.
text
=
''
;
},
},
onmessage
:
(
msg
)
=>
{
onmessage
:
(
msg
)
=>
{
if
(
msg
.
data
===
'
[DONE]
'
)
{
if
(
msg
.
data
===
'
[DONE]
'
)
{
this
.
loading
=
false
;
this
.
loading
=
false
;
return
;
return
;
}
;
}
const
data
=
JSON
.
parse
(
msg
.
data
);
const
data
=
JSON
.
parse
(
msg
.
data
);
const
finish_reason
=
data
.
choices
[
0
].
finish_reason
;
const
content
=
data
.
choices
[
0
]?.
delta
?.
content
;
const
finish
=
finish_reason
===
'
stop
'
||
finish_reason
===
'
length
'
;
if
(
content
)
{
const
content
=
data
.
choices
[
0
].
delta
.
content
;
dialog
.
text
+=
content
;
if
(
finish
)
{
this
.
loading
=
false
;
}
else
if
(
content
)
{
const
text
=
content
;
dialog
.
text
+=
text
;
}
}
},
},
onerror
:
(
err
)
=>
{
onerror
:
(
err
)
=>
{
console
.
log
(
"
error
"
,
err
);
console
.
error
(
'
错误:
'
,
err
);
this
.
loading
=
false
;
}
}
});
});
},
},
handleNewChat
()
{
handleNewChat
()
{
this
.
dialogs
=
[];
this
.
dialogs
=
[];
this
.
startConversation
();
},
startConversation
()
{
// 女友主动发送随机话题
const
randomTopic
=
this
.
aiTopics
[
Math
.
floor
(
Math
.
random
()
*
this
.
aiTopics
.
length
)];
this
.
dialogs
.
push
({
role
:
'
ai
'
,
text
:
`你好,我是你的 AI 女友
${
this
.
userName
}
。
${
randomTopic
}
`
,
avatar
:
this
.
aiAvatar
});
}
}
}
}
}
}
;
</
script
>
</
script
>
<
style
>
<
style
scoped
>
.container
{
.container
{
height
:
100%
;
padding
:
20px
;
max-width
:
600px
;
margin
:
0
auto
;
}
.header
{
display
:
flex
;
display
:
flex
;
flex-direction
:
column
;
justify-content
:
space-between
;
align-items
:
center
;
}
}
.dialog
{
.dialog
{
flex
:
1
;
flex
:
1
;
overflow
:
auto
;
overflow-y
:
auto
;
max-height
:
400px
;
margin-bottom
:
20px
;
}
}
.dialog-item
{
.dialog-item
{
display
:
flex
;
display
:
flex
;
align-items
:
center
;
margin
:
10px
0
;
}
.dialog-item-me
{
justify-content
:
flex-end
;
/* 用户对话整体对齐到右侧 */
}
.dialog-item-ai
{
justify-content
:
flex-start
;
/* AI 对话整体对齐到左侧 */
}
}
.dialog-item-main
{
.dialog-item-main
{
max-width
:
80%
;
max-width
:
60%
;
padding
:
8px
;
padding
:
10px
;
border-radius
:
10px
;
word-wrap
:
break-word
;
word-wrap
:
break-word
;
margin-top
:
16px
;
border-radius
:
4px
;
}
.dialog-item-me
{
justify-content
:
flex-end
;
}
}
.dialog-item-me
.dialog-item-main
{
.dialog-item-me
.dialog-item-main
{
background-color
:
antiquewhite
;
margin-left
:
10px
;
/* 用户对话内容左侧间距 */
margin-right
:
0
;
/* 去掉右侧间距 */
background-color
:
#d1ffd1
;
/* 用户对话背景色 */
}
}
.dialog-item-ai
.dialog-item-main
{
.dialog-item-ai
.dialog-item-main
{
background-color
:
#eee
;
margin-right
:
10px
;
/* AI 对话内容右侧间距 */
margin-left
:
0
;
/* 去掉左侧间距 */
background-color
:
#eee
;
/* AI 对话背景色 */
}
}
.logo
{
.avatar-me
{
width
:
16px
;
width
:
40px
;
height
:
16px
;
height
:
40px
;
vertical-align
:
middle
;
border-radius
:
50%
;
position
:
relative
;
margin-left
:
10px
;
/* 用户头像右侧间距 */
top
:
-1px
;
}
}
</
style
>
.avatar-ai
{
\ No newline at end of file
width
:
40px
;
height
:
40px
;
border-radius
:
50%
;
margin-right
:
10px
;
/* AI 头像左侧间距 */
}
.input-area
{
display
:
flex
;
align-items
:
center
;
position
:
fixed
;
/* 将 input-area 固定 */
bottom
:
0
;
/* 置于页面底部 */
left
:
0
;
/* 使其与页面左侧对齐 */
right
:
0
;
/* 使其与页面右侧对齐 */
padding
:
10px
;
background-color
:
white
;
/* 添加背景色 */
box-shadow
:
0
-2px
10px
rgba
(
0
,
0
,
0
,
0.1
);
/* 添加阴影效果 */
}
.input-area
Input
{
flex
:
1
;
margin-right
:
10px
;
}
</
style
>
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录