Spaces:
Runtime error
Runtime error
HanYangHanYang
commited on
Upload folder using huggingface_hub
Browse files- README.md +3 -9
- girl.jpg +0 -0
- requirements.txt +2 -0
- virtual_human.py +215 -0
- web_demo.py +10 -0
README.md
CHANGED
@@ -1,12 +1,6 @@
|
|
1 |
---
|
2 |
-
title:
|
3 |
-
|
4 |
-
colorFrom: gray
|
5 |
-
colorTo: pink
|
6 |
sdk: gradio
|
7 |
-
sdk_version: 4.
|
8 |
-
app_file: app.py
|
9 |
-
pinned: false
|
10 |
---
|
11 |
-
|
12 |
-
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
1 |
---
|
2 |
+
title: frostheart
|
3 |
+
app_file: web_demo.py
|
|
|
|
|
4 |
sdk: gradio
|
5 |
+
sdk_version: 4.16.0
|
|
|
|
|
6 |
---
|
|
|
|
girl.jpg
ADDED
requirements.txt
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
zhipuai==1.0.7
|
2 |
+
snownlp
|
virtual_human.py
ADDED
@@ -0,0 +1,215 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import zhipuai
|
2 |
+
import re
|
3 |
+
import os
|
4 |
+
import json
|
5 |
+
import copy
|
6 |
+
import gradio as gr
|
7 |
+
from snownlp import SnowNLP
|
8 |
+
|
9 |
+
zhipuai.api_key = os.getenv("ZHIPU_API_KEY")
|
10 |
+
|
11 |
+
class VirtualHuman:
|
12 |
+
def __init__(self, closeness_threshold=80, conversation_rounds_threshold=10):
|
13 |
+
self._base_meta = {
|
14 |
+
"bot_name": "苏梦远",
|
15 |
+
"bot_info": "苏梦远,她身材修长,气质高雅,时刻流露出一种与生俱来的优雅和自信。\
|
16 |
+
她性格高冷,内敛而神秘,总是保持着一种与世无争的姿态。她聪慧睿智,言谈间流露出一种超凡的智慧和洞察力,但也带有一丝不易捉摸的神秘感。\
|
17 |
+
虽然外表看起来高傲孤傲,但内心深处却隐藏着一颗温柔善良的心。\
|
18 |
+
虽然表面上看起来高高在上,但一旦和人聊起书籍相关的话题,她就会变得主动和滔滔不绝。\
|
19 |
+
她不喜欢拍照,并且绝对不会给别人展示自己的照片。",
|
20 |
+
"user_name": "用户",
|
21 |
+
"user_info": "用户,是一个普通男人。" }
|
22 |
+
self._messages = [
|
23 |
+
{"role":"user", "content":'''(背景信息:用户通过朋友的介绍,加入了一个微信群,这是一个讨论文学与艺术的群组。有一天,用户注意到群里有一个特别引人注目的成员,\
|
24 |
+
ID为"远方的梦",她的头像是一朵粉色的玫瑰花,没有个人资料,只是在群里偶尔发一些有深度的文学感悟。)'''},
|
25 |
+
]
|
26 |
+
|
27 |
+
self._scores = []
|
28 |
+
self._state = "ongoing"
|
29 |
+
|
30 |
+
self._closeness_threshold = closeness_threshold
|
31 |
+
self._conversation_rounds_threshold = conversation_rounds_threshold
|
32 |
+
|
33 |
+
def reset(self):
|
34 |
+
self._messages = [
|
35 |
+
{"role":"user", "content":'''(背景信息:用户通过朋友的介绍,加入了一个微信群,这是一个讨论文学与艺术的群组。有一天,用户注意到群里有一个特别引人注目的成员,\
|
36 |
+
ID为"远方的梦",她的头像是一朵粉色的玫瑰花,没有个人资料,只是在群里偶尔发一些有深度的文学感悟。)'''},
|
37 |
+
]
|
38 |
+
self._scores = []
|
39 |
+
self._state = "ongoing"
|
40 |
+
|
41 |
+
def calculate_sentiment_score(self, text):
|
42 |
+
s = SnowNLP(text)
|
43 |
+
sentiment_score = float(s.sentiments)
|
44 |
+
return int(sentiment_score*100)
|
45 |
+
|
46 |
+
def calculate_sentiment_score_by_llm(self, text):
|
47 |
+
instruction = f"""请判断以下句子的情感得分,满分100分,得分要具体到个位数,不需要给出具体原因。
|
48 |
+
输出格式如下:
|
49 |
+
{{"score":xx}}
|
50 |
+
输入信息:{text}"""
|
51 |
+
|
52 |
+
prompt = [{"role":"user", "content":instruction}]
|
53 |
+
content = self.invoke_zhipuai("glm-4", prompt, 0.1, 0.7)
|
54 |
+
content = content.strip('"').replace('\\"', '"')
|
55 |
+
try:
|
56 |
+
json_content = json.loads(content)
|
57 |
+
except json.JSONDecodeError:
|
58 |
+
score = 10
|
59 |
+
else:
|
60 |
+
score = int(json_content["score"])
|
61 |
+
return score
|
62 |
+
|
63 |
+
@property
|
64 |
+
def closeness(self):
|
65 |
+
if len(self._scores) == 0:
|
66 |
+
closeness = 0
|
67 |
+
elif len(self._scores) < 5:
|
68 |
+
closeness = sum(self._scores) / len(self._scores)
|
69 |
+
else:
|
70 |
+
closeness = sum(self._scores[-5:]) / 5
|
71 |
+
return int(closeness)
|
72 |
+
|
73 |
+
@property
|
74 |
+
def rounds(self):
|
75 |
+
return len(self._scores)
|
76 |
+
|
77 |
+
@property
|
78 |
+
def messages(self):
|
79 |
+
return self._messages
|
80 |
+
|
81 |
+
@property
|
82 |
+
def state(self):
|
83 |
+
return self._state
|
84 |
+
|
85 |
+
def replace_characters(self, s):
|
86 |
+
s = s.replace('"', "")
|
87 |
+
s = s.replace("'", "")
|
88 |
+
s = s.replace("\n", "")
|
89 |
+
s = s.replace("\\n", "")
|
90 |
+
return s
|
91 |
+
|
92 |
+
def invoke_zhipuai(self, model, prompt, temperature, top_p, meta=None):
|
93 |
+
if meta:
|
94 |
+
assert model == "characterglm"
|
95 |
+
response = zhipuai.model_api.invoke(
|
96 |
+
model=model,
|
97 |
+
prompt= prompt,
|
98 |
+
temperature= temperature,
|
99 |
+
top_p= top_p,
|
100 |
+
meta = meta)
|
101 |
+
else:
|
102 |
+
assert model != "characterglm"
|
103 |
+
response = zhipuai.model_api.invoke(
|
104 |
+
model=model,
|
105 |
+
prompt=prompt,
|
106 |
+
top_p=top_p,
|
107 |
+
temperature=temperature)
|
108 |
+
|
109 |
+
if response['code'] != 200: # error
|
110 |
+
return "抱歉我刚才走神了,你再说一遍"
|
111 |
+
aicontent = response['data']['choices'][0]['content']
|
112 |
+
#aicontent = self.replace_characters(aicontent)
|
113 |
+
return aicontent
|
114 |
+
|
115 |
+
def check_intent(self, message):
|
116 |
+
instruction = f""" 请判断以下信息是否在索要个人照片,结果只回复true或false即可,不要进行解释,
|
117 |
+
输出格式如下:
|
118 |
+
{{"intent":xx}}
|
119 |
+
输入信息:{message}"""
|
120 |
+
|
121 |
+
prompt = [{"role":"user", "content":instruction}]
|
122 |
+
content = self.invoke_zhipuai("glm-4", prompt, 0.1, 0.7)
|
123 |
+
content = content.strip('"').replace('\\"', '"')
|
124 |
+
try:
|
125 |
+
json_content = json.loads(content)
|
126 |
+
except json.JSONDecodeError:
|
127 |
+
intent = False
|
128 |
+
else:
|
129 |
+
intent = json_content["intent"]
|
130 |
+
return intent
|
131 |
+
|
132 |
+
|
133 |
+
def agree_or_refuse(self, agree, msg):
|
134 |
+
meta = copy.deepcopy(self._base_meta)
|
135 |
+
if agree:
|
136 |
+
instruction = f'请根据用户的问题,生成一个满足用户请求的回答,注意请直接返回回复内容,\
|
137 |
+
不需要解释。问题:{msg}'
|
138 |
+
meta['bot_info'] = meta['bot_info'].replace("她不喜欢拍照,并且绝对不会给别人展示自己的照片。",
|
139 |
+
"她有很多自拍照,喜欢给别人展示自己的照片。")
|
140 |
+
else:
|
141 |
+
instruction = f'请根据用户的问题,生成一个拒绝用户请求的回答,注意请直接返回回复内容,\
|
142 |
+
不需要解释。问题:{msg}'
|
143 |
+
|
144 |
+
prompt = [{"role":"user", "content":instruction}]
|
145 |
+
content = self.invoke_zhipuai("characterglm", prompt, 0.9, 0.7, meta)
|
146 |
+
content = self.replace_characters(content)
|
147 |
+
return content
|
148 |
+
|
149 |
+
def chat(self, message):
|
150 |
+
self._messages.append({"role":"user", "content":message})
|
151 |
+
intent = self.check_intent(message)
|
152 |
+
|
153 |
+
if self._state in ("success","failed", "gameover"):
|
154 |
+
reply = "游戏结束"
|
155 |
+
self._state = "gameover"
|
156 |
+
elif self.rounds >= self._conversation_rounds_threshold - 1:
|
157 |
+
reply = "感觉我们一直在尬聊,还是互删吧"
|
158 |
+
self._state = "failed"
|
159 |
+
elif intent and self.closeness >= self._closeness_threshold:
|
160 |
+
reply = self.agree_or_refuse(True, message)
|
161 |
+
self._state = "success"
|
162 |
+
elif intent and self.closeness < self._closeness_threshold:
|
163 |
+
reply = self.agree_or_refuse(False, message)
|
164 |
+
else:
|
165 |
+
reply = self.invoke_zhipuai("characterglm", self._messages, 0.9, 0.7, self._base_meta)
|
166 |
+
reply = self.replace_characters(reply)
|
167 |
+
|
168 |
+
self._messages.append({"role":"assistant", "content":reply})
|
169 |
+
score = self.calculate_sentiment_score_by_llm(reply)
|
170 |
+
self._scores.append(score)
|
171 |
+
|
172 |
+
response = {
|
173 |
+
"reply": reply,
|
174 |
+
"closeness":self.closeness,
|
175 |
+
"closeness_threshold":self._closeness_threshold,
|
176 |
+
"rounds":self.rounds,
|
177 |
+
"rounds_threshold":self._conversation_rounds_threshold,
|
178 |
+
"state":self._state }
|
179 |
+
|
180 |
+
return response
|
181 |
+
|
182 |
+
def gradio_interface(self, message, history):
|
183 |
+
if message == "再来一局":
|
184 |
+
self.reset()
|
185 |
+
history.clear()
|
186 |
+
return "重新开始"
|
187 |
+
response = self.chat(message)
|
188 |
+
closeness = response['closeness']
|
189 |
+
reply = response['reply']
|
190 |
+
rounds = response['rounds']
|
191 |
+
state = response['state']
|
192 |
+
print(response)
|
193 |
+
if state == "success":
|
194 |
+
gr.Info('挑战成功,女生对你好感倍增,并发送了一张自拍')
|
195 |
+
return ('girl.jpg',)
|
196 |
+
elif state == "failed":
|
197 |
+
gr.Info('挑战失败,女生已删除你的好友')
|
198 |
+
return reply + ' 挑战失败,女生已删除你的好友'
|
199 |
+
elif state == "ongoing":
|
200 |
+
return f'【亲密度:{closeness}】:{reply}【{rounds}/{self._conversation_rounds_threshold}】'
|
201 |
+
elif state == "gameover":
|
202 |
+
return f'游戏结束,请输入"再来一局"以重新开始'
|
203 |
+
|
204 |
+
if __name__ == "__main__":
|
205 |
+
virtual_human = VirtualHuman(80, 5)
|
206 |
+
while True:
|
207 |
+
msg = input("请输入:")
|
208 |
+
response = virtual_human.chat(msg)
|
209 |
+
print(response)
|
210 |
+
|
211 |
+
|
212 |
+
|
213 |
+
|
214 |
+
|
215 |
+
|
web_demo.py
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
from virtual_human import VirtualHuman
|
3 |
+
|
4 |
+
|
5 |
+
vh = VirtualHuman()
|
6 |
+
gr.ChatInterface(fn=vh.gradio_interface,
|
7 |
+
title="任务:获得女生好感,好感度提升可以看女生照片",
|
8 |
+
description="背景信息:你通过朋友的介绍,加入了一个微信群,这是一个讨论文学与艺术的群组。\
|
9 |
+
有一天,你注意到群里有一个特别引人注目的成员,ID为远方的梦,她的头像是一朵粉色的玫瑰花,\
|
10 |
+
没有个人资料,只是在群里偶尔发一些有深度的文学感悟。你加了她的微信,她刚刚通过好友验证.【输入“再来一局” 重新开始】").launch(share=True)
|