From f4ed2c6b17f3ccfd1803a9dfc85e34663ddf9c48 Mon Sep 17 00:00:00 2001 From: "majiahui@haimaqingfan.com" Date: Tue, 7 Nov 2023 14:13:08 +0800 Subject: [PATCH] =?UTF-8?q?chatgpt=E6=9C=8D=E5=8A=A1=E4=BD=BF=E7=94=A8vllm?= =?UTF-8?q?=E6=96=B9=E5=BC=8F=E9=A2=84=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 54 +++--------------------------- flask_predict.py | 51 +++++++++++++++++++++++++++++ gunicorn_config.py | 21 ++++++++++++ mistral_model_predict_vllm.py | 57 ++++++++++++++++++++++++++++++++ run_api.sh | 1 + run_model_predict.sh | 1 + yace.py | 47 ++++++++++++++++++++++++++ yace2.py | 76 +++++++++++++++++++++++++++++++++++++++++++ yuce3.py | 51 +++++++++++++++++++++++++++++ 9 files changed, 310 insertions(+), 49 deletions(-) create mode 100644 flask_predict.py create mode 100644 gunicorn_config.py create mode 100644 mistral_model_predict_vllm.py create mode 100644 run_api.sh create mode 100644 run_model_predict.sh create mode 100644 yace.py create mode 100644 yace2.py create mode 100644 yuce3.py diff --git a/README.md b/README.md index fdedd3f..08740e6 100644 --- a/README.md +++ b/README.md @@ -1,58 +1,14 @@ # VLLM项目 ## 项目启动 -bash run_app_flask.sh +bash run_model_predict.sh +bash run_api.sh + ## 调用示例 -![img.png](img.png) -http://114.116.25.228:18000/predict +"http://192.168.31.74:12000/predict" { - "texts": "论文题目是“晚清至民国温州瓯柑运销体制的转变”,目录是“一、引言\n1. 研究背景\n2. 研究意义\n3. 研究方法\n\n二、晚清至民国时期温州瓯柑的运销体制\n1. 温州瓯柑的产地和品种\n2. 运销渠道及其特点\n3. 运销体制的演变\n\n三、温州瓯柑运销体制转变的原因\n1. 经济背景\n2. 政治背景\n3. 社会背景\n\n四、温州瓯柑运销体制转变的影响\n1. 经济影响\n2. 社会影响\n3. 文化影响\n\n五、温州瓯柑运销体制转变的启示\n1. 历史经验\n2. 现实意义\n3. 发展前景\n\n六、结论\n\n七、参考文献”,请为这篇论文生成15篇左右的参考文献,要求其中有有中文参考文献不低于12篇,英文参考文献不低于2篇" + "texts": "User:你好\nAssistant:" } ## 返回示例 -![img_1.png](img_1.png) ## 请求参数 -### 仅有标题生成的任务 -{ -"生成论文来源的背景#\n问:以《习近平新时代中国特色社会主义法治观初探》为论文题目,写一段题目来源的背景,要求字数在200字以内\n答:\n" - -"生成研究内容#\n问:请帮我生成《基于神经网络的商品推荐系统的研究与实现》为题目的研究内容,包括整体简介和分最少三个方面总结\n答:\n" - -"生成目录#\n问:为论文题目《我国医患纠纷行政调解前置程序问题的研究》生成目录,要求只有一级标题和二级标题,一级标题使用中文数字 例如一、xxx;二级标题使用阿拉伯数字 例如1.1 xxx;一级标题不少于7个;每个一级标题至少包含3个二级标题\n答:\n" - -"生成课题的研究背景和意义#\n问:请分别写出以《商业车险费率市场化改革对财险公司影响研究》为课题的研究背景和意义,字数不少于1000字\n答:\n" - -"生成论文简短总结#\n问:以《用于智能马桶盖的无袖带式血压监测系统开发》为论文题目,写一个论文简短总结,要求在300字以内\n答:\n" - -"生成课题的国内外研究状况综述#\n问:请写出以《新时代中国院线电影观感积极率研究》为课题的国内外研究状况综述,字数在800字左右\n答:\n" - -"生成6点本篇论文应完成的主要内容#\n问:请根据题目为《兰州市数字化城市管理提升研究》,和研究内容为“{生成研究内容}”总结出至少6点本篇论文应完成的主要内容,使用阿拉伯数字排列\"\n答:\n" - -"生成参考文献#" - -"生成论文小标题内容#\n问:论文题目是《1926-1930年归绥地区灾荒与社会流动》,目录是“{生成目录}”,请把其中的小标题“{小标题}”的内容补充完整,补充内容字数在900字左右\n答:\n" - -"生成论文摘要#\n问:论文题目是《纳米水化硅酸钙改性隔热涂料的研究》,目录是“{生成目录}”,生成论文摘要,要求生成的字数在600字左右\"\n答:\n" - -"生成关键字#\n问:请为“{生成论文摘要}”这段论文摘要生成3-5个关键字,使用阿拉伯数字作为序号标注,例如“1.xxx \n2.xxx \n3.xxx \n4.xxx \n5.xxx \n”\"\n答:\n" - -"翻译摘要#\n问:请把“{生成论文摘要}”这段文字翻译成英文\"\n答:\n" - -"翻译关键词#\n问:请把“{生成关键字}”这几个关键字翻译成英文\"\n答:\n" -} - -### 带着核心内容和标题的生成任务 -{ - -"生成论文来源的背景#\n问:以《民航繁忙干线机票最低价格预测方法研究》为论文题目,以“本研究旨在探索一种新的机票价格预测方法,以提高乘客购票体验和航空公司的经济效益。该研究包括数据采集、数据预处理、特征工程、机器学习模型构建和模型评估等步骤。最终成果是开发出一款可预测繁忙干线机票最低价格的模型,并通过对比实际价格和预测价格的误差,验证该模型的准确性和可靠性。通过本研究,我们希望能为航空公司提供更准确的价格预测,为乘客提供更便捷的购票体验。”为论文的研究方向,写一段题目来源的背景,要求字数在200字以内\n答:\n" - -"生成研究内容#\n问:请帮我生成《A公司3C产品逆向物流业务流程优化》为题目,以“本文旨在优化A公司3C产品逆向物流业务流程,包括对退货、维修、换货等环节进行调研和分析,提出改善方案。最终成果是优化后的逆向物流业务流程实施,并以一个特定3C产品的退货流程为例,验证所设计方案的可行性和有效性。”为论文的研究方向,生成论文研究内容,包括整体简介和分最少三个方面总结\n答:\n" - -"生成目录#\n问:论文题目为《低碳试点城市的绿色GDP核算研究》,以“该研究旨在通过对低碳试点城市的绿色GDP核算,探索一种新的经济发展模式,以实现经济增长与环境保护的双赢。研究将结合城市资源利用情况、环境质量、生态系统服务等方面进行综合评估,建立低碳经济发展指标体系,从而为低碳试点城市的可持续发展提供理论和实践支持。最终成果将是一份完整的绿色GDP核算报告,以低碳试点城市为例,验证该研究的可行性和实用性。”为论文的研究方向,为论文生成目录,要求只有一级标题和二级标题,一级标题使用中文数字 例如一、xxx;二级标题使用阿拉伯数字 例如1.1 xxx;一级标题不少于7个;每个一级标题至少包含3个二级标题\n答:\n" - -"生成课题的研究背景和意义#\n问:请分别写出以《企业拟上市过程中的政府服务方式探析》为课题,以“研究拟上市企业在上市过程中,政府部门如何提供服务,探讨政府服务方式的优化和提升。最终成果是通过实地调研和案例分析,总结出一套适用于拟上市企业的政府服务模式,以提高拟上市企业上市成功率和促进经济发展。”为论文的研究方向,生成论文的研究背景和意义,字数不少于1000字\n答:\n" - -"生成论文简短总结#\n问:以《韩国民主巩固的困境问题研究》为论文题目,以“研究韩国民主化进程中所面临的困境问题,包括政治、经济、社会等多个方面的因素。最终成果是通过对韩国民主化进程的深入分析,提出一些可行的解决方案,以促进韩国民主巩固的发展。通过对韩国政治体制、经济发展、社会文化等方面的综合研究,探讨韩国民主化进程中所面临的困境问题,如政治腐败、经济不平等、社会分化等,分析其根源及影响因素。在此基础上,提出一些可行的解决方案,如加强反腐败力度、促进经济平等、强化社会文化建设等,以推动韩国民主巩固的进程。最终,通过实践验证所提出的解决方案的可行性,为韩国民主巩固的发展提供有益的借鉴。”为论文的研究方向,写一个论文简短总结,要求在300字以内\n答:\n" - -"生成课题的国内外研究状况综述#\n问:以《鲤疱疹病毒3型vIL-10基因的克隆表达及其对免疫相关因子调节作用的研究》为课题,以“研究鲤疱疹病毒3型vIL-10基因的克隆表达,探究其在免疫调节中的作用。通过实验验证其对免疫相关因子的调节作用,并分析其在免疫调节过程中的机制。最终成果是获得鲤疱疹病毒3型vIL-10基因的表达载体,并证明其在免疫调节中具有重要的调节作用。”为论文的研究方向,请写出这篇论文的国内外研究状况综述,字数在800字左右\n答:\n" -} diff --git a/flask_predict.py b/flask_predict.py new file mode 100644 index 0000000..e019bf0 --- /dev/null +++ b/flask_predict.py @@ -0,0 +1,51 @@ +from flask import Flask, jsonify +from flask import request +import redis +import uuid +import json +import time +import socket + +def get_host_ip(): + """ + 查询本机ip地址 + :return: ip + """ + try: + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.connect(('8.8.8.8', 80)) + ip = s.getsockname()[0] + finally: + s.close() + + return ip + +app = Flask(__name__) +app.config["JSON_AS_ASCII"] = False +pool = redis.ConnectionPool(host='localhost', port=63179, max_connections=50,db=11, password="zhicheng123*") +redis_ = redis.Redis(connection_pool=pool, decode_responses=True) + +db_key_query = 'query' +db_key_query_articles_directory = 'query_articles_directory' +db_key_result = 'result' +batch_size = 32 + + +@app.route("/predict", methods=["POST"]) +def handle_query(): + text = request.json["texts"] # 获取用户query中的文本 例如"I love you" + id_ = str(uuid.uuid1()) # 为query生成唯一标识 + d = {'id': id_, 'text': text} # 绑定文本和query id + redis_.rpush(db_key_query, json.dumps(d)) # 加入redis + while True: + result = redis_.get(id_) # 获取该query的模型结果 + if result is not None: + redis_.delete(id_) + result_text = {'code': "200", 'data': json.loads(result)} + break + time.sleep(1) + + return jsonify(result_text) # 返回结果 + +if __name__ == "__main__": + app.run(debug=False, host='0.0.0.0', port=18001) \ No newline at end of file diff --git a/gunicorn_config.py b/gunicorn_config.py new file mode 100644 index 0000000..4a46265 --- /dev/null +++ b/gunicorn_config.py @@ -0,0 +1,21 @@ +# 并行工作线程数 +workers = 8 +# 监听内网端口5000【按需要更改】 +bind = '0.0.0.0:12000' + +loglevel = 'debug' + +worker_class = "gevent" +# 设置守护进程【关闭连接时,程序仍在运行】 +daemon = True +# 设置超时时间120s,默认为30s。按自己的需求进行设置 +timeout = 120 +# 设置访问日志和错误信息日志路径 +accesslog = './logs/acess.log' +errorlog = './logs/error.log' +# access_log_format = '%(h) - %(t)s - %(u)s - %(s)s %(H)s' +# errorlog = '-' # 记录到标准输出 + + +# 设置最大并发量 +worker_connections = 20000 diff --git a/mistral_model_predict_vllm.py b/mistral_model_predict_vllm.py new file mode 100644 index 0000000..a470c09 --- /dev/null +++ b/mistral_model_predict_vllm.py @@ -0,0 +1,57 @@ +import os +os.environ["CUDA_VISIBLE_DEVICES"] = "3" +from transformers import pipeline +import redis +import uuid +import json +from threading import Thread +from vllm import LLM, SamplingParams +import time +import threading +import time +import concurrent.futures +import requests +import socket + + +pool = redis.ConnectionPool(host='localhost', port=63179, max_connections=50,db=11, password="zhicheng123*") +redis_ = redis.Redis(connection_pool=pool, decode_responses=True) + +db_key_query = 'query' +db_key_query_articles_directory = 'query_articles_directory' +db_key_result = 'result' +batch_size = 512 + +sampling_params = SamplingParams(temperature=0.95, top_p=0.7,presence_penalty=0.9,stop="", max_tokens=4096) +models_path = "/home/majiahui/project/models-llm/openbuddy-llama-7b-finetune" +llm = LLM(model=models_path, tokenizer_mode="slow") + +def classify(batch_size): # 调用模型,设置最大batch_size + while True: + texts = [] + query_ids = [] + if redis_.llen(db_key_query) == 0: # 若队列中没有元素就继续获取 + time.sleep(2) + continue + for i in range(min(redis_.llen(db_key_query), batch_size)): + query = redis_.lpop(db_key_query).decode('UTF-8') # 获取query的text + query_ids.append(json.loads(query)['id']) + texts.append(json.loads(query)['text']) # 拼接若干text 为batch + outputs = llm.generate(texts, sampling_params) # 调用模型 + + generated_text_list = [""] * len(texts) + print("outputs", len(outputs)) + for i, output in enumerate(outputs): + index = output.request_id + generated_text = output.outputs[0].text + generated_text_list[int(index)] = generated_text + + + for (id_, output) in zip(query_ids, generated_text_list): + res = output + redis_.set(id_, json.dumps(res)) # 将模型结果送回队列 + + +if __name__ == '__main__': + t = Thread(target=classify, args=(batch_size,)) + t.start() \ No newline at end of file diff --git a/run_api.sh b/run_api.sh new file mode 100644 index 0000000..31f8d81 --- /dev/null +++ b/run_api.sh @@ -0,0 +1 @@ +gunicorn flask_predict:app -c gunicorn_config.py \ No newline at end of file diff --git a/run_model_predict.sh b/run_model_predict.sh new file mode 100644 index 0000000..c7631dd --- /dev/null +++ b/run_model_predict.sh @@ -0,0 +1 @@ +nohup python mistral_model_predict_vllm.py > mistral_model_predict_vllm_logs.file 2>&1 & \ No newline at end of file diff --git a/yace.py b/yace.py new file mode 100644 index 0000000..dea4e97 --- /dev/null +++ b/yace.py @@ -0,0 +1,47 @@ +import concurrent.futures +import requests +import socket + + +def dialog_line_parse(url, text): + """ + 将数据输入模型进行分析并输出结果 + :param url: 模型url + :param text: 进入模型的数据 + :return: 模型返回结果 + """ + + response = requests.post( + url, + json=text, + timeout=1000 + ) + if response.status_code == 200: + return response.json() + else: + # logger.error( + # "【{}】 Failed to get a proper response from remote " + # "server. Status Code: {}. Response: {}" + # "".format(url, response.status_code, response.text) + # ) + print("【{}】 Failed to get a proper response from remote " + "server. Status Code: {}. Response: {}" + "".format(url, response.status_code, response.text)) + print(text) + return [] + +nums = 1000 +url = "http://192.168.31.74:18001/predict" + +input_data = [] +for i in range(nums): + input_data.append([url, {"texts": "User:你好\nAssistant:"}]) + +with concurrent.futures.ThreadPoolExecutor() as executor: + # 使用submit方法将任务提交给线程池,并获取Future对象 + futures = [executor.submit(dialog_line_parse, i[0], i[1]) for i in input_data] + + # 使用as_completed获取已完成的任务,并获取返回值 + results = [future.result() for future in concurrent.futures.as_completed(futures)] + +print(results) \ No newline at end of file diff --git a/yace2.py b/yace2.py new file mode 100644 index 0000000..ea605a8 --- /dev/null +++ b/yace2.py @@ -0,0 +1,76 @@ +import threading +import requests +import time + + +# 用于记录成功和失败请求的全局变量 +success_count = 0 +failure_count = 0 +lock = threading.Lock() + + +def dialog_line_parse(url, text): + """ + 将数据输入模型进行分析并输出结果 + :param url: 模型url + :param text: 进入模型的数据 + :return: 模型返回结果 + """ + + response = requests.post( + url, + json=text, + timeout=1000 + ) + if response.status_code == 200: + return response.json() + else: + # logger.error( + # "【{}】 Failed to get a proper response from remote " + # "server. Status Code: {}. Response: {}" + # "".format(url, response.status_code, response.text) + # ) + print("【{}】 Failed to get a proper response from remote " + "server. Status Code: {}. Response: {}" + "".format(url, response.status_code, response.text)) + print(text) + return [] + + +# 定义一个函数来执行 HTTP 请求 +def make_request(url): + global success_count, failure_count + + try: + a = dialog_line_parse(url, {"texts": "User:你好\nAssistant:"})['data'] + print(a) + with lock: + success_count += 1 + except: + with lock: + failure_count += 1 + +# 要并发请求的 URL 列表 +urls = [ + 'http://192.168.31.74:18001/predict', + # 可以添加更多的 URL +] * 30 + + +# 创建一个线程列表 +threads = [] + +# 创建并启动线程 +start= time.time() +for url in urls: + thread = threading.Thread(target=make_request, args=(url,)) + thread.start() + threads.append(thread) + +# 等待所有线程完成 +for thread in threads: + thread.join() +end = time.time() +print(end-start) +print(f"Successful requests: {success_count}") +print(f"Failed requests: {failure_count}") \ No newline at end of file diff --git a/yuce3.py b/yuce3.py new file mode 100644 index 0000000..bc99d5d --- /dev/null +++ b/yuce3.py @@ -0,0 +1,51 @@ +import concurrent.futures +import requests +import socket + + +def dialog_line_parse(url, text): + """ + 将数据输入模型进行分析并输出结果 + :param url: 模型url + :param text: 进入模型的数据 + :return: 模型返回结果 + """ + + response = requests.post( + url, + json=text, + timeout=1000 + ) + if response.status_code == 200: + return response.json() + else: + # logger.error( + # "【{}】 Failed to get a proper response from remote " + # "server. Status Code: {}. Response: {}" + # "".format(url, response.status_code, response.text) + # ) + print("【{}】 Failed to get a proper response from remote " + "server. Status Code: {}. Response: {}" + "".format(url, response.status_code, response.text)) + print(text) + return [] + + +text = "User:生成目录#\n问:为论文题目《基于跨文化意识培养的中职英语词汇教学模式及策略行动研究》生成目录,要求只有一级标题和二级标题,一级标题使用中文数字 例如一、xxx;二级标题使用阿拉伯数字 例如1.1 xxx;一级标题不少于7个;每个一级标题至少包含3个二级标题\n答:\n\nAssistant:" # 获取用户query中的文本 例如"I love you" +nums = 10 + +nums = int(nums) +url = "http://192.168.31.74:18001/predict" + +input_data = [] +for i in range(nums): + input_data.append([url, {"texts": text}]) + +with concurrent.futures.ThreadPoolExecutor() as executor: + # 使用submit方法将任务提交给线程池,并获取Future对象 + futures = [executor.submit(dialog_line_parse, i[0], i[1]) for i in input_data] + + # 使用as_completed获取已完成的任务,并获取返回值 + results = [future.result() for future in concurrent.futures.as_completed(futures)] + +print(results) \ No newline at end of file