htmlgen-mcp 0.2.5__py3-none-any.whl → 0.3.2__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.
- htmlgen_mcp/__init__.py +1 -1
- htmlgen_mcp/agents/ai_content_generator.py +328 -0
- htmlgen_mcp/agents/cluster_state.py +414 -0
- htmlgen_mcp/agents/cluster_storage.py +341 -0
- htmlgen_mcp/agents/quick_generator.py +270 -0
- htmlgen_mcp/agents/smart_web_agent.py +118 -12
- htmlgen_mcp/agents/web_tools/__init__.py +16 -6
- htmlgen_mcp/agents/web_tools/html_templates_improved.py +696 -0
- htmlgen_mcp/agents/web_tools/navigation.py +29 -0
- htmlgen_mcp/config.py +326 -0
- htmlgen_mcp/sse_optimizations.py +195 -0
- htmlgen_mcp/web_agent_server.py +61 -21
- {htmlgen_mcp-0.2.5.dist-info → htmlgen_mcp-0.3.2.dist-info}/METADATA +1 -1
- {htmlgen_mcp-0.2.5.dist-info → htmlgen_mcp-0.3.2.dist-info}/RECORD +17 -10
- {htmlgen_mcp-0.2.5.dist-info → htmlgen_mcp-0.3.2.dist-info}/WHEEL +0 -0
- {htmlgen_mcp-0.2.5.dist-info → htmlgen_mcp-0.3.2.dist-info}/entry_points.txt +0 -0
- {htmlgen_mcp-0.2.5.dist-info → htmlgen_mcp-0.3.2.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,341 @@
|
|
|
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}")
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""快速单页网站生成器 - 优化生成速度"""
|
|
4
|
+
|
|
5
|
+
from typing import Dict, Any, Optional, List
|
|
6
|
+
import json
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class QuickSiteGenerator:
|
|
10
|
+
"""快速生成单页面网站的辅助类"""
|
|
11
|
+
|
|
12
|
+
@staticmethod
|
|
13
|
+
def create_single_page_plan(
|
|
14
|
+
project_name: str,
|
|
15
|
+
site_type: str,
|
|
16
|
+
description: str
|
|
17
|
+
) -> Dict[str, Any]:
|
|
18
|
+
"""创建单页面网站的简化计划
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
project_name: 项目名称
|
|
22
|
+
site_type: 网站类型(咖啡店、企业、作品集等)
|
|
23
|
+
description: 用户需求描述
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
简化的执行计划
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
# 基础步骤(所有类型通用)
|
|
30
|
+
base_steps = [
|
|
31
|
+
{
|
|
32
|
+
"step": 1,
|
|
33
|
+
"tool": "create_project_structure",
|
|
34
|
+
"params": {
|
|
35
|
+
"project_name": project_name,
|
|
36
|
+
"project_path": "."
|
|
37
|
+
},
|
|
38
|
+
"description": "创建项目目录结构",
|
|
39
|
+
"rationale": "建立规范的项目结构"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"step": 2,
|
|
43
|
+
"tool": "create_css_file",
|
|
44
|
+
"params": {
|
|
45
|
+
"file_path": "assets/css/style.css"
|
|
46
|
+
},
|
|
47
|
+
"description": "创建样式文件",
|
|
48
|
+
"rationale": "定义网站视觉风格"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"step": 3,
|
|
52
|
+
"tool": "create_js_file",
|
|
53
|
+
"params": {
|
|
54
|
+
"file_path": "assets/js/main.js"
|
|
55
|
+
},
|
|
56
|
+
"description": "创建交互脚本",
|
|
57
|
+
"rationale": "添加动态效果和交互"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"step": 4,
|
|
61
|
+
"tool": "create_html_file",
|
|
62
|
+
"params": {
|
|
63
|
+
"file_path": "index.html",
|
|
64
|
+
"title": f"{project_name} - 首页"
|
|
65
|
+
},
|
|
66
|
+
"description": "创建单页面网站主文件",
|
|
67
|
+
"rationale": "生成包含所有内容的单页面"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"step": 5,
|
|
71
|
+
"tool": "add_bootstrap",
|
|
72
|
+
"params": {
|
|
73
|
+
"project_path": "."
|
|
74
|
+
},
|
|
75
|
+
"description": "添加Bootstrap框架",
|
|
76
|
+
"rationale": "加速响应式开发"
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"step": 6,
|
|
80
|
+
"tool": "create_responsive_navbar",
|
|
81
|
+
"params": {
|
|
82
|
+
"file_path": "index.html",
|
|
83
|
+
"brand_name": project_name,
|
|
84
|
+
"nav_items": QuickSiteGenerator._get_nav_items(site_type)
|
|
85
|
+
},
|
|
86
|
+
"description": "创建导航栏",
|
|
87
|
+
"rationale": "页面内导航锚点"
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"step": 7,
|
|
91
|
+
"tool": "inject_images",
|
|
92
|
+
"params": {
|
|
93
|
+
"file_path": "index.html",
|
|
94
|
+
"provider": "pollinations",
|
|
95
|
+
"topics": QuickSiteGenerator._get_image_topics(site_type),
|
|
96
|
+
"size": "1920x1080",
|
|
97
|
+
"save": True
|
|
98
|
+
},
|
|
99
|
+
"description": "注入AI生成图片",
|
|
100
|
+
"rationale": "添加视觉内容"
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"step": 8,
|
|
104
|
+
"tool": "open_in_browser",
|
|
105
|
+
"params": {
|
|
106
|
+
"file_path": "index.html"
|
|
107
|
+
},
|
|
108
|
+
"description": "浏览器预览",
|
|
109
|
+
"rationale": "查看最终效果"
|
|
110
|
+
}
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
# 根据网站类型定制配色
|
|
114
|
+
color_scheme = QuickSiteGenerator._get_color_scheme(site_type)
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
"task_analysis": f"快速生成{site_type}单页面网站",
|
|
118
|
+
"project_name": project_name,
|
|
119
|
+
"site_type": site_type,
|
|
120
|
+
"design_style": "现代简洁",
|
|
121
|
+
"color_scheme": color_scheme,
|
|
122
|
+
"estimated_time": "2-3分钟",
|
|
123
|
+
"tools_sequence": base_steps
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
@staticmethod
|
|
127
|
+
def _get_nav_items(site_type: str) -> List[Dict[str, str]]:
|
|
128
|
+
"""根据网站类型返回导航项(锚点链接)"""
|
|
129
|
+
|
|
130
|
+
nav_templates = {
|
|
131
|
+
"咖啡店": [
|
|
132
|
+
{"name": "首页", "link": "#hero"},
|
|
133
|
+
{"name": "菜单", "link": "#menu"},
|
|
134
|
+
{"name": "关于", "link": "#about"},
|
|
135
|
+
{"name": "联系", "link": "#contact"}
|
|
136
|
+
],
|
|
137
|
+
"企业": [
|
|
138
|
+
{"name": "首页", "link": "#hero"},
|
|
139
|
+
{"name": "服务", "link": "#services"},
|
|
140
|
+
{"name": "关于", "link": "#about"},
|
|
141
|
+
{"name": "联系", "link": "#contact"}
|
|
142
|
+
],
|
|
143
|
+
"作品集": [
|
|
144
|
+
{"name": "首页", "link": "#hero"},
|
|
145
|
+
{"name": "作品", "link": "#portfolio"},
|
|
146
|
+
{"name": "技能", "link": "#skills"},
|
|
147
|
+
{"name": "联系", "link": "#contact"}
|
|
148
|
+
],
|
|
149
|
+
"餐厅": [
|
|
150
|
+
{"name": "首页", "link": "#hero"},
|
|
151
|
+
{"name": "菜单", "link": "#menu"},
|
|
152
|
+
{"name": "预约", "link": "#booking"},
|
|
153
|
+
{"name": "位置", "link": "#location"}
|
|
154
|
+
]
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
# 默认导航
|
|
158
|
+
default = [
|
|
159
|
+
{"name": "首页", "link": "#hero"},
|
|
160
|
+
{"name": "介绍", "link": "#about"},
|
|
161
|
+
{"name": "服务", "link": "#services"},
|
|
162
|
+
{"name": "联系", "link": "#contact"}
|
|
163
|
+
]
|
|
164
|
+
|
|
165
|
+
# 查找最匹配的类型
|
|
166
|
+
for key in nav_templates:
|
|
167
|
+
if key in site_type:
|
|
168
|
+
return nav_templates[key]
|
|
169
|
+
|
|
170
|
+
return default
|
|
171
|
+
|
|
172
|
+
@staticmethod
|
|
173
|
+
def _get_image_topics(site_type: str) -> List[str]:
|
|
174
|
+
"""根据网站类型返回图片主题"""
|
|
175
|
+
|
|
176
|
+
topics_map = {
|
|
177
|
+
"咖啡": ["coffee shop interior modern", "latte art", "coffee beans", "cozy cafe"],
|
|
178
|
+
"餐厅": ["restaurant interior elegant", "gourmet food", "dining table", "chef cooking"],
|
|
179
|
+
"企业": ["modern office", "business team", "corporate building", "technology workspace"],
|
|
180
|
+
"作品集": ["creative workspace", "design portfolio", "artistic studio", "digital art"],
|
|
181
|
+
"电商": ["product showcase", "online shopping", "ecommerce", "shopping cart"],
|
|
182
|
+
"博客": ["writing desk", "laptop workspace", "books and coffee", "minimal desk setup"]
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
# 查找匹配的主题
|
|
186
|
+
for key, topics in topics_map.items():
|
|
187
|
+
if key in site_type:
|
|
188
|
+
return topics
|
|
189
|
+
|
|
190
|
+
# 默认主题
|
|
191
|
+
return ["modern website hero", "business concept", "technology background", "professional workspace"]
|
|
192
|
+
|
|
193
|
+
@staticmethod
|
|
194
|
+
def _get_color_scheme(site_type: str) -> Dict[str, str]:
|
|
195
|
+
"""根据网站类型返回配色方案"""
|
|
196
|
+
|
|
197
|
+
schemes = {
|
|
198
|
+
"咖啡": {
|
|
199
|
+
"primary": "#6F4E37", # 咖啡棕
|
|
200
|
+
"secondary": "#C8A882", # 奶泡色
|
|
201
|
+
"accent": "#D2691E" # 焦糖色
|
|
202
|
+
},
|
|
203
|
+
"餐厅": {
|
|
204
|
+
"primary": "#8B0000", # 深红
|
|
205
|
+
"secondary": "#FFD700", # 金色
|
|
206
|
+
"accent": "#228B22" # 森林绿
|
|
207
|
+
},
|
|
208
|
+
"企业": {
|
|
209
|
+
"primary": "#003366", # 企业蓝
|
|
210
|
+
"secondary": "#F0F0F0", # 浅灰
|
|
211
|
+
"accent": "#FF6B35" # 橙色
|
|
212
|
+
},
|
|
213
|
+
"作品集": {
|
|
214
|
+
"primary": "#2C3E50", # 深蓝灰
|
|
215
|
+
"secondary": "#ECF0F1", # 云白
|
|
216
|
+
"accent": "#E74C3C" # 红色
|
|
217
|
+
},
|
|
218
|
+
"电商": {
|
|
219
|
+
"primary": "#FF6B6B", # 珊瑚红
|
|
220
|
+
"secondary": "#4ECDC4", # 青绿
|
|
221
|
+
"accent": "#FFE66D" # 黄色
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
# 查找匹配的配色
|
|
226
|
+
for key, scheme in schemes.items():
|
|
227
|
+
if key in site_type:
|
|
228
|
+
return scheme
|
|
229
|
+
|
|
230
|
+
# 默认配色(现代通用)
|
|
231
|
+
return {
|
|
232
|
+
"primary": "#3B82F6", # 蓝色
|
|
233
|
+
"secondary": "#F3F4F6", # 浅灰
|
|
234
|
+
"accent": "#10B981" # 绿色
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
@staticmethod
|
|
238
|
+
def optimize_for_speed(plan: Dict[str, Any]) -> Dict[str, Any]:
|
|
239
|
+
"""优化计划以提升生成速度
|
|
240
|
+
|
|
241
|
+
- 移除不必要的验证步骤
|
|
242
|
+
- 简化图片生成
|
|
243
|
+
- 减少工具调用次数
|
|
244
|
+
"""
|
|
245
|
+
optimized_steps = []
|
|
246
|
+
|
|
247
|
+
for step in plan.get("tools_sequence", []):
|
|
248
|
+
tool = step.get("tool", "")
|
|
249
|
+
|
|
250
|
+
# 跳过验证类工具(可选)
|
|
251
|
+
if tool in ["validate_html", "check_mobile_friendly"]:
|
|
252
|
+
continue
|
|
253
|
+
|
|
254
|
+
# 简化图片参数
|
|
255
|
+
if tool == "inject_images":
|
|
256
|
+
params = step.get("params", {})
|
|
257
|
+
# 限制图片数量
|
|
258
|
+
if "topics" in params and len(params["topics"]) > 3:
|
|
259
|
+
params["topics"] = params["topics"][:3]
|
|
260
|
+
# 使用较小的尺寸
|
|
261
|
+
if "size" in params:
|
|
262
|
+
params["size"] = "1280x720"
|
|
263
|
+
step["params"] = params
|
|
264
|
+
|
|
265
|
+
optimized_steps.append(step)
|
|
266
|
+
|
|
267
|
+
plan["tools_sequence"] = optimized_steps
|
|
268
|
+
plan["estimated_time"] = "1-2分钟"
|
|
269
|
+
|
|
270
|
+
return plan
|