2024-07-07 01:58:23 +08:00
|
|
|
|
import os
|
|
|
|
|
|
import json
|
|
|
|
|
|
import yaml
|
2024-07-28 16:16:52 +08:00
|
|
|
|
from src.utils.logging_config import setup_logger
|
2024-07-07 01:58:23 +08:00
|
|
|
|
|
2024-07-14 21:44:27 +08:00
|
|
|
|
logger = setup_logger("Config")
|
2024-07-07 01:58:23 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SimpleConfig(dict):
|
|
|
|
|
|
|
|
|
|
|
|
def __key(self, key):
|
|
|
|
|
|
return "" if key is None else key.lower()
|
|
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
|
return json.dumps(self)
|
|
|
|
|
|
|
|
|
|
|
|
def __setattr__(self, key, value):
|
|
|
|
|
|
self[self.__key(key)] = value
|
|
|
|
|
|
|
|
|
|
|
|
def __getattr__(self, key):
|
|
|
|
|
|
return self.get(self.__key(key))
|
|
|
|
|
|
|
|
|
|
|
|
def __getitem__(self, key):
|
|
|
|
|
|
return super().get(self.__key(key))
|
|
|
|
|
|
|
|
|
|
|
|
def __setitem__(self, key, value):
|
|
|
|
|
|
return super().__setitem__(self.__key(key), value)
|
|
|
|
|
|
|
2024-07-25 20:30:28 +08:00
|
|
|
|
def __dict__(self):
|
|
|
|
|
|
return {k: v for k, v in self.items()}
|
|
|
|
|
|
|
2024-07-07 01:58:23 +08:00
|
|
|
|
|
|
|
|
|
|
class Config(SimpleConfig):
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, filename=None):
|
|
|
|
|
|
super().__init__()
|
2024-07-25 20:30:28 +08:00
|
|
|
|
self._config_items = {}
|
2024-07-07 01:58:23 +08:00
|
|
|
|
|
2024-07-17 18:52:20 +08:00
|
|
|
|
### >>> 默认配置
|
|
|
|
|
|
# 可以在 config/base.yaml 中覆盖
|
2024-07-25 20:30:28 +08:00
|
|
|
|
self.add_item("stream", default=True, des="是否开启流式输出")
|
2024-07-28 16:16:52 +08:00
|
|
|
|
self.add_item("save_dir", default="saves", des="保存目录")
|
2024-07-17 18:52:20 +08:00
|
|
|
|
# 功能选项
|
2024-07-29 01:00:02 +08:00
|
|
|
|
self.add_item("enable_reranker", default=False, des="是否开启重排序")
|
2024-07-31 20:22:05 +08:00
|
|
|
|
self.add_item("enable_knowledge_base", default=False, des="是否开启知识库")
|
2024-09-03 16:37:59 +08:00
|
|
|
|
self.add_item("enable_knowledge_graph", default=False, des="是否开启知识图谱")
|
2024-07-31 20:22:05 +08:00
|
|
|
|
self.add_item("enable_search_engine", default=False, des="是否开启搜索引擎")
|
2024-07-17 18:52:20 +08:00
|
|
|
|
|
|
|
|
|
|
# 模型配置
|
|
|
|
|
|
## 注意这里是模型名,而不是具体的模型路径,默认使用 HuggingFace 的路径
|
|
|
|
|
|
## 如果需要自定义路径,则在 config/base.yaml 中配置 model_local_paths
|
2024-09-28 00:41:18 +08:00
|
|
|
|
self.add_item("model_provider", default="zhipu", des="模型提供商", choices=list(MODEL_NAMES.keys()))
|
2024-07-31 20:22:05 +08:00
|
|
|
|
self.add_item("model_name", default=None, des="模型名称")
|
2024-08-25 20:29:24 +08:00
|
|
|
|
self.add_item("embed_model", default="zhipu-embedding-3", des="Embedding 模型", choices=list(EMBED_MODEL_INFO.keys()))
|
2024-09-28 00:41:18 +08:00
|
|
|
|
self.add_item("reranker", default="bge-reranker-v2-m3", des="Re-Ranker 模型", choices=list(RERANKER_LIST.keys()))
|
2024-07-25 20:30:28 +08:00
|
|
|
|
self.add_item("model_local_paths", default={}, des="本地模型路径")
|
2024-07-17 18:52:20 +08:00
|
|
|
|
### <<< 默认配置结束
|
2024-07-07 01:58:23 +08:00
|
|
|
|
|
2024-07-28 16:16:52 +08:00
|
|
|
|
self.filename = filename or os.path.join(self.save_dir, "config", "config.yaml")
|
2024-07-29 01:00:02 +08:00
|
|
|
|
os.makedirs(os.path.dirname(self.filename), exist_ok=True)
|
2024-07-28 16:16:52 +08:00
|
|
|
|
|
2024-07-07 01:58:23 +08:00
|
|
|
|
self.load()
|
2024-07-09 05:04:20 +08:00
|
|
|
|
self.handle_self()
|
|
|
|
|
|
|
2024-07-25 20:30:28 +08:00
|
|
|
|
def add_item(self, key, default, des=None, choices=None):
|
|
|
|
|
|
self.__setattr__(key, default)
|
|
|
|
|
|
self._config_items[key] = {
|
|
|
|
|
|
"default": default,
|
|
|
|
|
|
"des": des,
|
|
|
|
|
|
"choices": choices
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-03 16:37:59 +08:00
|
|
|
|
def __dict__(self):
|
|
|
|
|
|
blocklist = [
|
|
|
|
|
|
"_config_items",
|
|
|
|
|
|
"model_names",
|
2024-09-28 00:41:18 +08:00
|
|
|
|
"model_provider_status",
|
2024-09-03 16:37:59 +08:00
|
|
|
|
]
|
|
|
|
|
|
return {k: v for k, v in self.items() if k not in blocklist}
|
|
|
|
|
|
|
2024-07-09 05:04:20 +08:00
|
|
|
|
def handle_self(self):
|
2024-07-31 20:22:05 +08:00
|
|
|
|
self.model_names = MODEL_NAMES
|
2024-10-08 22:16:17 +08:00
|
|
|
|
model_provider_info = self.model_names.get(self.model_provider, {})
|
2024-07-31 20:22:05 +08:00
|
|
|
|
|
2024-10-08 22:16:17 +08:00
|
|
|
|
if self.model_provider != "custom":
|
|
|
|
|
|
if self.model_name not in model_provider_info["models"]:
|
|
|
|
|
|
logger.warning(f"Model name {self.model_name} not in {self.model_provider}, using default model name")
|
|
|
|
|
|
self.model_name = model_provider_info["default"]
|
2024-07-31 20:22:05 +08:00
|
|
|
|
|
2024-10-08 22:16:17 +08:00
|
|
|
|
default_model_name = model_provider_info["default"]
|
|
|
|
|
|
self.model_name = self.get("model_name") or default_model_name
|
|
|
|
|
|
else:
|
|
|
|
|
|
self.model_name = self.get("model_name")
|
|
|
|
|
|
if self.model_name not in [item["name"] for item in self.custom_models]:
|
|
|
|
|
|
logger.warning(f"Model name {self.model_name} not in custom models, using default model name")
|
|
|
|
|
|
self.model_name = self.custom_models[0]["name"]
|
2024-07-31 20:22:05 +08:00
|
|
|
|
|
2024-09-28 00:41:18 +08:00
|
|
|
|
self.model_provider_status = {}
|
|
|
|
|
|
for provider in self.model_names:
|
|
|
|
|
|
conds = [bool(os.getenv(_k)) for _k in self.model_names[provider]["env"]]
|
|
|
|
|
|
self.model_provider_status[provider] = all(conds)
|
|
|
|
|
|
|
2024-07-07 01:58:23 +08:00
|
|
|
|
def load(self):
|
2024-07-17 18:52:20 +08:00
|
|
|
|
"""根据传入的文件覆盖掉默认配置"""
|
2024-07-22 00:00:54 +08:00
|
|
|
|
logger.info(f"Loading config from {self.filename}")
|
2024-07-07 01:58:23 +08:00
|
|
|
|
if self.filename is not None and os.path.exists(self.filename):
|
2024-08-25 20:29:24 +08:00
|
|
|
|
|
2024-07-07 01:58:23 +08:00
|
|
|
|
if self.filename.endswith(".json"):
|
|
|
|
|
|
with open(self.filename, 'r') as f:
|
2024-07-25 20:30:28 +08:00
|
|
|
|
content = f.read()
|
|
|
|
|
|
if content:
|
2024-08-25 20:29:24 +08:00
|
|
|
|
local_config = json.loads(content)
|
|
|
|
|
|
self.update(local_config)
|
2024-07-25 20:30:28 +08:00
|
|
|
|
else:
|
|
|
|
|
|
print(f"{self.filename} is empty.")
|
2024-08-25 20:29:24 +08:00
|
|
|
|
|
2024-07-07 01:58:23 +08:00
|
|
|
|
elif self.filename.endswith(".yaml"):
|
|
|
|
|
|
with open(self.filename, 'r') as f:
|
2024-07-25 20:30:28 +08:00
|
|
|
|
content = f.read()
|
|
|
|
|
|
if content:
|
2024-08-25 20:29:24 +08:00
|
|
|
|
local_config = yaml.safe_load(content)
|
|
|
|
|
|
self.update(local_config)
|
2024-07-25 20:30:28 +08:00
|
|
|
|
else:
|
|
|
|
|
|
print(f"{self.filename} is empty.")
|
|
|
|
|
|
else:
|
|
|
|
|
|
logger.warning(f"Unknown config file type {self.filename}")
|
2024-08-25 20:29:24 +08:00
|
|
|
|
|
2024-07-07 01:58:23 +08:00
|
|
|
|
else:
|
2024-07-28 16:16:52 +08:00
|
|
|
|
logger.warning(f"\n\n{'='*70}\n{'Config file not found':^70}\n{'You can custum your config in `' + self.filename + '`':^70}\n{'='*70}\n\n")
|
2024-07-07 01:58:23 +08:00
|
|
|
|
|
|
|
|
|
|
def save(self):
|
2024-07-22 00:00:54 +08:00
|
|
|
|
logger.info(f"Saving config to {self.filename}")
|
|
|
|
|
|
if self.filename is None:
|
|
|
|
|
|
logger.warning("Config file is not specified, save to default config/base.yaml")
|
2024-07-28 16:16:52 +08:00
|
|
|
|
self.filename = os.path.join(self.save_dir, "config", "config.yaml")
|
2024-07-29 01:00:02 +08:00
|
|
|
|
os.makedirs(os.path.dirname(self.filename), exist_ok=True)
|
2024-07-22 00:00:54 +08:00
|
|
|
|
|
|
|
|
|
|
if self.filename.endswith(".json"):
|
|
|
|
|
|
with open(self.filename, 'w+') as f:
|
2024-07-25 20:30:28 +08:00
|
|
|
|
json.dump(self.__dict__(), f, indent=4, ensure_ascii=False)
|
2024-07-22 00:00:54 +08:00
|
|
|
|
elif self.filename.endswith(".yaml"):
|
|
|
|
|
|
with open(self.filename, 'w+') as f:
|
2024-07-25 20:30:28 +08:00
|
|
|
|
yaml.dump(self.__dict__(), f, indent=2, allow_unicode=True)
|
2024-07-22 00:00:54 +08:00
|
|
|
|
else:
|
|
|
|
|
|
logger.warning(f"Unknown config file type {self.filename}, save as json")
|
|
|
|
|
|
with open(self.filename, 'w+') as f:
|
2024-07-07 01:58:23 +08:00
|
|
|
|
json.dump(self, f, indent=4)
|
2024-07-22 00:00:54 +08:00
|
|
|
|
|
2024-07-31 20:22:05 +08:00
|
|
|
|
logger.info(f"Config file {self.filename} saved")
|
|
|
|
|
|
|
|
|
|
|
|
MODEL_NAMES = {
|
2024-09-28 00:41:18 +08:00
|
|
|
|
"openai": {
|
|
|
|
|
|
"name": "OpenAI",
|
|
|
|
|
|
"url": "https://platform.openai.com/docs/models",
|
|
|
|
|
|
"default": "gpt-3.5-turbo",
|
|
|
|
|
|
"env": ["OPENAI_API_KEY"],
|
|
|
|
|
|
"models": [
|
|
|
|
|
|
"gpt-4",
|
|
|
|
|
|
"gpt-4o",
|
|
|
|
|
|
"gpt-4o-mini",
|
|
|
|
|
|
"gpt-3.5-turbo"
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2024-07-31 20:22:05 +08:00
|
|
|
|
# https://platform.deepseek.com/api-docs/zh-cn/pricing
|
2024-09-28 00:41:18 +08:00
|
|
|
|
"deepseek": {
|
|
|
|
|
|
"name": "DeepSeek",
|
|
|
|
|
|
"url": "https://platform.deepseek.com/api-docs/zh-cn/pricing",
|
|
|
|
|
|
"default": "deepseek-chat",
|
|
|
|
|
|
"env": ["DEEPSEEK_API_KEY"],
|
|
|
|
|
|
"models": [
|
|
|
|
|
|
"deepseek-chat",
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
# https://open.bigmodel.cn/dev/api glm-4-plus、glm-4-0520、glm-4 、glm-4-air、glm-4-airx、glm-4-long 、 glm-4-flashx 、 glm-4-flash
|
|
|
|
|
|
"zhipu": {
|
|
|
|
|
|
"name": "智谱AI (Zhipu)",
|
|
|
|
|
|
"url": "https://open.bigmodel.cn/dev/api",
|
|
|
|
|
|
"default": "glm-4-flash",
|
|
|
|
|
|
"env": ["ZHIPUAI_API_KEY"],
|
|
|
|
|
|
"models": [
|
|
|
|
|
|
"glm-4",
|
|
|
|
|
|
"glm-4-plus",
|
|
|
|
|
|
"glm-4-air",
|
|
|
|
|
|
"glm-4-airx",
|
|
|
|
|
|
"glm-4-long",
|
|
|
|
|
|
"glm-4-flashx",
|
|
|
|
|
|
"glm-4-flash",
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
2024-07-31 20:22:05 +08:00
|
|
|
|
|
|
|
|
|
|
# {'ERNIE-4.0-8K-0104', 'ERNIE-Lite-8K-0308', 'ERNIE-Speed-128K', 'ERNIE-3.5-128K(预览版)', 'Yi-34B-Chat', 'ERNIE-4.0-8K-Preview-0518', 'ERNIE-Bot-4', 'ERNIE-3.5-128K', 'ChatGLM2-6B-32K', 'ERNIE-3.5-8K', 'EB-turbo-AppBuilder', 'ERNIE-Lite-AppBuilder-8K', 'ERNIE-4.0-8K-0329', 'AquilaChat-7B', 'Gemma-7B-it', 'Qianfan-Chinese-Llama-2-70B', 'Mixtral-8x7B-Instruct', 'Gemma-7B-It', 'ERNIE Speed-AppBuilder', 'ERNIE-Function-8K', 'ERNIE-4.0-8K-preview', 'ERNIE-Bot', 'Qianfan-BLOOMZ-7B-compressed', 'ERNIE-4.0-8K', 'BLOOMZ-7B', 'ERNIE-Character-8K', 'ERNIE-3.5-8K-0205', 'ERNIE-4.0-8K-0613', 'Llama-2-70B-Chat', 'ERNIE-Character-Fiction-8K', 'ERNIE-4.0-8K-Preview', 'ERNIE-3.5-8K-Preview', 'ERNIE-Speed', 'ERNIE-Tiny-8K', 'ERNIE-4.0-Turbo-8K-Preview', 'Meta-Llama-3-8B', 'ERNIE-4.0-8K-Latest', 'ERNIE 3.5', 'XuanYuan-70B-Chat-4bit', 'Llama-2-13B-Chat', 'ERNIE-Bot-turbo', 'ERNIE-3.5-8K-0613', 'ERNIE-Lite-AppBuilder-8K-0614', 'ERNIE-4.0-preview', 'Llama-2-7B-Chat', 'Qianfan-Chinese-Llama-2-13B', 'ERNIE-Bot-turbo-AI', 'Meta-Llama-3-70B', 'ERNIE-Functions-8K', 'ERNIE-Lite-8K-0922(原ERNIE-Bot-turbo-0922)', 'ERNIE Speed', 'ERNIE-3.5-preview', 'Qianfan-Chinese-Llama-2-7B', 'ERNIE-Speed-8K', 'ERNIE-Lite-8K-0922', 'ChatLaw', 'ERNIE-3.5-8K-0329', 'ERNIE-4.0-Turbo-8K', 'ERNIE-3.5-8K-preview', 'ERNIE-Lite-8K'}
|
2024-09-28 00:41:18 +08:00
|
|
|
|
"qianfan": {
|
|
|
|
|
|
"name": "百度千帆 (QianFan)",
|
|
|
|
|
|
"url": "https://open.bigmodel.cn/dev/api",
|
|
|
|
|
|
"default": "ERNIE-Speed",
|
|
|
|
|
|
"env": ["QIANFAN_ACCESS_KEY", "QIANFAN_SECRET_KEY"],
|
|
|
|
|
|
"models": [
|
|
|
|
|
|
"ERNIE-Speed",
|
|
|
|
|
|
"ERNIE-Speed-8K",
|
|
|
|
|
|
"ERNIE-Speed-128K",
|
|
|
|
|
|
"ERNIE-Tiny-8K",
|
|
|
|
|
|
"ERNIE-Lite-8K",
|
|
|
|
|
|
"ERNIE-4.0-8K-Latest",
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2024-07-31 20:22:05 +08:00
|
|
|
|
# https://bailian.console.aliyun.com/?switchAgent=10226727&productCode=p_efm#/model-market
|
2024-09-28 00:41:18 +08:00
|
|
|
|
"dashscope": {
|
|
|
|
|
|
"name": "阿里百炼 (DashScope)",
|
|
|
|
|
|
"url": "https://bailian.console.aliyun.com/?switchAgent=10226727&productCode=p_efm#/model-market",
|
|
|
|
|
|
"default": "qwen2.5-72b-instruct",
|
|
|
|
|
|
"env": ["DASHSCOPE_API_KEY"],
|
|
|
|
|
|
"models": [
|
|
|
|
|
|
"qwen-max-latest",
|
|
|
|
|
|
"qwen-plus-latest",
|
|
|
|
|
|
"qwen-long-latest",
|
|
|
|
|
|
"qwen-turbo-latest",
|
|
|
|
|
|
"qwen2.5-72b-instruct",
|
|
|
|
|
|
"qwen2.5-32b-instruct",
|
|
|
|
|
|
"qwen2.5-14b-instruct",
|
|
|
|
|
|
"qwen2.5-7b-instruct",
|
|
|
|
|
|
"qwen2.5-3b-instruct",
|
|
|
|
|
|
"qwen2.5-1.5b-instruct",
|
|
|
|
|
|
"qwen2.5-0.5b-instruct",
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
# https://cloud.siliconflow.cn/models
|
|
|
|
|
|
"siliconflow": {
|
|
|
|
|
|
"name": "SiliconFlow",
|
|
|
|
|
|
"url": "https://cloud.siliconflow.cn/models",
|
|
|
|
|
|
"default": "meta-llama/Meta-Llama-3.1-8B-Instruct",
|
|
|
|
|
|
"env": ["SILICONFLOW_API_KEY"],
|
|
|
|
|
|
"models": [
|
|
|
|
|
|
"meta-llama/Meta-Llama-3.1-8B-Instruct",
|
|
|
|
|
|
"meta-llama/Meta-Llama-3.1-70B-Instruct",
|
|
|
|
|
|
"meta-llama/Meta-Llama-3.1-405B-Instruct",
|
|
|
|
|
|
]
|
2024-10-08 22:16:17 +08:00
|
|
|
|
},
|
2024-08-25 20:29:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
EMBED_MODEL_INFO = {
|
|
|
|
|
|
"bge-large-zh-v1.5": SimpleConfig({
|
|
|
|
|
|
"name": "bge-large-zh-v1.5",
|
|
|
|
|
|
"default_path": "BAAI/bge-large-zh-v1.5",
|
|
|
|
|
|
"dimension": 1024,
|
|
|
|
|
|
"query_instruction": "为这个句子生成表示以用于检索相关文章:",
|
|
|
|
|
|
}),
|
|
|
|
|
|
"zhipu-embedding-2": SimpleConfig({
|
|
|
|
|
|
"name": "zhipu-embedding-2",
|
|
|
|
|
|
"default_path": "embedding-2",
|
|
|
|
|
|
"dimension": 1024,
|
|
|
|
|
|
}),
|
|
|
|
|
|
"zhipu-embedding-3": SimpleConfig({
|
|
|
|
|
|
"name": "zhipu-embedding-3",
|
|
|
|
|
|
"default_path": "embedding-3",
|
|
|
|
|
|
"dimension": 2048,
|
|
|
|
|
|
}),
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RERANKER_LIST = {
|
|
|
|
|
|
"bge-reranker-v2-m3": "BAAI/bge-reranker-v2-m3",
|
2024-07-31 20:22:05 +08:00
|
|
|
|
}
|