htmlgen-mcp 0.2.0__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.
- MCP/__init__.py +6 -0
- MCP/web_agent_server.py +1257 -0
- agents/__init__.py +6 -0
- agents/smart_web_agent.py +2384 -0
- agents/web_tools/__init__.py +84 -0
- agents/web_tools/bootstrap.py +49 -0
- agents/web_tools/browser.py +28 -0
- agents/web_tools/colors.py +137 -0
- agents/web_tools/css.py +1473 -0
- agents/web_tools/edgeone_deploy.py +541 -0
- agents/web_tools/html_templates.py +1770 -0
- agents/web_tools/images.py +600 -0
- agents/web_tools/images_fixed.py +195 -0
- agents/web_tools/js.py +235 -0
- agents/web_tools/navigation.py +386 -0
- agents/web_tools/project.py +34 -0
- agents/web_tools/simple_builder.py +346 -0
- agents/web_tools/simple_css.py +475 -0
- agents/web_tools/simple_js.py +454 -0
- agents/web_tools/simple_templates.py +220 -0
- agents/web_tools/validation.py +65 -0
- htmlgen_mcp-0.2.0.dist-info/METADATA +171 -0
- htmlgen_mcp-0.2.0.dist-info/RECORD +26 -0
- htmlgen_mcp-0.2.0.dist-info/WHEEL +5 -0
- htmlgen_mcp-0.2.0.dist-info/entry_points.txt +2 -0
- htmlgen_mcp-0.2.0.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""网页工具包模块化导出"""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from .bootstrap import add_bootstrap
|
|
5
|
+
from .browser import open_in_browser, start_live_server
|
|
6
|
+
from .css import create_css_file
|
|
7
|
+
from .html_templates import (
|
|
8
|
+
create_about_page,
|
|
9
|
+
create_contact_page,
|
|
10
|
+
create_html_file,
|
|
11
|
+
create_menu_page,
|
|
12
|
+
)
|
|
13
|
+
from .images import fetch_generated_images, inject_images
|
|
14
|
+
from .js import create_js_file
|
|
15
|
+
from .navigation import create_responsive_navbar
|
|
16
|
+
from .project import create_project_structure
|
|
17
|
+
from .validation import check_mobile_friendly, validate_html
|
|
18
|
+
from .colors import generate_color_scheme
|
|
19
|
+
|
|
20
|
+
# 新增简单模板支持
|
|
21
|
+
from .simple_templates import (
|
|
22
|
+
create_simple_html_file,
|
|
23
|
+
create_blank_html_file,
|
|
24
|
+
create_landing_page,
|
|
25
|
+
create_blog_page,
|
|
26
|
+
)
|
|
27
|
+
from .simple_css import (
|
|
28
|
+
create_clean_css_file,
|
|
29
|
+
create_landing_css_file,
|
|
30
|
+
create_blog_css_file,
|
|
31
|
+
create_minimal_css_file,
|
|
32
|
+
)
|
|
33
|
+
from .simple_js import (
|
|
34
|
+
create_simple_js_file,
|
|
35
|
+
create_minimal_js_file,
|
|
36
|
+
create_interactive_js_file,
|
|
37
|
+
)
|
|
38
|
+
from .simple_builder import (
|
|
39
|
+
create_simple_website,
|
|
40
|
+
create_simple_page_set,
|
|
41
|
+
)
|
|
42
|
+
from .edgeone_deploy import (
|
|
43
|
+
deploy_folder_or_zip_to_edgeone,
|
|
44
|
+
EdgeOneDeployer,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
__all__ = [
|
|
48
|
+
"create_project_structure",
|
|
49
|
+
"create_html_file",
|
|
50
|
+
"create_menu_page",
|
|
51
|
+
"create_about_page",
|
|
52
|
+
"create_contact_page",
|
|
53
|
+
"create_css_file",
|
|
54
|
+
"create_js_file",
|
|
55
|
+
"add_bootstrap",
|
|
56
|
+
"create_responsive_navbar",
|
|
57
|
+
"fetch_generated_images",
|
|
58
|
+
"inject_images",
|
|
59
|
+
"open_in_browser",
|
|
60
|
+
"start_live_server",
|
|
61
|
+
"validate_html",
|
|
62
|
+
"check_mobile_friendly",
|
|
63
|
+
"generate_color_scheme",
|
|
64
|
+
# 简单模板
|
|
65
|
+
"create_simple_html_file",
|
|
66
|
+
"create_blank_html_file",
|
|
67
|
+
"create_landing_page",
|
|
68
|
+
"create_blog_page",
|
|
69
|
+
# 简单CSS
|
|
70
|
+
"create_clean_css_file",
|
|
71
|
+
"create_landing_css_file",
|
|
72
|
+
"create_blog_css_file",
|
|
73
|
+
"create_minimal_css_file",
|
|
74
|
+
# 简单JS
|
|
75
|
+
"create_simple_js_file",
|
|
76
|
+
"create_minimal_js_file",
|
|
77
|
+
"create_interactive_js_file",
|
|
78
|
+
# 简单网站构建器
|
|
79
|
+
"create_simple_website",
|
|
80
|
+
"create_simple_page_set",
|
|
81
|
+
# EdgeOne部署工具
|
|
82
|
+
"deploy_folder_or_zip_to_edgeone",
|
|
83
|
+
"EdgeOneDeployer",
|
|
84
|
+
]
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""Bootstrap 相关工具"""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import re
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def add_bootstrap(project_path: str):
|
|
9
|
+
"""为项目添加Bootstrap CSS/JS(递归处理所有HTML)"""
|
|
10
|
+
try:
|
|
11
|
+
base = Path(project_path)
|
|
12
|
+
html_files = list(base.rglob("*.html"))
|
|
13
|
+
|
|
14
|
+
bootstrap_css = '<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">'
|
|
15
|
+
bootstrap_js = '<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>'
|
|
16
|
+
|
|
17
|
+
for html_file in html_files:
|
|
18
|
+
with open(html_file, "r", encoding="utf-8") as f:
|
|
19
|
+
content = f.read()
|
|
20
|
+
|
|
21
|
+
# 先移除所有重复的 bootstrap 片段,稍后统一按规范插入一次
|
|
22
|
+
content = re.sub(re.escape(bootstrap_css) + r"\s*", "", content)
|
|
23
|
+
content = re.sub(re.escape(bootstrap_js) + r"\s*", "", content)
|
|
24
|
+
|
|
25
|
+
# 添加Bootstrap CSS到head(带兜底)
|
|
26
|
+
if "</head>" in content:
|
|
27
|
+
content = content.replace("</head>", f" {bootstrap_css}\n</head>")
|
|
28
|
+
elif "<head>" in content:
|
|
29
|
+
content = content.replace("<head>", f"<head>\n {bootstrap_css}\n")
|
|
30
|
+
else:
|
|
31
|
+
# 没有head,前置插入
|
|
32
|
+
content = bootstrap_css + "\n" + content
|
|
33
|
+
|
|
34
|
+
# 添加Bootstrap JS到body末尾(带兜底)
|
|
35
|
+
if "</body>" in content:
|
|
36
|
+
content = content.replace("</body>", f" {bootstrap_js}\n</body>")
|
|
37
|
+
else:
|
|
38
|
+
content = content + "\n" + bootstrap_js
|
|
39
|
+
|
|
40
|
+
with open(html_file, "w", encoding="utf-8") as f:
|
|
41
|
+
f.write(content)
|
|
42
|
+
|
|
43
|
+
return f"Bootstrap已添加到 {len(html_files)} 个HTML文件"
|
|
44
|
+
except Exception as e:
|
|
45
|
+
raise RuntimeError(f"添加Bootstrap失败: {str(e)}")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
__all__ = ["add_bootstrap"]
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""浏览器预览与本地服务器工具"""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
import subprocess
|
|
6
|
+
import webbrowser
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def open_in_browser(file_path: str):
|
|
10
|
+
"""在默认浏览器中打开HTML文件"""
|
|
11
|
+
try:
|
|
12
|
+
abs_path = os.path.abspath(file_path)
|
|
13
|
+
webbrowser.open(f"file://{abs_path}")
|
|
14
|
+
return f"已在浏览器中打开: {abs_path}"
|
|
15
|
+
except Exception as e:
|
|
16
|
+
return f"打开浏览器失败: {str(e)}"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def start_live_server(directory: str, port: int = 8000):
|
|
20
|
+
"""启动简单的HTTP服务器用于预览"""
|
|
21
|
+
try:
|
|
22
|
+
cmd = f"cd {directory} && python -m http.server {port}"
|
|
23
|
+
subprocess.Popen(cmd, shell=True)
|
|
24
|
+
return f"开发服务器已启动: http://localhost:{port}"
|
|
25
|
+
except Exception as e:
|
|
26
|
+
return f"启动服务器失败: {str(e)}"
|
|
27
|
+
|
|
28
|
+
__all__ = ["open_in_browser", "start_live_server"]
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"""配色相关的工具函数与调色板生成逻辑"""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import colorsys
|
|
5
|
+
import json
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _normalize_hex_color(color: str) -> str:
|
|
9
|
+
"""规范化十六进制颜色字符串,支持 #RGB 与 #RRGGBB"""
|
|
10
|
+
if not color:
|
|
11
|
+
return "#000000"
|
|
12
|
+
value = color.strip().lstrip('#')
|
|
13
|
+
if len(value) == 3:
|
|
14
|
+
value = ''.join(ch * 2 for ch in value)
|
|
15
|
+
if len(value) != 6:
|
|
16
|
+
return "#000000"
|
|
17
|
+
try:
|
|
18
|
+
int(value, 16)
|
|
19
|
+
except ValueError:
|
|
20
|
+
return "#000000"
|
|
21
|
+
return f"#{value.lower()}"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _hex_to_rgb_tuple(color: str) -> tuple[int, int, int]:
|
|
25
|
+
"""将十六进制颜色转换为 RGB 元组"""
|
|
26
|
+
normalized = _normalize_hex_color(color)[1:]
|
|
27
|
+
return tuple(int(normalized[i:i + 2], 16) for i in (0, 2, 4))
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _hex_to_rgb_string(color: str) -> str:
|
|
31
|
+
"""将十六进制颜色转换为 r, g, b 字符串"""
|
|
32
|
+
r, g, b = _hex_to_rgb_tuple(color)
|
|
33
|
+
return f"{r}, {g}, {b}"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _hls_to_hex(h: float, l: float, s: float) -> str:
|
|
37
|
+
"""将 HLS 颜色转换为十六进制颜色字符串"""
|
|
38
|
+
r, g, b = colorsys.hls_to_rgb(h % 1.0, max(0.0, min(1.0, l)), max(0.0, min(1.0, s)))
|
|
39
|
+
return "#" + ''.join(f"{int(round(channel * 255)):02x}" for channel in (r, g, b))
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _shift_lightness(color: str, delta: float) -> str:
|
|
43
|
+
"""调节颜色亮度"""
|
|
44
|
+
r, g, b = [c / 255.0 for c in _hex_to_rgb_tuple(color)]
|
|
45
|
+
h, l, s = colorsys.rgb_to_hls(r, g, b)
|
|
46
|
+
return _hls_to_hex(h, max(0.0, min(1.0, l + delta)), s)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _shift_hue(color: str, delta: float, saturation_scale: float = 1.0, lightness_delta: float = 0.0) -> str:
|
|
50
|
+
"""在 HLS 空间中调整色相/饱和/亮度"""
|
|
51
|
+
r, g, b = [c / 255.0 for c in _hex_to_rgb_tuple(color)]
|
|
52
|
+
h, l, s = colorsys.rgb_to_hls(r, g, b)
|
|
53
|
+
return _hls_to_hex(
|
|
54
|
+
h + delta,
|
|
55
|
+
max(0.0, min(1.0, l + lightness_delta)),
|
|
56
|
+
max(0.0, min(1.0, s * saturation_scale)),
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def generate_color_scheme(base_color: str = "#007bff") -> str:
|
|
61
|
+
"""生成进阶配色方案,返回JSON与CSS示例"""
|
|
62
|
+
try:
|
|
63
|
+
base = _normalize_hex_color(base_color or "#007bff")
|
|
64
|
+
accent = _shift_hue(base, 0.12, 1.05, 0.02)
|
|
65
|
+
accent_alt = _shift_hue(base, -0.08, 1.08, 0.08)
|
|
66
|
+
secondary = _shift_hue(base, 0.55, 0.7, 0.04)
|
|
67
|
+
success = _shift_hue(base, 0.33, 0.6, 0.08)
|
|
68
|
+
warning = _shift_hue(base, -0.18, 0.55, 0.18)
|
|
69
|
+
danger = _shift_hue(base, -0.08, 0.8, -0.22)
|
|
70
|
+
|
|
71
|
+
palette = {
|
|
72
|
+
"primary": base,
|
|
73
|
+
"primary_light": _shift_lightness(base, 0.2),
|
|
74
|
+
"primary_dark": _shift_lightness(base, -0.2),
|
|
75
|
+
"accent": accent,
|
|
76
|
+
"accent_light": _shift_lightness(accent, 0.18),
|
|
77
|
+
"accent_alt": accent_alt,
|
|
78
|
+
"secondary": secondary,
|
|
79
|
+
"neutral_light": "#f6f7fb",
|
|
80
|
+
"neutral_dark": "#171a23",
|
|
81
|
+
"dark_primary": _shift_lightness(base, -0.1),
|
|
82
|
+
"dark_accent": _shift_lightness(accent, -0.15),
|
|
83
|
+
"support": {
|
|
84
|
+
"success": success,
|
|
85
|
+
"warning": warning,
|
|
86
|
+
"danger": danger,
|
|
87
|
+
"info": _shift_hue(base, 0.2, 0.8, 0.05),
|
|
88
|
+
},
|
|
89
|
+
"gradients": {
|
|
90
|
+
"primary": f"linear-gradient(135deg, {base} 0%, {_shift_lightness(accent, 0.25)} 100%)",
|
|
91
|
+
"warm": f"linear-gradient(135deg, {warning} 0%, {_shift_lightness(warning, 0.18)} 100%)",
|
|
92
|
+
"cool": f"linear-gradient(135deg, {secondary} 0%, {accent} 100%)",
|
|
93
|
+
},
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
css_preview = (
|
|
97
|
+
f":root {{\n"
|
|
98
|
+
f" --primary: {palette['primary']};\n"
|
|
99
|
+
f" --primary-light: {palette['primary_light']};\n"
|
|
100
|
+
f" --primary-dark: {palette['primary_dark']};\n"
|
|
101
|
+
f" --accent: {palette['accent']};\n"
|
|
102
|
+
f" --accent-rgb: {_hex_to_rgb_string(palette['accent'])};\n"
|
|
103
|
+
f" --secondary: {palette['secondary']};\n"
|
|
104
|
+
f" --gray-50: {palette['neutral_light']};\n"
|
|
105
|
+
f" --gray-900: {palette['neutral_dark']};\n"
|
|
106
|
+
f" --gradient-primary: {palette['gradients']['primary']};\n"
|
|
107
|
+
f" --gradient-cool: {palette['gradients']['cool']};\n"
|
|
108
|
+
f"}}\n"
|
|
109
|
+
f":root[data-theme='dark'] {{\n"
|
|
110
|
+
f" --primary: {palette['dark_primary']};\n"
|
|
111
|
+
f" --accent: {palette['dark_accent']};\n"
|
|
112
|
+
f" --gradient-primary: linear-gradient(135deg, {palette['dark_primary']} 0%, {palette['dark_accent']} 100%);\n"
|
|
113
|
+
f"}}"
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
palette_json = json.dumps(palette, ensure_ascii=False, indent=2)
|
|
117
|
+
guidance = (
|
|
118
|
+
"配色方案生成完成。\n"
|
|
119
|
+
f"palette = {palette_json}\n\n"
|
|
120
|
+
"✅ 可用于 create_css_file(path, palette=palette) 自动写入 CSS 变量。\n"
|
|
121
|
+
"✅ 支持在 HTML/JS 中引用 palette['gradients'] 做背景或按钮。\n"
|
|
122
|
+
"CSS 变量示例:\n" + css_preview
|
|
123
|
+
)
|
|
124
|
+
return guidance
|
|
125
|
+
except Exception as exc: # noqa: BLE001
|
|
126
|
+
return f"生成配色方案失败: {str(exc)}"
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
__all__ = [
|
|
130
|
+
"generate_color_scheme",
|
|
131
|
+
"_normalize_hex_color",
|
|
132
|
+
"_hex_to_rgb_tuple",
|
|
133
|
+
"_hex_to_rgb_string",
|
|
134
|
+
"_hls_to_hex",
|
|
135
|
+
"_shift_lightness",
|
|
136
|
+
"_shift_hue",
|
|
137
|
+
]
|