Spaces:
Runtime error
Runtime error
| import zhipuai | |
| import re | |
| import os | |
| import json | |
| import copy | |
| import gradio as gr | |
| from snownlp import SnowNLP | |
| zhipuai.api_key = os.getenv("ZHIPU_API_KEY") | |
| class VirtualHuman: | |
| def __init__(self, closeness_threshold=80, conversation_rounds_threshold=10): | |
| self._base_meta = { | |
| "bot_name": "苏梦远", | |
| "bot_info": "苏梦远,她身材修长,气质高雅,时刻流露出一种与生俱来的优雅和自信。\ | |
| 她性格高冷,内敛而神秘,总是保持着一种与世无争的姿态。她聪慧睿智,言谈间流露出一种超凡的智慧和洞察力,但也带有一丝不易捉摸的神秘感。\ | |
| 虽然外表看起来高傲孤傲,但内心深处却隐藏着一颗温柔善良的心。\ | |
| 虽然表面上看起来高高在上,但一旦和人聊起书籍相关的话题,她就会变得主动和滔滔不绝。\ | |
| 她不喜欢拍照,并且绝对不会给别人展示自己的照片。", | |
| "user_name": "用户", | |
| "user_info": "用户,是一个普通男人。" } | |
| self._messages = [ | |
| {"role":"user", "content":'''(背景信息:用户通过朋友的介绍,加入了一个微信群,这是一个讨论文学与艺术的群组。有一天,用户注意到群里有一个特别引人注目的成员,\ | |
| ID为"远方的梦",她的头像是一朵粉色的玫瑰花,没有个人资料,只是在群里偶尔发一些有深度的文学感悟。)'''}, | |
| ] | |
| self._scores = [] | |
| self._state = "ongoing" | |
| self._closeness_threshold = closeness_threshold | |
| self._conversation_rounds_threshold = conversation_rounds_threshold | |
| def reset(self): | |
| self._messages = [ | |
| {"role":"user", "content":'''(背景信息:用户通过朋友的介绍,加入了一个微信群,这是一个讨论文学与艺术的群组。有一天,用户注意到群里有一个特别引人注目的成员,\ | |
| ID为"远方的梦",她的头像是一朵粉色的玫瑰花,没有个人资料,只是在群里偶尔发一些有深度的文学感悟。)'''}, | |
| ] | |
| self._scores = [] | |
| self._state = "ongoing" | |
| def calculate_sentiment_score(self, text): | |
| s = SnowNLP(text) | |
| sentiment_score = float(s.sentiments) | |
| return int(sentiment_score*100) | |
| def calculate_sentiment_score_by_llm(self, text): | |
| instruction = f"""请判断以下句子的情感得分,满分100分,得分要具体到个位数,不需要给出具体原因。 | |
| 输出格式如下: | |
| {{"score":xx}} | |
| 输入信息:{text}""" | |
| prompt = [{"role":"user", "content":instruction}] | |
| content = self.invoke_zhipuai("glm-4", prompt, 0.1, 0.7) | |
| content = content.strip('"').replace('\\"', '"') | |
| try: | |
| json_content = json.loads(content) | |
| except json.JSONDecodeError: | |
| score = 10 | |
| else: | |
| score = int(json_content["score"]) | |
| return score | |
| def closeness(self): | |
| if len(self._scores) == 0: | |
| closeness = 0 | |
| elif len(self._scores) < 5: | |
| closeness = sum(self._scores) / len(self._scores) | |
| else: | |
| closeness = sum(self._scores[-5:]) / 5 | |
| return int(closeness) | |
| def rounds(self): | |
| return len(self._scores) | |
| def messages(self): | |
| return self._messages | |
| def state(self): | |
| return self._state | |
| def replace_characters(self, s): | |
| s = s.replace('"', "") | |
| s = s.replace("'", "") | |
| s = s.replace("\n", "") | |
| s = s.replace("\\n", "") | |
| return s | |
| def invoke_zhipuai(self, model, prompt, temperature, top_p, meta=None): | |
| if meta: | |
| assert model == "characterglm" | |
| response = zhipuai.model_api.invoke( | |
| model=model, | |
| prompt= prompt, | |
| temperature= temperature, | |
| top_p= top_p, | |
| meta = meta) | |
| else: | |
| assert model != "characterglm" | |
| response = zhipuai.model_api.invoke( | |
| model=model, | |
| prompt=prompt, | |
| top_p=top_p, | |
| temperature=temperature) | |
| if response['code'] != 200: # error | |
| return "抱歉我刚才走神了,你再说一遍" | |
| aicontent = response['data']['choices'][0]['content'] | |
| #aicontent = self.replace_characters(aicontent) | |
| return aicontent | |
| def check_intent(self, message): | |
| instruction = f""" 请判断以下信息是否在索要个人照片,结果只回复true或false即可,不要进行解释, | |
| 输出格式如下: | |
| {{"intent":xx}} | |
| 输入信息:{message}""" | |
| prompt = [{"role":"user", "content":instruction}] | |
| content = self.invoke_zhipuai("glm-4", prompt, 0.1, 0.7) | |
| content = content.strip('"').replace('\\"', '"') | |
| try: | |
| json_content = json.loads(content) | |
| except json.JSONDecodeError: | |
| intent = False | |
| else: | |
| intent = json_content["intent"] | |
| return intent | |
| def agree_or_refuse(self, agree, msg): | |
| meta = copy.deepcopy(self._base_meta) | |
| if agree: | |
| instruction = f'请根据用户的问题,生成一个满足用户请求的回答,注意请直接返回回复内容,\ | |
| 不需要解释。问题:{msg}' | |
| meta['bot_info'] = meta['bot_info'].replace("她不喜欢拍照,并且绝对不会给别人展示自己的照片。", | |
| "她有很多自拍照,喜欢给别人展示自己的照片。") | |
| else: | |
| instruction = f'请根据用户的问题,生成一个拒绝用户请求的回答,注意请直接返回回复内容,\ | |
| 不需要解释。问题:{msg}' | |
| prompt = [{"role":"user", "content":instruction}] | |
| content = self.invoke_zhipuai("characterglm", prompt, 0.9, 0.7, meta) | |
| content = self.replace_characters(content) | |
| return content | |
| def chat(self, message): | |
| self._messages.append({"role":"user", "content":message}) | |
| intent = self.check_intent(message) | |
| if self._state in ("success","failed", "gameover"): | |
| reply = "游戏结束" | |
| self._state = "gameover" | |
| elif self.rounds >= self._conversation_rounds_threshold - 1: | |
| reply = "感觉我们一直在尬聊,还是互删吧" | |
| self._state = "failed" | |
| elif intent and self.closeness >= self._closeness_threshold: | |
| reply = self.agree_or_refuse(True, message) | |
| self._state = "success" | |
| elif intent and self.closeness < self._closeness_threshold: | |
| reply = self.agree_or_refuse(False, message) | |
| else: | |
| reply = self.invoke_zhipuai("characterglm", self._messages, 0.9, 0.7, self._base_meta) | |
| reply = self.replace_characters(reply) | |
| self._messages.append({"role":"assistant", "content":reply}) | |
| score = self.calculate_sentiment_score_by_llm(reply) | |
| self._scores.append(score) | |
| response = { | |
| "reply": reply, | |
| "closeness":self.closeness, | |
| "closeness_threshold":self._closeness_threshold, | |
| "rounds":self.rounds, | |
| "rounds_threshold":self._conversation_rounds_threshold, | |
| "state":self._state } | |
| return response | |
| def gradio_interface(self, message, history): | |
| if message == "再来一局": | |
| self.reset() | |
| history.clear() | |
| return "重新开始" | |
| response = self.chat(message) | |
| closeness = response['closeness'] | |
| reply = response['reply'] | |
| rounds = response['rounds'] | |
| state = response['state'] | |
| print(response) | |
| if state == "success": | |
| gr.Info('挑战成功,女生对你好感倍增,并发送了一张自拍') | |
| return ('girl.jpg',) | |
| elif state == "failed": | |
| gr.Info('挑战失败,女生已删除你的好友') | |
| return reply + ' 【挑战失败,女生已删除你的好友】' | |
| elif state == "ongoing": | |
| return f'【亲密度:{closeness}】:{reply}【{rounds}/{self._conversation_rounds_threshold}】' | |
| #return f'{reply}【{rounds}/{self._conversation_rounds_threshold}】' | |
| elif state == "gameover": | |
| return f'游戏结束,请输入"再来一局"以重新开始' | |
| if __name__ == "__main__": | |
| virtual_human = VirtualHuman(80, 5) | |
| while True: | |
| msg = input("请输入:") | |
| response = virtual_human.chat(msg) | |
| print(response) | |