From 84f6761a67e258e31d88865dcf6589d12187c834 Mon Sep 17 00:00:00 2001 From: Wenjie Zhang Date: Thu, 25 Jul 2024 20:30:28 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8D=87=E7=BA=A7=E4=BA=86=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2/=E8=81=8A=E5=A4=A9=E5=B8=83=E5=B1=80/?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=BA=93=E5=B1=95=E7=A4=BA=E7=AD=89=EF=BC=8C?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=BA=86=E5=8F=82=E8=80=83=E8=B5=84=E6=96=99?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +- scripts/run_vllm.sh | 2 +- src/config/__init__.py | 61 ++-- src/config/base.yaml | 13 - src/core/retriever.py | 4 +- src/models/README.md | 2 + web/src/assets/base.css | 20 +- web/src/components/ChatComponent.vue | 455 +++++++++++++++------------ web/src/layouts/AppLayout.vue | 86 +++-- web/src/stores/counter.js | 8 + web/src/views/ChatView.vue | 75 ++--- web/src/views/DataBaseInfoView.vue | 77 +++-- web/src/views/DataBaseView.vue | 26 +- web/src/views/GraphView.vue | 38 ++- web/src/views/SettingView.vue | 157 +++++++-- 15 files changed, 631 insertions(+), 396 deletions(-) delete mode 100644 src/config/base.yaml diff --git a/.gitignore b/.gitignore index 90f3cb2c..efa33f5e 100644 --- a/.gitignore +++ b/.gitignore @@ -30,4 +30,5 @@ cache *.pdf src/data neo4j* -*/package-lock.json \ No newline at end of file +*/package-lock.json +src/config/base.yaml diff --git a/scripts/run_vllm.sh b/scripts/run_vllm.sh index a1e80915..72ea353e 100644 --- a/scripts/run_vllm.sh +++ b/scripts/run_vllm.sh @@ -1,4 +1,4 @@ -python -m vllm.entrypoints.openai.api_server \ +CUDA_VISIBLE_DEVICES=0 python -m vllm.entrypoints.openai.api_server \ --model="/home/zwj/workspace/models/chatglm3-6b" \ --tensor-parallel-size 1 \ --trust-remote-code \ diff --git a/src/config/__init__.py b/src/config/__init__.py index 2948cb7c..4fa70ba4 100644 --- a/src/config/__init__.py +++ b/src/config/__init__.py @@ -26,43 +26,56 @@ class SimpleConfig(dict): def __setitem__(self, key, value): return super().__setitem__(self.__key(key), value) + def __dict__(self): + return {k: v for k, v in self.items()} + class Config(SimpleConfig): def __init__(self, filename=None): super().__init__() self.filename = filename or "config/base.yaml" + self._config_items = {} ### >>> 默认配置 # 可以在 config/base.yaml 中覆盖 - self.mode = "cli" - self.stream = True - + self.add_item("mode", default="cli", des="运行模式", choices=["cli", "api"]) + self.add_item("stream", default=True, des="是否开启流式输出") # 功能选项 - self.enable_query_rewrite = True - self.enable_knowledge_base = True - self.enable_knowledge_graph = True - self.enable_search_engine = True + self.add_item("enable_query_rewrite", default=True, des="是否开启查询重写") + self.add_item("enable_knowledge_base", default=True, des="是否开启知识库") + self.add_item("enable_knowledge_graph", default=True, des="是否开启知识图谱") + self.add_item("enable_search_engine", default=True, des="是否开启搜索引擎") # 模型配置 ## 注意这里是模型名,而不是具体的模型路径,默认使用 HuggingFace 的路径 ## 如果需要自定义路径,则在 config/base.yaml 中配置 model_local_paths - self.model_provider = "qianfan" - self.model_name = None # 默认使用 provider 的默认模型 - self.embed_model = "bge-large-zh-v1.5" - self.reranker = "bge-reranker-v2-m3" + self.add_item("model_provider", default="qianfan", des="模型提供商", choices=["qianfan", "vllm", "zhipu", "deepseek"]) + self.add_item("model_name", default=None, des="模型名称,为空则表示使用默认值") + self.add_item("embed_model", default="bge-large-zh-v1.5", des="Embedding 模型", choices=["bge-large-zh-v1.5", "zhipu"]) + self.add_item("reranker", default="bge-reranker-v2-m3", des="Re-Ranker 模型", choices=["bge-reranker-v2-m3"]) + self.add_item("model_local_paths", default={}, des="本地模型路径") ### <<< 默认配置结束 self.load() self.handle_self() + def add_item(self, key, default, des=None, choices=None): + self.__setattr__(key, default) + self._config_items[key] = { + "default": default, + "des": des, + "choices": choices + } + def handle_self(self): ### handle local model model_root_dir = os.getenv("MODEL_ROOT_DIR", "pretrained_models") - for model, model_rel_path in self.model_local_paths.items(): - # 如果 model_rel_path 不是绝对路径,那么拼接 model_root_dir - if not model_rel_path.startswith("/"): - self.model_local_paths[model] = os.path.join(model_root_dir, model_rel_path) + if self.model_local_paths is not None: + for model, model_rel_path in self.model_local_paths.items(): + # 如果 model_rel_path 不是绝对路径,那么拼接 model_root_dir + if not model_rel_path.startswith("/"): + self.model_local_paths[model] = os.path.join(model_root_dir, model_rel_path) def load(self): @@ -71,10 +84,20 @@ class Config(SimpleConfig): if self.filename is not None and os.path.exists(self.filename): if self.filename.endswith(".json"): with open(self.filename, 'r') as f: - self.update(json.load(f)) + content = f.read() + if content: + self.update(json.loads(content)) + else: + print(f"{self.filename} is empty.") elif self.filename.endswith(".yaml"): with open(self.filename, 'r') as f: - self.update(yaml.safe_load(f)) + content = f.read() + if content: + self.update(yaml.safe_load(content)) + else: + print(f"{self.filename} is empty.") + else: + logger.warning(f"Unknown config file type {self.filename}") else: logger.warning(f"Config file {self.filename} not found") @@ -86,10 +109,10 @@ class Config(SimpleConfig): if self.filename.endswith(".json"): with open(self.filename, 'w+') as f: - json.dump(self, f, indent=4, ensure_ascii=False) + json.dump(self.__dict__(), f, indent=4, ensure_ascii=False) elif self.filename.endswith(".yaml"): with open(self.filename, 'w+') as f: - yaml.dump(self, f, indent=2) + yaml.dump(self.__dict__(), f, indent=2, allow_unicode=True) else: logger.warning(f"Unknown config file type {self.filename}, save as json") with open(self.filename, 'w+') as f: diff --git a/src/config/base.yaml b/src/config/base.yaml deleted file mode 100644 index 56a9cd5e..00000000 --- a/src/config/base.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# 默认配置请参考 config/__init__.py -name: base - -## model -### model_provider, option in deepseek, zhipu -model_provider: vllm -model_name: null # for default - -## model dir 可以写相对路径和绝对路径 -### 相对路径是相对于环境变量 (.env) 中 MODEL_ROOT_DIR 的路径 -model_local_paths: - bge-large-zh-v1.5: bge-large-zh-v1.5 - oneke: oneke \ No newline at end of file diff --git a/src/core/retriever.py b/src/core/retriever.py index 4cc183e7..98420004 100644 --- a/src/core/retriever.py +++ b/src/core/retriever.py @@ -15,7 +15,6 @@ class Retriever: refs = {} - # TODO: 查询分类、查询重写、查询分解、查询伪文档生成(HyDE)) refs["meta"] = meta refs["rewrite_query"] = self.rewrite_query(query, history, meta) refs["knowledge_base"] = self.query_knowledgebase(query, history, meta) @@ -35,7 +34,7 @@ class Retriever: external += f"知识库信息: \n\n{kb_text}" db_res = refs.get("graph_base").get("results", []) - if len(db_res) > 0: + if len(db_res["nodes"]) > 0: db_text = '\n'.join([f"{edge['source_name']}和{edge['target_name']}的关系是{edge['type']}" for edge in db_res['edges']]) external += f"图数据库信息: \n\n{db_text}" @@ -164,4 +163,5 @@ class Retriever: def __call__(self, query, history, meta): refs = self.retrieval(query, history, meta) query = self.construct_query(query, refs, meta) + logger.debug(f"Retriever query: {query}") return query, refs \ No newline at end of file diff --git a/src/models/README.md b/src/models/README.md index df9f79ca..27e344ac 100644 --- a/src/models/README.md +++ b/src/models/README.md @@ -30,6 +30,8 @@ python -m vllm.entrypoints.openai.api_server \ ### 2. 向量模型支持 +需要注意,由于知识库和图数据库的构建都依赖于向量模型,如果中途更改向量模型,回导致知识库不可用。未来考虑增加一键迁移脚本。 + |模型名称(`config.embed_model`)|默认路径/模型|需要配置项目(`config.model_local_paths`)| |:-|:-|:-| diff --git a/web/src/assets/base.css b/web/src/assets/base.css index aef969dc..7ba37b7a 100644 --- a/web/src/assets/base.css +++ b/web/src/assets/base.css @@ -10,10 +10,10 @@ --c-indigo: #2c3e50; - --c-divider-light-1: rgba(60, 60, 60, 0.29); - --c-divider-light-2: rgba(60, 60, 60, 0.12); - --c-divider-dark-1: rgba(84, 84, 84, 0.65); - --c-divider-dark-2: rgba(84, 84, 84, 0.48); + --c-black-light-1: #333333; + --c-black-light-2: #454545; + --c-black-light-3: #666666; + --c-black-light-4: #999999; --c-text-light-1: var(--c-indigo); --c-text-light-2: rgba(60, 66, 70, 0.66); @@ -27,8 +27,8 @@ --color-background-soft: var(--c-white-soft); --color-background-mute: var(--c-white-mute); - --color-border: var(--c-divider-light-2); - --color-border-hover: var(--c-divider-light-1); + --color-border: var(--c-black-light-2); + --color-border-hover: var(--c-black-light-1); --color-heading: var(--c-text-light-1); --color-text: var(--c-text-light-1); @@ -36,8 +36,10 @@ --section-gap: 160px; --main-color: #005f77; - --main-color-light: #007f96; --main-color-dark: #004d5c; + --main-light-1: #007f96; + --main-light-2: #F2F6F7; + --main-light-3: #E2EEF3; --min-width: 400px; --min-header-width: 80px; --min-sider-width: 100px; @@ -50,8 +52,8 @@ --color-background-soft: var(--c-black-soft); --color-background-mute: var(--c-black-mute); - --color-border: var(--c-divider-dark-2); - --color-border-hover: var(--c-divider-dark-1); + --color-border: var(--c-black-dark-2); + --color-border-hover: var(--c-black-dark-1); --color-heading: var(--c-text-dark-1); --color-text: var(--c-text-dark-2); diff --git a/web/src/components/ChatComponent.vue b/web/src/components/ChatComponent.vue index f1156691..cf7866bb 100644 --- a/web/src/components/ChatComponent.vue +++ b/web/src/components/ChatComponent.vue @@ -1,6 +1,6 @@