26 KiB
Quy trình triển khai Auto User Guide Generation
Mục tiêu của tính năng này là biến OpenScreen từ công cụ quay màn hình thành công cụ tự tạo tài liệu hướng dẫn sử dụng phần mềm. Người dùng bật Guide Mode, quay thao tác như bình thường, hệ thống ghi lại thời điểm click hoặc hotkey, trích ảnh từ video sau khi quay xong, chạy OCR local để đọc chữ trên giao diện, sau đó dùng AI tạo bản nháp hướng dẫn từng bước.
Tài liệu này được viết để có thể bắt đầu coding ngay: có kiến trúc, schema, file cần thêm/sửa, thứ tự task, tiêu chí test và định nghĩa MVP.
Trạng Thái MVP Hiện Tại
- Đã có Guide Mode trong HUD, ghi click/marker vào
.guide.json. - Đã có GuidePanel trong editor để chạy: prepare events, capture snapshots, OCR, generate draft, export Markdown/HTML.
- Đã có local deterministic draft để test không cần DeepSeek key.
- DeepSeek được gọi khi chọn provider
DeepSeekvà cóDEEPSEEK_API_KEY. - OCR local mặc định gọi
OPENSCREEN_GUIDE_OCR_URLhoặchttp://127.0.0.1:8866/ocr. - Verification hiện tại: targeted guide tests pass,
npm testpass,npm run build-vitepass,npm run i18n:checkpass.
Mục Tiêu Sản Phẩm
Flow người dùng:
- Bật Guide Mode.
- Quay màn hình phần mềm cần hướng dẫn.
- Trong lúc quay, hệ thống tự ghi timestamp các click chuột.
- Người dùng có thể bấm một hotkey/nút marker nếu muốn đánh dấu bước thủ công.
- Sau khi dừng quay, hệ thống trích ảnh màn hình từ video tại các timestamp đó.
- OCR local đọc text trên ảnh giao diện.
- Hệ thống map vị trí click tới text/control gần nhất.
- AI Agent tạo tài liệu dạng từng bước.
- Người dùng review, sửa nội dung, export Markdown/HTML.
Ví dụ output:
# Hướng dẫn xuất báo cáo
## Bước 1: Mở phần cài đặt
Nhấn nút **Settings** ở thanh điều hướng bên trái.
## Bước 2: Chọn Export
Trong màn hình Settings, chọn **Export report**.
Phạm Vi MVP
MVP cần làm:
- Bật/tắt Guide Mode trước khi quay.
- Tận dụng recorder hiện tại, không viết recorder mới.
- Tận dụng
.cursor.jsonhiện tại để lấy click timestamp. - Thêm marker bằng hotkey hoặc nút trên HUD.
- Tạo sidecar
.guide.jsonriêng cho guide. - Trích screenshot sau khi quay xong, từ video đã lưu.
- OCR local bằng PaddleOCR service.
- Tạo step candidate từ click position + OCR blocks.
- Gọi DeepSeek bằng text metadata, không gửi ảnh mặc định.
- Có panel review trong editor.
- Export Markdown và HTML.
Không làm trong MVP:
- Không chụp screenshot realtime trong lúc quay nếu chưa có benchmark cần thiết.
- Không gửi raw screenshot lên cloud AI mặc định.
- Không sửa schema
.cursor.jsonnếu không bắt buộc. - Không build full UI automation engine.
- Không làm PDF/DOCX ngay.
- Không bundle OCR runtime vào app packaged ngay.
Code Hiện Có Cần Tận Dụng
Các điểm đã có trong codebase:
- Recording orchestration:
src/hooks/useScreenRecorder.ts - Launch/HUD UI:
src/components/launch/LaunchWindow.tsx - Source selection:
src/components/launch/SourceSelector.tsx - Editor chính:
src/components/video-editor/VideoEditor.tsx - Project/session persistence:
src/components/video-editor/projectPersistence.ts - Cursor contracts:
src/native/contracts.ts - Hook đọc cursor data:
src/native/hooks/useCursorRecordingData.ts - IPC main handlers:
electron/ipc/handlers.ts - Native bridge:
electron/ipc/nativeBridge.ts - Cursor service:
electron/native-bridge/services/cursorService.ts - Windows cursor recording:
electron/native-bridge/cursor/recording/windowsNativeRecordingSession.ts - macOS cursor recording:
electron/native-bridge/cursor/recording/macNativeCursorRecordingSession.ts - Frame/export primitives:
src/lib/exporter/frameRenderer.ts
Nhận định kỹ thuật:
- Windows/macOS native cursor recording đã có dữ liệu click.
- Cursor sample hiện có thể có
interactionType: "click" | "mouseup" | "move". - Editor hiện đã dùng click timestamp để render hiệu ứng click.
- Vì schema cursor đang được nhiều nơi dùng, MVP nên tạo
.guide.jsonriêng thay vì mở rộng.cursor.json.
Kiến Trúc Tổng Thể
flowchart TD
A["User bật Guide Mode"] --> B["Quay video bằng recorder hiện tại"]
B --> C["Cursor recorder ghi click timestamp"]
B --> D["Hotkey/HUD marker ghi manual event"]
C --> E["Dừng quay"]
D --> E
E --> F["Guide assembler tạo .guide.json"]
F --> G["Snapshot extractor seek video và xuất PNG"]
G --> H["PaddleOCR local đọc text + bounding boxes"]
H --> I["Target mapper map click tới OCR text/control"]
I --> J["DeepSeek/local LLM viết draft guide"]
J --> K["GuidePanel cho user review/sửa"]
K --> L["Export Markdown/HTML"]
Quyết định chính:
- Realtime recording chỉ ghi event/timestamp, không xử lý OCR/AI.
- Screenshot được trích từ video sau khi quay, tránh ảnh hưởng performance recorder.
- OCR chạy local-first.
- DeepSeek chỉ nhận text metadata trừ khi user opt-in gửi ảnh.
- Guide data nằm cạnh recording artifact.
File Cần Thêm
src/guide/
contracts.ts
eventBuilder.ts
targetMapper.ts
promptBuilder.ts
generatedGuideSchema.ts
snapshot/
extractGuideSnapshots.ts
export/
markdownExporter.ts
htmlExporter.ts
__tests__/
eventBuilder.test.ts
targetMapper.test.ts
promptBuilder.test.ts
markdownExporter.test.ts
src/components/video-editor/guide/
GuidePanel.tsx
GuideStepList.tsx
GuideStepEditor.tsx
GuideSnapshotPreview.tsx
electron/guide/
guideStore.ts
guidePaths.ts
guideIpc.ts
ocr/
paddleOcrClient.ts
ai/
deepseekGuideClient.ts
File hiện có khả năng phải sửa:
src/hooks/useScreenRecorder.tssrc/components/launch/LaunchWindow.tsxsrc/components/video-editor/VideoEditor.tsxelectron/ipc/handlers.tselectron/preload.ts- file khai báo type cho
window.electronAPI package.jsonnếu thêm script test hoặc dependency nhỏ
Artifact Đầu Ra
Với video recording-123.mp4, hệ thống tạo:
recording-123.mp4
recording-123.cursor.json
recording-123.guide.json
recording-123-guide/
step-001.png
step-002.png
ocr.json
guide.md
guide.html
Quy tắc:
.cursor.jsonvẫn là dữ liệu cursor gốc..guide.jsonlà source of truth cho guide workflow.- Folder
recording-123-guide/chứa file phát sinh từ guide. guide.mdvàguide.htmlcó thể được tạo lại từ.guide.json.
Contract Chính
Tạo src/guide/contracts.ts.
export type GuideEventKind = "click" | "hotkey" | "manual";
export type GuideEventSource =
| "cursor-recording"
| "guide-hotkey"
| "review-ui";
export interface GuideEvent {
id: string;
recordingId: string;
kind: GuideEventKind;
source: GuideEventSource;
timeMs: number;
x?: number;
y?: number;
normalizedX?: number;
normalizedY?: number;
button?: "left" | "right" | "middle" | "unknown";
label?: string;
screenshotOffsetMs?: number;
createdAt: string;
}
export interface GuideSnapshot {
id: string;
eventId: string;
timeMs: number;
offsetMs: number;
path: string;
width: number;
height: number;
}
export interface OcrBlock {
id: string;
snapshotId: string;
text: string;
confidence: number;
box: {
x: number;
y: number;
width: number;
height: number;
};
}
export interface GuideStepCandidate {
id: string;
eventId: string;
snapshotId?: string;
timeMs: number;
action: "click" | "choose" | "type" | "wait" | "manual";
targetText?: string;
targetRole?: "button" | "menu" | "tab" | "field" | "link" | "unknown";
nearbyText: string[];
confidence: number;
}
export interface GeneratedGuideStep {
id: string;
order: number;
title: string;
instruction: string;
screenshotPath?: string;
sourceCandidateId?: string;
}
export interface GeneratedGuide {
title: string;
summary?: string;
steps: GeneratedGuideStep[];
}
export interface GuideSession {
schemaVersion: 1;
recordingId: string;
videoPath: string;
cursorPath?: string;
guidePath: string;
outputDir: string;
status:
| "recording"
| "events-ready"
| "snapshots-ready"
| "ocr-ready"
| "draft-ready"
| "reviewed";
events: GuideEvent[];
snapshots: GuideSnapshot[];
ocrBlocks: OcrBlock[];
candidates: GuideStepCandidate[];
generatedGuide?: GeneratedGuide;
createdAt: string;
updatedAt: string;
}
Quy tắc dữ liệu:
timeMsluôn tính theo timeline video cuối cùng.x/ylà tọa độ pixel nếu có.normalizedX/Ydùng để chống lệch khi video scale.screenshotOffsetMsmặc định500, nghĩa là lấy ảnh sau click 0.5 giây để bắt trạng thái UI sau thao tác.- AI output chỉ là draft, user edit mới là nội dung cuối.
IPC Cần Thêm
MVP dùng app-level Electron IPC, không cần đưa vào native bridge vì đây là workflow cấp ứng dụng.
Preload API đề xuất:
window.electronAPI.guide = {
startSession(recordingId: string): Promise<GuideSession>;
addMarker(input: AddGuideMarkerInput): Promise<GuideEvent>;
finalizeEvents(input: FinalizeGuideEventsInput): Promise<GuideSession>;
writeSnapshot(input: WriteGuideSnapshotInput): Promise<GuideSnapshot>;
runOcr(input: RunGuideOcrInput): Promise<GuideSession>;
generateDraft(input: GenerateGuideDraftInput): Promise<GuideSession>;
saveGuide(input: SaveGuideInput): Promise<GuideSession>;
exportMarkdown(input: ExportGuideInput): Promise<{ path: string }>;
exportHtml(input: ExportGuideInput): Promise<{ path: string }>;
};
Input types:
export interface AddGuideMarkerInput {
recordingId: string;
timeMs: number;
kind: "hotkey" | "manual";
label?: string;
}
export interface FinalizeGuideEventsInput {
recordingId: string;
videoPath: string;
cursorPath?: string;
}
export interface WriteGuideSnapshotInput {
recordingId: string;
eventId: string;
timeMs: number;
offsetMs: number;
pngBytes: ArrayBuffer;
width: number;
height: number;
}
export interface RunGuideOcrInput {
recordingId: string;
snapshotIds?: string[];
}
export interface GenerateGuideDraftInput {
recordingId: string;
language: "vi" | "en";
provider: "deepseek" | "local";
}
export interface SaveGuideInput {
recordingId: string;
generatedGuide: GeneratedGuide;
}
export interface ExportGuideInput {
recordingId: string;
}
Phase 1: Contracts, Store, IPC
Mục tiêu: tạo khung lưu trữ .guide.json mà chưa đụng recorder.
Task coding:
- Tạo
src/guide/contracts.ts. - Tạo
electron/guide/guidePaths.ts. - Tạo
electron/guide/guideStore.ts. - Tạo
electron/guide/guideIpc.ts. - Register guide IPC trong
electron/ipc/handlers.ts. - Expose API trong
electron/preload.ts. - Bổ sung type cho
window.electronAPI.guide.
Yêu cầu kỹ thuật:
- Ghi file atomically: write temp file rồi rename.
- Validate
schemaVersion. - Không throw raw error ra renderer, trả error code ổn định.
- Không yêu cầu AI/OCR trong phase này.
Acceptance:
- Tạo được guide session fake bằng IPC.
- Đọc/ghi
.guide.jsonround-trip không mất dữ liệu. - Input thiếu
recordingIdhoặcvideoPathbị reject rõ ràng.
Test:
guideStoretạo path đúng.guideStoređọc file lỗi schema và trả error.- IPC handler reject input thiếu field.
Phase 2: Build Event Từ Cursor Click
Mục tiêu: lấy click event từ .cursor.json hiện tại.
Task coding:
- Tạo
src/guide/eventBuilder.ts. - Thêm hàm
buildGuideEventsFromCursor. - Lọc sample có
interactionType === "click". - Convert sang
GuideEvent. - De-duplicate click trong cửa sổ
250ms. - Sort theo
timeMs. - Merge với marker thủ công nếu có.
Pseudo-code:
export function buildGuideEventsFromCursor(input: {
recordingId: string;
samples: CursorRecordingSample[];
videoWidth?: number;
videoHeight?: number;
}): GuideEvent[] {
const events = input.samples
.filter((sample) => sample.interactionType === "click")
.map((sample) => ({
id: createGuideEventId(input.recordingId, sample.timeMs),
recordingId: input.recordingId,
kind: "click" as const,
source: "cursor-recording" as const,
timeMs: sample.timeMs,
x: sample.cx,
y: sample.cy,
normalizedX: normalize(sample.cx, input.videoWidth),
normalizedY: normalize(sample.cy, input.videoHeight),
button: "left" as const,
screenshotOffsetMs: 500,
createdAt: new Date().toISOString(),
}));
return sortGuideEvents(dedupeGuideEvents(events));
}
Acceptance:
- 5 click samples tạo 5 guide events.
movevàmouseupkhông tạo step.- Double click hoặc click bounce không tạo quá nhiều step nếu nằm trong dedupe window.
- Không có cursor click thì vẫn dùng được manual marker.
Test:
- convert click sample.
- bỏ qua move/mouseup.
- dedupe theo thời gian.
- sort đúng thứ tự.
- xử lý sample thiếu tọa độ.
Phase 3: Guide Mode UI Và Manual Marker
Mục tiêu: user bật được Guide Mode và đánh dấu bước thủ công.
Task coding:
- Thêm Guide Mode toggle trong
LaunchWindow.tsx. - Truyền trạng thái guide vào flow recording trong
useScreenRecorder.ts. - Khi start recording và Guide Mode on, gọi
guide.startSession(recordingId). - Thêm nút marker trong HUD.
- Thêm global hotkey ở Electron main, ví dụ
CommandOrControl+Shift+G. - Khi bấm marker/hotkey, gọi
guide.addMarker. - Khi stop recording, gọi
guide.finalizeEvents.
Lưu ý:
- Global hotkey phải nằm ở Electron main vì app đang được quay có thể đang focus.
- Nếu register hotkey fail, UI vẫn dùng nút marker.
- Không làm thay đổi behavior khi Guide Mode off.
Acceptance:
- Guide Mode off: quay/sửa/export vẫn như cũ.
- Guide Mode on: stop recording tạo
.guide.json. - Hotkey tạo event đúng timestamp.
- Cancel recording không để lại guide artifact rác.
Phase 4: Snapshot Extraction
Mục tiêu: trích ảnh PNG cho từng event sau khi quay xong.
Quyết định MVP:
- Không chụp realtime trong lúc quay.
- Dùng video đã lưu, seek tới timestamp cần lấy.
- Thực hiện trong renderer/editor bằng hidden
<video>+<canvas>. - Persist PNG qua IPC.
Task coding:
- Tạo
src/guide/snapshot/extractGuideSnapshots.ts. - Nhận
GuideSession+videoPath. - Với mỗi event, lấy timestamp
event.timeMs + screenshotOffsetMs. - Clamp timestamp vào duration video.
- Seek hidden video tới timestamp.
- Draw frame vào canvas.
- Convert canvas thành PNG bytes.
- Gọi
guide.writeSnapshot. - Update
.guide.jsonvới danh sách snapshots.
Acceptance:
- Mỗi event có một ảnh
step-xxx.png. - Nếu một event fail snapshot, các event khác vẫn chạy.
- Ảnh được lưu trong
recording-123-guide/. - UI báo lỗi recoverable, không crash editor.
Test:
- clamp timestamp.
- tên file đúng thứ tự.
- handle seek timeout.
- không abort toàn bộ batch khi một frame lỗi.
Phase 5: OCR Local
Mục tiêu: đọc text trên giao diện phần mềm từ screenshot.
Khuyến nghị:
- Dùng PaddleOCR làm OCR chính.
- Tesseract chỉ nên là fallback đơn giản.
- VLM local như Gemma 3 4B/MiniCPM/Qwen-VL chỉ dùng cho trường hợp icon/no-text khó, không dùng làm OCR chính.
Kiến trúc MVP:
- Chạy PaddleOCR như local HTTP service tại
127.0.0.1:8866. - Electron main gọi OCR service.
- Renderer không gọi OCR trực tiếp.
API local OCR đề xuất:
GET /health
POST /ocr
Content-Type: application/json
{
"imagePath": "D:\\Code\\OpenScreen\\recording-123-guide\\step-001.png",
"language": "vi,en"
}
Response:
{
"blocks": [
{
"text": "Settings",
"confidence": 0.97,
"box": { "x": 120, "y": 80, "width": 90, "height": 24 }
}
]
}
Task coding:
- Tạo
electron/guide/ocr/paddleOcrClient.ts. - Thêm health check.
- Gọi OCR cho từng snapshot.
- Convert output sang
OcrBlock. - Ghi
ocrBlocksvào.guide.json. - Ghi bản tổng hợp vào
recording-123-guide/ocr.json.
Config đề xuất:
export interface GuideOcrConfig {
provider: "paddleocr";
baseUrl: string; // default http://127.0.0.1:8866
language: string; // default vi,en
timeoutMs: number; // default 30000
}
Acceptance:
- OCR service offline thì UI báo lỗi rõ ràng.
- OCR fail không xóa snapshots.
- OCR result có text, confidence, bounding box.
- Guide vẫn export thủ công được nếu OCR không chạy.
Phase 6: Target Mapper
Mục tiêu: xác định user đã click vào nút/menu/field nào dựa trên tọa độ click và OCR.
Task coding:
- Tạo
src/guide/targetMapper.ts. - Với mỗi
GuideEvent, lấy snapshot tương ứng. - Lấy OCR blocks của snapshot đó.
- Score từng OCR block.
- Chọn target tốt nhất.
- Sinh
GuideStepCandidate.
Scoring đề xuất:
+100nếu click nằm trong OCR box.- Điểm cao hơn nếu box center gần click hơn.
- Cộng điểm nếu text ngắn, giống label button/menu.
- Trừ điểm nếu confidence thấp.
- Nếu không có block đủ tốt, để
targetRole: "unknown".
Role heuristic:
button: click vào/near text dạng action label.menu: text nằm trong danh sách dọc.tab: text nằm trong hàng ngang gần đầu giao diện.field: click vào vùng giống input.unknown: không đủ tự tin.
Acceptance:
- Click trực tiếp vào nút text map đúng target text.
- Click gần label map được OCR block gần nhất.
- Click vùng icon/no-text tạo candidate confidence thấp để user review.
Test:
- click inside box.
- nearest box.
- low-confidence penalty.
- no OCR fallback.
Phase 7: AI Draft Generation
Mục tiêu: tạo bản nháp hướng dẫn từ candidate metadata.
Provider MVP:
- DeepSeek API cho cloud text generation.
- Local LLM có thể thêm sau qua cùng prompt contract.
- Không gửi ảnh lên DeepSeek mặc định.
Task coding:
- Tạo
src/guide/promptBuilder.ts. - Tạo
electron/guide/ai/deepseekGuideClient.ts. - Đọc API key ở Electron main qua env/config.
- Build prompt từ candidates + OCR nearby text.
- Yêu cầu output JSON.
- Validate output.
- Ghi
generatedGuidevào.guide.json.
Env:
$env:DEEPSEEK_API_KEY="..."
$env:DEEPSEEK_BASE_URL="https://api.deepseek.com"
$env:DEEPSEEK_MODEL="deepseek-v4-flash"
Prompt input:
{
"language": "vi",
"softwareContext": {
"recordingName": "recording-123",
"userGoal": "Tạo báo cáo"
},
"steps": [
{
"order": 1,
"eventKind": "click",
"targetText": "Settings",
"targetRole": "button",
"nearbyText": ["Home", "Settings", "Account"],
"confidence": 0.91
}
]
}
Expected AI output:
{
"title": "Hướng dẫn thao tác",
"summary": "Tài liệu này mô tả các bước thực hiện thao tác đã ghi hình.",
"steps": [
{
"order": 1,
"title": "Mở phần cài đặt",
"instruction": "Nhấn nút Settings ở thanh điều hướng bên trái."
}
]
}
Acceptance:
- Thiếu API key thì UI báo lỗi rõ ràng.
- AI trả invalid JSON thì reject và cho retry.
- Output được validate trước khi lưu.
- Có thể generate tiếng Việt.
Test:
- promptBuilder không đưa raw image vào prompt.
- parser reject JSON sai schema.
- DeepSeek client handle timeout/401/rate limit.
Phase 8: GuidePanel Review UI
Mục tiêu: người dùng sửa được guide trước khi export.
Task coding:
- Tạo
src/components/video-editor/guide/GuidePanel.tsx. - Tạo
GuideStepList.tsx. - Tạo
GuideStepEditor.tsx. - Tạo
GuideSnapshotPreview.tsx. - Mount panel trong
VideoEditor.tsx. - Load
.guide.jsonkhi mở video có guide sidecar. - Thêm action:
- Generate snapshots.
- Run OCR.
- Generate AI draft.
- Save edits.
- Export Markdown.
- Export HTML.
UX:
- AI output là draft, không khóa nội dung.
- User sửa title/instruction từng step.
- User xóa step nhiễu.
- User merge step sau nếu cần.
- Confidence hiển thị nhỏ, không làm UI rối.
- Guide fail không ảnh hưởng video editing.
Acceptance:
- User sửa step và save được.
- User xóa step được.
- Regenerate cần confirm nếu đang có manual edits.
- Export dùng nội dung đã sửa, không dùng lại AI raw output.
Phase 9: Export Markdown/HTML
Mục tiêu: tạo tài liệu dùng được ngay.
Task coding:
- Tạo
src/guide/export/markdownExporter.ts. - Tạo
src/guide/export/htmlExporter.ts. - Gọi exporter từ Electron IPC.
- Ghi file vào
recording-123-guide/guide.md. - Ghi file vào
recording-123-guide/guide.html. - Dùng relative screenshot link.
Markdown format:
# Hướng dẫn thao tác
Tài liệu này mô tả các bước thực hiện thao tác đã ghi hình.
## Bước 1: Mở phần cài đặt
Nhấn nút **Settings** ở thanh điều hướng bên trái.

Acceptance:
- Markdown mở được và thấy ảnh local.
- HTML mở được bằng browser.
- Export vẫn chạy nếu guide được viết thủ công, không cần AI.
Thứ Tự Coding Ngay
Nên làm theo thứ tự này để giảm rủi ro:
- Tạo
src/guide/contracts.ts. - Tạo
electron/guide/guidePaths.ts. - Tạo
electron/guide/guideStore.ts. - Tạo
electron/guide/guideIpc.ts. - Expose
window.electronAPI.guide. - Viết unit test cho guide store.
- Tạo
src/guide/eventBuilder.ts. - Viết unit test convert cursor samples sang guide events.
- Thêm Guide Mode toggle vào launch UI.
- Gọi
startSessionkhi bắt đầu quay. - Gọi
finalizeEventskhi dừng quay. - Tạo snapshot extractor trong renderer.
- Tạo
paddleOcrClient. - Tạo
targetMapper. - Tạo
promptBuilder. - Tạo
deepseekGuideClient. - Tạo
GuidePanel. - Tạo Markdown/HTML exporters.
- Chạy lint/test/build.
- Test thủ công flow đầy đủ.
Chia PR đề xuất:
- PR 1: contracts, store, IPC, unit tests.
- PR 2: cursor-click event builder, Guide Mode toggle, manual marker.
- PR 3: snapshot extraction và GuidePanel shell.
- PR 4: PaddleOCR integration và target mapping.
- PR 5: DeepSeek generation, review UI, Markdown/HTML export.
Error Codes
Dùng error code ổn định để UI xử lý:
export type GuideErrorCode =
| "guide-session-not-found"
| "guide-invalid-schema"
| "guide-video-load-failed"
| "guide-snapshot-failed"
| "guide-ocr-unavailable"
| "guide-ocr-failed"
| "guide-ai-key-missing"
| "guide-ai-request-failed"
| "guide-ai-invalid-output"
| "guide-export-failed";
Quy tắc:
- IPC không throw raw provider error ra renderer.
- OCR fail là recoverable.
- AI fail là recoverable.
- Export fail phải giữ nguyên
.guide.json.
Local Development
Baseline:
npm install
npm run lint
npm test
npm run build-vite
OCR service dev:
python -m venv .venv-ocr
.venv-ocr\Scripts\Activate.ps1
pip install paddleocr fastapi uvicorn
uvicorn local_ocr_service:app --host 127.0.0.1 --port 8866
DeepSeek env:
$env:DEEPSEEK_API_KEY="..."
$env:DEEPSEEK_BASE_URL="https://api.deepseek.com"
$env:DEEPSEEK_MODEL="deepseek-v4-flash"
Không commit API key.
Testing Matrix
Unit tests:
eventBuilder: cursor sample -> guide events.targetMapper: OCR blocks -> step candidates.promptBuilder: candidates -> AI prompt.markdownExporter: generated guide -> Markdown.htmlExporter: generated guide -> HTML.
Renderer/browser tests:
- snapshot extractor seek video fixture.
- GuidePanel edit/delete/save step.
Manual integration:
- Quay với Guide Mode off, xác nhận behavior cũ không đổi.
- Quay với Guide Mode on và 3 click.
- Kiểm tra
.guide.jsoncó 3 click events. - Generate snapshots.
- Run OCR local.
- Generate Vietnamese draft.
- Sửa một step.
- Export Markdown.
- Mở Markdown/HTML xem ảnh local.
- Tắt OCR service và test lỗi recoverable.
- Xóa DeepSeek key và test lỗi recoverable.
Lệnh trước khi merge:
npm run lint
npm test
npm run build-vite
Nếu phase không sửa native recorder thì chưa cần chạy native helper tests.
Definition Of Done Cho MVP
MVP được xem là xong khi:
- Guide Mode bật/tắt được.
- Guide Mode off không ảnh hưởng recording hiện tại.
- Click events lấy được từ cursor telemetry hiện có.
- Hotkey/HUD marker tạo event thủ công.
.guide.jsonđược tạo cạnh recording.- Snapshot PNG được trích từ final video.
- PaddleOCR local đọc được text và bounding boxes.
- Target mapper tạo step candidates.
- DeepSeek tạo được draft tiếng Việt từ text metadata.
- User review/sửa/xóa step được.
- Export Markdown/HTML dùng nội dung đã review.
- Lint/test/build pass.
Nâng Cấp Sau MVP
- Export PDF/DOCX.
- Bundle local OCR runtime vào packaged app.
- Thêm local VLM fallback cho icon-only control.
- Cho phép user opt-in gửi crop ảnh lên remote vision model.
- Merge/dedupe step thông minh hơn cho double click/menu navigation.
- Dùng transcript giọng nói làm ngữ cảnh thêm.
- Template theo từng loại phần mềm.
- Computer vision detect UI element ngoài OCR.