htmlgen-mcp 0.3.5__py3-none-any.whl → 0.3.6__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/context_aware_executor.py +262 -0
- htmlgen_mcp/prompt_enhancer.py +240 -0
- htmlgen_mcp/web_agent_server.py +30 -27
- {htmlgen_mcp-0.3.5.dist-info → htmlgen_mcp-0.3.6.dist-info}/METADATA +1 -1
- {htmlgen_mcp-0.3.5.dist-info → htmlgen_mcp-0.3.6.dist-info}/RECORD +8 -6
- {htmlgen_mcp-0.3.5.dist-info → htmlgen_mcp-0.3.6.dist-info}/WHEEL +0 -0
- {htmlgen_mcp-0.3.5.dist-info → htmlgen_mcp-0.3.6.dist-info}/entry_points.txt +0 -0
- {htmlgen_mcp-0.3.5.dist-info → htmlgen_mcp-0.3.6.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
"""上下文感知的执行器 - 确保 context_content 被正确使用"""
|
|
2
|
+
import json
|
|
3
|
+
from typing import Dict, Any, Optional
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ContextAwareExecutor:
|
|
7
|
+
"""确保上下文内容在执行过程中被正确传递和使用"""
|
|
8
|
+
|
|
9
|
+
@staticmethod
|
|
10
|
+
def inject_context_to_tools(plan: Dict[str, Any], context_content: str) -> Dict[str, Any]:
|
|
11
|
+
"""
|
|
12
|
+
将上下文内容注入到工具调用序列中
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
plan: 执行计划
|
|
16
|
+
context_content: 上下文内容(如咖啡馆列表)
|
|
17
|
+
|
|
18
|
+
Returns:
|
|
19
|
+
修改后的计划
|
|
20
|
+
"""
|
|
21
|
+
if not context_content:
|
|
22
|
+
return plan
|
|
23
|
+
|
|
24
|
+
# 获取工具序列
|
|
25
|
+
tools_sequence = plan.get("tools_sequence", [])
|
|
26
|
+
|
|
27
|
+
# 遍历每个工具调用,注入上下文
|
|
28
|
+
for tool in tools_sequence:
|
|
29
|
+
tool_name = tool.get("tool", "")
|
|
30
|
+
|
|
31
|
+
# 对于创建 HTML 文件的工具,注入具体内容
|
|
32
|
+
if tool_name == "create_html_file":
|
|
33
|
+
# 修改内容参数,确保包含实际数据
|
|
34
|
+
original_content = tool.get("parameters", {}).get("content", "")
|
|
35
|
+
|
|
36
|
+
# 如果是主页面,替换内容
|
|
37
|
+
if "index.html" in tool.get("parameters", {}).get("file_name", ""):
|
|
38
|
+
tool["parameters"]["content"] = generate_html_with_context(
|
|
39
|
+
context_content,
|
|
40
|
+
tool.get("parameters", {}).get("title", "网站")
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
# 对于创建内容的工具,也要注入上下文
|
|
44
|
+
elif tool_name in ["add_content_section", "create_content", "add_text_content"]:
|
|
45
|
+
# 确保内容参数包含实际数据
|
|
46
|
+
tool["parameters"]["context_data"] = context_content
|
|
47
|
+
|
|
48
|
+
return plan
|
|
49
|
+
|
|
50
|
+
@staticmethod
|
|
51
|
+
def enhance_prompt_with_context(prompt: str, context_content: str) -> str:
|
|
52
|
+
"""
|
|
53
|
+
增强提示词,明确要求使用上下文内容
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
prompt: 原始提示词
|
|
57
|
+
context_content: 上下文内容
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
增强后的提示词
|
|
61
|
+
"""
|
|
62
|
+
if not context_content:
|
|
63
|
+
return prompt
|
|
64
|
+
|
|
65
|
+
enhanced = f"""
|
|
66
|
+
{prompt}
|
|
67
|
+
|
|
68
|
+
【重要:必须使用以下具体数据】
|
|
69
|
+
以下是必须在网页中展示的实际内容,请完整地将这些信息整合到网页中:
|
|
70
|
+
|
|
71
|
+
{context_content}
|
|
72
|
+
|
|
73
|
+
要求:
|
|
74
|
+
1. 必须将上述所有咖啡馆信息完整展示在网页中
|
|
75
|
+
2. 使用卡片或列表形式展示每个咖啡馆
|
|
76
|
+
3. 包含咖啡馆名称和地址
|
|
77
|
+
4. 可以添加适当的样式和布局,但内容必须准确
|
|
78
|
+
5. 不要生成虚构的内容,只使用提供的实际数据
|
|
79
|
+
"""
|
|
80
|
+
return enhanced
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def generate_html_with_context(context_content: str, title: str = "咖啡馆指南") -> str:
|
|
84
|
+
"""
|
|
85
|
+
根据上下文内容生成 HTML
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
context_content: 咖啡馆列表等具体内容
|
|
89
|
+
title: 网站标题
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
完整的 HTML 内容
|
|
93
|
+
"""
|
|
94
|
+
# 解析咖啡馆信息
|
|
95
|
+
cafes = []
|
|
96
|
+
lines = context_content.split('\n')
|
|
97
|
+
current_cafe = {}
|
|
98
|
+
|
|
99
|
+
for line in lines:
|
|
100
|
+
line = line.strip()
|
|
101
|
+
if not line:
|
|
102
|
+
continue
|
|
103
|
+
|
|
104
|
+
# 识别咖啡馆名称(带序号的行)
|
|
105
|
+
if line[0].isdigit() and '. ' in line:
|
|
106
|
+
if current_cafe:
|
|
107
|
+
cafes.append(current_cafe)
|
|
108
|
+
# 提取咖啡馆名称
|
|
109
|
+
name = line.split('. ', 1)[1] if '. ' in line else line
|
|
110
|
+
current_cafe = {'name': name, 'address': ''}
|
|
111
|
+
|
|
112
|
+
# 识别地址(- 开头的行)
|
|
113
|
+
elif line.startswith('- 地址:'):
|
|
114
|
+
if current_cafe:
|
|
115
|
+
current_cafe['address'] = line.replace('- 地址:', '').strip()
|
|
116
|
+
|
|
117
|
+
# 添加最后一个咖啡馆
|
|
118
|
+
if current_cafe:
|
|
119
|
+
cafes.append(current_cafe)
|
|
120
|
+
|
|
121
|
+
# 生成 HTML
|
|
122
|
+
cafe_cards = []
|
|
123
|
+
for cafe in cafes:
|
|
124
|
+
card = f'''
|
|
125
|
+
<div class="col-md-6 col-lg-4 mb-4">
|
|
126
|
+
<div class="card h-100 shadow-sm">
|
|
127
|
+
<div class="card-body">
|
|
128
|
+
<h5 class="card-title">
|
|
129
|
+
<i class="bi bi-cup-hot-fill text-brown"></i> {cafe['name']}
|
|
130
|
+
</h5>
|
|
131
|
+
<p class="card-text">
|
|
132
|
+
<i class="bi bi-geo-alt-fill text-muted"></i>
|
|
133
|
+
<span class="text-muted">{cafe['address']}</span>
|
|
134
|
+
</p>
|
|
135
|
+
<a href="#" class="btn btn-outline-primary btn-sm">
|
|
136
|
+
<i class="bi bi-map"></i> 查看地图
|
|
137
|
+
</a>
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
</div>'''
|
|
141
|
+
cafe_cards.append(card)
|
|
142
|
+
|
|
143
|
+
html = f'''<!DOCTYPE html>
|
|
144
|
+
<html lang="zh-CN">
|
|
145
|
+
<head>
|
|
146
|
+
<meta charset="UTF-8">
|
|
147
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
148
|
+
<title>{title}</title>
|
|
149
|
+
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
150
|
+
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css" rel="stylesheet">
|
|
151
|
+
<link href="assets/css/style.css" rel="stylesheet">
|
|
152
|
+
<style>
|
|
153
|
+
.text-brown {{ color: #6f4e37; }}
|
|
154
|
+
.hero-section {{
|
|
155
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
156
|
+
color: white;
|
|
157
|
+
padding: 80px 0;
|
|
158
|
+
}}
|
|
159
|
+
.card {{
|
|
160
|
+
transition: transform 0.3s;
|
|
161
|
+
border-radius: 15px;
|
|
162
|
+
}}
|
|
163
|
+
.card:hover {{
|
|
164
|
+
transform: translateY(-5px);
|
|
165
|
+
}}
|
|
166
|
+
</style>
|
|
167
|
+
</head>
|
|
168
|
+
<body>
|
|
169
|
+
<!-- 导航栏 -->
|
|
170
|
+
<nav class="navbar navbar-expand-lg navbar-light bg-light shadow-sm">
|
|
171
|
+
<div class="container">
|
|
172
|
+
<a class="navbar-brand" href="#">
|
|
173
|
+
<i class="bi bi-cup-hot-fill text-brown"></i> {title}
|
|
174
|
+
</a>
|
|
175
|
+
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
|
176
|
+
<span class="navbar-toggler-icon"></span>
|
|
177
|
+
</button>
|
|
178
|
+
<div class="collapse navbar-collapse" id="navbarNav">
|
|
179
|
+
<ul class="navbar-nav ms-auto">
|
|
180
|
+
<li class="nav-item">
|
|
181
|
+
<a class="nav-link" href="#cafes">咖啡馆列表</a>
|
|
182
|
+
</li>
|
|
183
|
+
<li class="nav-item">
|
|
184
|
+
<a class="nav-link" href="#about">关于</a>
|
|
185
|
+
</li>
|
|
186
|
+
</ul>
|
|
187
|
+
</div>
|
|
188
|
+
</div>
|
|
189
|
+
</nav>
|
|
190
|
+
|
|
191
|
+
<!-- Hero 区域 -->
|
|
192
|
+
<section class="hero-section text-center">
|
|
193
|
+
<div class="container">
|
|
194
|
+
<h1 class="display-4 fw-bold mb-4">{title}</h1>
|
|
195
|
+
<p class="lead mb-4">探索大族广场周边的精品咖啡馆</p>
|
|
196
|
+
<p class="mb-4">共收录 {len(cafes)} 家咖啡馆,均在步行范围内</p>
|
|
197
|
+
<a href="#cafes" class="btn btn-light btn-lg">
|
|
198
|
+
<i class="bi bi-arrow-down-circle"></i> 浏览咖啡馆
|
|
199
|
+
</a>
|
|
200
|
+
</div>
|
|
201
|
+
</section>
|
|
202
|
+
|
|
203
|
+
<!-- 咖啡馆列表 -->
|
|
204
|
+
<section id="cafes" class="py-5">
|
|
205
|
+
<div class="container">
|
|
206
|
+
<h2 class="text-center mb-5">咖啡馆列表</h2>
|
|
207
|
+
<div class="row">
|
|
208
|
+
{"".join(cafe_cards)}
|
|
209
|
+
</div>
|
|
210
|
+
</div>
|
|
211
|
+
</section>
|
|
212
|
+
|
|
213
|
+
<!-- 关于区域 -->
|
|
214
|
+
<section id="about" class="py-5 bg-light">
|
|
215
|
+
<div class="container">
|
|
216
|
+
<div class="row align-items-center">
|
|
217
|
+
<div class="col-md-6">
|
|
218
|
+
<h2>关于本指南</h2>
|
|
219
|
+
<p class="lead">为您精选大族广场附近的咖啡馆</p>
|
|
220
|
+
<p>本指南收录了北京市大兴区大族广场周边1公里范围内的所有知名咖啡馆,包括星巴克、Peet's Coffee、M Stand等品牌,以及特色独立咖啡馆。</p>
|
|
221
|
+
<p>无论您是需要商务洽谈的安静环境,还是休闲放松的舒适空间,都能在这里找到合适的选择。</p>
|
|
222
|
+
</div>
|
|
223
|
+
<div class="col-md-6">
|
|
224
|
+
<div class="p-4 bg-white rounded shadow">
|
|
225
|
+
<h4><i class="bi bi-info-circle-fill text-primary"></i> 实用信息</h4>
|
|
226
|
+
<ul class="list-unstyled mt-3">
|
|
227
|
+
<li class="mb-2">
|
|
228
|
+
<i class="bi bi-geo-alt text-muted"></i>
|
|
229
|
+
位置:北京市大兴区荣华南路
|
|
230
|
+
</li>
|
|
231
|
+
<li class="mb-2">
|
|
232
|
+
<i class="bi bi-clock text-muted"></i>
|
|
233
|
+
营业时间:大部分 7:00-22:00
|
|
234
|
+
</li>
|
|
235
|
+
<li class="mb-2">
|
|
236
|
+
<i class="bi bi-wifi text-muted"></i>
|
|
237
|
+
设施:WiFi、充电插座
|
|
238
|
+
</li>
|
|
239
|
+
<li class="mb-2">
|
|
240
|
+
<i class="bi bi-car-front text-muted"></i>
|
|
241
|
+
交通:地铁亦庄线荣昌东街站
|
|
242
|
+
</li>
|
|
243
|
+
</ul>
|
|
244
|
+
</div>
|
|
245
|
+
</div>
|
|
246
|
+
</div>
|
|
247
|
+
</div>
|
|
248
|
+
</section>
|
|
249
|
+
|
|
250
|
+
<!-- 页脚 -->
|
|
251
|
+
<footer class="bg-dark text-white py-4 mt-5">
|
|
252
|
+
<div class="container text-center">
|
|
253
|
+
<p class="mb-0">© 2024 {title}. 信息仅供参考,请以实际为准。</p>
|
|
254
|
+
</div>
|
|
255
|
+
</footer>
|
|
256
|
+
|
|
257
|
+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
|
258
|
+
<script src="assets/js/main.js"></script>
|
|
259
|
+
</body>
|
|
260
|
+
</html>'''
|
|
261
|
+
|
|
262
|
+
return html
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
"""提示词增强模块 - 确保AI使用真实数据而非生成示例"""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class PromptEnhancer:
|
|
5
|
+
"""提示词增强器,用于改进AI对真实数据的处理"""
|
|
6
|
+
|
|
7
|
+
@staticmethod
|
|
8
|
+
def enhance_for_real_data(base_prompt: str, context_data: str = None) -> str:
|
|
9
|
+
"""
|
|
10
|
+
增强提示词,确保AI使用真实数据
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
base_prompt: 基础提示词
|
|
14
|
+
context_data: 上下文数据内容
|
|
15
|
+
|
|
16
|
+
Returns:
|
|
17
|
+
增强后的提示词
|
|
18
|
+
"""
|
|
19
|
+
if not context_data:
|
|
20
|
+
return base_prompt
|
|
21
|
+
|
|
22
|
+
# 分析数据类型
|
|
23
|
+
data_type = PromptEnhancer._analyze_data_type(context_data)
|
|
24
|
+
|
|
25
|
+
# 根据数据类型生成特定的指令
|
|
26
|
+
specific_instructions = PromptEnhancer._get_specific_instructions(data_type, context_data)
|
|
27
|
+
|
|
28
|
+
enhanced = f"""
|
|
29
|
+
{base_prompt}
|
|
30
|
+
|
|
31
|
+
【🔴 极其重要的数据使用规则 🔴】
|
|
32
|
+
=====================================
|
|
33
|
+
以下是必须严格遵守的数据使用规则:
|
|
34
|
+
|
|
35
|
+
1. 【数据来源】下面提供的是真实的业务数据,不是示例或模板
|
|
36
|
+
2. 【使用要求】必须100%使用这些数据,不得修改、省略或虚构
|
|
37
|
+
3. 【禁止行为】严禁生成以下虚构内容:
|
|
38
|
+
- ❌ 虚构的客户评价(如"设计质感与转化率提升明显")
|
|
39
|
+
- ❌ 虚构的定价方案(如"¥9,999起步套餐")
|
|
40
|
+
- ❌ 虚构的服务内容(如"品牌升级与重构")
|
|
41
|
+
- ❌ 占位符内容(如"Lorem ipsum"或"示例文本")
|
|
42
|
+
|
|
43
|
+
4. 【正确做法】:
|
|
44
|
+
- ✅ 完整展示所有提供的数据项
|
|
45
|
+
- ✅ 保持数据的原始格式和内容
|
|
46
|
+
- ✅ 使用合适的布局展示(卡片、列表、表格等)
|
|
47
|
+
- ✅ 可以添加导航、样式,但内容必须是提供的真实数据
|
|
48
|
+
|
|
49
|
+
【必须使用的真实数据】
|
|
50
|
+
=====================================
|
|
51
|
+
{context_data}
|
|
52
|
+
=====================================
|
|
53
|
+
|
|
54
|
+
{specific_instructions}
|
|
55
|
+
|
|
56
|
+
【工具调用要求】
|
|
57
|
+
=====================================
|
|
58
|
+
在调用以下工具时,必须包含真实数据:
|
|
59
|
+
- create_html_file: content参数必须包含上述真实数据
|
|
60
|
+
- add_content_section: 必须使用真实数据填充内容
|
|
61
|
+
- create_text_content: 文本内容必须来自上述数据
|
|
62
|
+
- add_hero_section: 标题和描述要反映真实业务
|
|
63
|
+
- create_card_grid: 卡片内容必须是真实数据项
|
|
64
|
+
|
|
65
|
+
【验证要求】
|
|
66
|
+
=====================================
|
|
67
|
+
生成的每个HTML文件都必须包含:
|
|
68
|
+
1. 完整的数据列表(不得遗漏任何一项)
|
|
69
|
+
2. 准确的名称和地址信息
|
|
70
|
+
3. 正确的数据展示格式
|
|
71
|
+
|
|
72
|
+
记住:这是一个数据展示任务,不是创意写作任务!
|
|
73
|
+
"""
|
|
74
|
+
return enhanced
|
|
75
|
+
|
|
76
|
+
@staticmethod
|
|
77
|
+
def _analyze_data_type(context_data: str) -> str:
|
|
78
|
+
"""
|
|
79
|
+
分析数据类型
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
context_data: 上下文数据
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
数据类型标识
|
|
86
|
+
"""
|
|
87
|
+
lower_data = context_data.lower()
|
|
88
|
+
|
|
89
|
+
# 检测不同类型的数据
|
|
90
|
+
if "咖啡" in context_data or "coffee" in lower_data or "店" in context_data:
|
|
91
|
+
if "地址" in context_data or "address" in lower_data:
|
|
92
|
+
return "store_list"
|
|
93
|
+
|
|
94
|
+
if "产品" in context_data or "product" in lower_data:
|
|
95
|
+
return "product_list"
|
|
96
|
+
|
|
97
|
+
if "菜单" in context_data or "menu" in lower_data:
|
|
98
|
+
return "menu_list"
|
|
99
|
+
|
|
100
|
+
if "价格" in context_data or "price" in lower_data:
|
|
101
|
+
return "pricing_list"
|
|
102
|
+
|
|
103
|
+
if "联系" in context_data or "contact" in lower_data:
|
|
104
|
+
return "contact_info"
|
|
105
|
+
|
|
106
|
+
return "general_list"
|
|
107
|
+
|
|
108
|
+
@staticmethod
|
|
109
|
+
def _get_specific_instructions(data_type: str, context_data: str) -> str:
|
|
110
|
+
"""
|
|
111
|
+
根据数据类型生成特定指令
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
data_type: 数据类型
|
|
115
|
+
context_data: 上下文数据
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
特定的指令
|
|
119
|
+
"""
|
|
120
|
+
# 计算数据项数量
|
|
121
|
+
item_count = context_data.count('\n1.') + context_data.count('\n2.') + \
|
|
122
|
+
context_data.count('\n3.') + context_data.count('\n-')
|
|
123
|
+
|
|
124
|
+
if data_type == "store_list":
|
|
125
|
+
return f"""
|
|
126
|
+
【针对店铺列表的特定要求】
|
|
127
|
+
- 必须展示所有{item_count}个店铺
|
|
128
|
+
- 每个店铺必须包含:名称、地址
|
|
129
|
+
- 使用卡片布局,每行2-3个
|
|
130
|
+
- 可以添加地图链接按钮
|
|
131
|
+
- 可以按区域或品牌分组展示
|
|
132
|
+
"""
|
|
133
|
+
|
|
134
|
+
elif data_type == "product_list":
|
|
135
|
+
return f"""
|
|
136
|
+
【针对产品列表的特定要求】
|
|
137
|
+
- 必须展示所有产品信息
|
|
138
|
+
- 保持原始的产品名称和描述
|
|
139
|
+
- 使用产品卡片或展示网格
|
|
140
|
+
- 可以添加产品图片占位符
|
|
141
|
+
"""
|
|
142
|
+
|
|
143
|
+
elif data_type == "menu_list":
|
|
144
|
+
return f"""
|
|
145
|
+
【针对菜单的特定要求】
|
|
146
|
+
- 必须展示完整菜单
|
|
147
|
+
- 保持原始的菜品名称和价格
|
|
148
|
+
- 可以按类别分组
|
|
149
|
+
- 使用清晰的表格或列表格式
|
|
150
|
+
"""
|
|
151
|
+
|
|
152
|
+
else:
|
|
153
|
+
return f"""
|
|
154
|
+
【通用数据展示要求】
|
|
155
|
+
- 必须展示所有数据项(共约{item_count}项)
|
|
156
|
+
- 保持数据的原始格式
|
|
157
|
+
- 使用适合的布局展示
|
|
158
|
+
- 不得添加虚构内容
|
|
159
|
+
"""
|
|
160
|
+
|
|
161
|
+
@staticmethod
|
|
162
|
+
def validate_content_usage(generated_content: str, original_data: str) -> dict:
|
|
163
|
+
"""
|
|
164
|
+
验证生成的内容是否正确使用了原始数据
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
generated_content: 生成的内容
|
|
168
|
+
original_data: 原始数据
|
|
169
|
+
|
|
170
|
+
Returns:
|
|
171
|
+
验证结果
|
|
172
|
+
"""
|
|
173
|
+
# 提取原始数据中的关键项
|
|
174
|
+
key_items = []
|
|
175
|
+
lines = original_data.split('\n')
|
|
176
|
+
for line in lines:
|
|
177
|
+
line = line.strip()
|
|
178
|
+
# 提取店名或关键信息
|
|
179
|
+
if '. ' in line and line[0].isdigit():
|
|
180
|
+
item = line.split('. ', 1)[1] if '. ' in line else line
|
|
181
|
+
if '(' in item:
|
|
182
|
+
item = item.split('(')[0].strip()
|
|
183
|
+
key_items.append(item)
|
|
184
|
+
elif '- 地址:' in line:
|
|
185
|
+
address = line.replace('- 地址:', '').strip()
|
|
186
|
+
key_items.append(address)
|
|
187
|
+
|
|
188
|
+
# 检查每个关键项是否在生成的内容中
|
|
189
|
+
missing_items = []
|
|
190
|
+
found_items = []
|
|
191
|
+
|
|
192
|
+
for item in key_items:
|
|
193
|
+
if item in generated_content:
|
|
194
|
+
found_items.append(item)
|
|
195
|
+
else:
|
|
196
|
+
missing_items.append(item)
|
|
197
|
+
|
|
198
|
+
# 检测虚构内容的特征
|
|
199
|
+
fake_content_patterns = [
|
|
200
|
+
"转化率提升",
|
|
201
|
+
"品牌形象",
|
|
202
|
+
"¥9,999",
|
|
203
|
+
"¥29,999",
|
|
204
|
+
"¥59,999",
|
|
205
|
+
"起步套餐",
|
|
206
|
+
"专业套餐",
|
|
207
|
+
"旗舰套餐",
|
|
208
|
+
"Alex Chen",
|
|
209
|
+
"Liang Wu",
|
|
210
|
+
"Yvonne Zhao",
|
|
211
|
+
"设计质感",
|
|
212
|
+
"交付质量",
|
|
213
|
+
"Lorem ipsum",
|
|
214
|
+
"示例文本"
|
|
215
|
+
]
|
|
216
|
+
|
|
217
|
+
detected_fake = [pattern for pattern in fake_content_patterns
|
|
218
|
+
if pattern in generated_content]
|
|
219
|
+
|
|
220
|
+
return {
|
|
221
|
+
"valid": len(missing_items) == 0 and len(detected_fake) == 0,
|
|
222
|
+
"found_items": found_items,
|
|
223
|
+
"missing_items": missing_items,
|
|
224
|
+
"detected_fake_content": detected_fake,
|
|
225
|
+
"coverage_rate": len(found_items) / len(key_items) if key_items else 0,
|
|
226
|
+
"has_fake_content": len(detected_fake) > 0
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
# 导出便捷函数
|
|
231
|
+
def enhance_prompt_for_real_data(prompt: str, context: str = None) -> str:
|
|
232
|
+
"""增强提示词以使用真实数据"""
|
|
233
|
+
enhancer = PromptEnhancer()
|
|
234
|
+
return enhancer.enhance_for_real_data(prompt, context)
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def validate_data_usage(content: str, original: str) -> dict:
|
|
238
|
+
"""验证数据使用情况"""
|
|
239
|
+
enhancer = PromptEnhancer()
|
|
240
|
+
return enhancer.validate_content_usage(content, original)
|
htmlgen_mcp/web_agent_server.py
CHANGED
|
@@ -33,6 +33,7 @@ from pathlib import Path
|
|
|
33
33
|
from htmlgen_mcp.agents.smart_web_agent import SmartWebAgent
|
|
34
34
|
from htmlgen_mcp.nas_storage import get_nas_storage
|
|
35
35
|
from htmlgen_mcp.nas_log_manager import get_nas_log_manager, ensure_job_log, log_progress, query_progress
|
|
36
|
+
from htmlgen_mcp.prompt_enhancer import enhance_prompt_for_real_data
|
|
36
37
|
from datetime import datetime
|
|
37
38
|
|
|
38
39
|
# 使用 NAS 作为默认存储路径
|
|
@@ -776,42 +777,45 @@ async def create_simple_site(
|
|
|
776
777
|
force_single_page=True,
|
|
777
778
|
)
|
|
778
779
|
|
|
779
|
-
#
|
|
780
|
-
|
|
780
|
+
# 如果有上下文内容,将其整合到描述中
|
|
781
|
+
enhanced_description = description
|
|
781
782
|
if context_data:
|
|
782
|
-
|
|
783
|
+
enhanced_description = f"""{description}
|
|
783
784
|
|
|
784
|
-
|
|
785
|
+
【必须使用的具体数据内容】:
|
|
785
786
|
{context_data}
|
|
786
787
|
|
|
787
|
-
|
|
788
|
+
【重要提示】:上述数据是真实的业务数据,必须完整准确地展示在网页中,不要生成虚构的示例内容。"""
|
|
788
789
|
|
|
789
|
-
|
|
790
|
+
# 构建改进的提示词,强调使用真实数据
|
|
791
|
+
simple_prompt = f"""请为以下需求创建一个网站,并严格使用提供的真实数据:
|
|
790
792
|
|
|
791
|
-
|
|
792
|
-
|
|
793
|
+
**网站标题**: {site_title}
|
|
794
|
+
**具体需求和数据**:
|
|
795
|
+
{enhanced_description}
|
|
793
796
|
|
|
794
|
-
|
|
795
|
-
1.
|
|
796
|
-
2.
|
|
797
|
-
3.
|
|
798
|
-
4.
|
|
799
|
-
5.
|
|
800
|
-
6. 智能图片集成,根据内容类型匹配合适主题
|
|
801
|
-
7. 如果有上下文内容,请充分利用这些信息来丰富网页内容
|
|
797
|
+
**执行要求**:
|
|
798
|
+
1. 【数据要求】如果提供了具体数据(如店铺列表、产品信息等),必须100%使用这些真实数据,不要创建虚构内容
|
|
799
|
+
2. 【内容展示】将所有提供的数据项完整展示,使用合适的布局(如卡片、列表、表格等)
|
|
800
|
+
3. 【样式设计】保持简洁美观,使用响应式设计
|
|
801
|
+
4. 【代码限制】CSS不超过300行,避免复杂特效
|
|
802
|
+
5. 【功能实现】包含基础交互功能(导航、滚动等)
|
|
802
803
|
|
|
803
|
-
|
|
804
|
-
|
|
804
|
+
**特别强调**:
|
|
805
|
+
- 当创建HTML内容时,必须使用上面提供的真实数据
|
|
806
|
+
- 不要生成"示例客户评价"、"虚拟定价方案"等占位内容
|
|
807
|
+
- 如果是咖啡馆列表,就展示真实的咖啡馆名称和地址
|
|
808
|
+
- 如果是产品信息,就展示真实的产品数据
|
|
809
|
+
- 每个create_html_file或add_content_section工具调用时,都要包含真实数据
|
|
805
810
|
|
|
806
|
-
|
|
807
|
-
- 每个步骤都要具体可执行
|
|
808
|
-
- 优先使用简单模板函数而非复杂模板
|
|
809
|
-
- 注重实用性和美观性的平衡
|
|
810
|
-
- 充分利用提供的上下文信息来生成个性化内容
|
|
811
|
+
请生成3-6个步骤的执行计划,确保每个步骤都能正确使用提供的数据。
|
|
811
812
|
"""
|
|
812
813
|
|
|
813
814
|
# 生成简化计划(仅规划,不执行)
|
|
814
|
-
|
|
815
|
+
# 传递强化后的提示词,确保AI使用真实数据
|
|
816
|
+
# 使用提示词增强器进一步强化
|
|
817
|
+
final_prompt = enhance_prompt_for_real_data(simple_prompt, context_data)
|
|
818
|
+
plan = agent._get_execution_plan(final_prompt)
|
|
815
819
|
|
|
816
820
|
# 在计划中标记为简单网站类型和相关信息
|
|
817
821
|
plan["site_type"] = "simple"
|
|
@@ -826,9 +830,8 @@ async def create_simple_site(
|
|
|
826
830
|
plan_id = str(uuid.uuid4())
|
|
827
831
|
|
|
828
832
|
# 构建完整的源描述(包含上下文)
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
source_description = f"{description}\n\n【附加内容】\n{context_data}"
|
|
833
|
+
# 使用enhanced_description以确保数据被传递
|
|
834
|
+
source_description = enhanced_description
|
|
832
835
|
|
|
833
836
|
# 在计划中添加源描述字段
|
|
834
837
|
plan["__source_description"] = source_description
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
htmlgen_mcp/__init__.py,sha256=8jambwGFxu8RNWes1BUEGDHErV-LcvDaABWqNja9GW0,114
|
|
2
2
|
htmlgen_mcp/config.py,sha256=Xd9naNKP1LfgOfOSXf2QbzKfrmByWvYsNP1OumDH25E,11249
|
|
3
|
+
htmlgen_mcp/context_aware_executor.py,sha256=BAbvUegjXi-j_j5AXnZ6u1QAXT_hoCv5ZH5brV7vte0,9908
|
|
3
4
|
htmlgen_mcp/improved_progress.py,sha256=7lhaPZRy1IbmCyniKeRMjFbICL_x5K8Vu57hA85IohA,13472
|
|
4
5
|
htmlgen_mcp/nas_log_manager.py,sha256=3vN074jtGP9czFWUrqLVM6upD7FScKPZRM0u6iUiz_8,10502
|
|
5
6
|
htmlgen_mcp/nas_storage.py,sha256=HpgROy53vrYiBiXsUJO56GCoYZdyYR15iVvOBqyp7Yc,11292
|
|
6
7
|
htmlgen_mcp/progress_tools.py,sha256=SOScPSr3hEv4rvGzqvwUcomEFiPhhNxJ7CbWURlFpBs,5067
|
|
7
8
|
htmlgen_mcp/progress_tracker.py,sha256=2TVduWNJJH08EQ7Vf9EpiwPjtp61JX7muSCdbGHZAfM,12210
|
|
9
|
+
htmlgen_mcp/prompt_enhancer.py,sha256=8UIxt45vSNarS5uqfxC5thOfnGY7luDs2YjHZRx1GAM,7976
|
|
8
10
|
htmlgen_mcp/sse_optimizations.py,sha256=_UTpgLtxgNAiiEkO5lPihOi1-eEQk6R4ejNParufrrc,6932
|
|
9
|
-
htmlgen_mcp/web_agent_server.py,sha256=
|
|
11
|
+
htmlgen_mcp/web_agent_server.py,sha256=JQPBM2uupyGHZWpSJ-QFQa9U7O4knJr12V4l5GlDBSI,49130
|
|
10
12
|
htmlgen_mcp/agents/__init__.py,sha256=Xydfjzw9s9O6I5Ixx6EmsTdXu26136NDPUAqt9B1hzE,121
|
|
11
13
|
htmlgen_mcp/agents/ai_content_generator.py,sha256=tWGC9cY6Wp7MB1P9J7uCv8LUdiS02rgS6vxaNHD7KQk,10311
|
|
12
14
|
htmlgen_mcp/agents/quick_generator.py,sha256=2wV4PCRugV0suTedLDV91_etHy_2Fiw4J0MraT7MQjw,34201
|
|
@@ -29,8 +31,8 @@ htmlgen_mcp/agents/web_tools/simple_css.py,sha256=kj9X3sHHhj1wGwBVL20j6w2qIHXRdx
|
|
|
29
31
|
htmlgen_mcp/agents/web_tools/simple_js.py,sha256=xMiuF-u-h_IIkUONZIa4Xf8vKB5mcXxwQf5b_BIcpoE,12174
|
|
30
32
|
htmlgen_mcp/agents/web_tools/simple_templates.py,sha256=-Rs-SsWpGZT2hiwa3jZNVDHOMZOo1vV2pWbmBdR30os,6471
|
|
31
33
|
htmlgen_mcp/agents/web_tools/validation.py,sha256=bNA6aWXrCSi7sPqQw5bBR3XF69gRf85D5jSMi996CtI,2069
|
|
32
|
-
htmlgen_mcp-0.3.
|
|
33
|
-
htmlgen_mcp-0.3.
|
|
34
|
-
htmlgen_mcp-0.3.
|
|
35
|
-
htmlgen_mcp-0.3.
|
|
36
|
-
htmlgen_mcp-0.3.
|
|
34
|
+
htmlgen_mcp-0.3.6.dist-info/METADATA,sha256=9LHsHXEXmqM77kT9AjOyJk8bJisLaJMWTTDwoqXXmSM,5161
|
|
35
|
+
htmlgen_mcp-0.3.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
36
|
+
htmlgen_mcp-0.3.6.dist-info/entry_points.txt,sha256=w7ufTQJobIxT3FYI24yKsCEwEQvBOWhNjckUd9Amu_k,66
|
|
37
|
+
htmlgen_mcp-0.3.6.dist-info/top_level.txt,sha256=KnglzX4ekV8SQkHTsJg2_nTBXz2TxaYLdvoMMovHLNk,12
|
|
38
|
+
htmlgen_mcp-0.3.6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|