super-dev 2.0.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.
- super_dev/__init__.py +11 -0
- super_dev/analyzer/__init__.py +34 -0
- super_dev/analyzer/analyzer.py +440 -0
- super_dev/analyzer/detectors.py +511 -0
- super_dev/analyzer/models.py +285 -0
- super_dev/cli.py +3257 -0
- super_dev/config/__init__.py +11 -0
- super_dev/config/frontend.py +557 -0
- super_dev/config/manager.py +281 -0
- super_dev/creators/__init__.py +26 -0
- super_dev/creators/creator.py +134 -0
- super_dev/creators/document_generator.py +2473 -0
- super_dev/creators/frontend_builder.py +371 -0
- super_dev/creators/implementation_builder.py +789 -0
- super_dev/creators/prompt_generator.py +289 -0
- super_dev/creators/requirement_parser.py +354 -0
- super_dev/creators/spec_builder.py +195 -0
- super_dev/deployers/__init__.py +20 -0
- super_dev/deployers/cicd.py +1269 -0
- super_dev/deployers/delivery.py +229 -0
- super_dev/deployers/migration.py +1032 -0
- super_dev/design/__init__.py +74 -0
- super_dev/design/aesthetics.py +530 -0
- super_dev/design/charts.py +396 -0
- super_dev/design/codegen.py +379 -0
- super_dev/design/engine.py +528 -0
- super_dev/design/generator.py +395 -0
- super_dev/design/landing.py +422 -0
- super_dev/design/tech_stack.py +524 -0
- super_dev/design/tokens.py +269 -0
- super_dev/design/ux_guide.py +391 -0
- super_dev/exceptions.py +119 -0
- super_dev/experts/__init__.py +19 -0
- super_dev/experts/service.py +161 -0
- super_dev/integrations/__init__.py +7 -0
- super_dev/integrations/manager.py +264 -0
- super_dev/orchestrator/__init__.py +12 -0
- super_dev/orchestrator/engine.py +958 -0
- super_dev/orchestrator/experts.py +423 -0
- super_dev/orchestrator/knowledge.py +352 -0
- super_dev/orchestrator/quality.py +356 -0
- super_dev/reviewers/__init__.py +17 -0
- super_dev/reviewers/code_review.py +471 -0
- super_dev/reviewers/quality_gate.py +964 -0
- super_dev/reviewers/redteam.py +881 -0
- super_dev/skills/__init__.py +7 -0
- super_dev/skills/manager.py +307 -0
- super_dev/specs/__init__.py +44 -0
- super_dev/specs/generator.py +264 -0
- super_dev/specs/manager.py +428 -0
- super_dev/specs/models.py +348 -0
- super_dev/specs/validator.py +415 -0
- super_dev/utils/__init__.py +11 -0
- super_dev/utils/logger.py +133 -0
- super_dev/web/api.py +1402 -0
- super_dev-2.0.0.dist-info/METADATA +252 -0
- super_dev-2.0.0.dist-info/RECORD +61 -0
- super_dev-2.0.0.dist-info/WHEEL +5 -0
- super_dev-2.0.0.dist-info/entry_points.txt +2 -0
- super_dev-2.0.0.dist-info/licenses/LICENSE +21 -0
- super_dev-2.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
"""
|
|
2
|
+
开发:Excellent(11964948@qq.com)
|
|
3
|
+
功能:Landing 页面模式生成器
|
|
4
|
+
作用:生成转化优化的 Landing 页面布局
|
|
5
|
+
创建时间:2025-01-04
|
|
6
|
+
最后修改:2025-01-04
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import csv
|
|
10
|
+
from dataclasses import dataclass, field
|
|
11
|
+
from enum import Enum
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class LandingCategory(str, Enum):
|
|
17
|
+
"""Landing 页面类别"""
|
|
18
|
+
CLASSIC = "classic"
|
|
19
|
+
VIDEO = "video"
|
|
20
|
+
PRICING = "pricing"
|
|
21
|
+
PRODUCT = "product"
|
|
22
|
+
SOCIAL = "social"
|
|
23
|
+
COMPARISON = "comparison"
|
|
24
|
+
FAQ = "faq"
|
|
25
|
+
LAYOUT = "layout"
|
|
26
|
+
MINIMAL = "minimal"
|
|
27
|
+
CONVERSION = "conversion"
|
|
28
|
+
INTERACTIVE = "interactive"
|
|
29
|
+
NARRATIVE = "narrative"
|
|
30
|
+
DATA = "data"
|
|
31
|
+
TRUST = "trust"
|
|
32
|
+
THEME = "theme"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dataclass
|
|
36
|
+
class LandingSection:
|
|
37
|
+
"""页面区块"""
|
|
38
|
+
name: str
|
|
39
|
+
type: str # hero, features, pricing, testimonial, cta, etc.
|
|
40
|
+
content_hint: str
|
|
41
|
+
required: bool = False
|
|
42
|
+
order: int = 0
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@dataclass
|
|
46
|
+
class CTAStrategy:
|
|
47
|
+
"""CTA 策略"""
|
|
48
|
+
primary_placement: str # where the main CTA goes
|
|
49
|
+
secondary_placements: list[str] = field(default_factory=list)
|
|
50
|
+
style: str = "button" # button, link, text
|
|
51
|
+
urgency: str = "medium" # low, medium, high
|
|
52
|
+
text_variations: list[str] = field(default_factory=list)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@dataclass
|
|
56
|
+
class LandingPattern:
|
|
57
|
+
"""Landing 页面模式"""
|
|
58
|
+
name: str
|
|
59
|
+
category: LandingCategory
|
|
60
|
+
description: str
|
|
61
|
+
sections: list[LandingSection]
|
|
62
|
+
cta_strategy: CTAStrategy
|
|
63
|
+
best_for: list[str] # SaaS, Marketing, E-commerce, etc.
|
|
64
|
+
conversion_tips: list[str]
|
|
65
|
+
complexity: str # low, medium, high
|
|
66
|
+
keywords: list[str]
|
|
67
|
+
|
|
68
|
+
def to_dict(self) -> dict[str, Any]:
|
|
69
|
+
"""转换为字典"""
|
|
70
|
+
return {
|
|
71
|
+
"name": self.name,
|
|
72
|
+
"category": self.category.value,
|
|
73
|
+
"description": self.description,
|
|
74
|
+
"sections": [
|
|
75
|
+
{
|
|
76
|
+
"name": s.name,
|
|
77
|
+
"type": s.type,
|
|
78
|
+
"content_hint": s.content_hint,
|
|
79
|
+
"required": s.required,
|
|
80
|
+
"order": s.order
|
|
81
|
+
}
|
|
82
|
+
for s in self.sections
|
|
83
|
+
],
|
|
84
|
+
"cta_strategy": {
|
|
85
|
+
"primary_placement": self.cta_strategy.primary_placement,
|
|
86
|
+
"secondary_placements": self.cta_strategy.secondary_placements,
|
|
87
|
+
"style": self.cta_strategy.style,
|
|
88
|
+
"urgency": self.cta_strategy.urgency,
|
|
89
|
+
"text_variations": self.cta_strategy.text_variations
|
|
90
|
+
},
|
|
91
|
+
"best_for": self.best_for,
|
|
92
|
+
"conversion_tips": self.conversion_tips,
|
|
93
|
+
"complexity": self.complexity,
|
|
94
|
+
"keywords": self.keywords
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class LandingPatternGenerator:
|
|
99
|
+
"""Landing 页面模式生成器"""
|
|
100
|
+
|
|
101
|
+
def __init__(self, data_dir: Path | None = None):
|
|
102
|
+
"""
|
|
103
|
+
初始化生成器
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
data_dir: 数据目录路径
|
|
107
|
+
"""
|
|
108
|
+
if data_dir is None:
|
|
109
|
+
data_dir = Path(__file__).parent.parent / "data" / "design"
|
|
110
|
+
|
|
111
|
+
self.data_dir = Path(data_dir)
|
|
112
|
+
self.patterns: list[LandingPattern] = []
|
|
113
|
+
self._load_patterns()
|
|
114
|
+
|
|
115
|
+
def _load_patterns(self):
|
|
116
|
+
"""从 CSV 加载模式数据"""
|
|
117
|
+
csv_path = self.data_dir / "landing_patterns.csv"
|
|
118
|
+
|
|
119
|
+
if not csv_path.exists():
|
|
120
|
+
# 使用默认模式
|
|
121
|
+
self.patterns = self._get_default_patterns()
|
|
122
|
+
return
|
|
123
|
+
|
|
124
|
+
with open(csv_path, encoding='utf-8') as f:
|
|
125
|
+
reader = csv.DictReader(f)
|
|
126
|
+
for row in reader:
|
|
127
|
+
pattern = self._parse_pattern(row)
|
|
128
|
+
if pattern:
|
|
129
|
+
self.patterns.append(pattern)
|
|
130
|
+
|
|
131
|
+
def _parse_pattern(self, row: dict[str, str]) -> LandingPattern | None:
|
|
132
|
+
"""解析 CSV 行为模式对象"""
|
|
133
|
+
try:
|
|
134
|
+
# 解析 sections
|
|
135
|
+
sections_raw = row.get("sections", "")
|
|
136
|
+
section_names = [s.strip() for s in sections_raw.split(",")]
|
|
137
|
+
|
|
138
|
+
sections = []
|
|
139
|
+
for i, name in enumerate(section_names):
|
|
140
|
+
section_type = self._infer_section_type(name)
|
|
141
|
+
sections.append(LandingSection(
|
|
142
|
+
name=name.replace("_", " ").title(),
|
|
143
|
+
type=section_type,
|
|
144
|
+
content_hint=self._get_content_hint(section_type),
|
|
145
|
+
required=(i == 0), # 第一部分通常是必需的
|
|
146
|
+
order=i
|
|
147
|
+
))
|
|
148
|
+
|
|
149
|
+
# 解析 CTA 策略
|
|
150
|
+
cta_strategy = CTAStrategy(
|
|
151
|
+
primary_placement=section_names[0] if section_names else "hero",
|
|
152
|
+
style="button",
|
|
153
|
+
urgency="medium",
|
|
154
|
+
text_variations=self._get_cta_variations(row.get("best_for", ""))
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
return LandingPattern(
|
|
158
|
+
name=row["name"],
|
|
159
|
+
category=LandingCategory(row.get("category", "classic")),
|
|
160
|
+
description=row["description"],
|
|
161
|
+
sections=sections,
|
|
162
|
+
cta_strategy=cta_strategy,
|
|
163
|
+
best_for=row.get("best_for", "").split(","),
|
|
164
|
+
conversion_tips=row.get("conversion_tips", "").split(",") if row.get("conversion_tips") else [],
|
|
165
|
+
complexity=row.get("complexity", "medium"),
|
|
166
|
+
keywords=row.get("keywords", "").split(",") if row.get("keywords") else []
|
|
167
|
+
)
|
|
168
|
+
except Exception as e:
|
|
169
|
+
print(f"Warning: Failed to parse pattern: {e}")
|
|
170
|
+
return None
|
|
171
|
+
|
|
172
|
+
def _infer_section_type(self, name: str) -> str:
|
|
173
|
+
"""推断区块类型"""
|
|
174
|
+
name_lower = name.lower()
|
|
175
|
+
type_map = {
|
|
176
|
+
"hero": ["hero", "video_hero", "split_hero", "dark_hero", "single_cta"],
|
|
177
|
+
"features": ["features", "zigzag_features", "dark_features", "feature"],
|
|
178
|
+
"pricing": ["pricing_plans", "pricing", "plans"],
|
|
179
|
+
"testimonials": ["testimonials", "social_proof", "reviews"],
|
|
180
|
+
"comparison": ["comparison_table", "comparison"],
|
|
181
|
+
"faq": ["faq", "faq_categories", "questions"],
|
|
182
|
+
"demo": ["interactive_demo", "video_hero", "product_gallery"],
|
|
183
|
+
"stats": ["stats_dashboard", "trust_badges", "stats"],
|
|
184
|
+
"cta": ["cta", "contact_cta", "repeating_ctas"],
|
|
185
|
+
"story": ["story_sections", "timeline", "narrative"],
|
|
186
|
+
}
|
|
187
|
+
for type_name, patterns in type_map.items():
|
|
188
|
+
if any(pattern in name_lower for pattern in patterns):
|
|
189
|
+
return type_name
|
|
190
|
+
return "content"
|
|
191
|
+
|
|
192
|
+
def _get_content_hint(self, section_type: str) -> str:
|
|
193
|
+
"""获取内容提示"""
|
|
194
|
+
hints = {
|
|
195
|
+
"hero": "Compelling headline, subheadline, primary CTA, hero image/video",
|
|
196
|
+
"features": "3-6 key features with icons, titles, descriptions",
|
|
197
|
+
"pricing": "2-4 pricing tiers, highlight recommended plan",
|
|
198
|
+
"testimonials": "3-5 customer quotes with photos and titles",
|
|
199
|
+
"comparison": "Side-by-side feature comparison table",
|
|
200
|
+
"faq": "5-10 common questions with clear answers",
|
|
201
|
+
"demo": "Interactive or video demonstration",
|
|
202
|
+
"stats": "Key metrics, social proof numbers",
|
|
203
|
+
"cta": "Clear call-to-action with benefit statement",
|
|
204
|
+
"content": "Relevant content for this section",
|
|
205
|
+
}
|
|
206
|
+
return hints.get(section_type, "Content for this section")
|
|
207
|
+
|
|
208
|
+
def _get_cta_variations(self, best_for: str) -> list[str]:
|
|
209
|
+
"""获取 CTA 文本变体"""
|
|
210
|
+
base_ctas = {
|
|
211
|
+
"SaaS": ["Start Free Trial", "Get Started", "Request Demo", "Start Now"],
|
|
212
|
+
"E-commerce": ["Shop Now", "Browse Collection", "Add to Cart", "Buy Now"],
|
|
213
|
+
"Marketing": ["Learn More", "Get Started", "Contact Us", "Sign Up"],
|
|
214
|
+
"B2B": ["Request Demo", "Contact Sales", "Enterprise Plans", "Book a Call"],
|
|
215
|
+
"Freemium": ["Start Free", "Upgrade Now", "Get Pro", "Unlock Features"],
|
|
216
|
+
"Mobile": ["Download App", "Get on iOS", "Get on Android", "Install Now"],
|
|
217
|
+
"Default": ["Get Started", "Learn More", "Contact Us", "Sign Up"]
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
for key, cta_list in base_ctas.items():
|
|
221
|
+
if key.lower() in best_for.lower():
|
|
222
|
+
return cta_list
|
|
223
|
+
|
|
224
|
+
return base_ctas["Default"]
|
|
225
|
+
|
|
226
|
+
def _get_default_patterns(self) -> list[LandingPattern]:
|
|
227
|
+
"""获取默认模式(当 CSV 不存在时)"""
|
|
228
|
+
return [
|
|
229
|
+
LandingPattern(
|
|
230
|
+
name="Hero + Features",
|
|
231
|
+
category=LandingCategory.CLASSIC,
|
|
232
|
+
description="Classic landing page with hero section and feature showcase",
|
|
233
|
+
sections=[
|
|
234
|
+
LandingSection("Hero", "hero", "Compelling headline and primary CTA", True, 0),
|
|
235
|
+
LandingSection("Features", "features", "3-6 key features with icons", False, 1),
|
|
236
|
+
LandingSection("Social Proof", "testimonials", "Customer testimonials", False, 2),
|
|
237
|
+
LandingSection("CTA", "cta", "Final call-to-action", False, 3),
|
|
238
|
+
],
|
|
239
|
+
cta_strategy=CTAStrategy(
|
|
240
|
+
primary_placement="hero",
|
|
241
|
+
secondary_placements=["features", "cta"],
|
|
242
|
+
style="button",
|
|
243
|
+
urgency="medium",
|
|
244
|
+
text_variations=["Get Started", "Learn More", "Start Free Trial"]
|
|
245
|
+
),
|
|
246
|
+
best_for=["SaaS", "Marketing", "Product"],
|
|
247
|
+
conversion_tips=["Place primary CTA in hero section", "Use contrasting color for CTA"],
|
|
248
|
+
complexity="medium",
|
|
249
|
+
keywords=["hero", "features", "classic", "landing"]
|
|
250
|
+
),
|
|
251
|
+
LandingPattern(
|
|
252
|
+
name="Minimal Single CTA",
|
|
253
|
+
category=LandingCategory.MINIMAL,
|
|
254
|
+
description="Ultra-minimalist page with single focused action",
|
|
255
|
+
sections=[
|
|
256
|
+
LandingSection("Single CTA", "hero", "One clear headline and one button", True, 0),
|
|
257
|
+
],
|
|
258
|
+
cta_strategy=CTAStrategy(
|
|
259
|
+
primary_placement="hero",
|
|
260
|
+
style="button",
|
|
261
|
+
urgency="high",
|
|
262
|
+
text_variations=["Sign Up", "Get Started", "Join Now"]
|
|
263
|
+
),
|
|
264
|
+
best_for=["Newsletter", "Signup", "Waitlist"],
|
|
265
|
+
conversion_tips=["Remove all distractions", "Use plenty of whitespace"],
|
|
266
|
+
complexity="low",
|
|
267
|
+
keywords=["minimal", "simple", "focused", "single"]
|
|
268
|
+
)
|
|
269
|
+
]
|
|
270
|
+
|
|
271
|
+
def search(self, query: str, max_results: int = 5) -> list[LandingPattern]:
|
|
272
|
+
"""
|
|
273
|
+
搜索 Landing 页面模式
|
|
274
|
+
|
|
275
|
+
Args:
|
|
276
|
+
query: 搜索查询
|
|
277
|
+
max_results: 最大结果数
|
|
278
|
+
|
|
279
|
+
Returns:
|
|
280
|
+
匹配的模式列表
|
|
281
|
+
"""
|
|
282
|
+
query_lower = query.lower()
|
|
283
|
+
|
|
284
|
+
# 简单的关键词匹配
|
|
285
|
+
scored_patterns = []
|
|
286
|
+
for pattern in self.patterns:
|
|
287
|
+
score = 0
|
|
288
|
+
|
|
289
|
+
# 名称匹配
|
|
290
|
+
if query_lower in pattern.name.lower():
|
|
291
|
+
score += 10
|
|
292
|
+
|
|
293
|
+
# 类别匹配
|
|
294
|
+
if query_lower in pattern.category.value:
|
|
295
|
+
score += 5
|
|
296
|
+
|
|
297
|
+
# 关键词匹配
|
|
298
|
+
for keyword in pattern.keywords:
|
|
299
|
+
if query_lower in keyword.lower():
|
|
300
|
+
score += 3
|
|
301
|
+
|
|
302
|
+
# 最佳用途匹配
|
|
303
|
+
for use_case in pattern.best_for:
|
|
304
|
+
if query_lower in use_case.lower():
|
|
305
|
+
score += 2
|
|
306
|
+
|
|
307
|
+
if score > 0:
|
|
308
|
+
scored_patterns.append((pattern, score))
|
|
309
|
+
|
|
310
|
+
# 按分数排序
|
|
311
|
+
scored_patterns.sort(key=lambda x: x[1], reverse=True)
|
|
312
|
+
|
|
313
|
+
return [p for p, _ in scored_patterns[:max_results]]
|
|
314
|
+
|
|
315
|
+
def get_pattern(self, name: str) -> LandingPattern | None:
|
|
316
|
+
"""
|
|
317
|
+
获取指定名称的模式
|
|
318
|
+
|
|
319
|
+
Args:
|
|
320
|
+
name: 模式名称
|
|
321
|
+
|
|
322
|
+
Returns:
|
|
323
|
+
模式对象或 None
|
|
324
|
+
"""
|
|
325
|
+
for pattern in self.patterns:
|
|
326
|
+
if pattern.name.lower() == name.lower():
|
|
327
|
+
return pattern
|
|
328
|
+
return None
|
|
329
|
+
|
|
330
|
+
def recommend(self, product_type: str, goal: str, audience: str) -> LandingPattern | None:
|
|
331
|
+
"""
|
|
332
|
+
推荐最适合的模式
|
|
333
|
+
|
|
334
|
+
Args:
|
|
335
|
+
product_type: 产品类型 (SaaS, E-commerce, Mobile, etc.)
|
|
336
|
+
goal: 目标 (signup, purchase, demo, etc.)
|
|
337
|
+
audience: 受众 (B2B, B2C, Enterprise, etc.)
|
|
338
|
+
|
|
339
|
+
Returns:
|
|
340
|
+
推荐的模式
|
|
341
|
+
"""
|
|
342
|
+
# 基于目标和产品类型的推荐逻辑
|
|
343
|
+
goal_lower = goal.lower()
|
|
344
|
+
product_lower = product_type.lower()
|
|
345
|
+
|
|
346
|
+
if goal_lower in ["signup", "register", "newsletter"]:
|
|
347
|
+
# 注册类目标:推荐简单聚焦的模式
|
|
348
|
+
return self.get_pattern("Minimal Single CTA") or self.get_pattern("Hero + Features")
|
|
349
|
+
|
|
350
|
+
elif goal_lower in ["purchase", "buy", "order"]:
|
|
351
|
+
# 购买类目标:推荐产品展示模式
|
|
352
|
+
return self.get_pattern("Product Showcase") or self.get_pattern("Hero + Features")
|
|
353
|
+
|
|
354
|
+
elif goal_lower in ["demo", "trial"]:
|
|
355
|
+
# 演示类目标:推荐交互演示
|
|
356
|
+
return self.get_pattern("Interactive Demo") or self.get_pattern("Video-First")
|
|
357
|
+
|
|
358
|
+
elif "pricing" in goal_lower:
|
|
359
|
+
# 价格相关:推荐价格预览
|
|
360
|
+
return self.get_pattern("Pricing Preview")
|
|
361
|
+
|
|
362
|
+
elif product_lower in ["b2b", "enterprise", "saas"]:
|
|
363
|
+
# B2B/SaaS:推荐对比或信任导向
|
|
364
|
+
return self.get_pattern("Comparison Table") or self.get_pattern("Trust Badges")
|
|
365
|
+
|
|
366
|
+
else:
|
|
367
|
+
# 默认推荐经典模式
|
|
368
|
+
return self.get_pattern("Hero + Features")
|
|
369
|
+
|
|
370
|
+
def generate_structure(self, pattern: LandingPattern) -> dict[str, Any]:
|
|
371
|
+
"""
|
|
372
|
+
生成页面结构
|
|
373
|
+
|
|
374
|
+
Args:
|
|
375
|
+
pattern: 模式对象
|
|
376
|
+
|
|
377
|
+
Returns:
|
|
378
|
+
页面结构字典
|
|
379
|
+
"""
|
|
380
|
+
return {
|
|
381
|
+
"pattern": pattern.name,
|
|
382
|
+
"description": pattern.description,
|
|
383
|
+
"sections": [
|
|
384
|
+
{
|
|
385
|
+
"name": section.name,
|
|
386
|
+
"type": section.type,
|
|
387
|
+
"content_hint": section.content_hint,
|
|
388
|
+
"order": section.order
|
|
389
|
+
}
|
|
390
|
+
for section in pattern.sections
|
|
391
|
+
],
|
|
392
|
+
"cta_strategy": {
|
|
393
|
+
"primary": {
|
|
394
|
+
"placement": pattern.cta_strategy.primary_placement,
|
|
395
|
+
"style": pattern.cta_strategy.style,
|
|
396
|
+
"texts": pattern.cta_strategy.text_variations[:3]
|
|
397
|
+
},
|
|
398
|
+
"secondary": [
|
|
399
|
+
{
|
|
400
|
+
"placement": placement,
|
|
401
|
+
"style": pattern.cta_strategy.style
|
|
402
|
+
}
|
|
403
|
+
for placement in pattern.cta_strategy.secondary_placements
|
|
404
|
+
]
|
|
405
|
+
},
|
|
406
|
+
"conversion_tips": pattern.conversion_tips,
|
|
407
|
+
"complexity": pattern.complexity
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
def list_patterns(self) -> list[str]:
|
|
411
|
+
"""列出所有可用模式"""
|
|
412
|
+
return [p.name for p in self.patterns]
|
|
413
|
+
|
|
414
|
+
def list_categories(self) -> list[str]:
|
|
415
|
+
"""列出所有类别"""
|
|
416
|
+
return list(set(p.category.value for p in self.patterns))
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
# 便捷函数
|
|
420
|
+
def get_landing_generator(data_dir: Path | None = None) -> LandingPatternGenerator:
|
|
421
|
+
"""获取 Landing 页面生成器实例"""
|
|
422
|
+
return LandingPatternGenerator(data_dir)
|