- Vấn đề: Học viên có thể nghĩ ra ý rời rạc nhưng không biết phát triển thành một flow nói có logic. Khi nói dài hơn 1 câu, các ý dễ bị ngang hàng, lặp lại, hoặc đi lan man.
- Đối tượng chính: Học viên luyện IELTS Speaking cần triển khai câu trả lời bằng Linearthinking trước khi chuyển sang luyện nói cả bài.
- Tín hiệu thành công: Học viên tự tạo được idea flow trên canvas, gắn đúng Linear Tool cho từng ý, thấy AI hoàn thiện từng ý thành câu nói tự nhiên, rồi dùng các câu đó để luyện nói.
- Source inventory ghi
Linear Tools dùng demo https://speakinglineartools.dol.vn/ và note là “Giống hệt như app đã deploy”.
Speak Many Sentences dùng cùng app, khác ở tab luyện nói từng câu: https://speakinglineartools.dol.vn/sis.html.
- Vì vậy file này mô tả canvas engine của Linear Tools;
PRA_EXAI_Speak_Many_Sentences.md chỉ ghi phần package/delta cho luyện nói.
Linear Tools là trải nghiệm canvas-based idea flow. Học viên bắt đầu từ một câu hỏi Speaking, tạo Answer, rồi thêm các panel theo chiều ngang hoặc chiều dọc để phát triển ý bằng Linear Tool.
AI không thay học viên nghĩ ý. Học viên nhập note ngắn trong từng panel; AI side panel bên phải dùng note đó, tool label, và quan hệ parent-child trên canvas để hoàn thiện thành câu nói tự nhiên. Kết quả của bước này là một chuỗi câu có thể chuyển tiếp sang tab Luyện nói cả bài.
- File này là canonical spec cho Linear Tool canvas engine:
question -> idea flow canvas -> AI sentence composer -> speaking rehearsal.
Speak Many Sentences build trên engine này như learner-facing package có thêm progress/replay.
| Field | Mô tả |
|---|
exercise_type | Dạng bài hiện tại, dùng để nhớ mic check theo từng loại bài |
question_id | ID câu hỏi được giao hoặc câu hỏi user chọn |
question_text | Câu hỏi Speaking hiển thị ở start card và Question node |
mic_check_key | Key lưu trạng thái mic, khuyến nghị user_id + exercise_type |
mic_check_status | unchecked, passed, skipped, failed |
mic_permission_status | unknown, granted, denied |
entry_state | mic_check, start_card, canvas_started |
Canvas không phải grid cố định. Canvas là một graph trực quan gồm các node và edge:
| Element | Vai trò |
|---|
Question | Câu hỏi gốc, là root context, không phải câu luyện nói |
Answer | Câu trả lời trực tiếp đầu tiên |
Description / Cause / Effect | Các Linear Tool dùng để phát triển ý (3 loại - không có Opinion) |
| Horizontal edge | Mở một ý mới phát triển trực tiếp từ answer/main idea |
| Vertical edge | Đào sâu node ngay trước đó |
| AI side panel | Hoàn thiện note trong mỗi node thành câu nói có thể luyện |
| Field | Mô tả |
|---|
id | Định danh kỹ thuật của node |
tool_type | answer, description, cause, hoặc effect |
note | Ý ngắn user nhập trong canvas |
generated_sentence | Câu nói AI hoàn thiện từ note |
parent_id | Node mà ý này đang phát triển |
relation | horizontal hoặc vertical |
display_label | Label học viên thấy, ví dụ #2, #2.A |
status | Empty, editing, analyzing, ready, needs_fix |
| Field | Mô tả |
|---|
selected_node_id | Node đang được focus trên canvas |
active_sentence_node_id | Node/card đang được chọn để luyện nói |
add_branch_source_id | Node nguồn khi user bấm nút mũi tên/plus thêm nhánh |
add_branch_direction | horizontal hoặc vertical |
tool_menu_node_id | Node đang mở menu đổi tool |
canvas_zoom | Zoom hiện tại của canvas |
canvas_viewport | Tọa độ pan/viewport hiện tại |
is_fullscreen | Canvas đang ở chế độ toàn màn hình hay không |
right_panel_mode | idea_suggestions, sentence_practice, full_speaking |
Tab Luyện nói cả bài dùng output của canvas nhưng có attempt snapshot riêng để việc chấm bài ổn định.
| Field | Mô tả |
|---|
script_snapshot | Full answer text tại thời điểm user bấm luyện nói |
sentence_segments | Danh sách câu theo flow ordering, giữ node_id, tool_type, display_label |
attempt_no | Lần nói hiện tại, ví dụ #1 |
recording_status | idle, recording, processing, completed, needs_retry |
user_recording_url | Audio user nói full answer trong một lần |
transcript | STT từ bản thu full answer |
alignment | Mapping transcript với sentence_segments để highlight |
full_score | Điểm tổng 0-100 cho bài nói |
coverage_status | enough, partial, hoặc silent |
is_stale | Attempt cũ không còn khớp khi canvas/script đã đổi |
- Mic check chỉ xuất hiện khi user chưa có reusable mic status cho
mic_check_key hiện tại. Reusable status gồm passed hoặc skipped.
- Khuyến nghị lưu theo
user_id + exercise_type để user chỉ cần test một lần cho cùng dạng bài. Nếu trình duyệt báo đổi mic, revoke permission, hoặc audio input liên tục silent ở lần ghi âm thật, hệ thống có thể yêu cầu test lại.
- Mic check không chấm nội dung và không ảnh hưởng điểm bài nói. Mục tiêu chỉ là xác nhận:
- user đã cấp quyền mic;
- input có tín hiệu âm thanh đủ nghe;
- recorder/STT có thể nhận audio.
- UI test mic nên đơn giản:
- tiêu đề
Kiểm tra microphone;
- waveform + countdown ngắn, ví dụ
5s;
- prompt nói thử, ví dụ: “Hãy nói gì đó bất kỳ…” + một câu vui dễ đọc;
- link phụ:
Bỏ qua, mic của tôi đã sẵn sàng.
- Nếu user bấm bỏ qua, hệ thống cho vào bài và lưu
skipped theo key này để lần sau không hỏi lại. Nếu lần ghi âm thật silent thì invalidate skipped và quay lại message retry/mic check.
| Trường hợp | Message UI thân thiện | CTA phù hợp |
|---|
| Cần test mic lần đầu | ”Kiểm tra mic một lần để AI nghe rõ bài nói của bạn nhé.” | Bắt đầu kiểm tra |
| Đang test | ”Hãy nói gì đó bất kỳ trong vài giây nhé.” | - |
| Mic pass | ”Mic đã sẵn sàng. Bắt đầu luyện nhé.” | Tiếp tục |
| Không có tín hiệu | ”AI chưa nghe thấy tiếng. Bạn kiểm tra mic rồi thử lại nhé.” | Thử lại |
| Permission denied | ”Bạn cần cho phép dùng micro để luyện nói.” | Mở quyền micro |
| User bỏ qua | ”Bạn có thể bắt đầu ngay. Nếu AI không nghe thấy tiếng, hệ thống sẽ nhắc kiểm tra lại mic.” | Bắt đầu |
- Entry mặc định của bài là câu hỏi cho sẵn. User trả lời theo câu hỏi này, không tự do nói một chủ đề khác.
- Start card hiển thị câu hỏi, ví dụ
What do you usually do to relax?, CTA Bắt đầu, và social proof nếu có.
- Khi user bấm
Bắt đầu, canvas tạo Question root và node Answer đầu tiên.
Question node là context cố định, không phải node user luyện nói.
Answer node là nơi user nhập ý trả lời trực tiếp cho câu hỏi được giao. Node này là nền cho toàn bộ Linear Tool flow phía sau.
- Nếu
Answer đang trống, user không được mở thêm node hoặc chuyển sang luyện cả bài. UI focus vào Answer và nhắc trả lời câu hỏi trước.
- Mỗi panel là một
Idea Node.
- User nhập note ngắn bằng tiếng Anh hoặc tiếng Việt.
- Node sau
Answer phải có tool label rõ ràng: Description, Cause, hoặc Effect (3 loại Linear Tool, không có Opinion).
- Mỗi node có thể đổi tool label; khi đổi label, AI recompute suggestion theo logic mới.
- Plus ngang bắt đầu flow thêm một nhánh ý mới phát triển từ answer/main idea.
- Plus dọc bắt đầu flow thêm một ý đào sâu node đang chọn.
- Khi user bấm nút mũi tên/plus thêm nhánh, hệ thống mở popover chọn Linear Tool thay vì tạo node ngay lập tức.
- Nếu node nguồn đang trống, user không tạo được node mới. UI focus lại input của node nguồn và nhắc điền ý trước.
- Nếu node nguồn đã có nội dung và AI đang phân tích, user vẫn được tạo node mới để giữ momentum.
- Nếu AI đã trả về lỗi blocking cho bất kỳ node nào trong flow, user không tạo thêm node mới cho tới khi các lỗi blocking đó được sửa.
- Canvas nên nudge học viên quay lại mở nhánh ngang sau khoảng 2-3 ý dọc để tránh lan man. Đây là coaching rule, không phải hard delete dữ liệu.
- Popover mở tại nút mũi tên/plus của node đang chọn.
- Header nên nói rõ node nguồn, ví dụ
Chọn Linear Tool phát triển "#di xem phim".
- Popover có 2 mode:
AI gợi ý: AI đề xuất 2-3 tool cards phù hợp với node nguồn.
Tự viết: user tự chọn tool type rồi nhập note trong node mới.
- Mỗi AI suggestion card gồm:
- tool label (
Description, Cause, hoặc Effect);
- note gợi ý ngắn;
- câu giải thích ngắn để user hiểu suggestion đang phát triển ý theo hướng nào.
- Khi user chọn AI suggestion:
- tạo node mới theo
add_branch_direction;
- set
tool_type theo card;
- prefill
note bằng note gợi ý;
- set node mới thành
selected_node_id;
- AI composer tạo hoặc refresh
generated_sentence.
- Khi user chọn
Tự viết:
- tạo node mới rỗng với tool type user chọn;
- focus input của node mới;
- chưa báo lỗi empty cho tới khi user bấm plus/chuyển luyện nói.
- Nếu source node đang empty hoặc flow còn
needs_fix, popover không nên mở rộng danh sách suggestion; chỉ hiển thị message ngắn và focus node cần sửa.
- Click vào badge tool trên node mở menu
Chỉnh tool hiện tại.
- Menu hiển thị tool hiện tại ở trạng thái disabled/checked, các tool còn lại là lựa chọn có thể đổi.
- Đổi tool chỉ đổi vai trò logic của node, không xóa note user đã nhập.
- Sau khi đổi tool:
- set node về
analyzing;
- clear warning cũ của node đó;
- AI recompute
generated_sentence theo tool mới và parent-chain hiện tại;
- side panel card giữ cùng
display_label, chỉ cập nhật tool label và sentence.
- Nếu đổi tool làm nội dung không khớp, AI có thể trả
needs_fix với message Wrong tool.
- Menu có thể có
Xóa nhánh, nhưng không áp dụng cho Question và Answer root.
Xóa nhánh xóa node hiện tại và toàn bộ node con của nó. Nếu nhánh đã có audio/attempt hoặc nhiều node con, UI nên xác nhận ngắn trước khi xóa.
- Khi xóa hoặc đổi tool làm script thay đổi, full speaking attempt cũ phải bị mark
stale.
- Canvas có các control điều hướng: phóng to, thu nhỏ, fit view, và toàn màn hình.
- Các control này chỉ thay đổi viewport, không thay đổi graph data, ordering, score, hoặc completion.
Zoom in/out: điều chỉnh canvas_zoom; giữ node đang chọn gần trung tâm nếu có thể.
Fit view: đưa toàn bộ graph liên quan vào viewport; nếu đang chọn node, ưu tiên fit cả node chọn và các node kết nối gần nó.
Fullscreen: mở canvas ở không gian rộng hơn để user thao tác nhiều nhánh. Side panel có thể thu gọn hoặc chuyển thành overlay, nhưng không làm mất state đang luyện.
- Khi thoát fullscreen, giữ lại
selected_node_id, active_sentence_node_id, và viewport gần nhất nếu hợp lý.
- Control cần có tooltip/icon rõ ràng; không dùng text dài trên canvas.
- Linear Tool gồm 3 loại (không có Opinion - quan điểm/nhận định cá nhân được hiểu là một dạng
Description về cảm xúc/đánh giá, không cần tool riêng):
- Description: cụ thể hóa ý trước đó bằng hành động, đối tượng, nơi chốn, thời điểm, điều kiện, tính chất, hoặc biểu hiện.
- Cause: giải thích lý do cho node trước đó.
- Effect: nêu hệ quả của node trước đó.
- AI phải hiểu rõ node dọc phát triển parent node trực tiếp, không tự động quy về
Answer.
- Panel bên phải hiển thị các câu nói đã được AI hoàn thiện từ canvas.
- Mỗi suggestion card giữ tool label và
display_label tương ứng với node trên canvas.
- Khi user chọn một node, side panel ưu tiên suggestion của node đó và dùng parent-chain làm context.
- Khi user click một suggestion card, card đó trở thành active item để luyện nói. Canvas cũng highlight node tương ứng.
- AI không tự ghi đè note trong canvas. AI chỉ tạo hoặc cập nhật
generated_sentence.
- Side panel có thể hiển thị “Tiếp tục chờ ý tưởng của bạn…” khi node chưa đủ note để compose.
- Nếu logic yếu, AI hiển thị warning nhẹ tại node hoặc side panel, ví dụ: tool label không khớp nội dung, node dọc không thật sự phát triển parent, hoặc flow quá sâu.
- Active card là bridge giữa canvas idea và luyện nói từng câu.
- Click card trong side panel:
- set
active_sentence_node_id;
- set
selected_node_id cùng node;
- scroll/center node trên canvas nếu node đang ngoài viewport;
- expand card để hiện
Nghe mẫu và Luyện nói.
- Active state phải hiển thị đồng bộ:
- node trên canvas có border/indicator active;
- card bên phải có border/controls active;
- các card khác vẫn xem được nhưng không mở control luyện nói chính.
- Khi user bấm
Luyện nói trên active card:
- chỉ thu âm câu của card đó;
- node/card chuyển sang recording state;
- sau khi nói xong, highlight pronunciation nằm trong card và có thể phản chiếu nhẹ trên node.
- Nếu user click card khác trong lúc đang recording, hệ thống nên hỏi/dừng attempt hiện tại trước khi chuyển active item.
Validation của canvas phải bảo vệ chất lượng flow nhưng không làm user mất nhịp khi AI còn đang xử lý.
| Trạng thái | User có được tạo node mới? | UI response |
|---|
| Node trống, user chưa bấm plus | Không cần báo lỗi | Chỉ hiện placeholder |
| User bấm plus từ node trống | Không | Focus node nguồn + nhắc “Điền ý cho ô này trước nhé.” |
| Node có nội dung, AI đang analyzing | Có | Cho mở add-branch popover và tạo node sau khi user chọn tool/suggestion |
AI trả về ready | Có | Sentence card được cập nhật |
AI trả về needs_fix | Không | Khóa tạo node mới; hiển thị lỗi thân thiện tại node và side panel |
| User sửa node lỗi, AI analyzing lại | Chưa khóa theo lỗi cũ nếu nội dung đã thay đổi | Cho tạo tiếp trong lúc chờ kết quả mới |
Message phải ngắn, thân thiện, và chỉ rõ việc user nên làm tiếp. Không dùng wording kiểu “sai”, “lỗi”, “không đúng” trên UI chính; dùng badge/state để hệ thống hiểu severity, còn copy nói theo hướng hỗ trợ.
| Trường hợp | Khi nào xảy ra | Branch gating | Message trên card | Message/label ở side panel | Quick action |
|---|
| Empty idle | Node chưa có nội dung, user chưa bấm plus | Không báo lỗi | Placeholder: “Chi tiết rõ hơn…” | Không hiện warning | - |
| Empty branch attempt | User bấm plus từ node trống | Chặn tạo node mới | ”Điền ý cho ô này trước nhé." | "Cần có ý trước khi mở nhánh mới.” | Focus input |
| Empty answer | Answer node trống nhưng user bấm plus hoặc chuyển tab luyện nói | Chặn tạo node/chuyển luyện nói | ”Trả lời câu hỏi này trước nhé." | "Cần có câu trả lời đầu tiên để bắt đầu phát triển ý.” | Focus Answer (đã có design - frame Empty trong file Figma: tooltip “Empty thì không được tạo thêm” + side-block icon ⊘ trên active card + side panel hiện “Chờ nội dung…” cho card #2) |
| AI analyzing | Node có nội dung, AI đang phân tích | Cho tạo node mới | Không warning; có loading nhỏ nếu cần | ”Chờ nội dung…” | - |
| Too short | Note có nội dung nhưng quá ngắn để compose câu tự nhiên | Chặn sau khi AI trả needs_fix | ”Ý này còn hơi ngắn. Thêm chi tiết như hành động, đối tượng hoặc thời điểm để rõ ý hơn nhé.” | Badge: “Cần thêm chi tiết" | "Viết rõ hơn” |
| Too vague | AI không hiểu rõ user muốn nói gì | Chặn sau khi AI trả needs_fix | ”AI chưa hiểu rõ ý này lắm. Bạn viết cụ thể hơn một chút nhé.” | Badge: “Chưa rõ ý" | "Viết cụ thể hơn” |
| Off-topic | Note chưa liên quan rõ tới câu hỏi hoặc answer chính | Chặn sau khi AI trả needs_fix | ”Ý này chưa nối rõ với câu hỏi lắm. Bạn thử kéo nó gần hơn với chủ đề chính nhé.” | Badge: “Chưa sát đề" | "Đổi ý” |
| Wrong tool - general | Nội dung hợp với tool khác hơn tool đang chọn | Chặn sau khi AI trả needs_fix | ”Ý này nghe giống {tool} hơn. Đổi sang {tool} để flow tự nhiên hơn nhé.” | Badge: “Nên đổi tool" | "Đổi sang {tool}“ |
| Description lacks detail | Node Description nhưng note không mô tả rõ ai/cái gì/ở đâu/khi nào | Chặn sau khi AI trả needs_fix | ”Ý này cần mô tả rõ hơn. Thêm ai, cái gì, ở đâu hoặc khi nào nhé.” | Badge: “Cần mô tả rõ hơn" | "Thêm chi tiết” |
| Cause lacks reason | Node Cause nhưng note chưa nói lý do | Chặn sau khi AI trả needs_fix | ”Ý này chưa nói rõ lý do. Thử viết vì sao điều đó xảy ra nhé.” | Badge: “Cần lý do" | "Thêm lý do” |
| Effect lacks result | Node Effect nhưng note chưa nêu hệ quả | Chặn sau khi AI trả needs_fix | ”Ý này chưa cho thấy kết quả sau đó. Thử viết điều gì xảy ra tiếp theo nhé.” | Badge: “Cần hệ quả" | "Thêm hệ quả” |
| Wrong parent | Node dọc không phát triển node cha trực tiếp | Chặn sau khi AI trả needs_fix | ”Ý này có vẻ đang nối với một ý khác. Bạn thử đặt nó dưới node phù hợp hơn nhé.” | Badge: “Cần nối lại flow" | "Chọn node cha” |
| Duplicate idea | Note lặp lại nội dung đã có trong flow | Chặn nếu làm flow không thêm ý mới; nếu nhẹ thì chỉ warning | ”Ý này hơi giống một ý phía trên. Bạn thử đổi sang một góc khác nhé.” | Badge: “Hơi trùng ý" | "Thử góc khác” |
| Contradiction | Note mâu thuẫn với answer hoặc node trước mà không phải contrast có chủ đích | Chặn sau khi AI trả needs_fix | ”Hai ý này đang hơi ngược nhau. Bạn muốn giữ hướng nào rõ hơn?” | Badge: “Ý đang lệch hướng" | "Chọn hướng chính” |
| Too long | User nhập cả đoạn dài vào một node | Không chặn nếu AI vẫn compose được; ưu tiên soft hint | ”Ý này hơi dài. Bạn có thể tách thành 2 ý để flow dễ theo dõi hơn.” | Badge: “Có thể tách ý" | "Tách thành 2 ý” |
| Too deep | Nhánh dọc đã đi quá sâu | Không chặn mặc định; dùng nudge | ”Nhánh này đang đi khá sâu rồi. Có thể mở thêm một ý mới bên cạnh nhé.” | Badge: “Nên mở nhánh mới" | "Mở nhánh ngang” |
| Delete branch with children | User bấm Xóa nhánh trên node có node con | Xác nhận trước khi xóa | ”Nhánh này có ý con bên dưới. Xóa nhánh sẽ xóa các ý đó luôn nhé.” | - | “Xóa nhánh” / “Giữ lại” |
| Switch active while recording | User click card khác khi câu hiện tại đang ghi âm | Chặn chuyển trực tiếp | ”Bạn dừng câu đang nói trước rồi chuyển sang câu khác nhé.” | - | “Dừng nói” |
Khi có needs_fix, các nút plus vẫn có thể hiện nhưng disabled. Tooltip/callout ngắn: “Bạn cần hoàn thiện các nội dung trước”.
- Câu nói hoàn chỉnh phải follow thứ tự đọc tự nhiên, không chỉ thứ tự tạo node.
- Rule mặc định: đọc
Answer trước, sau đó đi qua từng nhánh ngang từ trái sang phải; trong mỗi nhánh, đọc node cha rồi các node dọc liên quan trước khi sang nhánh ngang tiếp theo.
display_label cần giữ dấu quan hệ để user hiểu flow, ví dụ #2 là nhánh chính và #2.A là ý dọc của nhánh đó.
- Mỗi
generated_sentence trở thành một câu để luyện nói.
- Học viên tập trung một câu tại một thời điểm.
- Pronunciation feedback highlight từng từ: xanh = ổn, đỏ = cần cải thiện.
- Học viên được nói lại nhiều lần và nghe câu mẫu.
- Hệ thống nối các
generated_sentence theo flow ordering thành một full answer script.
- Tab này không phải nơi chỉnh ý. Nếu muốn đổi nội dung, user quay lại tab Lên ý tưởng hoặc bấm Tiếp tục phát triển.
- Mục tiêu chính: yêu cầu user nói liền mạch toàn bộ câu trả lời trong một lần ghi âm, không chỉ nghe mẫu hoặc ghép các câu đã luyện lẻ.
- Panel bên phải hiển thị:
- header
Luyện nói cả bài;
- bối cảnh/câu hỏi;
- chip tóm tắt tool count, ví dụ
DESCRIPTION: 2, CAUSE: 3, EFFECT: 3;
- full answer script;
- CTA
Luyện nói, Nghe mẫu, và warning nếu user chưa luyện full bài.
- Khi user bấm
Luyện nói, hệ thống tạo script_snapshot, bắt đầu recording, và đổi CTA sang trạng thái đang nói, ví dụ Đang nói #1 + Dừng nói.
- Khi user bấm
Nói xong/Dừng nói, hệ thống transcribe + align bản thu với script rồi trả về:
- highlight ngay trong full answer text;
- nút
Nghe lại, Nói lại;
- score tổng, ví dụ
Điểm luyện nói: 80/100;
- message định hướng tiếp theo.
- Highlight nên ở cấp cụm từ/từ, nhưng feedback chính vẫn là fluency toàn bài. Không biến tab này thành màn sửa phát âm từng từ chi tiết.
- Hover hoặc click vào highlight có thể mở annotation ngắn để giải thích vì sao đoạn đó tốt/chưa tốt; annotation không được che mất đoạn text đang đọc.
- Nếu user sửa canvas sau khi đã nói full bài, attempt cũ vẫn giữ để nghe lại nhưng bị đánh dấu
is_stale; user cần luyện lại để completion tính theo script mới.
| State | Khi nào | UI chính | Completion impact |
|---|
not_ready | Canvas chưa đủ readiness hoặc còn needs_fix | Disable Luyện nói; nhắc hoàn thiện ý trước (xem frame Empty trong Figma cho UI khi Answer card chưa có nội dung) | Chưa tính hoàn thành |
idle_ready | Full script đã sẵn sàng, user chưa ghi âm | Hiển thị script + Luyện nói + Nghe mẫu + warning cần luyện full bài | Chưa tính hoàn thành |
recording | User đang nói full answer | Đang nói #n hoặc Nói nhiều #n; nút Dừng nói; có thể highlight tiến độ nhẹ | Chưa tính hoàn thành |
processing | User vừa dừng nói, AI đang chấm | Disable CTA chính; hiện trạng thái đang chấm | Chưa tính hoàn thành |
completed | Có transcript, alignment, score, coverage đủ | Hiển thị highlight, Nghe lại, Nói lại, score, Tiếp tục | Có thể tính hoàn thành |
needs_retry | Không nghe thấy tiếng hoặc user mới nói một phần | Giữ script, show message retry, CTA Nói lại | Chưa tính hoàn thành |
stale | User đổi canvas/script sau attempt | Attempt cũ nghe lại được nhưng không còn tính cho script hiện tại | Cần luyện lại |
| Trường hợp | Message UI thân thiện | CTA phù hợp |
|---|
| Canvas chưa sẵn sàng | ”Bạn hoàn thiện các ý trước rồi luyện cả bài nhé.” | Tiếp tục phát triển |
| Chưa luyện full bài | ”Bạn cần luyện nói đầy đủ câu trả lời để hoàn thành bài tập này.” | Luyện nói |
| Mic chưa được cấp quyền | ”Cho phép dùng micro để bắt đầu luyện nói nhé.” | Thử lại |
| Đang ghi âm | ”Cứ nói liền mạch đến hết câu trả lời nhé.” | Dừng nói |
| Đang chấm | ”AI đang chấm bài nói của bạn…” | - |
| Không nghe thấy tiếng | ”AI chưa nghe thấy bài nói. Kiểm tra micro rồi thử lại nhé.” | Nói lại |
| Nói quá ngắn / thiếu nhiều đoạn | ”Bạn mới nói một phần câu trả lời. Thử nói liền mạch cả bài một lần nữa nhé.” | Nói lại |
| Nói xong, kết quả tốt | ”Bạn có thể làm câu tiếp theo, hoặc tiếp tục luyện lại câu trả lời hiện tại.” | Tiếp tục, Nói lại |
| Nói xong, cần cải thiện | ”Bài nói đã được lưu. Bạn có thể nói lại để mượt hơn trước khi tiếp tục.” | Nói lại, Tiếp tục |
| Script đã đổi sau khi nói | ”Nội dung bài nói đã thay đổi. Bạn luyện lại một lần để lưu kết quả mới nhé.” | Luyện nói lại |
| Bài mẫu chưa tải được | ”Chưa tải được bài mẫu. Bạn vẫn có thể luyện nói trước.” | Luyện nói |
| Bước | User làm gì | Hệ thống/AI phản hồi |
|---|
| 0.1 | Vào bài Linear Tool | Check mic_check_key = user_id + exercise_type |
| 0.2 | Nếu mic đã pass hoặc đã được user xác nhận bỏ qua trước đó | Bỏ qua màn test mic, đi thẳng tới start card |
| 0.3 | Nếu mic chưa pass | Hiển thị màn Kiểm tra microphone |
| 0.4 | User nói thử trong 5s | Hiển thị waveform; kiểm tra permission + audio signal |
| 0.5 | Mic pass | Lưu mic_check_status = passed cho dạng bài này |
| 0.6 | Không nghe thấy tiếng | Không lưu pass; nhắc thử lại hoặc kiểm tra quyền mic |
| 0.7 | User chọn bỏ qua | Cho vào start card và lưu mic_check_status = skipped |
| 0.8 | User bấm Bắt đầu ở start card | Tạo Question node và Answer #1 node |
| Bước | User làm gì | Hệ thống/AI phản hồi |
|---|
| 1.1 | Nhìn Question node | Thấy câu hỏi đã chọn/được giao, dùng làm context cố định |
| 1.2 | Nhập answer trực tiếp vào Answer #1 | AI analyze + compose câu answer đầu tiên |
| 1.3 | Bấm plus khi Answer trống | Không tạo node mới; focus Answer và nhắc trả lời câu hỏi trước |
| 1.4 | Bấm mũi tên/plus từ node có nội dung | Mở popover chọn Linear Tool phát triển node đó |
| 1.5 | Bấm plus khi flow có node needs_fix | Không tạo node mới; nhắc hoàn thiện nội dung trước |
| 1.6 | Chọn card AI gợi ý | Tạo node mới theo hướng plus, prefill note, AI compose sentence |
| 1.7 | Chọn Tự viết | Tạo node mới rỗng, focus input để user nhập note |
| 1.8 | Bấm badge tool trên node | Mở menu đổi tool hoặc xóa nhánh |
| 1.9 | Đổi tool label | Giữ note, AI hiểu lại vai trò logic và recompute sentence |
| 1.10 | Gõ/chỉnh note ngắn | AI analyze + compose câu nói ở side panel |
| 1.11 | Bấm zoom/fit/fullscreen | Canvas đổi viewport, không đổi dữ liệu flow |
| 1.12 | Bấm chuyển tab luyện nói | Hệ thống dùng flow ordering để tạo danh sách câu luyện |
Đây là bước hỗ trợ khi package bật sentence drill. Với flow 2 tab hiện tại, completion chính nằm ở Bước 3 - Luyện nói cả bài.
| Bước | User làm gì | Hệ thống/AI phản hồi |
|---|
| 2.1 | Mở tab/section luyện nói các câu | Danh sách sentence cards hiển thị theo flow ordering |
| 2.2 | Click một suggestion card trong side panel | Set card đó thành active item, highlight node tương ứng trên canvas |
| 2.3 | Nghe mẫu | Phát TTS của câu đang active |
| 2.4 | Bấm mic/Luyện nói trên active card | STT + pronunciation assessment cho câu đang active |
| 2.5 | Xem highlight | Từ đúng/sai được tô màu trong active card |
| 2.6 | Nói lại | Update highlight và lưu best attempt cho node/card đó |
| 2.7 | Click card khác | Chuyển active item nếu không có recording đang chạy |
| Bước | User làm gì | Hệ thống/AI phản hồi |
|---|
| 3.1 | Mở tab Luyện nói cả bài | Hệ thống assemble full answer script theo flow ordering, hiển thị bối cảnh + tool chips + script |
| 3.2 | Chưa luyện, chỉ đọc script | Hiển thị warning: “Bạn cần luyện nói đầy đủ câu trả lời để hoàn thành bài tập này.” |
| 3.3 | Bấm Nghe mẫu | Phát full TTS; có thể highlight theo script nếu audio timing có sẵn |
| 3.4 | Bấm Luyện nói | Tạo script_snapshot, xin quyền mic nếu cần, bắt đầu ghi âm full answer |
| 3.5 | Đang nói | CTA chuyển sang Đang nói #n hoặc Nói nhiều #n; hiện Dừng nói |
| 3.6 | Bấm Nói xong / Dừng nói | Dừng ghi âm, gửi audio đi STT + alignment + scoring |
| 3.7 | AI xử lý xong | Hiển thị transcript alignment bằng highlight, score tổng, Nghe lại, Nói lại |
| 3.8 | Hover/click highlight | Hiển thị annotation ngắn: phát âm tốt, thiếu từ, nói khác script, hoặc cần rõ hơn |
| 3.9 | Bấm Nói lại | Tạo attempt mới trên cùng script; giữ best/latest attempt trong session |
| 3.10 | Bấm Tiếp tục phát triển | Quay lại canvas để chỉnh ý; nếu script đổi, full speaking attempt cũ bị đánh dấu stale |
| 3.11 | Bấm Tiếp tục | Chỉ enable sau khi có full attempt đủ coverage; chuyển sang câu/bài tiếp theo |
| Trigger | AI action | Hiển thị trên UI |
|---|
| User vào bài | Check mic status theo user_id + exercise_type | Test mic hoặc start card |
| Mic test có tín hiệu | Save mic_check_status = passed | Cho qua start card |
| Mic test silent/denied | Không save pass | Message retry/permission |
User bấm Bắt đầu trên start card | Create Question root + Answer #1 | Canvas started |
User nhập Answer #1 | Compose answer sentence theo given question | Side panel card đầu tiên |
| Node idle sau khi user nhập note | Compose hoặc refresh generated_sentence | Side panel card tương ứng |
| User chọn node | Load suggestion theo selected node + parent-chain | Highlight node và card liên quan |
| User bấm mũi tên/plus thêm nhánh | Load add-branch suggestions theo source node + direction | Popover AI gợi ý / Tự viết |
| User chọn AI suggestion | Create node with suggested tool/note | Node mới + side panel card mới |
| User click badge tool | Open tool menu | Menu đổi tool / xóa nhánh |
| User đổi tool label | Reinterpret note theo tool mới | Suggestion update, warning nếu mismatch |
| User xóa nhánh | Delete node + descendants sau xác nhận nếu cần | Recompute ordering; mark attempts stale nếu script đổi |
| User dùng zoom/fit/fullscreen | Update viewport only | Canvas thay đổi khung nhìn, không đổi graph |
| User click suggestion card | Set active sentence/node | Card mở control luyện nói, node được highlight |
User bấm Luyện nói trên active card | Start sentence-level recording | Active node/card recording state |
| User bấm plus từ node trống | Không tạo node | Focus input + “Điền ý cho ô này trước nhé.” |
| User bấm plus khi AI đang analyzing node có nội dung | Vẫn cho mở add-branch popover | Node cũ vẫn loading, user có thể chọn tool để tạo node mới |
AI trả needs_fix cho node bất kỳ | Lock tạo node mới | Node/card có warning, plus disabled |
User sửa node needs_fix | Clear lỗi cũ, analyze lại | Plus được mở trong lúc chờ kết quả mới |
| User thêm node dọc | Treat node mới as child of selected node | Edge dọc + label như #2.A |
| Flow quá sâu | Nudge mở nhánh ngang mới | Warning nhẹ, không xóa node |
| Node thiếu note | Không compose full sentence | Placeholder chờ ý tưởng |
| Chuyển sang luyện nói | Freeze flow ordering tạm thời | Danh sách câu luyện |
| Mở tab luyện cả bài khi canvas chưa sẵn sàng | Không tạo script luyện nói | Nhắc hoàn thiện ý trước |
| Mở tab luyện cả bài khi script sẵn sàng | Assemble full script theo flow ordering | Panel Luyện nói cả bài + warning chưa luyện |
User bấm Luyện nói | Freeze script_snapshot cho attempt hiện tại | Recording state |
User bấm Dừng nói | Transcribe, align, score full attempt | Processing state |
| Coverage đủ | Lưu full attempt, hiển thị score + highlight | Enable Tiếp tục |
| Coverage thiếu hoặc không có tiếng | Không tính completion | Message retry + Nói lại |
| User đổi canvas sau full attempt | Mark attempt cũ stale | Nhắc luyện lại theo script mới |
| User hover/click highlight | Return annotation ngắn theo span | Popover/tooltip gần đoạn text |
| Thời điểm | Audio source | Trigger |
|---|
| Test mic | Short microphone sample | User nói thử trong preflight |
Sau khi có generated_sentence | Pre-generate TTS per sentence | Tự động, chạy ngầm nếu khả thi |
| Bước luyện từng câu | Play sentence TTS | User bấm nghe mẫu |
| Active sentence recording | Sentence-level recording | User bấm Luyện nói trên active card |
| Bước luyện cả bài | Concat hoặc stream các sentence TTS | User bấm play full |
| Bài full của user | Full recording trong một lần nói | User bấm Luyện nói rồi Dừng nói |
| Nghe lại bài user | Playback full recording; có thể seek theo segment nếu alignment có sẵn | User bấm Nghe lại |
- Có
Question.
- Có
Answer trả lời trực tiếp cho câu hỏi được giao.
- Có ít nhất 2 supporting Linear Tool nodes.
- Mỗi supporting node có tool label và note.
- Không còn node
needs_fix.
- AI đã tạo
generated_sentence cho các node được đưa vào bài nói.
- Mic check không phải hard gate nếu user đã có một full recording nghe được. Nếu user skip mic check nhưng audio thật bị silent, hệ thống invalidate
skipped và quay lại retry/mic check.
- Canvas đạt readiness.
- Full answer script đã được assemble theo flow ordering.
- Không còn sentence segment đang analyzing.
- Nếu user đã nói full bài trước đó nhưng canvas/script thay đổi, attempt cũ không còn tính completion cho script mới.
| Mức | Điều kiện | Label |
|---|
| Chưa đạt | Chưa nói hoặc > 50% từ đỏ | - |
| Đạt | <= 30% từ đỏ | ”Phát âm ổn” |
| Xuất sắc | 100% xanh | ”Phát âm chuẩn” |
Per-sentence scoring chỉ là hard gate khi package có bước luyện từng câu. Với tab luyện cả bài, dùng score tổng và coverage để quyết định completion.
| Signal | Vai trò | Completion rule |
|---|
| Coverage | User có nói đủ phần lớn full answer không | Hard gate |
| Fluency | Mức liền mạch, ít ngắt quãng, tự nhiên | Feedback chính |
| Pronunciation | Phát âm theo từ/cụm nổi bật | Feedback phụ, không biến thành drill từng từ |
| Coherence | Logic bài nói có nối ý được không | Chủ yếu kế thừa từ canvas; chỉ flag nếu transcript lệch mạnh |
V1 recommendation: completion cần coverage_status = enough, không bắt buộc score phải đạt 80/100. Score dùng để thúc đẩy nói lại, còn quyền Tiếp tục mở sau khi user đã thật sự nói full answer.
- Session tính là hoàn thành khi:
- Canvas đạt readiness.
- Full speaking readiness đạt.
- Học viên đã ghi âm full answer ít nhất 1 lần.
- Full attempt có coverage đủ, không phải silent/partial.
- Nếu sentence drill được bật, per-sentence practice có thể là gate riêng của package đó, không phải gate mặc định của flow 2 tab.
- Không yêu cầu mọi từ phải xanh hoặc score tổng phải đạt 100/100.
- Mini-map / fit-to-screen: hữu ích khi canvas có nhiều nhánh, tránh user mất phương hướng.
- Branch focus mode: click một nhánh để side panel chỉ hiện câu của nhánh đó; giảm overload khi flow dài.
- Tool mismatch hint: AI phát hiện note kiểu nguyên nhân nhưng node đang để
Description, rồi đề xuất đổi tool label.
- Depth nudge: sau 2-3 node dọc, UI gợi ý mở nhánh ngang mới thay vì tiếp tục kéo dọc.
- Version history per sentence: lưu các generated sentence gần nhất khi user chỉnh note, để tránh mất câu tốt.
- Mini-map: nếu graph thường lớn hơn viewport, thêm mini-map compact hơn các nút zoom rời.
- Full-answer attempt history: lưu best/latest attempt để user so sánh lần nói đầu và lần nói lại.
- Auto-scroll script during recording: nếu full answer dài, script tự giữ đoạn đang nói trong viewport.
- Sentence-level heatmap after full attempt: sau khi nói xong, click một câu trong script để thấy đoạn audio tương ứng và lỗi nổi bật.
- Knowledge base: Logic Linear Tools, chiều ngang/chiều dọc, và Part-specific framework.
- Mic permission + audio signal detector: Kiểm tra mic preflight và phát hiện silent recording.
- AI composer: Convert note + tool label + parent-chain thành sentence.
- Branch suggestion engine: Đề xuất Linear Tool + note khi user bấm thêm nhánh từ một node.
- Canvas viewport engine: Pan, zoom, fit view, fullscreen, và center selected node.
- TTS engine: Pre-generate audio mẫu khi có sentence.
- Speech-to-text + pronunciation assessment: Nhận diện câu nói, align với script, đánh giá phát âm per word/cụm từ.
- Full answer scorer: Tính coverage, fluency, pronunciation, và score tổng cho attempt nói liền mạch.
| # | Question | Status |
|---|
| 1 | Demo deployed có phải source-of-truth 1:1 cho interaction v1, hay chỉ là reference để nâng cấp? | Cần confirm product/tech |
| 2 | Side panel có cần nút Accept / Regenerate, hay auto-refresh là đủ cho v1? | Cần quyết định UX |
| 3 | Khi user đổi flow sau khi đã luyện nói, có freeze attempt cũ hay recompute toàn bộ? | Đề xuất V1: freeze attempt cũ theo snapshot, mark stale nếu script đổi |
| 4 | TTS latency có đủ nhanh để pre-gen sau mỗi sentence update không? | Cần confirm tech |
| 5 | Ngưỡng “Đạt” cụ thể có giữ <= 30% từ đỏ không? | Chỉ áp dụng rõ cho sentence drill; full speaking ưu tiên coverage + score tổng |
| 6 | Mic check có cần invalidate theo device/browser không? | Đề xuất V1: nhớ passed/skipped theo user_id + exercise_type, invalidate khi permission revoked, device đổi, hoặc recording thật silent |
| 7 | AI suggestion khi thêm nhánh có cần cache theo node không? | Đề xuất V1: cache ngắn theo node_id + note + tool_type + direction, refresh khi note/tool đổi |
- 2026-04-29: Loại bỏ
Opinion khỏi Linear Tool framework - chỉ còn 3 loại: Description, Cause, Effect. Cập nhật ở Element table, tool_type enum, F2 node label rule, F2.1 Add Branch popover, F3 Linear Tool Logic, và F5.1 validation catalog (xóa case Opinion lacks viewpoint). Lý do: quan điểm/nhận định cá nhân về một node được hiểu là một dạng Description về cảm xúc/đánh giá; không cần tool riêng.
- 2026-04-29: Confirm Empty Answer (
not_ready) UI đã có thiết kế trong Figma (frame Empty) - tooltip “Empty thì không được tạo thêm” + ⊘ icon trên active card + side panel “Chờ nội dung…” cho card pending. Confirm Tự viết tab đã có sẵn trong Add Branch popover (2 tab: AI gợi ý + Tự viết).
- 2026-04-29: Tài liệu hóa các state Full Speaking còn thiếu UI -
processing, needs_retry, stale, và session completion sau 4 câu - dưới dạng wireframe trong Figma section Wireframe - Logic bổ sung (Linear Tool).
- 2026-04-24: Bổ sung canvas operations - thêm nhánh bằng popover AI gợi ý/tự viết, đổi tool bằng badge menu, viewport controls, và active sentence card để luyện nói từng câu.
- 2026-04-24: Bổ sung entry flow - mic check preflight nhớ theo user + exercise type, start card với câu hỏi cho sẵn, và
Question -> Answer canvas start.
- 2026-04-24: Bổ sung logic tab
Luyện nói cả bài - attempt snapshot, recording states, full speaking messages, coverage gate, hover annotation, stale attempt khi script đổi.
- 2026-04-24: Cập nhật branch gating và validation message catalog - node trống chặn tạo node mới; node đang AI analyzing vẫn cho tạo tiếp; node có lỗi
needs_fix khóa tạo mới cho tới khi sửa.
- 2026-04-21: Reframe Linear Tools từ outline grid sang canvas graph; bổ sung node/edge model, AI sentence composer panel, flow ordering, canvas readiness, và cải tiến dài hạn.
- 2026-04-06: Rewrite - bổ sung Features, User Actions per bước, AI-UI Interaction, System Audio, Completion & Scoring.
- 2026-04-06: Khởi tạo draft từ meeting note.