htmlgen-mcp 0.3.3__py3-none-any.whl → 0.3.5__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.

Potentially problematic release.


This version of htmlgen-mcp might be problematic. Click here for more details.

@@ -1,341 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- """
4
- 集群文件存储模块 - 支持对象存储
5
- """
6
-
7
- import os
8
- import mimetypes
9
- from pathlib import Path
10
- from typing import Optional, List
11
-
12
-
13
- class StorageBackend:
14
- """存储后端抽象基类"""
15
-
16
- def upload_file(self, local_path: str, remote_path: str) -> str:
17
- """
18
- 上传文件到存储
19
-
20
- Args:
21
- local_path: 本地文件路径
22
- remote_path: 远程存储路径
23
-
24
- Returns:
25
- 可访问的 URL
26
- """
27
- raise NotImplementedError
28
-
29
- def download_file(self, remote_path: str, local_path: str) -> bool:
30
- """下载文件到本地"""
31
- raise NotImplementedError
32
-
33
- def delete_file(self, remote_path: str) -> bool:
34
- """删除文件"""
35
- raise NotImplementedError
36
-
37
- def list_files(self, prefix: str) -> List[str]:
38
- """列出指定前缀的所有文件"""
39
- raise NotImplementedError
40
-
41
- def get_url(self, remote_path: str, expires: int = 3600) -> str:
42
- """获取文件访问URL"""
43
- raise NotImplementedError
44
-
45
-
46
- class LocalStorageBackend(StorageBackend):
47
- """
48
- 本地文件系统存储(开发/单机环境)
49
- 适用于开发测试,生产环境请使用对象存储
50
- """
51
-
52
- def __init__(self, base_dir: str = "/tmp/agent_storage"):
53
- self.base_dir = Path(base_dir)
54
- self.base_dir.mkdir(parents=True, exist_ok=True)
55
-
56
- def upload_file(self, local_path: str, remote_path: str) -> str:
57
- """复制文件到存储目录"""
58
- target_path = self.base_dir / remote_path
59
- target_path.parent.mkdir(parents=True, exist_ok=True)
60
-
61
- import shutil
62
- shutil.copy2(local_path, target_path)
63
-
64
- return f"file://{target_path}"
65
-
66
- def download_file(self, remote_path: str, local_path: str) -> bool:
67
- """从存储目录复制文件"""
68
- source_path = self.base_dir / remote_path
69
- if not source_path.exists():
70
- return False
71
-
72
- import shutil
73
- Path(local_path).parent.mkdir(parents=True, exist_ok=True)
74
- shutil.copy2(source_path, local_path)
75
- return True
76
-
77
- def delete_file(self, remote_path: str) -> bool:
78
- """删除文件"""
79
- target_path = self.base_dir / remote_path
80
- if target_path.exists():
81
- target_path.unlink()
82
- return True
83
- return False
84
-
85
- def list_files(self, prefix: str) -> List[str]:
86
- """列出文件"""
87
- prefix_path = self.base_dir / prefix
88
- if not prefix_path.exists():
89
- return []
90
-
91
- files = []
92
- for file_path in prefix_path.rglob("*"):
93
- if file_path.is_file():
94
- rel_path = file_path.relative_to(self.base_dir)
95
- files.append(str(rel_path))
96
- return files
97
-
98
- def get_url(self, remote_path: str, expires: int = 3600) -> str:
99
- """获取文件URL"""
100
- target_path = self.base_dir / remote_path
101
- return f"file://{target_path}"
102
-
103
-
104
- class OSSStorageBackend(StorageBackend):
105
- """阿里云 OSS 存储"""
106
-
107
- def __init__(self, access_key: str, secret_key: str, endpoint: str, bucket: str):
108
- try:
109
- import oss2
110
- except ImportError:
111
- raise ImportError("请安装 oss2: pip install oss2")
112
-
113
- auth = oss2.Auth(access_key, secret_key)
114
- self.bucket = oss2.Bucket(auth, endpoint, bucket)
115
- self.bucket_name = bucket
116
- self.endpoint = endpoint
117
-
118
- def upload_file(self, local_path: str, remote_path: str) -> str:
119
- """上传文件到 OSS"""
120
- # 自动检测 Content-Type
121
- content_type, _ = mimetypes.guess_type(local_path)
122
-
123
- headers = {}
124
- if content_type:
125
- headers['Content-Type'] = content_type
126
-
127
- self.bucket.put_object_from_file(remote_path, local_path, headers=headers)
128
-
129
- return f"https://{self.bucket_name}.{self.endpoint}/{remote_path}"
130
-
131
- def download_file(self, remote_path: str, local_path: str) -> bool:
132
- """从 OSS 下载文件"""
133
- try:
134
- Path(local_path).parent.mkdir(parents=True, exist_ok=True)
135
- self.bucket.get_object_to_file(remote_path, local_path)
136
- return True
137
- except Exception:
138
- return False
139
-
140
- def delete_file(self, remote_path: str) -> bool:
141
- """删除 OSS 文件"""
142
- try:
143
- self.bucket.delete_object(remote_path)
144
- return True
145
- except Exception:
146
- return False
147
-
148
- def list_files(self, prefix: str) -> List[str]:
149
- """列出 OSS 文件"""
150
- files = []
151
- for obj in oss2.ObjectIterator(self.bucket, prefix=prefix):
152
- files.append(obj.key)
153
- return files
154
-
155
- def get_url(self, remote_path: str, expires: int = 3600) -> str:
156
- """获取 OSS 签名 URL"""
157
- return self.bucket.sign_url('GET', remote_path, expires)
158
-
159
-
160
- class S3StorageBackend(StorageBackend):
161
- """AWS S3 / MinIO 存储"""
162
-
163
- def __init__(self, access_key: str, secret_key: str, endpoint: str, bucket: str, region: str = "us-east-1"):
164
- try:
165
- import boto3
166
- except ImportError:
167
- raise ImportError("请安装 boto3: pip install boto3")
168
-
169
- self.s3_client = boto3.client(
170
- 's3',
171
- aws_access_key_id=access_key,
172
- aws_secret_access_key=secret_key,
173
- endpoint_url=endpoint if endpoint else None,
174
- region_name=region
175
- )
176
- self.bucket = bucket
177
- self.endpoint = endpoint
178
-
179
- def upload_file(self, local_path: str, remote_path: str) -> str:
180
- """上传文件到 S3"""
181
- content_type, _ = mimetypes.guess_type(local_path)
182
-
183
- extra_args = {}
184
- if content_type:
185
- extra_args['ContentType'] = content_type
186
-
187
- self.s3_client.upload_file(local_path, self.bucket, remote_path, ExtraArgs=extra_args)
188
-
189
- if self.endpoint:
190
- return f"{self.endpoint}/{self.bucket}/{remote_path}"
191
- return f"https://{self.bucket}.s3.amazonaws.com/{remote_path}"
192
-
193
- def download_file(self, remote_path: str, local_path: str) -> bool:
194
- """从 S3 下载文件"""
195
- try:
196
- Path(local_path).parent.mkdir(parents=True, exist_ok=True)
197
- self.s3_client.download_file(self.bucket, remote_path, local_path)
198
- return True
199
- except Exception:
200
- return False
201
-
202
- def delete_file(self, remote_path: str) -> bool:
203
- """删除 S3 文件"""
204
- try:
205
- self.s3_client.delete_object(Bucket=self.bucket, Key=remote_path)
206
- return True
207
- except Exception:
208
- return False
209
-
210
- def list_files(self, prefix: str) -> List[str]:
211
- """列出 S3 文件"""
212
- files = []
213
- paginator = self.s3_client.get_paginator('list_objects_v2')
214
- for page in paginator.paginate(Bucket=self.bucket, Prefix=prefix):
215
- if 'Contents' in page:
216
- for obj in page['Contents']:
217
- files.append(obj['Key'])
218
- return files
219
-
220
- def get_url(self, remote_path: str, expires: int = 3600) -> str:
221
- """获取 S3 签名 URL"""
222
- return self.s3_client.generate_presigned_url(
223
- 'get_object',
224
- Params={'Bucket': self.bucket, 'Key': remote_path},
225
- ExpiresIn=expires
226
- )
227
-
228
-
229
- class COSStorageBackend(StorageBackend):
230
- """腾讯云 COS 存储"""
231
-
232
- def __init__(self, secret_id: str, secret_key: str, region: str, bucket: str):
233
- try:
234
- from qcloud_cos import CosConfig, CosS3Client
235
- except ImportError:
236
- raise ImportError("请安装 cos-python-sdk-v5: pip install cos-python-sdk-v5")
237
-
238
- config = CosConfig(Region=region, SecretId=secret_id, SecretKey=secret_key)
239
- self.client = CosS3Client(config)
240
- self.bucket = bucket
241
- self.region = region
242
-
243
- def upload_file(self, local_path: str, remote_path: str) -> str:
244
- """上传文件到 COS"""
245
- content_type, _ = mimetypes.guess_type(local_path)
246
-
247
- with open(local_path, 'rb') as f:
248
- self.client.put_object(
249
- Bucket=self.bucket,
250
- Body=f,
251
- Key=remote_path,
252
- ContentType=content_type or 'application/octet-stream'
253
- )
254
-
255
- return f"https://{self.bucket}.cos.{self.region}.myqcloud.com/{remote_path}"
256
-
257
- def download_file(self, remote_path: str, local_path: str) -> bool:
258
- """从 COS 下载文件"""
259
- try:
260
- Path(local_path).parent.mkdir(parents=True, exist_ok=True)
261
- response = self.client.get_object(Bucket=self.bucket, Key=remote_path)
262
- response['Body'].get_stream_to_file(local_path)
263
- return True
264
- except Exception:
265
- return False
266
-
267
- def delete_file(self, remote_path: str) -> bool:
268
- """删除 COS 文件"""
269
- try:
270
- self.client.delete_object(Bucket=self.bucket, Key=remote_path)
271
- return True
272
- except Exception:
273
- return False
274
-
275
- def list_files(self, prefix: str) -> List[str]:
276
- """列出 COS 文件"""
277
- files = []
278
- marker = ""
279
- while True:
280
- response = self.client.list_objects(Bucket=self.bucket, Prefix=prefix, Marker=marker)
281
- if 'Contents' in response:
282
- for obj in response['Contents']:
283
- files.append(obj['Key'])
284
- if response['IsTruncated'] == 'false':
285
- break
286
- marker = response['NextMarker']
287
- return files
288
-
289
- def get_url(self, remote_path: str, expires: int = 3600) -> str:
290
- """获取 COS 签名 URL"""
291
- return self.client.get_presigned_download_url(
292
- Bucket=self.bucket,
293
- Key=remote_path,
294
- Expired=expires
295
- )
296
-
297
-
298
- def create_storage_backend(
299
- backend_type: str = "local",
300
- **kwargs
301
- ) -> StorageBackend:
302
- """
303
- 工厂函数:创建存储后端
304
-
305
- Args:
306
- backend_type: 后端类型 'local', 'oss', 's3', 'cos'
307
- **kwargs: 各后端的配置参数
308
- - local: base_dir
309
- - oss: access_key, secret_key, endpoint, bucket
310
- - s3: access_key, secret_key, endpoint, bucket, region
311
- - cos: secret_id, secret_key, region, bucket
312
-
313
- Returns:
314
- StorageBackend 实例
315
- """
316
- if backend_type == "local":
317
- return LocalStorageBackend(kwargs.get("base_dir", "/tmp/agent_storage"))
318
- elif backend_type == "oss":
319
- return OSSStorageBackend(
320
- access_key=kwargs["access_key"],
321
- secret_key=kwargs["secret_key"],
322
- endpoint=kwargs["endpoint"],
323
- bucket=kwargs["bucket"]
324
- )
325
- elif backend_type == "s3":
326
- return S3StorageBackend(
327
- access_key=kwargs["access_key"],
328
- secret_key=kwargs["secret_key"],
329
- endpoint=kwargs.get("endpoint"),
330
- bucket=kwargs["bucket"],
331
- region=kwargs.get("region", "us-east-1")
332
- )
333
- elif backend_type == "cos":
334
- return COSStorageBackend(
335
- secret_id=kwargs["secret_id"],
336
- secret_key=kwargs["secret_key"],
337
- region=kwargs["region"],
338
- bucket=kwargs["bucket"]
339
- )
340
- else:
341
- raise ValueError(f"不支持的存储后端: {backend_type}")