doc: 添加部分注释

This commit is contained in:
Rock Chin
2023-03-05 15:39:13 +08:00
parent e4b581f197
commit 651b291ef6
13 changed files with 172 additions and 70 deletions
+2
View File
@@ -0,0 +1,2 @@
"""OpenAI 接口处理及会话管理相关
"""
+5
View File
@@ -1,8 +1,13 @@
# 多情景预设值管理
__current__ = "default"
"""当前默认使用的情景预设的名称
由管理员使用`!default <名称>`指令切换
"""
__prompts_from_files__ = {}
"""从文件中读取的情景预设值"""
def read_prompt_from_file() -> str:
+20 -13
View File
@@ -5,18 +5,26 @@ import logging
import pkg.plugin.host as plugin_host
import pkg.plugin.models as plugin_models
class KeysManager:
api_key = {}
"""所有api-key"""
# api-key的使用量
# 其中键为api-key的md5值,值为使用量
using_key = ""
"""当前使用的api-key
"""
alerted = []
"""已提示过超额的key
记录在此以避免重复提示
"""
# 在此list中的都是经超额报错标记过的api-key
# 记录的是key值,仅在运行时有效
exceeded = []
"""已超额的key
供自动切换功能识别
"""
def get_using_key(self):
return self.using_key
@@ -25,8 +33,6 @@ class KeysManager:
return hashlib.md5(self.using_key.encode('utf-8')).hexdigest()
def __init__(self, api_key):
# if hasattr(config, 'api_key_usage_threshold'):
# self.api_key_usage_threshold = config.api_key_usage_threshold
if type(api_key) is dict:
self.api_key = api_key
@@ -42,9 +48,13 @@ class KeysManager:
self.auto_switch()
# 根据tested自动切换到可用的api-key
# 返回是否切换成功, 切换后的api-key的别名
def auto_switch(self) -> (bool, str):
"""尝试切换api-key
Returns:
是否切换成功, 切换后的api-key的别名
"""
for key_name in self.api_key:
if self.api_key[key_name] not in self.exceeded:
self.using_key = self.api_key[key_name]
@@ -68,12 +78,9 @@ class KeysManager:
def add(self, key_name, key):
self.api_key[key_name] = key
# 设置当前使用的api-key使用量超限
# 这是在尝试调用api时发生超限异常时调用的
def set_current_exceeded(self):
# md5 = hashlib.md5(self.using_key.encode('utf-8')).hexdigest()
# self.usage[md5] = self.api_key_usage_threshold
# self.fee[md5] = self.api_key_fee_threshold
"""设置当前使用的api-key使用量超限
"""
self.exceeded.append(self.using_key)
def get_key_name(self, api_key):
+23 -5
View File
@@ -7,9 +7,12 @@ import pkg.utils.context
import pkg.audit.gatherer
from pkg.openai.modelmgr import ModelRequest, create_openai_model_request
# 为其他模块提供与OpenAI交互的接口
class OpenAIInteract:
api_params = {}
"""OpenAI 接口封装
将文字接口和图片接口封装供调用方使用
"""
key_mgr: pkg.openai.keymgr.KeysManager = None
@@ -20,7 +23,6 @@ class OpenAIInteract:
}
def __init__(self, api_key: str):
# self.api_key = api_key
self.key_mgr = pkg.openai.keymgr.KeysManager(api_key)
self.audit_mgr = pkg.audit.gatherer.DataGatherer()
@@ -32,7 +34,16 @@ class OpenAIInteract:
pkg.utils.context.set_openai_manager(self)
# 请求OpenAI Completion
def request_completion(self, prompts):
def request_completion(self, prompts) -> str:
"""请求补全接口回复
Parameters:
prompts (str): 提示语
Returns:
str: 回复
"""
config = pkg.utils.context.get_config()
# 根据模型选择使用的接口
@@ -58,8 +69,15 @@ class OpenAIInteract:
return ai.get_message()
def request_image(self, prompt):
def request_image(self, prompt) -> dict:
"""请求图片接口回复
Parameters:
prompt (str): 提示语
Returns:
dict: 响应
"""
config = pkg.utils.context.get_config()
params = config.image_api_params if hasattr(config, "image_api_params") else self.default_image_api_params
+22 -8
View File
@@ -1,4 +1,10 @@
# 提供与模型交互的抽象接口
"""OpenAI 接口底层封装
目前使用的对话接口有:
ChatCompletion - gpt-3.5-turbo 等模型
Completion - text-davinci-003 等模型
此模块封装此两个接口的请求实现,为上层提供统一的调用方式
"""
import openai, logging, threading, asyncio
import openai.error as aiE
@@ -26,14 +32,15 @@ IMAGE_MODELS = {
}
class ModelRequest():
"""GPT父类"""
class ModelRequest:
"""模型接口请求父类"""
can_chat = False
runtime:threading.Thread = None
runtime: threading.Thread = None
ret = {}
proxy:str = None
proxy: str = None
request_ready = True
error_info:str = "若在没有任何错误的情况下看到这句话,请带着配置文件上报Issues"
error_info: str = "若在没有任何错误的情况下看到这句话,请带着配置文件上报Issues"
def __init__(self, model_name, user_name, request_fun, http_proxy:str = None, time_out = None):
self.model_name = model_name
@@ -46,6 +53,8 @@ class ModelRequest():
self.request_ready = False
async def __a_request__(self, **kwargs):
"""异步请求"""
try:
self.ret:dict = await self.request_fun(**kwargs)
self.request_ready = True
@@ -59,6 +68,8 @@ class ModelRequest():
raise Exception(self.error_info)
def request(self, **kwargs):
"""向接口发起请求"""
if self.proxy != None: #异步请求
self.request_ready = False
loop = asyncio.new_event_loop()
@@ -97,8 +108,10 @@ class ModelRequest():
def get_response(self):
return self.ret
class ChatCompletionModel(ModelRequest):
"""ChatCompletion类模型"""
"""ChatCompletion接口的请求实现"""
Chat_role = ['system', 'user', 'assistant']
def __init__(self, model_name, user_name, http_proxy:str = None, **kwargs):
if http_proxy == None:
@@ -126,7 +139,8 @@ class ChatCompletionModel(ModelRequest):
class CompletionModel(ModelRequest):
"""Completion类模型"""
"""Completion接口的请求实现"""
def __init__(self, model_name, user_name, http_proxy:str = None, **kwargs):
if http_proxy == None:
request_fun = openai.Completion.create
+28 -14
View File
@@ -1,3 +1,8 @@
"""主线使用的会话管理模块
每个人、每个群单独一个session,session内部保留了对话的上下文,
"""
import logging
import threading
import time
@@ -19,6 +24,7 @@ class SessionOfflineStatus:
ON_GOING = 'on_going'
EXPLICITLY_CLOSED = 'explicitly_closed'
# 重置session.prompt
def reset_session_prompt(session_name, prompt):
# 备份原始数据
@@ -43,11 +49,14 @@ def reset_session_prompt(session_name, prompt):
用户[{}]的数据已被重置,有可能是因为数据版本过旧或存储错误
原始数据将备份在:
{}""".format(session_name, bak_path)
)
) # 为保证多行文本格式正确故无缩进
return prompt
# 从数据加载session
def load_sessions():
"""从数据库加载sessions"""
global sessions
db_inst = pkg.utils.context.get_database_manager()
@@ -93,10 +102,13 @@ class Session:
name = ''
prompt = []
"""使用list来保存会话中的回合"""
create_timestamp = 0
"""会话创建时间"""
last_interact_timestamp = 0
"""上次交互(产生回复)时间"""
just_switched_to_exist_session = False
@@ -116,7 +128,7 @@ class Session:
logging.debug('{},lock release successfully,{}'.format(self.name, self.response_lock))
# 从配置文件获取会话预设信息
def get_default_prompt(self, use_default: str=None):
def get_default_prompt(self, use_default: str = None):
config = pkg.utils.context.get_config()
import pkg.openai.dprompt as dprompt
@@ -130,7 +142,7 @@ class Session:
{
'role': 'user',
'content': current_default_prompt
},{
}, {
'role': 'assistant',
'content': 'ok'
}
@@ -182,6 +194,8 @@ class Session:
# 请求回复
# 这个函数是阻塞的
def append(self, text: str) -> str:
"""向session中添加一条消息,返回接口回复"""
self.last_interact_timestamp = int(time.time())
# 触发插件事件
@@ -215,14 +229,14 @@ class Session:
res_ans = '\n\n'.join(res_ans_spt)
# 将此次对话的双方内容加入到prompt中
self.prompt.append({'role':'user', 'content':text})
self.prompt.append({'role':'assistant', 'content':res_ans})
self.prompt.append({'role': 'user', 'content': text})
self.prompt.append({'role': 'assistant', 'content': res_ans})
if self.just_switched_to_exist_session:
self.just_switched_to_exist_session = False
self.set_ongoing()
return res_ans if res_ans[0]!='\n' else res_ans[1:]
return res_ans if res_ans[0] != '\n' else res_ans[1:]
# 删除上一回合并返回上一回合的问题
def undo(self) -> str:
@@ -231,10 +245,10 @@ class Session:
# 删除最后两个消息
if len(self.prompt) < 2:
raise Exception('之前无对话,无法撤销')
question = self.prompt[-2]['content']
self.prompt = self.prompt[:-2]
# 返回上一回合的问题
return question
@@ -242,13 +256,13 @@ class Session:
def cut_out(self, msg: str, max_tokens: int) -> list:
"""将现有prompt进行切割处理,使得新的prompt长度不超过max_tokens"""
# 如果用户消息长度超过max_tokens,直接返回
temp_prompt = [
{
'role': 'user',
'content': msg
}
]
{
'role': 'user',
'content': msg
}
]
token_count = len(msg)
# 倒序遍历prompt