Spaces:
Runtime error
Runtime error
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)
|