maque 0.2.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- maque/__init__.py +30 -0
- maque/__main__.py +926 -0
- maque/ai_platform/__init__.py +0 -0
- maque/ai_platform/crawl.py +45 -0
- maque/ai_platform/metrics.py +258 -0
- maque/ai_platform/nlp_preprocess.py +67 -0
- maque/ai_platform/webpage_screen_shot.py +195 -0
- maque/algorithms/__init__.py +78 -0
- maque/algorithms/bezier.py +15 -0
- maque/algorithms/bktree.py +117 -0
- maque/algorithms/core.py +104 -0
- maque/algorithms/hilbert.py +16 -0
- maque/algorithms/rate_function.py +92 -0
- maque/algorithms/transform.py +27 -0
- maque/algorithms/trie.py +272 -0
- maque/algorithms/utils.py +63 -0
- maque/algorithms/video.py +587 -0
- maque/api/__init__.py +1 -0
- maque/api/common.py +110 -0
- maque/api/fetch.py +26 -0
- maque/api/static/icon.png +0 -0
- maque/api/static/redoc.standalone.js +1782 -0
- maque/api/static/swagger-ui-bundle.js +3 -0
- maque/api/static/swagger-ui.css +3 -0
- maque/cli/__init__.py +1 -0
- maque/cli/clean_invisible_chars.py +324 -0
- maque/cli/core.py +34 -0
- maque/cli/groups/__init__.py +26 -0
- maque/cli/groups/config.py +205 -0
- maque/cli/groups/data.py +615 -0
- maque/cli/groups/doctor.py +259 -0
- maque/cli/groups/embedding.py +222 -0
- maque/cli/groups/git.py +29 -0
- maque/cli/groups/help.py +410 -0
- maque/cli/groups/llm.py +223 -0
- maque/cli/groups/mcp.py +241 -0
- maque/cli/groups/mllm.py +1795 -0
- maque/cli/groups/mllm_simple.py +60 -0
- maque/cli/groups/quant.py +210 -0
- maque/cli/groups/service.py +490 -0
- maque/cli/groups/system.py +570 -0
- maque/cli/mllm_run.py +1451 -0
- maque/cli/script.py +52 -0
- maque/cli/tree.py +49 -0
- maque/clustering/__init__.py +52 -0
- maque/clustering/analyzer.py +347 -0
- maque/clustering/clusterers.py +464 -0
- maque/clustering/sampler.py +134 -0
- maque/clustering/visualizer.py +205 -0
- maque/constant.py +13 -0
- maque/core.py +133 -0
- maque/cv/__init__.py +1 -0
- maque/cv/image.py +219 -0
- maque/cv/utils.py +68 -0
- maque/cv/video/__init__.py +3 -0
- maque/cv/video/keyframe_extractor.py +368 -0
- maque/embedding/__init__.py +43 -0
- maque/embedding/base.py +56 -0
- maque/embedding/multimodal.py +308 -0
- maque/embedding/server.py +523 -0
- maque/embedding/text.py +311 -0
- maque/git/__init__.py +24 -0
- maque/git/pure_git.py +912 -0
- maque/io/__init__.py +29 -0
- maque/io/core.py +38 -0
- maque/io/ops.py +194 -0
- maque/llm/__init__.py +111 -0
- maque/llm/backend.py +416 -0
- maque/llm/base.py +411 -0
- maque/llm/server.py +366 -0
- maque/mcp_server.py +1096 -0
- maque/mllm_data_processor_pipeline/__init__.py +17 -0
- maque/mllm_data_processor_pipeline/core.py +341 -0
- maque/mllm_data_processor_pipeline/example.py +291 -0
- maque/mllm_data_processor_pipeline/steps/__init__.py +56 -0
- maque/mllm_data_processor_pipeline/steps/data_alignment.py +267 -0
- maque/mllm_data_processor_pipeline/steps/data_loader.py +172 -0
- maque/mllm_data_processor_pipeline/steps/data_validation.py +304 -0
- maque/mllm_data_processor_pipeline/steps/format_conversion.py +411 -0
- maque/mllm_data_processor_pipeline/steps/mllm_annotation.py +331 -0
- maque/mllm_data_processor_pipeline/steps/mllm_refinement.py +446 -0
- maque/mllm_data_processor_pipeline/steps/result_validation.py +501 -0
- maque/mllm_data_processor_pipeline/web_app.py +317 -0
- maque/nlp/__init__.py +14 -0
- maque/nlp/ngram.py +9 -0
- maque/nlp/parser.py +63 -0
- maque/nlp/risk_matcher.py +543 -0
- maque/nlp/sentence_splitter.py +202 -0
- maque/nlp/simple_tradition_cvt.py +31 -0
- maque/performance/__init__.py +21 -0
- maque/performance/_measure_time.py +70 -0
- maque/performance/_profiler.py +367 -0
- maque/performance/_stat_memory.py +51 -0
- maque/pipelines/__init__.py +15 -0
- maque/pipelines/clustering.py +252 -0
- maque/quantization/__init__.py +42 -0
- maque/quantization/auto_round.py +120 -0
- maque/quantization/base.py +145 -0
- maque/quantization/bitsandbytes.py +127 -0
- maque/quantization/llm_compressor.py +102 -0
- maque/retriever/__init__.py +35 -0
- maque/retriever/chroma.py +654 -0
- maque/retriever/document.py +140 -0
- maque/retriever/milvus.py +1140 -0
- maque/table_ops/__init__.py +1 -0
- maque/table_ops/core.py +133 -0
- maque/table_viewer/__init__.py +4 -0
- maque/table_viewer/download_assets.py +57 -0
- maque/table_viewer/server.py +698 -0
- maque/table_viewer/static/element-plus-icons.js +5791 -0
- maque/table_viewer/static/element-plus.css +1 -0
- maque/table_viewer/static/element-plus.js +65236 -0
- maque/table_viewer/static/main.css +268 -0
- maque/table_viewer/static/main.js +669 -0
- maque/table_viewer/static/vue.global.js +18227 -0
- maque/table_viewer/templates/index.html +401 -0
- maque/utils/__init__.py +56 -0
- maque/utils/color.py +68 -0
- maque/utils/color_string.py +45 -0
- maque/utils/compress.py +66 -0
- maque/utils/constant.py +183 -0
- maque/utils/core.py +261 -0
- maque/utils/cursor.py +143 -0
- maque/utils/distance.py +58 -0
- maque/utils/docker.py +96 -0
- maque/utils/downloads.py +51 -0
- maque/utils/excel_helper.py +542 -0
- maque/utils/helper_metrics.py +121 -0
- maque/utils/helper_parser.py +168 -0
- maque/utils/net.py +64 -0
- maque/utils/nvidia_stat.py +140 -0
- maque/utils/ops.py +53 -0
- maque/utils/packages.py +31 -0
- maque/utils/path.py +57 -0
- maque/utils/tar.py +260 -0
- maque/utils/untar.py +129 -0
- maque/web/__init__.py +0 -0
- maque/web/image_downloader.py +1410 -0
- maque-0.2.1.dist-info/METADATA +450 -0
- maque-0.2.1.dist-info/RECORD +143 -0
- maque-0.2.1.dist-info/WHEEL +4 -0
- maque-0.2.1.dist-info/entry_points.txt +3 -0
- maque-0.2.1.dist-info/licenses/LICENSE +21 -0
maque/io/__init__.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from .core import *
|
|
2
|
+
from .ops import *
|
|
3
|
+
from subprocess import Popen, PIPE
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def run(cmd, **env):
|
|
8
|
+
cmd = cmd.split(" ") if isinstance(cmd, str) else cmd
|
|
9
|
+
p = Popen(cmd, cwd=str(Path(__file__).parent), env={**os.environ, **env})
|
|
10
|
+
p.communicate()
|
|
11
|
+
return p.returncode
|
|
12
|
+
|
|
13
|
+
def replace_in_file(file, old, new):
|
|
14
|
+
with open(file, "r") as f:
|
|
15
|
+
content = f.read()
|
|
16
|
+
content = content.replace(old, new)
|
|
17
|
+
with open(file, "w") as f:
|
|
18
|
+
f.write(content)
|
|
19
|
+
|
|
20
|
+
def replace_var_in_file(filename, var, new, from_line=0, to_line=-1):
|
|
21
|
+
with open(filename, 'r') as fr:
|
|
22
|
+
init_list = fr.readlines()
|
|
23
|
+
for idx, line in enumerate(init_list[from_line:to_line]):
|
|
24
|
+
if "__version__" in line:
|
|
25
|
+
new_line = f"""{var} = {new}\n"""
|
|
26
|
+
init_list[idx] = new_line
|
|
27
|
+
break
|
|
28
|
+
with open(filename, 'w') as fw:
|
|
29
|
+
fw.writelines(init_list)
|
maque/io/core.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from functools import wraps
|
|
2
|
+
import pickle
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def save_var(filename, data):
|
|
6
|
+
with open(filename, "wb") as fw:
|
|
7
|
+
pickle.dump(data, fw)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def load_var(filename):
|
|
11
|
+
with open(filename, "rb") as fi:
|
|
12
|
+
data = pickle.load(fi)
|
|
13
|
+
return data
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def broadcast(func): # It can be replaced by `np.vectorize`
|
|
17
|
+
"""Only for a functions with a single argument
|
|
18
|
+
example:
|
|
19
|
+
@broadcast
|
|
20
|
+
def f(x):
|
|
21
|
+
# A function that can map only a single element
|
|
22
|
+
if x==1 or x==0:
|
|
23
|
+
return x
|
|
24
|
+
else:
|
|
25
|
+
return f(x-1)+f(x-2)
|
|
26
|
+
|
|
27
|
+
>> f([2,4,10])
|
|
28
|
+
>> (1, 3, 832040)
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
@wraps(func)
|
|
32
|
+
def wrapper(*args, **kwargs):
|
|
33
|
+
value_list = []
|
|
34
|
+
for arg in args:
|
|
35
|
+
value_list.append(func(arg, **kwargs))
|
|
36
|
+
return tuple(value_list)
|
|
37
|
+
|
|
38
|
+
return wrapper
|
maque/io/ops.py
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
from maque.utils.path import rel_to_abs, ls
|
|
2
|
+
import pickle
|
|
3
|
+
from typing import Union, List, Dict
|
|
4
|
+
import shutil
|
|
5
|
+
import os
|
|
6
|
+
import yaml
|
|
7
|
+
import orjson
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def rm(*file_pattern: str, rel=False):
|
|
11
|
+
"""Remove files or directories.
|
|
12
|
+
Example:
|
|
13
|
+
--------
|
|
14
|
+
>>> rm("*.jpg", "*.png")
|
|
15
|
+
>>> rm("*.jpg", "*.png", rel=True)
|
|
16
|
+
"""
|
|
17
|
+
path_list = ls(".", *file_pattern, relp=rel, concat="extend")
|
|
18
|
+
for file in path_list:
|
|
19
|
+
if os.path.isfile(file):
|
|
20
|
+
os.remove(file)
|
|
21
|
+
elif os.path.isdir(file):
|
|
22
|
+
shutil.rmtree(file, ignore_errors=True)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def save(filename, data):
|
|
26
|
+
import pickle
|
|
27
|
+
|
|
28
|
+
with open(filename, "wb") as fw:
|
|
29
|
+
pickle.dump(data, fw)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def load(filename):
|
|
33
|
+
import pickle
|
|
34
|
+
|
|
35
|
+
with open(filename, "rb") as fi:
|
|
36
|
+
file = pickle.load(fi)
|
|
37
|
+
return file
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def json_load(filepath: str, rel=False, mode="rb"):
|
|
41
|
+
abs_path = rel_to_abs(filepath, parents=1) if rel else filepath
|
|
42
|
+
with open(abs_path, mode=mode) as f:
|
|
43
|
+
return orjson.loads(f.read())
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def json_dump(
|
|
47
|
+
data: Union[List, Dict], filepath: str, rel=False, indent_2=False, mode="wb"
|
|
48
|
+
):
|
|
49
|
+
orjson_option = 0
|
|
50
|
+
if indent_2:
|
|
51
|
+
orjson_option = orjson.OPT_INDENT_2
|
|
52
|
+
abs_path = rel_to_abs(filepath, parents=1) if rel else filepath
|
|
53
|
+
with open(abs_path, mode=mode) as f:
|
|
54
|
+
f.write(orjson.dumps(data, option=orjson_option))
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def jsonl_load(
|
|
58
|
+
filepath: str,
|
|
59
|
+
rel=False,
|
|
60
|
+
mode="rb",
|
|
61
|
+
on_error: str = "warn",
|
|
62
|
+
) -> list:
|
|
63
|
+
"""Load JSONL file.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
filepath: Path to the JSONL file.
|
|
67
|
+
rel: If True, treat filepath as relative to caller's directory.
|
|
68
|
+
mode: File open mode.
|
|
69
|
+
on_error: Error handling strategy for malformed lines:
|
|
70
|
+
- "warn": Skip malformed lines but print warning (default)
|
|
71
|
+
- "raise": Raise exception on first error
|
|
72
|
+
- "skip": Silently skip malformed lines
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
List of parsed JSON objects.
|
|
76
|
+
"""
|
|
77
|
+
abs_path = rel_to_abs(filepath, parents=1) if rel else filepath
|
|
78
|
+
results = []
|
|
79
|
+
errors = []
|
|
80
|
+
|
|
81
|
+
with open(abs_path, mode=mode) as f:
|
|
82
|
+
for line_num, line in enumerate(f, 1):
|
|
83
|
+
line = line.strip()
|
|
84
|
+
if not line:
|
|
85
|
+
continue
|
|
86
|
+
try:
|
|
87
|
+
results.append(orjson.loads(line))
|
|
88
|
+
except orjson.JSONDecodeError as e:
|
|
89
|
+
if on_error == "raise":
|
|
90
|
+
raise ValueError(
|
|
91
|
+
f"Failed to parse line {line_num} in {filepath}: {e}"
|
|
92
|
+
) from e
|
|
93
|
+
errors.append((line_num, str(e)))
|
|
94
|
+
|
|
95
|
+
if errors and on_error == "warn":
|
|
96
|
+
import warnings
|
|
97
|
+
|
|
98
|
+
warnings.warn(
|
|
99
|
+
f"jsonl_load: Skipped {len(errors)} malformed line(s) in {filepath}. "
|
|
100
|
+
f"First error at line {errors[0][0]}: {errors[0][1]}"
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
return results
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def jsonl_dump(data: List[Dict], filepath: str, rel=False, mode="wb"):
|
|
107
|
+
abs_path = rel_to_abs(filepath, parents=1) if rel else filepath
|
|
108
|
+
with open(abs_path, mode=mode) as f:
|
|
109
|
+
for item in data:
|
|
110
|
+
f.write(orjson.dumps(item) + b"\n")
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
# 自定义多行字符串的显示方式,去除行尾空格
|
|
114
|
+
def str_presenter(dumper, data):
|
|
115
|
+
""" """
|
|
116
|
+
# 去除每一行的行尾空格
|
|
117
|
+
data = "\n".join([line.rstrip() for line in data.splitlines()])
|
|
118
|
+
if "\n" in data:
|
|
119
|
+
return dumper.represent_scalar("tag:yaml.org,2002:str", data, style="|")
|
|
120
|
+
return dumper.represent_scalar("tag:yaml.org,2002:str", data)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
# 添加自定义表示器
|
|
124
|
+
yaml.add_representer(str, str_presenter)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def yaml_dump(filepath, data, rel_path=False, mode="w"):
|
|
128
|
+
"""Yaml dump"""
|
|
129
|
+
abs_path = rel_to_abs(filepath, parents=1) if rel_path else filepath
|
|
130
|
+
|
|
131
|
+
with open(abs_path, mode=mode, encoding="utf-8") as fw:
|
|
132
|
+
yaml.dump(
|
|
133
|
+
data,
|
|
134
|
+
fw,
|
|
135
|
+
allow_unicode=True,
|
|
136
|
+
indent=4,
|
|
137
|
+
sort_keys=False,
|
|
138
|
+
default_flow_style=False,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def yaml_load(filepath, rel_path=False, mode="r"):
|
|
143
|
+
import yaml
|
|
144
|
+
|
|
145
|
+
abs_path = rel_to_abs(filepath, parents=1) if rel_path else filepath
|
|
146
|
+
with open(abs_path, mode=mode, encoding="utf-8") as stream:
|
|
147
|
+
content = yaml.safe_load(stream)
|
|
148
|
+
return content
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def split_file(file_path, chunk_size=1024 * 1024 * 1024):
|
|
152
|
+
"""将大文件分割成多个块。
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
file_path (str): 原始文件的路径。
|
|
156
|
+
chunk_size (int): 每个块的大小(字节)。
|
|
157
|
+
"""
|
|
158
|
+
with open(file_path, "rb") as f:
|
|
159
|
+
chunk_number = 0
|
|
160
|
+
while True:
|
|
161
|
+
chunk = f.read(int(chunk_size))
|
|
162
|
+
if not chunk:
|
|
163
|
+
break
|
|
164
|
+
with open(f"{file_path}_part_{chunk_number:03}", "wb") as chunk_file:
|
|
165
|
+
chunk_file.write(chunk)
|
|
166
|
+
chunk_number += 1
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def join_files(input_prefix, input_dir, output_path=None):
|
|
170
|
+
"""将分割后的文件块拼接回一个文件。
|
|
171
|
+
|
|
172
|
+
Args:
|
|
173
|
+
input_prefix (str): 分割文件的前缀。
|
|
174
|
+
output_path (str): 拼接后的文件路径。
|
|
175
|
+
"""
|
|
176
|
+
import glob
|
|
177
|
+
|
|
178
|
+
if output_path is None:
|
|
179
|
+
output_path = os.path.join(input_dir, input_prefix)
|
|
180
|
+
|
|
181
|
+
parts = sorted(glob.glob(f"{input_prefix}_part_*", root_dir=input_dir))
|
|
182
|
+
with open(output_path, "wb") as output_file:
|
|
183
|
+
for part in parts:
|
|
184
|
+
with open(os.path.join(input_dir, part), "rb") as part_file:
|
|
185
|
+
output_file.write(part_file.read())
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def find_free_port():
|
|
189
|
+
"""Find a free port to use for the server."""
|
|
190
|
+
import socket
|
|
191
|
+
|
|
192
|
+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
|
193
|
+
s.bind(("", 0))
|
|
194
|
+
return s.getsockname()[1]
|
maque/llm/__init__.py
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
#! /usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
LLM 模块 - 提供 LLM/MLLM 推理服务
|
|
6
|
+
|
|
7
|
+
模块结构:
|
|
8
|
+
- base: 抽象基类 BaseLLMBackend,可继承实现自定义后端
|
|
9
|
+
- backend: Transformers 后端实现
|
|
10
|
+
- server: FastAPI HTTP 服务
|
|
11
|
+
|
|
12
|
+
使用示例:
|
|
13
|
+
|
|
14
|
+
1. 启动服务 (CLI):
|
|
15
|
+
```bash
|
|
16
|
+
# 标准 LLM
|
|
17
|
+
maque llm serve Qwen/Qwen2.5-7B-Instruct
|
|
18
|
+
|
|
19
|
+
# 多模态 VL 模型
|
|
20
|
+
maque llm serve Qwen/Qwen2.5-VL-3B-Instruct --port=8001
|
|
21
|
+
|
|
22
|
+
# 自定义模型类 (如 HunyuanOCR)
|
|
23
|
+
maque llm serve tencent/HunyuanOCR \\
|
|
24
|
+
--model_class=HunYuanVLForConditionalGeneration \\
|
|
25
|
+
--vision_processor=general
|
|
26
|
+
|
|
27
|
+
# Qwen3 带 thinking 模式
|
|
28
|
+
maque llm serve Qwen/Qwen3-0.6B --enable_thinking
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
2. 编程方式启动:
|
|
32
|
+
```python
|
|
33
|
+
from maque.llm import create_server, ModelConfig
|
|
34
|
+
|
|
35
|
+
# 简单启动
|
|
36
|
+
server = create_server(model="Qwen/Qwen2.5-7B-Instruct")
|
|
37
|
+
server.run(port=8000)
|
|
38
|
+
|
|
39
|
+
# 带自定义配置
|
|
40
|
+
server = create_server(
|
|
41
|
+
model="tencent/HunyuanOCR",
|
|
42
|
+
model_class="HunYuanVLForConditionalGeneration",
|
|
43
|
+
vision_processor="general",
|
|
44
|
+
chat_template_kwargs={"enable_thinking": True},
|
|
45
|
+
)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
3. 自定义后端:
|
|
49
|
+
```python
|
|
50
|
+
from maque.llm import BaseLLMBackend, ModelConfig, GenerateConfig
|
|
51
|
+
|
|
52
|
+
class MyBackend(BaseLLMBackend):
|
|
53
|
+
def _load_model_impl(self, model_path, config):
|
|
54
|
+
# 自定义加载逻辑
|
|
55
|
+
pass
|
|
56
|
+
|
|
57
|
+
def _generate_impl(self, messages, config):
|
|
58
|
+
# 自定义生成逻辑
|
|
59
|
+
return "response", 10, 20
|
|
60
|
+
|
|
61
|
+
# 使用自定义后端
|
|
62
|
+
from maque.llm import LLMServer
|
|
63
|
+
server = LLMServer(backend=MyBackend(), model="my-model")
|
|
64
|
+
server.run()
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
ModelConfig 配置说明:
|
|
68
|
+
- model_id: 模型名称或路径
|
|
69
|
+
- model_class: 模型类名 (如 "AutoModelForCausalLM", "HunYuanVLForConditionalGeneration")
|
|
70
|
+
- processor_class: 处理器类名 (如 "AutoTokenizer", "AutoProcessor")
|
|
71
|
+
- vision_processor: 视觉处理器类型 ("qwen_vl" 或 "general")
|
|
72
|
+
- chat_template_kwargs: chat template 额外参数 (如 {"enable_thinking": True})
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
# 基类和数据模型
|
|
76
|
+
from .base import (
|
|
77
|
+
BaseLLMBackend,
|
|
78
|
+
ModelConfig,
|
|
79
|
+
GenerateConfig,
|
|
80
|
+
ChatMessage,
|
|
81
|
+
ContentPart,
|
|
82
|
+
ImageURL,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
# 后端实现
|
|
86
|
+
from .backend import TransformersBackend, LLMBackend
|
|
87
|
+
|
|
88
|
+
# 服务端 (延迟导入,避免强依赖 fastapi)
|
|
89
|
+
def __getattr__(name):
|
|
90
|
+
if name in ("LLMServer", "create_server"):
|
|
91
|
+
from .server import LLMServer, create_server
|
|
92
|
+
return {"LLMServer": LLMServer, "create_server": create_server}[name]
|
|
93
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
__all__ = [
|
|
97
|
+
# 基类
|
|
98
|
+
"BaseLLMBackend",
|
|
99
|
+
# 数据模型
|
|
100
|
+
"ModelConfig",
|
|
101
|
+
"GenerateConfig",
|
|
102
|
+
"ChatMessage",
|
|
103
|
+
"ContentPart",
|
|
104
|
+
"ImageURL",
|
|
105
|
+
# 后端
|
|
106
|
+
"TransformersBackend",
|
|
107
|
+
"LLMBackend", # 别名
|
|
108
|
+
# 服务端
|
|
109
|
+
"LLMServer",
|
|
110
|
+
"create_server",
|
|
111
|
+
]
|