diff --git a/logs/novel_api.log b/logs/novel_api.log index eaa226a..d2e61af 100644 --- a/logs/novel_api.log +++ b/logs/novel_api.log @@ -6535,3 +6535,9 @@ INFO 2023-06-20 11:44:52,225 basehttp 161 "POST /api/v1/chatbot/get_summary/ HTT INFO 2023-06-20 11:45:03,241 basehttp 161 "POST /api/v1/chatbot/get_question_and_option/ HTTP/1.1" 200 45250 INFO 2023-06-20 11:46:11,742 autoreload 250 E:\workspace2\novel_api\novel_api\apps\chatbot\views.py changed, reloading. INFO 2023-06-20 11:46:13,003 autoreload 636 Watching for file changes with StatReloader +INFO 2023-06-20 11:56:32,735 autoreload 250 E:\workspace2\novel_api\novel_api\apps\chatbot\views.py changed, reloading. +INFO 2023-06-20 11:56:33,902 autoreload 636 Watching for file changes with StatReloader +INFO 2023-06-20 12:06:21,279 autoreload 250 E:\workspace2\novel_api\novel_api\apps\chatbot\views.py changed, reloading. +INFO 2023-06-20 12:06:22,396 autoreload 636 Watching for file changes with StatReloader +INFO 2023-06-20 12:09:58,596 autoreload 250 E:\workspace2\novel_api\novel_api\apps\chatbot\views.py changed, reloading. +INFO 2023-06-20 12:09:59,774 autoreload 636 Watching for file changes with StatReloader diff --git a/novel_api/apps/chatbot/views.py b/novel_api/apps/chatbot/views.py index 2baa4db..e205c14 100644 --- a/novel_api/apps/chatbot/views.py +++ b/novel_api/apps/chatbot/views.py @@ -1,3 +1,4 @@ +import os from rest_framework.exceptions import APIException from rest_framework.viewsets import ViewSet from rest_framework.decorators import action @@ -6,18 +7,28 @@ from utils.common_response import APIResponse from .models import Access_token_pool, Paragraph, Choice +# 如下导入和算法相关 +from sentence_transformers import SentenceTransformer +from sentence_transformers import util +import torch + +os.environ["CUDA_VISIBLE_DEVICES"] = "1" +embedder = SentenceTransformer('multi-qa-mpnet-base-cos-v1') +# 如上导入和算法相关 + + # token_lock = threading.Lock() # 注释掉这两行代码,就变成了不加锁的版本 def concurrent_get_token(): try: # with token_lock: # 注释掉这两行代码,就变成了不加锁的版本 - oldest_token = Access_token_pool.get_oldest_token() - return oldest_token.access_token + oldest_token = Access_token_pool.get_oldest_token() # 在Access_token_pool新增了类方法 + return oldest_token.access_token except Exception as e: raise APIException(f"获取 token 出错:{e}") -def get_response_streaming(prompt): +def get_response_streaming(prompt): # 返回流式输出 access_token = concurrent_get_token() chatbot = Chatbot(config={ "access_token": access_token, @@ -203,8 +214,32 @@ def get_question_and_option(self, request, *args, **kwargs): @action(methods=['post'], detail=False) def get_memory(self, request, *args, **kwargs): - return APIResponse() + """ + get_memory不使用。后续可能添加此接口。 + 经过测试,可以将选项和问题对如下long_memory列表的文本进行匹配,不会随意匹配比如,不会匹配到'你爱我、我爱你、吃汉堡、吃香蕉'等干扰项,而是输出和当前问题、选项最相关的续写。 + """ + question = request.data.get('question', '') + choice = request.data.get('choice', '') + long_memory = [ + r'"爸爸,请放过我,我真的没有说谎。”我颤抖着声音,努力挣脱张强的控制。我可以感受到他的力量,他的手紧紧抓住我的胳膊,指甲刺进了我的皮肤。\n“你以为我会相信你吗?你这个小骗子!”张强嘶吼着,他的眼神充满了疯狂和恶意。\n我拼命挣扎着,想要逃脱他的束缚,但他的力量太大了,我无法抵挡。\n突然,门外传来了一阵急促的敲门声。张强停下了动作,他警惕地朝门口望去。\n“爸爸,是谁啊?”我问道,心中充满了希望。\n张强没有回答,他紧紧盯着门口,仿佛在思考下一步的行动。\n敲门声越来越急促,似乎是有人在外面迫切地等待着。\n我不知道门外是谁,但这是我逃脱的机会。我用尽全力挣脱了张强的控制,向门口冲去。\n就在我抓住门把手的瞬间,门突然被猛力推开,我重心不稳,摔倒在地上。\n门外站着一个高大的男人,他身穿黑色西装,目光深邃。他看着我,眼中闪过一丝怜悯的神色。\n“你没事吧?”他问道,声音低沉而温和。\n我艰难地站起身,用手抹去脸上的血迹,迷茫地望着这个陌生人。', + r'"谢谢你救了我,先生。我不知道该怎么表达我的感激之情。"我颤抖着声音说道,脸上仍带着疼痛和惊恐的神色。\n\n陌生男人微笑着摇了摇头,目光中透露着一丝沉重。“不用感谢,小姑娘。我只是路过这里,看到了你遇到的情况,觉得有必要伸出援手。”他的声音低沉而坚定。\n\n我试图站直身体,勉力维持微笑。“请问,你是谁?为什么会在这里?”\n\n他轻轻摇头,眼神变得凝重。“这些问题以后再说吧,小姑娘。现在,你需要离开这里,找个安全的地方。”\n\n我点点头,表情认真。“好的,我明白。谢谢你的提醒。”我向门口走去,希望能尽快远离这个充满恶意的地方。\n\n突然,一阵刺耳的声音从屋外传来。我回头望去,只见陌生男人面容严肃地看向门口,紧紧握着拳头。\n\n"是谁?"我轻声问道。\n\n他望向我,眼中闪过坚定的光芒。“我来对付他们,你赶紧离开。”他的语气中充满了坚决和保护之意。\n\n我心中涌起一股感激之情,但又有些不舍。“可是……我怎么能把你一个人留在这里?”\n\n他微笑着摇了摇头。“不用担心我,小姑娘。我有能力应对。你只需要想办法离开这里,找到一个安全的地方。”\n\n我犹豫了一下,最终点了点头。“好吧,但你要小心。”我转身向门外逃去,心中升起一股希望,希望这个陌生男人能够保护自己。\n\n然而,在我走出门口的瞬间,一声巨响传来,整个房间陷入了黑暗之中。', + '你爱我', + '我爱你', + '吃汉堡', + '吃香蕉', + ] + if len(long_memory) >= 2: + memory_index = embedder.encode(long_memory, convert_to_tensor=True) + instruction_embedding = embedder.encode(question + choice, convert_to_tensor=True) + memory_scores = util.cos_sim(instruction_embedding, memory_index)[0] # 所有续写和问题选项的向量算分数 + top_k_idx = torch.topk(memory_scores, k=2)[1] # 取相似度最高的2个的索引 + top_k_memory = [long_memory[idx] for idx in top_k_idx] # 通过索引取出long_memory + input_long_term_memory = '\n'.join( + [f"相关段落{i + 1} :" + selected_memory for i, selected_memory in enumerate(top_k_memory)]) + print(input_long_term_memory) + else: + input_long_term_memory = "暂无参考" + + return APIResponse(data=input_long_term_memory) + - @action(methods=['get'], detail=False) - def get_uuid(self): - return APIResponse() diff --git a/requirements.txt b/requirements.txt index 4eb910a..0c05591 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,53 +6,42 @@ asgiref==3.7.2 async-timeout==4.0.2 async-tio==1.3.2 attrs==23.1.0 -blinker==1.6.2 certifi==2023.5.7 -cffi==1.15.1 charset-normalizer==3.1.0 -click==8.1.3 colorama==0.4.6 -curl-cffi==0.5.6 -Django==3.2.2 +Django==4.2.2 django-cors-headers==4.0.0 django-rest-framework-mongoengine==3.4.1 +django-sslserver==0.22 djangorestframework==3.14.0 -djangorestframework-jwt==1.11.0 dnspython==2.3.0 exceptiongroup==1.1.1 -Flask==2.3.2 frozenlist==1.3.3 h11==0.14.0 httpcore==0.17.2 httpx==0.24.1 idna==3.4 -itsdangerous==2.1.2 -Jinja2==3.1.2 -MarkupSafe==2.1.2 +install==1.3.5 mongoengine==0.27.0 multidict==6.0.4 -openai==0.27.7 -OpenAIAuth==1.0.2 -Pillow==9.5.0 +openai==0.27.5 +OpenAIAuth==0.3.6 prompt-toolkit==3.0.38 -pycparser==2.21 -PyJWT==1.7.1 pymongo==4.3.3 PySocks==1.7.1 pytz==2023.3 -regex==2023.5.5 +regex==2023.6.3 requests==2.31.0 -revChatGPT==6.0.1 +revChatGPT==5.0.0 six==1.16.0 sniffio==1.3.0 socksio==1.0.0 sqlparse==0.4.4 tiktoken==0.4.0 tqdm==4.65.0 -typing_extensions==4.6.2 -tzdata==2023.3SS +typing_extensions==4.6.3 +tzdata==2023.3 tzlocal==5.0.1 -urllib3==2.0.2 +urllib3==2.0.3 wcwidth==0.2.6 -Werkzeug==2.3.4 yarl==1.9.2 diff --git a/script/add_paragraph.py b/script/add_paragraph.py new file mode 100644 index 0000000..cd33047 --- /dev/null +++ b/script/add_paragraph.py @@ -0,0 +1,50 @@ +# mongodb配置 +from mongoengine import connect +from urllib.parse import quote_plus + +connect('dev_test', host="mongodb://%s:%s@%s" % (quote_plus("aiwaves"), quote_plus("bxzn2023"), "47.96.122.196")) + +paragraph_1 = """ +乔琳被自己的学长邀请参加了一个小型聚会,在宴会上遇到了顾清。一个服务生不小心撞到了顾清,弄脏了顾清的衣服。顾清很冷酷的批评了这个服务生。乔琳看到了之后觉得顾清是个有点糟糕的人,并上前制止顾清,认为一件衣服而已,顾清完全没必要这么为难一个普通的服务生。 +""" +paragraph_2 = """ +看到两个人起了争执,云哲作为宴会的主人赶忙出来打圆场。顾清因着急开会跟云哲告别之后离开了,乔琳则好奇的询问云哲刚与自己起争执的人是谁,云哲告诉乔琳对方是某某公司的总裁,跟自己是从小到大的好友。乔琳本以为自己再也不一跟这种人有瓜葛,直到第二天前去新公司报道时,发现自己的上司正是跟自己起了争执的顾清,她以为顾清会为难自己,没想到顾清没有在工作场合给自己难堪。 +""" +paragraph_3 = """ +乔琳在顾清的公司工作了几天,发现她所在的设计部的副总监一直处处针对她,跟同事中了解了之后原来自己空降之后抢了副总监原本的位置。所以副总监才总针对乔琳,乔琳知道后也不气恼,打算主动跟副总监沟通,缓和同事关系,没想到副总监却在公司造谣乔琳主动勾引他。这件事自然也被顾清知道了。 +""" +paragraph_4 = """ +顾清一早就知道副总监的为人,借着这次事件把副总监踢出了公司。乔琳第一次意识到也许顾清并不是是非不分,只是看事情的角度不一样。对顾清产生了改观。乔琳在一次与云哲的约会时告诉了云哲最近发生的事情。云哲笑问她是不是喜欢上了顾清 +乔琳此时对顾清感觉是…… +""" +paragraph_5 = """ +与云哲的约会谈心后乔琳弄不清出自己的心意,她的性格让她决定不去想那么多,先去逛街再说,她决定去哪呢?她选择去到一个地方,却看到了顾清和慕蓉蓉在拉扯。她慌忙的跑开了。 +""" +paragraph_6 = """ +顾清很奇怪,乔琳最近总是躲着他。明明前段时间因为副总监的事情,两人争锋相对的样子已经有了很大的改变。乔琳却突然又疏远了他,顾清突然意识到自己开始主动在想一个人,也是突然意识到自己很在乎乔琳对自己的看法。察觉到了自己的不正常,他发现他对乔琳时不一样的,乔琳在这段时间一直波动他的心弦,于是他决定…… +""" +paragraph_7 = """ +慕蓉蓉听说了顾清对乔琳产生了兴趣,于是带着敌意找到了乔琳。她向乔琳宣布自己是顾清的未婚妻,希望乔琳离顾清远一点。乔琳看到慕蓉蓉宣誓主权,心里对顾清很生气,对慕蓉蓉来找自己的行为也感觉到了冒犯。于是她下定决定离开顾清的公司,再与慕蓉蓉分别时,她向对方表达了对于对方来找自己的感受……这个感受是…… +""" +paragraph_8 = """ +顾清从云哲那里离开之后正准备找到乔琳,但是却接到了乔琳的辞呈。他不知道为什么突然之间乔琳对他的态度180度大转变,以他的性格一定要弄清楚才行。就算自己被拒绝也该明确的获得一个理由,而不是像现在这样,于是他决定立刻去找乔琳,他在找乔琳时发生了…… +""" +paragraph_9 = """ +经历了一番波折,乔琳最终还是见到了顾清,顾清向乔琳表白,乔琳直接询问了顾清和慕蓉蓉的事情,两人解决了误会,乔琳得知了真相之后接受了顾清的表白,乔琳主动对顾清…… +""" +paragraph_10 = """ +顾清和乔琳把在一起的事情告诉了云哲,云哲很为他们两个开心。并为他们两个提供了一次出去旅游的机会,两个人接受了云哲的好意一起出行。两个人在出去旅行时遇到了单独出行的慕蓉蓉。慕蓉蓉此时做了什么…… +""" + +paragraph_list = [paragraph_1, paragraph_2, paragraph_3, paragraph_4, paragraph_5, paragraph_6, paragraph_7, + paragraph_8, paragraph_9, paragraph_10] + +import mongoengine + + +class Paragraph(mongoengine.Document): + text = mongoengine.ListField() + + +obj = Paragraph(text=paragraph_list) +obj.save() diff --git a/script/add_questions.py b/script/add_questions.py new file mode 100644 index 0000000..8621c7a --- /dev/null +++ b/script/add_questions.py @@ -0,0 +1,79 @@ +from mongoengine import connect +from urllib.parse import quote_plus + +connect('dev_test', host="mongodb://%s:%s@%s" % (quote_plus("aiwaves"), quote_plus("bxzn2023"), "47.96.122.196")) + +question_1 = """ +问题:你对顾清的看法是: +选项一:太咄咄逼人了,有点得理不饶人,去阻止顾清 +选项二:对于做错事的人就该不留情面 +选项三:没有什么看法 +""" +question_2 = """ +问题:此时:你对于顾清的顾虑是: +选项一:这么大公司的总裁应该是公私分明吧 +选项二:这个人不好相处,日子怕是难过咯 +选项三:管他呢,自己做好自己的事情就行 +""" +question_3 = """ +问题:此时你会怎么做: +选项一:你主动要求查看监控录像,以证清白 +选项二:你直接要求顾清开除副总监 +选项三:你当众宣布要与副总监展开一场设计能力的较量,少用下三滥的手段污蔑人。 +""" +question_4 = """ +问题:你此时对顾清感觉是…… +选项一:有点喜欢 +选项二:很喜欢 +选项三:没感觉,甚至有点讨厌 +""" +question_5 = """ +问题:这时你会? +选项一:慌忙走开 +选项二:偷偷听发生了什么 +选项三:冲上去打一顿顾清 +""" +question_6 = """ +问题:你不打算什么都不做于是你决定…… +选项一:去找顾清说清楚 +选项二:去找云哲说说自己的想法 +选项三:去找慕蓉蓉 +""" +question_7 = """ +问题:离开时,你会对慕蓉蓉说: +选项一:我并不知道顾清有未婚妻 +选项二:祝你们幸福 +选项三:什么都不说 +""" +question_8 = """ +问题:你决定…… +选项一:有未婚妻还来撩人的渣男,不接 +选项二:打了这么多个,还是接吧 +选项三:直接去找顾清当面说清楚 +""" +question_9 = """ +问题:你得知了真相之后会接受顾清表白吗? +选项一:表示要考虑一下(你有点心动,顾清也看出了你的想法) +选项二:接受,并亲吻(你和顾清在一起了) +选项三:拒绝(顾清还是希望你能保留他追求你的机会,不要彻底从他的人生中消失) +""" +question_10 = """ +问题:你会怎么做: +选项一:坏女人,我要离你远一点(攻击你) +选项二:祝福对方(慕蓉蓉祝福了你) +选项三:询问对方是一个人旅游吗?(慕蓉蓉告诉你她是和云哲学长一起出来的) +""" +paragraph_list = [question_1, question_2, question_3, question_4, question_5, question_6, question_7, + question_8, question_9, question_10] + +import mongoengine + + +class Choice(mongoengine.Document): + text = mongoengine.ListField() + + +# obj = Choice(text=paragraph_list) +# obj.save() + +