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

@@ -44,6 +44,7 @@ class SmartWebAgent:
44
44
  verbose: bool = False,
45
45
  show_plan_stream: bool = False,
46
46
  save_output: bool = False,
47
+ force_single_page: bool = True,
47
48
  ):
48
49
  self.project_directory = project_directory
49
50
  self.model = model
@@ -51,6 +52,7 @@ class SmartWebAgent:
51
52
  self.verbose = verbose # 新增:详细输出模式
52
53
  self.show_plan_stream = show_plan_stream # 新增:流式显示计划生成
53
54
  self.save_output = save_output # 新增:保存输出到日志
55
+ self.force_single_page = force_single_page
54
56
  api_key, base_url = self._resolve_api_credentials()
55
57
  self.client = self._build_client(api_key, base_url)
56
58
 
@@ -786,6 +788,9 @@ class SmartWebAgent:
786
788
  2. 用户未列出具体的页面名称
787
789
  3. 用户未要求复杂的功能
788
790
  """
791
+ if getattr(self, "force_single_page", False):
792
+ return True
793
+
789
794
  lower_input = user_input.lower()
790
795
 
791
796
  # 检查是否明确要求多页面
@@ -879,32 +884,51 @@ class SmartWebAgent:
879
884
  "menu",
880
885
  ]
881
886
  )
882
-
883
- if is_restaurant:
884
- nav_structure = [
885
- {"name": "首页", "href": "index.html"},
886
- {"name": "菜单", "href": "menu.html"},
887
- {"name": "关于我们", "href": "about.html"},
888
- {"name": "联系我们", "href": "contact.html"},
887
+ is_mall = any(
888
+ k in key
889
+ for k in [
890
+ "购物",
891
+ "商场",
892
+ "mall",
893
+ "plaza",
894
+ "零售",
895
+ "shopping",
889
896
  ]
897
+ )
898
+
899
+ single_page_mode = getattr(self, "force_single_page", False)
900
+
901
+ if not single_page_mode:
902
+ if is_restaurant:
903
+ nav_structure = [
904
+ {"name": "首页", "href": "index.html"},
905
+ {"name": "菜单", "href": "menu.html"},
906
+ {"name": "关于我们", "href": "about.html"},
907
+ {"name": "联系我们", "href": "contact.html"},
908
+ ]
909
+ else:
910
+ nav_structure = [
911
+ {"name": "首页", "href": "index.html"},
912
+ {"name": "关于我们", "href": "about.html"},
913
+ {"name": "服务体系", "href": "services.html"},
914
+ {"name": "联系我们", "href": "contact.html"},
915
+ ]
916
+
917
+ def build_nav(active_href: str) -> list:
918
+ return [
919
+ {**item, "active": item["href"] == active_href}
920
+ for item in nav_structure
921
+ ]
890
922
  else:
891
- nav_structure = [
892
- {"name": "首页", "href": "index.html"},
893
- {"name": "关于我们", "href": "about.html"},
894
- {"name": "服务体系", "href": "services.html"},
895
- {"name": "联系我们", "href": "contact.html"},
896
- ]
923
+ nav_structure = []
897
924
 
898
- def build_nav(active_href: str) -> list:
899
- return [
900
- {**item, "active": item["href"] == active_href}
901
- for item in nav_structure
902
- ]
925
+ def build_nav(_: str) -> list:
926
+ return []
903
927
 
904
928
  plan: dict = {
905
929
  "task_analysis": "离线回退:根据描述创建现代化基础网站骨架",
906
930
  "project_name": project_name,
907
- "site_type": "restaurant" if is_restaurant else "basic-landing",
931
+ "site_type": "restaurant" if is_restaurant else ("shopping-mall" if is_mall else "basic-landing"),
908
932
  "design_style": "modern, responsive, glassmorphism",
909
933
  "color_scheme": {
910
934
  "primary": "#0d6efd",
@@ -930,17 +954,19 @@ class SmartWebAgent:
930
954
  }
931
955
  )
932
956
  # 为不同站点类型提供更有“品牌感”的默认配色
933
- cafe_palette = (
934
- {
935
- "primary": "#6B4F3A", # Coffee Brown
936
- "secondary": "#8C5E3C", # Deep Caramel
937
- "accent": "#D0A97A", # Latte Cream
938
- "neutral_light": "#F7F3EE",
939
- "neutral_dark": "#201A16",
940
- }
941
- if is_restaurant
942
- else {"primary": "#0d6efd", "secondary": "#6c757d", "accent": "#6610f2"}
943
- )
957
+ cafe_palette = {
958
+ "primary": "#6B4F3A",
959
+ "secondary": "#8C5E3C",
960
+ "accent": "#D0A97A",
961
+ "neutral_light": "#F7F3EE",
962
+ "neutral_dark": "#201A16",
963
+ } if is_restaurant else {
964
+ "primary": "#1E3A8A" if is_mall else "#0d6efd",
965
+ "secondary": "#4338CA" if is_mall else "#6c757d",
966
+ "accent": "#F59E0B" if is_mall else "#6610f2",
967
+ "neutral_light": "#F3F4F6",
968
+ "neutral_dark": "#111827" if is_mall else "#212529",
969
+ }
944
970
 
945
971
  steps.append(
946
972
  {
@@ -969,223 +995,639 @@ class SmartWebAgent:
969
995
  )
970
996
 
971
997
  # 页面创建
998
+ pretty_name = project_name.title()
999
+
1000
+ def build_single_page_sections() -> list[str]:
1001
+ """生成单页滚动式布局的各个版块"""
1002
+ hero_topic = "artisanal coffee shop interior, warm light, cinematic"
1003
+ lead_text = "星光级烘焙、当季风味和沉浸式空间,打造城市中的第三生活场景。"
1004
+ primary_cta = "查看菜单"
1005
+ secondary_cta = "预订座位"
1006
+ if is_mall:
1007
+ hero_topic = "luxury shopping mall atrium at night, cinematic lighting, visitors"
1008
+ lead_text = "星光购物中心聚合潮流零售、夜间餐饮与家庭娱乐,一站式点亮城市生活。"
1009
+ primary_cta = "了解亮点"
1010
+ secondary_cta = "预约参观"
1011
+ elif not is_restaurant:
1012
+ hero_topic = "modern business hero, gradient lighting, professional team"
1013
+ lead_text = "用策略、设计与工程思维,为品牌打造兼顾颜值与增长的数字体验。"
1014
+ primary_cta = "查看服务"
1015
+ secondary_cta = "联系团队"
1016
+
1017
+ sections = [
1018
+ textwrap.dedent(
1019
+ f"""
1020
+ <header id="hero" class="hero hero-ultra hero-overlay section text-center" data-bg-topic="{hero_topic}" data-parallax="0.25">
1021
+ <div class="overlay"></div>
1022
+ <div class="container hero-inner">
1023
+ <span class="badge badge-soft mb-3">全新体验</span>
1024
+ <h1 class="display-5 mb-3">{pretty_name}</h1>
1025
+ <p class="section-lead mx-auto">{lead_text}</p>
1026
+ <div class="mt-4 d-flex justify-content-center gap-3 flex-wrap">
1027
+ <a class="btn btn-gradient btn-lg px-4" href="#services">{primary_cta}</a>
1028
+ <a class="btn btn-outline-light btn-lg px-4" href="#contact">{secondary_cta}</a>
1029
+ </div>
1030
+ </div>
1031
+ </header>
1032
+ """
1033
+ ).strip()
1034
+ ]
1035
+
1036
+ if is_mall:
1037
+ sections.append(
1038
+ textwrap.dedent(
1039
+ """
1040
+ <section id="services" class="section">
1041
+ <div class="container">
1042
+ <div class="row g-4">
1043
+ <div class="col-md-4">
1044
+ <div class="feature-card glass h-100 p-4 reveal" data-tilt>
1045
+ <div class="icon-badge bg-warning mb-3">🌃</div>
1046
+ <h2 class="h5 mb-2">夜色生活目的地</h2>
1047
+ <p class="text-muted small mb-0">夜间餐饮、潮玩市集与沉浸演出齐聚,打造城市夜经济主场。</p>
1048
+ </div>
1049
+ </div>
1050
+ <div class="col-md-4">
1051
+ <div class="feature-card glass h-100 p-4 reveal" data-tilt>
1052
+ <div class="icon-badge bg-primary mb-3">🛍️</div>
1053
+ <h2 class="h5 mb-2">国际品牌旗舰矩阵</h2>
1054
+ <p class="text-muted small mb-0">200+ 国际与设计师品牌入驻,专属造型顾问与会员定制服务。</p>
1055
+ </div>
1056
+ </div>
1057
+ <div class="col-md-4">
1058
+ <div class="feature-card glass h-100 p-4 reveal" data-tilt>
1059
+ <div class="icon-badge bg-success mb-3">🎡</div>
1060
+ <h2 class="h5 mb-2">家庭娱乐社交场</h2>
1061
+ <p class="text-muted small mb-0">亲子探索乐园、家庭影院与艺术展演,满足全龄客群周末生活。</p>
1062
+ </div>
1063
+ </div>
1064
+ </div>
1065
+ </div>
1066
+ </section>
1067
+ """
1068
+ ).strip()
1069
+ )
1070
+ sections.append(
1071
+ textwrap.dedent(
1072
+ """
1073
+ <section id="flagship" class="section section-alt">
1074
+ <div class="container">
1075
+ <h2 class="h3 text-center mb-4">主力店铺</h2>
1076
+ <div class="row g-4">
1077
+ <article class="col-lg-4">
1078
+ <div class="card h-100 p-4 shadow-soft reveal" data-tilt>
1079
+ <img data-topic="luxury fashion flagship store interior" alt="星光旗舰时装馆" class="rounded-4 shadow-sm mb-3">
1080
+ <h3 class="h6 mb-2">星光旗舰时装馆</h3>
1081
+ <p class="text-muted small mb-0">轻奢首发系列、私享试衣间与造型顾问服务,重塑高端购物体验。</p>
1082
+ </div>
1083
+ </article>
1084
+ <article class="col-lg-4">
1085
+ <div class="card h-100 p-4 shadow-soft reveal" data-tilt>
1086
+ <img data-topic="gourmet food court night market neon" alt="夜焰美食街区" class="rounded-4 shadow-sm mb-3">
1087
+ <h3 class="h6 mb-2">夜焰美食街区</h3>
1088
+ <p class="text-muted small mb-0">40+ 全球料理、全天候营业与快闪主题活动,夜间精彩不停。</p>
1089
+ </div>
1090
+ </article>
1091
+ <article class="col-lg-4">
1092
+ <div class="card h-100 p-4 shadow-soft reveal" data-tilt>
1093
+ <img data-topic="family entertainment center modern play" alt="星空亲子探索乐园" class="rounded-4 shadow-sm mb-3">
1094
+ <h3 class="h6 mb-2">星空亲子探索乐园</h3>
1095
+ <p class="text-muted small mb-0">互动装置、科学实验与家庭影院,亲子共创灵感与回忆。</p>
1096
+ </div>
1097
+ </article>
1098
+ </div>
1099
+ </div>
1100
+ </section>
1101
+ """
1102
+ ).strip()
1103
+ )
1104
+ sections.append(
1105
+ textwrap.dedent(
1106
+ """
1107
+ <section id="membership" class="section">
1108
+ <div class="container">
1109
+ <h2 class="h3 text-center mb-4">会员礼遇</h2>
1110
+ <div class="row g-4">
1111
+ <div class="col-md-4">
1112
+ <div class="membership-card shadow-soft h-100 p-4 border-gradient">
1113
+ <h3 class="h6 mb-3">星耀卡 · ¥699 / 年</h3>
1114
+ <p class="text-muted small mb-0">免费停车 120 小时 · 生日礼遇 · 合作品牌限量优惠券。</p>
1115
+ </div>
1116
+ </div>
1117
+ <div class="col-md-4">
1118
+ <div class="membership-card shadow-soft h-100 p-4 border-gradient highlight">
1119
+ <h3 class="h6 mb-3">星耀黑金卡 · ¥1999 / 年</h3>
1120
+ <p class="text-muted small mb-0">私人购物顾问 · VIP 休息室 · 礼宾代客泊车 · 首发活动优先席位。</p>
1121
+ </div>
1122
+ </div>
1123
+ <div class="col-md-4">
1124
+ <div class="membership-card shadow-soft h-100 p-4 border-gradient">
1125
+ <h3 class="h6 mb-3">星悦家庭卡 · ¥1299 / 年</h3>
1126
+ <p class="text-muted small mb-0">亲子乐园畅玩 · 周末家庭影院 · 主题课程折扣与节日惊喜。</p>
1127
+ </div>
1128
+ </div>
1129
+ </div>
1130
+ </div>
1131
+ </section>
1132
+ """
1133
+ ).strip()
1134
+ )
1135
+ sections.append(
1136
+ textwrap.dedent(
1137
+ """
1138
+ <section id="stories" class="section section-alt">
1139
+ <div class="container">
1140
+ <h2 class="h3 text-center mb-4">顾客见证</h2>
1141
+ <div class="row g-4">
1142
+ <article class="col-md-6">
1143
+ <div class="testimonial-card glass h-100 p-4">
1144
+ <div class="d-flex align-items-center gap-3 mb-3">
1145
+ <img data-topic="fashion influencer portrait studio" alt="顾客" class="avatar rounded-circle shadow-sm">
1146
+ <div>
1147
+ <div class="fw-semibold">刘倩 · 时尚博主</div>
1148
+ <small class="text-muted">星耀黑金卡会员</small>
1149
+ </div>
1150
+ </div>
1151
+ <p class="text-muted small mb-0">“这里像是城市生活方式策展地,每月都能找到惊喜活动。”</p>
1152
+ </div>
1153
+ </article>
1154
+ <article class="col-md-6">
1155
+ <div class="testimonial-card glass h-100 p-4">
1156
+ <div class="d-flex align-items-center gap-3 mb-3">
1157
+ <img data-topic="happy asian family portrait lifestyle" alt="家庭用户" class="avatar rounded-circle shadow-sm">
1158
+ <div>
1159
+ <div class="fw-semibold">周末家庭 · 城市新锐</div>
1160
+ <small class="text-muted">星悦家庭卡会员</small>
1161
+ </div>
1162
+ </div>
1163
+ <p class="text-muted small mb-0">“亲子乐园与夜焰美食街已成为周末必打卡,活动福利超值。”</p>
1164
+ </div>
1165
+ </article>
1166
+ </div>
1167
+ </div>
1168
+ </section>
1169
+ """
1170
+ ).strip()
1171
+ )
1172
+ elif is_restaurant:
1173
+ sections.append(
1174
+ textwrap.dedent(
1175
+ """
1176
+ <section id="menu" class="section">
1177
+ <div class="container">
1178
+ <div class="row align-items-center g-5">
1179
+ <div class="col-lg-5">
1180
+ <h2 class="h3 mb-3">招牌菜单 · 星光甄选</h2>
1181
+ <p class="text-muted">每日现烘豆种、季节限定特调与匠心甜点,恰到好处的甜与苦。</p>
1182
+ <ul class="list-unstyled vstack gap-3 mt-4 text-muted small">
1183
+ <li>☕️ 精品单品手冲 · 果酸层次丰富</li>
1184
+ <li>🥐 法式可颂每日新鲜出炉</li>
1185
+ <li>🥤 冷萃与气泡咖啡带来夏日灵感</li>
1186
+ </ul>
1187
+ </div>
1188
+ <div class="col-lg-7">
1189
+ <div class="row g-4">
1190
+ <article class="col-sm-6">
1191
+ <div class="glass p-4 h-100 reveal" data-tilt>
1192
+ <img data-topic="signature latte art, golden hour" alt="拿铁" class="rounded shadow-sm mb-3">
1193
+ <div class="d-flex justify-content-between">
1194
+ <h3 class="h5 mb-0">星光拿铁</h3>
1195
+ <span class="badge bg-primary-subtle text-primary fw-semibold">¥36</span>
1196
+ </div>
1197
+ <p class="text-muted mt-2 small">丝滑奶泡配自家烘焙浓缩,口感层层递进。</p>
1198
+ </div>
1199
+ </article>
1200
+ <article class="col-sm-6">
1201
+ <div class="glass p-4 h-100 reveal" data-tilt>
1202
+ <img data-topic="pour over coffee setup minimal" alt="手冲咖啡" class="rounded shadow-sm mb-3">
1203
+ <div class="d-flex justify-content-between">
1204
+ <h3 class="h5 mb-0">北海道手冲</h3>
1205
+ <span class="badge bg-primary-subtle text-primary fw-semibold">¥42</span>
1206
+ </div>
1207
+ <p class="text-muted mt-2 small">慢萃 16 小时带来清爽果香与轻盈坚果尾韵。</p>
1208
+ </div>
1209
+ </article>
1210
+ </div>
1211
+ </div>
1212
+ </div>
1213
+ </div>
1214
+ </section>
1215
+ """
1216
+ ).strip()
1217
+ )
1218
+ sections.append(
1219
+ textwrap.dedent(
1220
+ f"""
1221
+ <section id="about" class="section section-alt">
1222
+ <div class="container">
1223
+ <div class="row g-4 align-items-center">
1224
+ <div class="col-lg-6">
1225
+ <img data-topic="coffee roastery studio, warm tone" alt="{pretty_name} 空间" class="rounded-4 shadow-lg w-100">
1226
+ </div>
1227
+ <div class="col-lg-6">
1228
+ <h2 class="h3 mb-3">空间故事 · 一杯咖啡的旅程</h2>
1229
+ <p class="text-muted">我们从产地挑豆、烘焙到杯中,所有步骤都由资深咖啡师亲自把关,确保每一口都带着温度与惊喜。</p>
1230
+ <div class="row g-3 mt-4 text-muted small">
1231
+ <div class="col-sm-6"><div class="glass p-3 h-100">🌱 直采可持续农场</div></div>
1232
+ <div class="col-sm-6"><div class="glass p-3 h-100">👩‍🍳 世界冠军团队驻店</div></div>
1233
+ <div class="col-sm-6"><div class="glass p-3 h-100">🎵 手工黑胶沉浸配乐</div></div>
1234
+ <div class="col-sm-6"><div class="glass p-3 h-100">📍 城市中最松弛的角落</div></div>
1235
+ </div>
1236
+ </div>
1237
+ </div>
1238
+ </div>
1239
+ </section>
1240
+ """
1241
+ ).strip()
1242
+ )
1243
+ else:
1244
+ sections.append(
1245
+ textwrap.dedent(
1246
+ """
1247
+ <section id="about" class="section">
1248
+ <div class="container">
1249
+ <div class="row g-4 align-items-center">
1250
+ <div class="col-lg-5">
1251
+ <h2 class="h3 mb-3">关于我们 · Strategy × Design × Tech</h2>
1252
+ <p class="text-muted">十年数字化品牌经验,聚焦增长体验、可持续设计系统与落地执行力。</p>
1253
+ <ul class="list-unstyled vstack gap-2 small text-muted">
1254
+ <li>✔️ 服务 80+ 创新品牌与上市企业</li>
1255
+ <li>✔️ 多端一致的组件化设计系统</li>
1256
+ <li>✔️ 数据驱动的转化优化闭环</li>
1257
+ </ul>
1258
+ </div>
1259
+ <div class="col-lg-7">
1260
+ <div class="row g-3">
1261
+ <div class="col-sm-6">
1262
+ <div class="glass p-4 h-100 reveal" data-tilt>
1263
+ <span class="display-5 fw-bold text-primary">98%</span>
1264
+ <p class="text-muted small mb-0">客户满意度,连续三年领跑行业。</p>
1265
+ </div>
1266
+ </div>
1267
+ <div class="col-sm-6">
1268
+ <div class="glass p-4 h-100 reveal" data-tilt>
1269
+ <span class="display-5 fw-bold text-primary">120+</span>
1270
+ <p class="text-muted small mb-0">完成项目,总计覆盖 12 个细分行业。</p>
1271
+ </div>
1272
+ </div>
1273
+ </div>
1274
+ </div>
1275
+ </div>
1276
+ </div>
1277
+ </section>
1278
+ """
1279
+ ).strip()
1280
+ )
1281
+
1282
+ if not is_mall:
1283
+ sections.append(
1284
+ textwrap.dedent(
1285
+ """
1286
+ <section id="services" class="section">
1287
+ <div class="container">
1288
+ <h2 class="h3 text-center mb-3">服务矩阵</h2>
1289
+ <p class="section-lead text-center text-muted mb-5">从品牌策略、视觉系统到线上交付,一站式协同推进。</p>
1290
+ <div class="row g-4">
1291
+ <div class="col-md-4">
1292
+ <div class="service-card glass p-4 h-100 reveal" data-tilt>
1293
+ <img data-topic="creative workshop, design sprint" alt="策略工作坊" class="rounded shadow-sm mb-3">
1294
+ <h3 class="h5">策略定位</h3>
1295
+ <p class="text-muted small mb-0">品牌北极星梳理、价值主张共创与产品架构重构。</p>
1296
+ </div>
1297
+ </div>
1298
+ <div class="col-md-4">
1299
+ <div class="service-card glass p-4 h-100 reveal" data-tilt>
1300
+ <img data-topic="modern ui design system" alt="设计系统" class="rounded shadow-sm mb-3">
1301
+ <h3 class="h5">设计系统</h3>
1302
+ <p class="text-muted small mb-0">跨平台组件库、主题配色、动态规范与品牌资产管理。</p>
1303
+ </div>
1304
+ </div>
1305
+ <div class="col-md-4">
1306
+ <div class="service-card glass p-4 h-100 reveal" data-tilt>
1307
+ <img data-topic="web development team collaboration" alt="工程交付" class="rounded shadow-sm mb-3">
1308
+ <h3 class="h5">工程落地</h3>
1309
+ <p class="text-muted small mb-0">高性能前端、内容管理、可观测性与持续迭代机制。</p>
1310
+ </div>
1311
+ </div>
1312
+ </div>
1313
+ </div>
1314
+ </section>
1315
+ """
1316
+ ).strip()
1317
+ )
1318
+
1319
+ sections.append(
1320
+ textwrap.dedent(
1321
+ f"""
1322
+ <section id="contact" class="section section-sm">
1323
+ <div class="container">
1324
+ <div class="row g-4 align-items-center">
1325
+ <div class="col-lg-5">
1326
+ <h2 class="h4 mb-3">马上联系 · 预约体验</h2>
1327
+ <p class="text-muted">留下联系方式,我们将在 24 小时内回电,提供定制化方案。</p>
1328
+ <ul class="list-unstyled small text-muted">
1329
+ <li>📞 电话:400-123-4567</li>
1330
+ <li>📍 地址:上海市静安区星光路 88 号</li>
1331
+ <li>🕒 营业:周一至周日 09:00 - 22:00</li>
1332
+ </ul>
1333
+ </div>
1334
+ <div class="col-lg-7">
1335
+ <form class="glass p-4 rounded-4 shadow-sm row g-3">
1336
+ <div class="col-md-6">
1337
+ <label class="form-label">姓名</label>
1338
+ <input type="text" class="form-control" placeholder="请输入姓名" required>
1339
+ </div>
1340
+ <div class="col-md-6">
1341
+ <label class="form-label">联系方式</label>
1342
+ <input type="tel" class="form-control" placeholder="手机或邮箱" required>
1343
+ </div>
1344
+ <div class="col-12">
1345
+ <label class="form-label">需求概述</label>
1346
+ <textarea class="form-control" rows="3" placeholder="请说明项目类型、预算或时间节点"></textarea>
1347
+ </div>
1348
+ <div class="col-12 d-grid">
1349
+ <button class="btn btn-primary" type="submit">提交信息</button>
1350
+ </div>
1351
+ </form>
1352
+ </div>
1353
+ </div>
1354
+ </div>
1355
+ </section>
1356
+ """
1357
+ ).strip()
1358
+ )
1359
+
1360
+ sections.append(
1361
+ textwrap.dedent(
1362
+ f"""
1363
+ <footer class="footer-creative text-center py-4">
1364
+ <div class="container small text-muted">
1365
+ <div>{pretty_name} · 现代品牌体验实验室</div>
1366
+ <div class="mt-1">© {datetime.now().year} All rights reserved.</div>
1367
+ </div>
1368
+ </footer>
1369
+ """
1370
+ ).strip()
1371
+ )
1372
+ return sections
1373
+
1374
+ single_page_sections = build_single_page_sections() if single_page_mode else None
1375
+
1376
+ create_index_params = {
1377
+ "file_path": os.path.join(project_root, "index.html"),
1378
+ "title": pretty_name,
1379
+ "content": "",
1380
+ "style": "ultra_modern",
1381
+ }
1382
+ if single_page_sections:
1383
+ create_index_params["sections"] = single_page_sections
1384
+
972
1385
  steps.append(
973
1386
  {
974
1387
  "step": 4,
975
1388
  "tool": "create_html_file",
976
- "params": {
977
- "file_path": os.path.join(project_root, "index.html"),
978
- "title": project_name.title(),
979
- "content": "",
980
- "style": "ultra_modern",
981
- },
1389
+ "params": create_index_params,
982
1390
  "description": "创建首页",
983
1391
  "rationale": "生成结构化HTML并挂接CSS/JS",
984
1392
  }
985
1393
  )
986
1394
 
987
- if is_restaurant:
988
- steps.append(
989
- {
990
- "step": 5,
991
- "tool": "create_menu_page",
992
- "params": {
993
- "file_path": os.path.join(project_root, "menu.html"),
994
- "project_name": project_name.title(),
995
- },
996
- "description": "创建菜单页面",
997
- "rationale": "餐饮类站点专用模板,分类清晰、价格醒目",
998
- }
999
- )
1000
- steps.append(
1001
- {
1002
- "step": 6,
1003
- "tool": "create_about_page",
1004
- "params": {
1005
- "file_path": os.path.join(project_root, "about.html"),
1006
- "project_name": project_name.title(),
1007
- "context": {
1008
- "site_type": "restaurant",
1009
- "project_description": plan.get("task_analysis"),
1010
- "nav_items": build_nav("about.html"),
1395
+ if not single_page_mode:
1396
+ if is_restaurant:
1397
+ steps.append(
1398
+ {
1399
+ "step": 5,
1400
+ "tool": "create_menu_page",
1401
+ "params": {
1402
+ "file_path": os.path.join(project_root, "menu.html"),
1403
+ "project_name": pretty_name,
1011
1404
  },
1012
- },
1013
- "description": "创建关于页面",
1014
- "rationale": "品牌故事、理念与团队展示",
1015
- }
1016
- )
1017
- steps.append(
1018
- {
1019
- "step": 7,
1020
- "tool": "create_contact_page",
1021
- "params": {
1022
- "file_path": os.path.join(project_root, "contact.html"),
1023
- "project_name": project_name.title(),
1024
- },
1025
- "description": "创建联系页面",
1026
- "rationale": "营业时间、地址、联系表单与地图占位",
1027
- }
1028
- )
1029
- else:
1030
- steps.append(
1031
- {
1032
- "step": 5,
1033
- "tool": "create_about_page",
1034
- "params": {
1035
- "file_path": os.path.join(project_root, "about.html"),
1036
- "project_name": project_name.title(),
1037
- "context": {
1038
- "site_type": plan.get("site_type"),
1039
- "project_description": plan.get("task_analysis"),
1040
- "nav_items": build_nav("about.html"),
1405
+ "description": "创建菜单页面",
1406
+ "rationale": "餐饮类站点专用模板,分类清晰、价格醒目",
1407
+ }
1408
+ )
1409
+ steps.append(
1410
+ {
1411
+ "step": 6,
1412
+ "tool": "create_about_page",
1413
+ "params": {
1414
+ "file_path": os.path.join(project_root, "about.html"),
1415
+ "project_name": pretty_name,
1416
+ "context": {
1417
+ "site_type": "restaurant",
1418
+ "project_description": plan.get("task_analysis"),
1419
+ "nav_items": build_nav("about.html"),
1420
+ },
1041
1421
  },
1042
- },
1043
- "description": "创建关于页面",
1044
- "rationale": "补充团队故事、理念与品牌背景",
1045
- }
1046
- )
1422
+ "description": "创建关于页面",
1423
+ "rationale": "品牌故事、理念与团队展示",
1424
+ }
1425
+ )
1426
+ steps.append(
1427
+ {
1428
+ "step": 7,
1429
+ "tool": "create_contact_page",
1430
+ "params": {
1431
+ "file_path": os.path.join(project_root, "contact.html"),
1432
+ "project_name": pretty_name,
1433
+ },
1434
+ "description": "创建联系页面",
1435
+ "rationale": "营业时间、地址、联系表单与地图占位",
1436
+ }
1437
+ )
1438
+ else:
1439
+ steps.append(
1440
+ {
1441
+ "step": 5,
1442
+ "tool": "create_about_page",
1443
+ "params": {
1444
+ "file_path": os.path.join(project_root, "about.html"),
1445
+ "project_name": pretty_name,
1446
+ "context": {
1447
+ "site_type": plan.get("site_type"),
1448
+ "project_description": plan.get("task_analysis"),
1449
+ "nav_items": build_nav("about.html"),
1450
+ },
1451
+ },
1452
+ "description": "创建关于页面",
1453
+ "rationale": "补充团队故事、理念与品牌背景",
1454
+ }
1455
+ )
1456
+ steps.append(
1457
+ {
1458
+ "step": 6,
1459
+ "tool": "create_html_file",
1460
+ "params": {
1461
+ "file_path": os.path.join(project_root, "services.html"),
1462
+ "title": f"{pretty_name} · 服务体系",
1463
+ "content": "",
1464
+ "style": "creative_gradient",
1465
+ },
1466
+ "description": "创建服务页面",
1467
+ "rationale": "呈现产品/服务矩阵与亮点",
1468
+ }
1469
+ )
1470
+ steps.append(
1471
+ {
1472
+ "step": 7,
1473
+ "tool": "create_html_file",
1474
+ "params": {
1475
+ "file_path": os.path.join(project_root, "contact.html"),
1476
+ "title": f"{pretty_name} · 联系我们",
1477
+ "content": "",
1478
+ "style": "minimal_elegant",
1479
+ },
1480
+ "description": "创建联系页面",
1481
+ "rationale": "提供表单、地图与联系方式",
1482
+ }
1483
+ )
1484
+
1485
+ # 框架与导航
1486
+ steps.append(
1487
+ {
1488
+ "step": 5 if single_page_mode else 8,
1489
+ "tool": "add_bootstrap",
1490
+ "params": {"project_path": project_root},
1491
+ "description": "接入Bootstrap以增强组件与响应式",
1492
+ "rationale": "快速获得导航栏、栅格与表单样式",
1493
+ }
1494
+ )
1495
+
1496
+ if not single_page_mode:
1497
+ for idx, page in enumerate(
1498
+ ["index.html"]
1499
+ + (
1500
+ ["menu.html", "about.html", "contact.html"]
1501
+ if is_restaurant
1502
+ else ["about.html", "services.html", "contact.html"]
1503
+ ),
1504
+ start=9,
1505
+ ):
1506
+ steps.append(
1507
+ {
1508
+ "step": idx,
1509
+ "tool": "create_responsive_navbar",
1510
+ "params": {
1511
+ "file_path": os.path.join(project_root, page),
1512
+ "brand_name": pretty_name,
1513
+ "nav_items": build_nav(page),
1514
+ },
1515
+ "description": f"同步 {page} 导航",
1516
+ "rationale": "保持跨页面导航一致、定位正确",
1517
+ }
1518
+ )
1519
+
1520
+ # 图片注入
1521
+ next_step = steps[-1]["step"] + 1
1522
+ if single_page_mode:
1523
+ if is_restaurant:
1524
+ sections_topics = ["signature coffee bar interior", "artisan baristas working", "minimalist cafe seating", "latte art macro"]
1525
+ elif is_mall:
1526
+ sections_topics = [
1527
+ "luxury shopping mall atrium night, cinematic lighting",
1528
+ "gourmet food court lifestyle photography",
1529
+ "vip shopping lounge interior, warm lighting",
1530
+ "family entertainment center vibrant"
1531
+ ]
1532
+ else:
1533
+ sections_topics = ["modern business team collaboration", "digital product design workspace", "technology innovation hub", "professional meeting room"]
1047
1534
  steps.append(
1048
1535
  {
1049
- "step": 6,
1050
- "tool": "create_html_file",
1536
+ "step": next_step,
1537
+ "tool": "inject_images",
1051
1538
  "params": {
1052
- "file_path": os.path.join(project_root, "services.html"),
1053
- "title": f"{project_name.title()} · 服务体系",
1054
- "content": "",
1055
- "style": "creative_gradient",
1539
+ "file_path": os.path.join(project_root, "index.html"),
1540
+ "provider": "pollinations",
1541
+ "topics": sections_topics,
1542
+ "size": "1280x720",
1543
+ "seed": 42,
1544
+ "save": True,
1545
+ "subdir": "assets/images",
1546
+ "prefix": "index",
1056
1547
  },
1057
- "description": "创建服务页面",
1058
- "rationale": "呈现产品/服务矩阵与亮点",
1548
+ "description": "注入首页图片",
1549
+ "rationale": "为单页面各版块填充视觉素材",
1059
1550
  }
1060
1551
  )
1552
+ next_step += 1
1553
+ else:
1061
1554
  steps.append(
1062
1555
  {
1063
- "step": 7,
1064
- "tool": "create_html_file",
1556
+ "step": next_step,
1557
+ "tool": "inject_images",
1065
1558
  "params": {
1066
- "file_path": os.path.join(project_root, "contact.html"),
1067
- "title": f"{project_name.title()} · 联系我们",
1068
- "content": "",
1069
- "style": "minimal_elegant",
1559
+ "file_path": os.path.join(project_root, "index.html"),
1560
+ "provider": "pollinations",
1561
+ "topics": ["cozy coffee hero, gradient glassmorphism"],
1562
+ "size": "1200x800",
1563
+ "seed": 42,
1564
+ "save": True,
1565
+ "subdir": "assets/images",
1566
+ "prefix": "img",
1070
1567
  },
1071
- "description": "创建联系页面",
1072
- "rationale": "提供表单、地图与联系方式",
1568
+ "description": "首页图片注入",
1569
+ "rationale": "让页面更具视觉表现",
1073
1570
  }
1074
1571
  )
1075
-
1076
- # 框架与导航
1077
- steps.append(
1078
- {
1079
- "step": 8,
1080
- "tool": "add_bootstrap",
1081
- "params": {"project_path": project_root},
1082
- "description": "接入Bootstrap以增强组件与响应式",
1083
- "rationale": "快速获得导航栏、栅格与表单样式",
1084
- }
1085
- )
1086
- # 为每个页面插入导航
1087
- for idx, page in enumerate(
1088
- ["index.html"]
1089
- + (
1090
- ["menu.html", "about.html", "contact.html"]
1091
- if is_restaurant
1092
- else ["about.html", "services.html", "contact.html"]
1093
- ),
1094
- start=9,
1095
- ):
1572
+ next_step += 1
1573
+ if is_restaurant:
1574
+ steps.append(
1575
+ {
1576
+ "step": next_step,
1577
+ "tool": "inject_images",
1578
+ "params": {
1579
+ "file_path": os.path.join(project_root, "menu.html"),
1580
+ "provider": "pollinations",
1581
+ "topics": ["latte art", "espresso shot", "pastry dessert"],
1582
+ "size": "1024x768",
1583
+ "seed": 7,
1584
+ "save": True,
1585
+ "subdir": "assets/images",
1586
+ "prefix": "menu",
1587
+ },
1588
+ "description": "为菜单页注入图片",
1589
+ "rationale": "展示咖啡/甜点,更贴合餐饮场景",
1590
+ }
1591
+ )
1592
+ next_step += 1
1096
1593
  steps.append(
1097
1594
  {
1098
- "step": idx,
1099
- "tool": "create_responsive_navbar",
1595
+ "step": next_step,
1596
+ "tool": "inject_images",
1100
1597
  "params": {
1101
- "file_path": os.path.join(project_root, page),
1102
- "brand_name": project_name.title(),
1103
- "nav_items": build_nav(page),
1598
+ "file_path": os.path.join(project_root, "about.html"),
1599
+ "provider": "pollinations",
1600
+ "topics": ["barista portrait", "coffee roasting", "cafe community"],
1601
+ "size": "1024x768",
1602
+ "seed": 11,
1603
+ "save": True,
1604
+ "subdir": "assets/images",
1605
+ "prefix": "about",
1104
1606
  },
1105
- "description": f"同步 {page} 导航",
1106
- "rationale": "保持跨页面导航一致、定位正确",
1607
+ "description": "关于页图片注入",
1608
+ "rationale": "呈现团队与品牌氛围",
1107
1609
  }
1108
1610
  )
1109
-
1110
- # 图片注入
1111
- next_step = steps[-1]["step"] + 1
1112
- steps.append(
1113
- {
1114
- "step": next_step,
1115
- "tool": "inject_images",
1116
- "params": {
1117
- "file_path": os.path.join(project_root, "index.html"),
1118
- "provider": "pollinations",
1119
- "topics": ["cozy coffee hero, gradient glassmorphism"],
1120
- "size": "1200x800",
1121
- "seed": 42,
1122
- "save": True,
1123
- "subdir": "assets/images",
1124
- "prefix": "img",
1125
- },
1126
- "description": "首页图片注入",
1127
- "rationale": "让页面更具视觉表现",
1128
- }
1129
- )
1130
- next_step += 1
1131
- if is_restaurant:
1611
+ next_step += 1
1132
1612
  steps.append(
1133
1613
  {
1134
1614
  "step": next_step,
1135
1615
  "tool": "inject_images",
1136
1616
  "params": {
1137
- "file_path": os.path.join(project_root, "menu.html"),
1617
+ "file_path": os.path.join(project_root, "contact.html"),
1138
1618
  "provider": "pollinations",
1139
- "topics": ["latte art", "espresso shot", "pastry dessert"],
1619
+ "topics": ["coffee shop storefront", "map pin"],
1140
1620
  "size": "1024x768",
1141
- "seed": 7,
1621
+ "seed": 13,
1142
1622
  "save": True,
1143
1623
  "subdir": "assets/images",
1144
- "prefix": "menu",
1624
+ "prefix": "contact",
1145
1625
  },
1146
- "description": "为菜单页注入图片",
1147
- "rationale": "展示咖啡/甜点,更贴合餐饮场景",
1626
+ "description": "联系页图片注入",
1627
+ "rationale": "增强门店信息表现",
1148
1628
  }
1149
1629
  )
1150
1630
  next_step += 1
1151
- steps.append(
1152
- {
1153
- "step": next_step,
1154
- "tool": "inject_images",
1155
- "params": {
1156
- "file_path": os.path.join(project_root, "about.html"),
1157
- "provider": "pollinations",
1158
- "topics": ["barista portrait", "coffee roasting", "cafe community"],
1159
- "size": "1024x768",
1160
- "seed": 11,
1161
- "save": True,
1162
- "subdir": "assets/images",
1163
- "prefix": "about",
1164
- },
1165
- "description": "关于页图片注入",
1166
- "rationale": "呈现团队与品牌氛围",
1167
- }
1168
- )
1169
- next_step += 1
1170
- steps.append(
1171
- {
1172
- "step": next_step,
1173
- "tool": "inject_images",
1174
- "params": {
1175
- "file_path": os.path.join(project_root, "contact.html"),
1176
- "provider": "pollinations",
1177
- "topics": ["coffee shop storefront", "map pin"],
1178
- "size": "1024x768",
1179
- "seed": 13,
1180
- "save": True,
1181
- "subdir": "assets/images",
1182
- "prefix": "contact",
1183
- },
1184
- "description": "联系页图片注入",
1185
- "rationale": "增强门店信息表现",
1186
- }
1187
- )
1188
- next_step += 1
1189
1631
 
1190
1632
  # 校验与预览
1191
1633
  steps.append(
@@ -1239,6 +1681,8 @@ class SmartWebAgent:
1239
1681
  if not isinstance(plan, dict):
1240
1682
  return plan
1241
1683
 
1684
+ single_page_mode = getattr(self, "force_single_page", False)
1685
+
1242
1686
  seq = plan.get("tools_sequence")
1243
1687
  if not isinstance(seq, list):
1244
1688
  seq = []
@@ -1286,6 +1730,25 @@ class SmartWebAgent:
1286
1730
  obj["params"] = {"file_path": p} if isinstance(p, str) else {}
1287
1731
  all_steps.append(obj)
1288
1732
 
1733
+ if single_page_mode:
1734
+ filtered_steps: list[dict] = []
1735
+ for obj in all_steps:
1736
+ tool = obj.get("tool")
1737
+ if tool in {
1738
+ "create_menu_page",
1739
+ "create_about_page",
1740
+ "create_contact_page",
1741
+ "create_responsive_navbar",
1742
+ }:
1743
+ continue
1744
+ params = obj.get("params") if isinstance(obj.get("params"), dict) else {}
1745
+ file_path = params.get("file_path")
1746
+ if file_path and str(file_path).lower().endswith(".html"):
1747
+ if os.path.basename(str(file_path)).lower() != "index.html":
1748
+ continue
1749
+ filtered_steps.append(obj)
1750
+ all_steps = filtered_steps
1751
+
1289
1752
  # 为导航中引用的页面补齐生成步骤(若规划中缺失)
1290
1753
  page_tools = {
1291
1754
  "create_html_file",
@@ -1307,36 +1770,38 @@ class SmartWebAgent:
1307
1770
  nav_required: dict[str, str] = {}
1308
1771
  nav_step_refs: list[tuple[int, int]] = [] # (index, step)
1309
1772
  nav_templates: list[dict[str, Any]] = []
1310
- for idx, obj in enumerate(all_steps):
1311
- if obj.get("tool") != "create_responsive_navbar":
1312
- continue
1313
- params = obj.get("params") if isinstance(obj.get("params"), dict) else {}
1314
- nav_items = params.get("nav_items") or []
1315
- if isinstance(nav_items, list):
1316
- cleaned_items = []
1317
- for item in nav_items:
1318
- if not isinstance(item, dict):
1773
+
1774
+ if not single_page_mode:
1775
+ for idx, obj in enumerate(all_steps):
1776
+ if obj.get("tool") != "create_responsive_navbar":
1777
+ continue
1778
+ params = obj.get("params") if isinstance(obj.get("params"), dict) else {}
1779
+ nav_items = params.get("nav_items") or []
1780
+ if isinstance(nav_items, list):
1781
+ cleaned_items = []
1782
+ for item in nav_items:
1783
+ if not isinstance(item, dict):
1784
+ cleaned_items.append(item)
1785
+ continue
1786
+ href = str(item.get("href", "")).strip()
1787
+ if href and href.lower().endswith(".html"):
1788
+ normalized = href.lstrip("./")
1789
+ basename = os.path.basename(normalized)
1790
+ if basename != href:
1791
+ item = dict(item)
1792
+ item["href"] = basename
1793
+ nav_required.setdefault(
1794
+ basename, str(item.get("name") or basename)
1795
+ )
1319
1796
  cleaned_items.append(item)
1320
- continue
1321
- href = str(item.get("href", "")).strip()
1322
- if href and href.lower().endswith(".html"):
1323
- normalized = href.lstrip("./")
1324
- basename = os.path.basename(normalized)
1325
- if basename != href:
1326
- item = dict(item)
1327
- item["href"] = basename
1328
- nav_required.setdefault(
1329
- basename, str(item.get("name") or basename)
1330
- )
1331
- cleaned_items.append(item)
1332
- params["nav_items"] = cleaned_items
1333
- nav_step_refs.append((idx, obj.get("step", idx + 1)))
1334
- nav_templates.append(
1335
- {
1336
- "params": copy.deepcopy(params) if isinstance(params, dict) else {},
1337
- "step": obj.get("step", idx + 1),
1338
- }
1339
- )
1797
+ params["nav_items"] = cleaned_items
1798
+ nav_step_refs.append((idx, obj.get("step", idx + 1)))
1799
+ nav_templates.append(
1800
+ {
1801
+ "params": copy.deepcopy(params) if isinstance(params, dict) else {},
1802
+ "step": obj.get("step", idx + 1),
1803
+ }
1804
+ )
1340
1805
 
1341
1806
  if nav_required:
1342
1807
  project_slug = plan.get("project_name") or "web-project"
@@ -2332,7 +2797,7 @@ class SmartWebAgent:
2332
2797
  # 最后一步:按工具白名单过滤参数,剔除 description/rationale 等无关键
2333
2798
  allowed = {
2334
2799
  "create_project_structure": {"project_name", "project_path"},
2335
- "create_html_file": {"file_path", "title", "content"},
2800
+ "create_html_file": {"file_path", "title", "content", "style", "sections"},
2336
2801
  "create_css_file": {"file_path", "content"},
2337
2802
  "create_js_file": {"file_path", "content"},
2338
2803
  "add_bootstrap": {"project_path"},
@@ -2388,6 +2853,11 @@ class SmartWebAgent:
2388
2853
  @click.option("--verbose", is_flag=True, help="显示详细执行信息")
2389
2854
  @click.option("--save-output", is_flag=True, help="保存所有生成的内容到日志文件")
2390
2855
  @click.option("--stream", is_flag=True, help="启用流式输出显示AI思考过程")
2856
+ @click.option(
2857
+ "--single-page/--multi-page",
2858
+ default=True,
2859
+ help="强制生成单页面滚动站点;如需保留多页面流程可切换为 --multi-page",
2860
+ )
2391
2861
  def main(
2392
2862
  project_directory,
2393
2863
  model,
@@ -2398,6 +2868,7 @@ def main(
2398
2868
  verbose,
2399
2869
  save_output,
2400
2870
  stream,
2871
+ single_page,
2401
2872
  ):
2402
2873
  """
2403
2874
  🧠 智能批量Web Agent - 2025年最佳实践
@@ -2425,6 +2896,7 @@ def main(
2425
2896
  verbose=verbose,
2426
2897
  show_plan_stream=stream,
2427
2898
  save_output=save_output,
2899
+ force_single_page=single_page,
2428
2900
  )
2429
2901
 
2430
2902
  print("🧠 智能批量Web Agent启动!")