Skip to content

Commit 4549fd7

Browse files
committed
feat: enhance prompt health checks with additional hints and improve user guidance in both English and Chinese
1 parent d755049 commit 4549fd7

11 files changed

Lines changed: 89 additions & 79 deletions

File tree

src/components/generator/GeneratorApp.tsx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,15 @@ const QUALITY_LABEL_KEYS: Record<PromptHealthCheckId, keyof Dictionary['generato
4646
metric: 'qualityMetric',
4747
};
4848

49+
const QUALITY_HINT_KEYS: Record<PromptHealthCheckId, keyof Dictionary['generator']> = {
50+
goal: 'qualityGoalHint',
51+
features: 'qualityFeaturesHint',
52+
io: 'qualityIoHint',
53+
acceptance: 'qualityAcceptanceHint',
54+
who: 'qualityWhoHint',
55+
metric: 'qualityMetricHint',
56+
};
57+
4958
export function GeneratorApp({ locale, dict }: Props) {
5059
const [state, setState] = useState<FormState>(DEFAULT_FORM);
5160
const [lang, setLang] = useState<PromptLang>(locale);
@@ -355,6 +364,7 @@ export function GeneratorApp({ locale, dict }: Props) {
355364
{promptHealth.checks.map((check) => (
356365
<span
357366
key={check.id}
367+
title={check.ok ? undefined : dict.generator[QUALITY_HINT_KEYS[check.id]]}
358368
className={cn(
359369
'rounded-full border px-2.5 py-1 text-[11px]',
360370
check.ok
@@ -368,6 +378,25 @@ export function GeneratorApp({ locale, dict }: Props) {
368378
</span>
369379
))}
370380
</div>
381+
{!promptHealth.ready && (
382+
<ul className="mt-3 space-y-1 text-[11.5px] leading-relaxed text-ink-mute">
383+
{promptHealth.checks
384+
.filter((check) => !check.ok)
385+
.slice(0, 2)
386+
.map((check) => (
387+
<li key={`hint-${check.id}`} className="flex gap-1.5">
388+
<span aria-hidden className="text-amber-600"></span>
389+
<span>
390+
<span className="font-medium text-ink-soft">
391+
{dict.generator[QUALITY_LABEL_KEYS[check.id]]}
392+
</span>
393+
{' · '}
394+
{dict.generator[QUALITY_HINT_KEYS[check.id]]}
395+
</span>
396+
</li>
397+
))}
398+
</ul>
399+
)}
371400
</div>
372401
<pre className="max-h-[520px] overflow-auto rounded-2xl border border-[color:var(--line)] bg-[#0F1115] p-4 text-[12.5px] leading-[1.75] text-[#E5E7EB]">
373402
<code className="whitespace-pre-wrap break-words">{prompt}</code>

src/data/cases/_more.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2249,7 +2249,7 @@ export const dataSkuProfitRadar: CaseBundle = {
22492249
communication: COMMUNICATION_ZH,
22502250
}, 'zh'),
22512251
en: composeCasePrompt({
2252-
role: caseRole('an e-commerce data analyst (tool must be usable by non-technical teammates)', 'en'),
2252+
role: caseRole('an e-commerce data analyst whose teammates across the business will use this tool — make it one-click and friendly', 'en'),
22532253
goal: 'Combine revenue, margin, ads, refunds, and stock turnover to find SKUs worth more resources.',
22542254
platform: '- Windows + macOS; Electron + React + TypeScript; local SQLite; SheetJS; ECharts',
22552255
features: `1. Import sales, cost, ad spend, refund, and stock sheets; merge by SKU.
@@ -2324,7 +2324,7 @@ export const productListingQualityChecker: CaseBundle = {
23242324
communication: COMMUNICATION_ZH,
23252325
}, 'zh'),
23262326
en: composeCasePrompt({
2327-
role: caseRole('merchandising/product teammates (must be usable by non-technical staff)', 'en'),
2327+
role: caseRole('merchandising/product teammates — the tool should feel natural in their hands, one-click with no setup', 'en'),
23282328
goal: 'Batch-check listing materials for completeness and consistency to reduce last-minute rework before launch.',
23292329
platform: '- Windows + macOS; Electron + React + TypeScript; SheetJS; local JSON rules',
23302330
features: `1. Import product sheet, image list, certificate file list.

src/data/cases/finance.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,13 @@ export const financeReconciliation: CaseBundle = {
5757
platform: `- 平台:Windows 10 / 11 桌面应用
5858
- 框架:Electron + React + TypeScript
5959
- 表格处理:SheetJS
60-
- 默认本地处理;联网传输须加密并告知用户
6160
- 交付时打包成 Windows .exe 安装包`,
6261
features: `1. 首页两个醒目按钮:「导入订单 Excel」「导入银行流水 Excel」,支持拖拽。
6362
2. 导入后自动显示表头和前 5 行预览,让用户从下拉框里选「订单号」「金额」「交易时间」「备注」字段。记住选择下次默认回填。
6463
3. 示例字段兼容:订单表常见列「订单号 / 实付金额 / 下单时间 / 店铺」;银行流水常见列「交易单号 / 收入金额 / 交易时间 / 摘要」。列名可有细微差异。
6564
4. 「开始对账」按钮显示进度条。匹配逻辑:订单号去空格后作为主键;金额差 <= 0.01 元视为匹配;重复订单号要合并提示;退款 / 冲正流水单独标记,不直接当异常。
6665
5. 结果页两栏:左边展示匹配数、差异数、匹配率、总金额;右边表格列出每一条差异,字段包括订单号、订单金额、银行金额、差额、可能原因(金额不一致 / 银行流水缺失 / 订单缺失 / 重复订单 / 疑似退款)。
67-
6. 「导出差异明细到 Excel」按钮,默认文件名 "差异明细-YYYY-MM.xlsx"。
68-
7. 数据默认本地处理,联网功能须告知用户并加密传输。`,
66+
6. 「导出差异明细到 Excel」按钮,默认文件名 "差异明细-YYYY-MM.xlsx"。`,
6967
sampleData: `sample-data/ 中放两个文件:
7068
orders.xlsx — 列:订单号, 实付金额, 下单时间, 店铺(示例:DD202401001, 299.00, 2024-01-05, 旗舰店)
7169
bank.xlsx — 列:交易单号, 收入金额, 交易时间, 摘要(示例:DD202401001, 299.00, 2024-01-06, 支付宝转入)
@@ -98,15 +96,13 @@ bank.xlsx — 列:交易单号, 收入金额, 交易时间, 摘要(示例:
9896
platform: `- Platform: Windows 10 / 11 desktop app
9997
- Framework: Electron + React + TypeScript
10098
- Spreadsheet parsing: SheetJS
101-
- Process locally by default; network calls require encryption and user consent
10299
- Deliver a Windows .exe installer`,
103100
features: `1. Home screen with two prominent buttons: "Import Orders Excel" and "Import Bank Excel". Drag-and-drop works.
104101
2. After import, show headers and first 5 rows. Let the user pick Order ID / Amount / Transaction Time / Notes columns from dropdowns. Remember and pre-fill next time.
105102
3. Example headers to support: orders may use Order ID / Paid Amount / Order Time / Store; bank statements may use Transaction ID / Income Amount / Transaction Time / Memo. Tolerate minor header wording differences.
106103
4. "Reconcile" button triggers a progress bar. Rule: trim order IDs and use them as keys; difference <= 0.01 = match; duplicate order IDs are grouped and flagged; refunds / reversals are tagged separately, not treated as ordinary mismatches.
107104
5. Results page has two panes. Left: matched count, mismatched count, match rate, total amount. Right: a mismatch table with order ID, order amount, bank amount, diff, reason (amounts differ / missing in bank / missing in orders / duplicate order / likely refund).
108-
6. "Export mismatches to Excel" with default filename "diff-YYYY-MM.xlsx".
109-
7. Process locally by default; network calls require encryption and user consent.`,
105+
6. "Export mismatches to Excel" with default filename "diff-YYYY-MM.xlsx".`,
110106
style: `- Minimal desktop-tool style: light background, clear sections, radius 8, moderate information density.
111107
- Primary button: muted dark. Secondary: light gray.
112108
- Follows Windows light/dark setting.

src/i18n/dictionaries/en.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,12 @@ export const en = {
190190
qualityMetric: 'Measurable gain',
191191
qualityPass: 'OK',
192192
qualityImprove: 'Add',
193+
qualityGoalHint: 'In one or two sentences, say who it is for, what it solves, and the outcome.',
194+
qualityFeaturesHint: 'One line each — be concrete: which file to drag in, which button to click, what comes out.',
195+
qualityIoHint: 'Name the input and output, e.g. "Import Excel → export diff sheet".',
196+
qualityAcceptanceHint: 'Spell out what counts as done in one line, e.g. "main flow runs, empty data does not crash, double-click to open".',
197+
qualityWhoHint: 'Say who will use it in one phrase, e.g. "finance teammate / teacher / just me".',
198+
qualityMetricHint: 'Give one measurable metric, e.g. "from 2 days to 1 hour" or "one click replaces 30 manual steps".',
193199

194200
quickTemplatesTitle: 'Start from a template',
195201
quickTemplatesHint: 'One click fills the form. Tweak and go.',

src/i18n/dictionaries/zh.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,12 @@ export const zh = {
191191
qualityMetric: '量化收益',
192192
qualityPass: '已填',
193193
qualityImprove: '待补充',
194+
qualityGoalHint: '一两句话说清楚:给谁用、解决什么、产出是什么。',
195+
qualityFeaturesHint: '一行一条,具体到拖入哪个文件、点哪个按钮、产出什么。',
196+
qualityIoHint: '写清楚输入和输出,例如"导入 Excel → 导出差异表"。',
197+
qualityAcceptanceHint: '补一句怎么算做完,例如"主流程跑通、空数据不闪退、可双击打开"。',
198+
qualityWhoHint: '写一下谁来用,例如"财务同事 / 老师 / 自己用都行"。',
199+
qualityMetricHint: '给一个量化指标,例如"从 2 天压到 1 小时"或"一键替代手工 30 步"。',
194200

195201
quickTemplatesTitle: '不想从零开始?挑个模板',
196202
quickTemplatesHint: '一键填好,改几个字就能用。',

src/lib/generatorPromptHealth.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ const WHO_WORDS = [
6767
'部门',
6868
'门店',
6969
'小伙伴',
70+
'客户',
71+
'用户',
72+
'学生',
73+
'老师',
7074
'team',
7175
'finance',
7276
'ops',
@@ -80,6 +84,11 @@ const WHO_WORDS = [
8084
'colleague',
8185
'department',
8286
'store',
87+
'teammate',
88+
'customer',
89+
'user',
90+
'student',
91+
'teacher',
8392
] as const;
8493

8594
const METRIC_WORDS = [
@@ -96,6 +105,9 @@ const METRIC_WORDS = [
96105
'节省',
97106
'省下',
98107
'快',
108+
'批量',
109+
'一键',
110+
'成倍',
99111
'hour',
100112
'minute',
101113
'second',
@@ -105,8 +117,17 @@ const METRIC_WORDS = [
105117
'faster',
106118
'times',
107119
'save time',
120+
'batch',
121+
'one-click',
122+
'instant',
123+
'in one go',
108124
] as const;
109125

126+
// Number + unit pattern: "2 天", "1 小时", "10 万行", "100k rows", "30%".
127+
// A measurable goal usually has a quantified change; this catches more cases
128+
// than the keyword list alone.
129+
const METRIC_NUMBER_UNIT = /\d+\s*(?:%|||||||||||||||||kb|mb|gb|k|m|day|hour|min|sec|week|month|year|row|item|page|file)/i;
130+
110131
function includesAny(text: string, words: readonly string[]) {
111132
const normalized = text.toLowerCase();
112133
return words.some((word) => normalized.includes(word.toLowerCase()));
@@ -136,7 +157,7 @@ export function getPromptHealth(
136157
},
137158
{
138159
id: 'metric',
139-
ok: includesAny(requestText, METRIC_WORDS),
160+
ok: includesAny(requestText, METRIC_WORDS) || METRIC_NUMBER_UNIT.test(requestText),
140161
},
141162
];
142163
const passed = checks.filter((check) => check.ok).length;

src/lib/promptBuilder.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ export function buildRecoveryPrompt(state: FormState, lang: PromptLang): string
352352
2. 最小 diff 修改;不删功能、不换技术栈来绕过
353353
3. 重新运行:安装 / lint / 类型检查 / 构建 / 启动
354354
4. 同一问题 3 次失败 → 降级边缘功能,先恢复主流程
355-
5. 修完后用示例数据走完主流程,看到产物再说修好
355+
5. 修完后用示例数据走完主流程,看到产物才算修好
356356
357357
遵守原提示词的所有安全底线和执行纪律。
358358

src/lib/promptModules.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,15 @@ describe('prompt module constants', () => {
4141
expect(CONSTRAINTS_ZH).toContain('脱敏 sample-data');
4242
expect(CONSTRAINTS_ZH).toContain('npm view');
4343
expect(CONSTRAINTS_ZH).toContain('立即运行验证');
44+
expect(CONSTRAINTS_ZH).toContain('另存为');
4445
});
4546

4647
it('CONSTRAINTS_EN contains key rules', () => {
4748
expect(CONSTRAINTS_EN).toContain('local');
4849
expect(CONSTRAINTS_EN).toContain('anonymized sample-data');
4950
expect(CONSTRAINTS_EN).toContain('npm view');
5051
expect(CONSTRAINTS_EN).toContain('Verify each feature');
52+
expect(CONSTRAINTS_EN).toContain('Save as');
5153
});
5254

5355
it('DOD_ZH has checklist format', () => {
@@ -114,7 +116,7 @@ describe('prompt module constants', () => {
114116

115117
it('OPENING_BRIEF_EN primes Codex to greet the user in 3-8 numbered lines', () => {
116118
expect(OPENING_BRIEF_EN).toContain('[Opening Brief]');
117-
expect(OPENING_BRIEF_EN).toContain('3-8 lines');
119+
expect(OPENING_BRIEF_EN).toContain('3-8 numbered lines');
118120
expect(OPENING_BRIEF_EN).toContain('numbered');
119121
expect(OPENING_BRIEF_EN).toContain("Don't wait");
120122
expect(OPENING_BRIEF_EN).toContain("Don't promise a timeline");
@@ -125,7 +127,6 @@ describe('prompt module constants', () => {
125127
expect(WARM_UX_ZH).toContain('Demo 模式');
126128
expect(WARM_UX_ZH).toContain('用示例数据试一试');
127129
expect(WARM_UX_ZH).toContain('业务语言');
128-
expect(WARM_UX_ZH).toContain('另存为');
129130
expect(WARM_UX_ZH).toContain('系统通知');
130131
});
131132

@@ -186,7 +187,6 @@ describe('prompt module constants', () => {
186187
expect(WARM_UX_EN).toContain('demo mode');
187188
expect(WARM_UX_EN).toContain('Try with sample data');
188189
expect(WARM_UX_EN).toContain('business language');
189-
expect(WARM_UX_EN).toContain('Save as');
190190
expect(WARM_UX_EN).toContain('system notification');
191191
});
192192

src/lib/promptModules.ts

Lines changed: 10 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ export type ModuleTech = 'electron' | 'tauri' | 'pyqt' | 'auto';
1212
export const SAFETY_RULES_ZH = `【安全底线】
1313
- 默认本地处理;需要联网时须加密传输并明确告知用户。
1414
- 不写死 API Key、绝对路径、个人邮箱或内网地址。
15-
- 输出不覆盖原文件,冲突加时间后缀
15+
- 写盘默认走"另存为";不覆盖原文件,冲突自动加时间后缀
1616
- 不引入不存在的 npm 包;不确定时先查 npm view。
1717
- 缺真实数据时先造脱敏 sample-data,不等用户提供文件才开工。`;
1818

1919
export const SAFETY_RULES_EN = `[Safety Rules]
2020
- Process locally by default; network calls require encryption and explicit user consent.
2121
- No hard-coded API keys, absolute paths, personal emails, or internal hosts.
22-
- Never overwrite inputs; timestamp conflicts.
22+
- All writes go through "Save as"; never overwrite originals; auto-timestamp on conflict.
2323
- Do not invent npm packages; verify with npm view first.
2424
- If real files are missing, create anonymized sample-data first; do not block on user files.`;
2525

@@ -38,36 +38,14 @@ export const CONSTRAINTS_EN = `${SAFETY_RULES_EN}\n\n${QUALITY_RULES_EN}`;
3838
// ─── Opening Brief (talk to the user before you build) ──────────
3939

4040
export const OPENING_BRIEF_ZH = `【开工前的开场白】
41-
动手之前,先用 3-8 句告诉用户接下来会发生什么。3 句够就只用 3 句。
42-
43-
每句一行,带数字序号。短句。干净。有节奏。不用专业词。用「你」对话。讲画面、讲体感、讲结果——不讲实现。
44-
45-
下面是可选的素材清单,挑用得上的写,按这个顺序排——用不上的直接跳过,宁缺毋滥:
46-
- 一句话点题:要做的是什么。
47-
- 它替你解决什么。
48-
- 关键的几步,一步一句。
49-
- 用到了什么,一行带过。
50-
- 打开后,你会看到什么。
51-
- 你的文件存在哪,谁能看到。
52-
- 下一步看什么。
53-
54-
不要承诺时间("X 分钟内可用"),因为不准。说完不等回话,按下面的流程立刻动手。`;
41+
动手之前,先用 3-8 句告诉用户接下来会发生什么。3 句够就 3 句,每句一行、带数字序号。
42+
讲画面、讲体感、讲结果——不讲实现。短句、不用专业词、用「你」对话。
43+
不要承诺时间("X 分钟内可用"),因为不准。说完不等回话,按下面的【快速启动协议】立刻动手。`;
5544

5645
export const OPENING_BRIEF_EN = `[Opening Brief]
57-
Before you build, use 3-8 lines to tell the user what's coming. If 3 lines do it, use 3.
58-
59-
One sentence per line, numbered. Short. Clean. Rhythmic. No jargon. Speak to "you". Picture, feel, result — not implementation.
60-
61-
Pick from this checklist — keep them in order, skip what doesn't fit. Better to leave one out than fill in fluff:
62-
- What you'll build, in one line.
63-
- The friction it removes.
64-
- The key steps — one per line.
65-
- The stack, in a line.
66-
- What you'll see when it opens.
67-
- Where your files live. Who sees them.
68-
- What to look at next.
69-
70-
Don't promise a timeline ("ready in X minutes") — you can't know. Don't wait for a reply. Follow the flow below immediately.`;
46+
Before you build, use 3-8 numbered lines to tell the user what's coming. If 3 lines do it, use 3 — one short sentence per line.
47+
Picture, feel, result — not implementation. Plain words. Speak to "you".
48+
Don't promise a timeline ("ready in X minutes") — you can't know. Don't wait for a reply. Follow the [Quick Start Protocol] below immediately.`;
7149

7250
// ─── Warm UX Contract (treat the user with care) ────────────────
7351

@@ -76,9 +54,8 @@ export const WARM_UX_ZH = `【温暖体验契约】
7654
- 首次启动 = Demo 模式:自动加载 sample-data/ 跑完主流程一次,让用户立刻看到结果界面,而不是空状态。
7755
- 工作台顶部永远有「用示例数据试一试」按钮,任何时候都能一键演示。
7856
- 按钮、提示、错误一律用业务语言。例:「找不到订单号这一列」,不是「Column "order_id" not found」。
79-
- 任何写盘操作默认走「另存为」;从不覆盖原文件,冲突自动加时间后缀。
8057
- 步骤 ≥3 的操作给"撤销"或"取消"出口;≥5 步的关键操作要二次确认。
81-
- 大批量任务显示进度条 + 预估剩余时间,最长每 1 秒刷新一次
58+
- 大批量任务显示进度条 + 预估剩余时间,每秒最多刷新一次
8259
- 主流程一完成就在应用内给反馈;若窗口在后台,再发一次系统通知(Toast),点击直达结果。
8360
- 失败时永远给出"下一步可以做什么"(重试 / 换文件 / 查看日志 / 复制错误),不要只留一行红色字。`;
8461

@@ -87,7 +64,6 @@ What happens around the code matters more than the code itself. The finish shoul
8764
- First launch = demo mode: auto-load sample-data/ and run the main flow once so the user sees a real result page, not an empty state.
8865
- The workspace always has a "Try with sample data" button up top — one click to a full demo any time.
8966
- Buttons, hints, and errors in business language. Example: "Can't find the Order ID column", not "Column 'order_id' not found".
90-
- Any write goes through "Save as"; never overwrite originals; timestamp on conflict.
9167
- Operations with ≥3 steps offer Undo or Cancel; ≥5-step critical actions require confirmation.
9268
- Long-running tasks show a progress bar + ETA, refreshed at most once per second.
9369
- The moment the main flow finishes, give in-app feedback; if the window is in the background, also fire a system notification that opens the result on click.
@@ -96,7 +72,7 @@ What happens around the code matters more than the code itself. The finish shoul
9672
// ─── Success Picture (the moment of "wow") ──────────────────────
9773

9874
export const SUCCESS_PICTURE_ZH = `【完成态画面】
99-
主流程结束的那一屏,是用户对这个工具的第一印象。把它当礼物来做。
75+
主流程结束的那一屏,是用户对这个工具最持久的印象。把它当礼物来做。
10076
- 大号数字 + 业务语言小结,30 字以内。例:「对账 482 单,差异 5 单。已存到 桌面/差异-2026-05.xlsx」。
10177
- 关键发现用一行带颜色的 chip 摘要:「⚠ 3 单金额不一致 · ✦ 2 单疑似退款」。
10278
- 三个动作按钮固定位置:「打开输出文件夹」「再做一次」「换一个文件」。

0 commit comments

Comments
 (0)