From 2b8f18157d359f388ddd68cae5d395df1ad27d59 Mon Sep 17 00:00:00 2001 From: Kakune55 Date: Fri, 17 Nov 2023 18:31:02 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=BB=BA=E5=AD=98=E5=82=A8=E5=BA=93?= =?UTF-8?q?=20PyGetGPT=E6=AD=A3=E5=BC=8F=E5=8F=91=E8=A1=8C=E7=89=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 + LICENSE | 21 +++ README.md | 3 + doc/clientConfig.md | 7 + doc/serverapi.md | 17 +++ src/Server/chatglmTurbo.py | 27 ++++ src/Server/config.py | 5 + src/Server/db.py | 58 ++++++++ src/Server/main.py | 48 +++++++ src/Server/qwenTurbo.py | 31 ++++ src/Web/index.html | 288 +++++++++++++++++++++++++++++++++++++ src/Web/popup.css | 47 ++++++ 12 files changed, 554 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 doc/clientConfig.md create mode 100644 doc/serverapi.md create mode 100644 src/Server/chatglmTurbo.py create mode 100644 src/Server/config.py create mode 100644 src/Server/db.py create mode 100644 src/Server/main.py create mode 100644 src/Server/qwenTurbo.py create mode 100644 src/Web/index.html create mode 100644 src/Web/popup.css diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7043ff1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ + +*.json diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..cf7b12c --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Kakune55 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..fdb72f7 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# PyGetGPT +使用python构建的简易语言模型api调用系统 +使用web页面作为GUI易于部署 diff --git a/doc/clientConfig.md b/doc/clientConfig.md new file mode 100644 index 0000000..36afe45 --- /dev/null +++ b/doc/clientConfig.md @@ -0,0 +1,7 @@ +# 配置文件说明 +{"url": "<此处为api URL>", "userkey": "<此处为你的UserKey>", "context": <此处为1 开启上下位关联功能 默认0关闭>} +注意:开启上下文关联会消耗大量的token +# 什么是Token +在大型语言模型中,"token"是指文本中的一个最小单位。 通常,一个token可以是一个单词、一个标点符号、一个数字、一个符号等。 在自然语言处理中,tokenization是将一个句子或文本分成tokens的过程。 在大型语言模型的训练和应用中,模型接收一串tokens作为输入,并尝试预测下一个最可能的token。 +# 上下文关联 +在使用上下文关联时,模型除了处理你当前的问题时还需要一并将历史对话的一部分共同处理。所以需要消耗更多的token。在本应用中token消耗平均值大约是不开启上下文功能的300%。 \ No newline at end of file diff --git a/doc/serverapi.md b/doc/serverapi.md new file mode 100644 index 0000000..66694e2 --- /dev/null +++ b/doc/serverapi.md @@ -0,0 +1,17 @@ +# server API 接口文档 + +## 请求格式(json) +| 键 | 类型 | 必选 | 示例 | +|---------|------|-----|-----| +| prompt | str | yes | "你好" | +| userkey | str | yes | "2b3j41b2xh1hz1" | +| history | list | no | "history":[{"user":"XXXXXX","bot":"XXXXXX"},{"user":"XXXXXX""bot":"XXXXXX"}] | + + +## 返回格式(json) +| 键 | 类型 | 示例 | +|----|------|------| +| code | int | 200 | +| output | str | "你好" | +| surplus | int | 10000 | +| | \ No newline at end of file diff --git a/src/Server/chatglmTurbo.py b/src/Server/chatglmTurbo.py new file mode 100644 index 0000000..3a58ce0 --- /dev/null +++ b/src/Server/chatglmTurbo.py @@ -0,0 +1,27 @@ +import zhipuai , config + +zhipuai.api_key = config.readConf()["chatglmturbo"]["Authorization"] + +def service(prompt,history = ""): + if history == "": + response = zhipuai.model_api.invoke( + model="chatglm_turbo", + prompt=[ + {"role": "user", "content": prompt}, + ] + ) + else: + response = zhipuai.model_api.invoke( + model="chatglm_turbo", + prompt=[ + {"role": "user", "content": history[1]["user"]}, + {"role": "assistant", "content": history[1]["bot"]}, + {"role": "user", "content": history[0]["user"]}, + {"role": "assistant", "content": history[0]["bot"]}, + {"role": "user", "content": prompt}, + ] + ) + if response["code"] == 200: + return 200, response["data"]["choices"][0]["content"], response["data"]["usage"]['total_tokens'] + else: + return 50 , str(response["code"])+response["msg"], 0 diff --git a/src/Server/config.py b/src/Server/config.py new file mode 100644 index 0000000..012db0c --- /dev/null +++ b/src/Server/config.py @@ -0,0 +1,5 @@ +import json + +def readConf(): + with open('config.json') as f: + return json.load(f) \ No newline at end of file diff --git a/src/Server/db.py b/src/Server/db.py new file mode 100644 index 0000000..852baf0 --- /dev/null +++ b/src/Server/db.py @@ -0,0 +1,58 @@ +import pymysql , config + + +def userSurplus(userkey): + #打开数据库连接 + db = pymysql.connect(host=config.readConf()["db"]["host"], + port=config.readConf()["db"]["port"], + user=config.readConf()["db"]["user"], + password=config.readConf()["db"]["passwd"], + database=config.readConf()["db"]["database"]) + # 使用 cursor() 方法创建一个游标对象 cursor + cursor = db.cursor() + + # 使用 execute() 方法执行 SQL 查询 + cursor.execute(f"SELECT surplus FROM usersurplus WHERE userkey = '{userkey}';") + # 使用 fetchone() 方法获取单条数据. + data = cursor.fetchone() + + # 关闭连接 + db.close() + + if data != None: + return data[0] + return -99999 + +def reduce_value(userkey, value): # 减去对应的值 + #打开数据库连接 + db = pymysql.connect(host=config.readConf()["db"]["host"], + port=config.readConf()["db"]["port"], + user=config.readConf()["db"]["user"], + password=config.readConf()["db"]["passwd"], + database=config.readConf()["db"]["database"]) + # 使用 cursor() 方法创建一个游标对象 cursor + cursor = db.cursor() + + # 执行 SQL 查询以获取当前值 + cursor.execute(f"SELECT surplus FROM usersurplus WHERE userkey = '{userkey}';") + current_value = cursor.fetchone()[0] + + # 如果没有找到用户,则返回错误信息 + if current_value is None: + db.close() + return -1 + + # 计算新的值 + new_value = current_value - value + + # 更新数据库中的值 + cursor.execute(f"UPDATE usersurplus SET surplus={new_value} WHERE userkey='{userkey}'") + + # 提交事务 + db.commit() + + # 关闭连接 + db.close() + + # 返回新值 + return 0 \ No newline at end of file diff --git a/src/Server/main.py b/src/Server/main.py new file mode 100644 index 0000000..450707d --- /dev/null +++ b/src/Server/main.py @@ -0,0 +1,48 @@ +import flask , requests , json +from flask_cors import CORS +import db , qwenTurbo ,chatglmTurbo + + + + +app = flask.Flask(__name__) +CORS(app,origins="*") + +@app.route('/api/user', methods=['POST']) +def post_data(): + userRequest = flask.request.json + surplusToken = db.userSurplus(userRequest['userkey']) + + if userRequest["prompt"] == "": + return {"code":42,"output":"Input is empty"} + + if userRequest["prompt"] == "": + return {"code":42,"output":"UserKey is empty"} + + if surplusToken == -99999: # 判断用户是否存在和余额 + return {"code":41,"output":"UserKey not found"} + elif surplusToken <= 0: + return {"code":40,"output":"Token has been use up"} + + if userRequest["model"] == "qwen-turbo": # 调用qwen-Turbo + if userRequest["context"] == 1: # 是否使用上文关联 + code , output , tokenUsed = qwenTurbo.service(userRequest['prompt'],userRequest['history']) + elif userRequest["context"] == 0: + code , output , tokenUsed = qwenTurbo.service(userRequest['prompt']) + + if userRequest["model"] == "chatglm-turbo": # 调用chatglm-turbo + if userRequest["context"] == 1: # 是否使用上文关联 + code , output , tokenUsed = chatglmTurbo.service(userRequest['prompt'],userRequest['history']) + elif userRequest["context"] == 0: + code , output , tokenUsed = chatglmTurbo.service(userRequest['prompt']) + + + + + + db.reduce_value(userRequest['userkey'], tokenUsed) + return {"code":code,"output":output,"surplus":surplusToken} + + +if __name__ == '__main__': + app.run(debug=True,host='0.0.0.0',port=5000) \ No newline at end of file diff --git a/src/Server/qwenTurbo.py b/src/Server/qwenTurbo.py new file mode 100644 index 0000000..70344dd --- /dev/null +++ b/src/Server/qwenTurbo.py @@ -0,0 +1,31 @@ +import requests , json , config + +# 设置请求的目标URL +url = config.readConf()["qwenturbo"]["url"] # 替换为你的API端点URL +header = { + "Content-Type":"application/json", + "Authorization":config.readConf()["qwenturbo"]["Authorization"] +} + +def service(prompt,history = ""): + # 设置请求数据 + if history == "": + data = { + "model": "qwen-turbo", + "input":{ + "prompt":f"{prompt}" + } + } + else: + data = { + "model": "qwen-turbo", + "input":{ + "prompt":f"{prompt}", + "history":history + } + } + # 发送POST请求 + response = json.loads(requests.post(url, json=data ,headers=header).text) + if 'code' in response: + return 50,response['code']+response['message'],0 + return 200,response['output']['text'],response["usage"]["total_tokens"] \ No newline at end of file diff --git a/src/Web/index.html b/src/Web/index.html new file mode 100644 index 0000000..4995769 --- /dev/null +++ b/src/Web/index.html @@ -0,0 +1,288 @@ + + + + + + + KakuAI + + + + +
+
+ + + +
+ + +
+
+ + + + + + diff --git a/src/Web/popup.css b/src/Web/popup.css new file mode 100644 index 0000000..fed8e77 --- /dev/null +++ b/src/Web/popup.css @@ -0,0 +1,47 @@ +#popup-container { + position: fixed; + top: 0; + right: -100%; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.5); +} + +#popup { + position: absolute; + top: 0; + right: 0; + height: 100%; + width: 20%; + min-width: 150px; + min-width: 200px; + background: white; + padding: 20px; +} + +.hidden { + display: none; +} + +#close-popup { + position: absolute; + top: 10px; + right: 10px; +} + +#dropdown { + margin: auto; + width: 80%; /* 让