Skip to content

Deepen local transcription run module - #33

Merged
makoMakoGo merged 2 commits into
mainfrom
codex/local-transcription-run-module
Jun 10, 2026
Merged

makoMakoGo merged 2 commits into
mainfrom
codex/local-transcription-run-module

Conversation

@makoMakoGo

@makoMakoGo makoMakoGo commented Jun 9, 2026 •

Copy link
Copy Markdown
Owner

关联 issue

Refs #20

依赖关系

这个 PR 叠在 #30 (codex/runtime-settings-slices) 之上,因为本地转录运行模块直接使用 #30 拆出的 AsrRunSettings 运行切片。

它和 #32(润色运行模块)互不依赖,都是 #30 之后可以独立 review 的兄弟 PR。#30 合并后,本 PR 再 rebase/retarget 到 main。

改动内容

  • 新增 lib/local-transcription-run.ts,集中一次本地音频 ASR 转录运行的状态、上传进度、等待识别心跳、成功、空结果、API 错误、请求失败和取消语义。
  • 收窄 hooks/use-transcription-flow.ts 的本地转录路径,让 hook 只负责清日志、重置 UI 外壳、AbortController 当前运行隔离,以及把 run module 的 state/log patch 落到 React state。
  • 新增 tests/unit/local-transcription-run.test.ts,覆盖 run-level 的 status、progress、heartbeat、abort、result 和错误语义。
  • 保留 tests/unit/asr-transcription.test.ts 对底层 XHR 请求构造和上传细节的覆盖。

验证

  • npm test -- --run tests/unit/local-transcription-run.test.ts tests/unit/asr-transcription.test.ts tests/unit/utils.test.ts
  • npm test
  • npm run build

Summary by Sourcery

Extract local ASR transcription run logic into a reusable module and wire it into the transcription flow hook while adding focused unit coverage.

Enhancements:

  • Introduce a local transcription run module that encapsulates ASR request lifecycle, status, progress, heartbeat handling, and logging.
  • Refine the transcription flow hook to delegate run lifecycle management to the new local run module and simplify UI state updates.

Tests:

  • Add unit tests for the local transcription run module covering success, empty result, API error, network failure, and abort scenarios.

@sourcery-ai

sourcery-ai Bot commented Jun 9, 2026 •

Copy link
Copy Markdown

Reviewer's Guide

Extracts local ASR run orchestration into a reusable run module and simplifies the React transcription flow hook to just wiring and state updates, with comprehensive unit tests for run-level behavior.

Sequence diagram for the new local transcription run orchestration

sequenceDiagram
  actor User
  participant ReactComponent
  participant useTranscriptionFlow
  participant runLocalTranscription
  participant runAsrTranscription
  participant AsrApi

  User ->> ReactComponent: clickTranscribe(file)
  ReactComponent ->> useTranscriptionFlow: transcribe(file)
  useTranscriptionFlow ->> useTranscriptionFlow: prepareRun()
  useTranscriptionFlow ->> runLocalTranscription: runLocalTranscription(file, settings, callbacks, options)

  runLocalTranscription ->> runLocalTranscription: normalizeAsrRunSettings(settings)
  runLocalTranscription ->> useTranscriptionFlow: callbacks.onState(initialState)
  runLocalTranscription ->> useTranscriptionFlow: callbacks.onLog(info logs)

  runLocalTranscription ->> runAsrTranscription: runAsrTranscription(file, effectiveSettings, handlers, options)
  runAsrTranscription ->> AsrApi: HTTP upload + transcribe

  loop upload
    AsrApi -->> runAsrTranscription: progress events
    runAsrTranscription ->> runLocalTranscription: onUploadProgress(progress)
    runLocalTranscription ->> useTranscriptionFlow: callbacks.onState({ uploadProgress, statusMessage })
    runLocalTranscription ->> useTranscriptionFlow: callbacks.onLog(upload progress)
  end

  runAsrTranscription ->> runLocalTranscription: onUploadComplete()
  runLocalTranscription ->> useTranscriptionFlow: callbacks.onState({ status: transcribing, statusMessage })
  runLocalTranscription ->> useTranscriptionFlow: callbacks.onLog(upload complete)

  loop heartbeat
    AsrApi -->> runAsrTranscription: wait heartbeat
    runAsrTranscription ->> runLocalTranscription: onWaitHeartbeat(heartbeat)
    runLocalTranscription ->> useTranscriptionFlow: callbacks.onState({ statusMessage })
    runLocalTranscription ->> useTranscriptionFlow: callbacks.onLog(wait log)
  end

  runAsrTranscription -->> runLocalTranscription: response
  alt response.ok && text
    runLocalTranscription ->> useTranscriptionFlow: callbacks.onState({ result: success, status: done })
    runLocalTranscription ->> useTranscriptionFlow: callbacks.onLog(success log)
  else response.ok && empty text
    runLocalTranscription ->> useTranscriptionFlow: callbacks.onState({ result: empty, status: done })
    runLocalTranscription ->> useTranscriptionFlow: callbacks.onLog(empty log)
  else !response.ok
    runLocalTranscription ->> useTranscriptionFlow: callbacks.onState({ result: error, status: error })
    runLocalTranscription ->> useTranscriptionFlow: callbacks.onLog(API error log)
  end

  runLocalTranscription -->> useTranscriptionFlow: LocalTranscriptionRunResult
  useTranscriptionFlow ->> ReactComponent: update React state
  ReactComponent -->> User: updated UI
Loading

File-Level Changes

Change Details Files
Introduce lib/local-transcription-run.ts as a self-contained local ASR run orchestrator with state, logging, and result semantics.
  • Defines LocalTranscriptionRunState, patch semantics, and callback-based state/log emission APIs.
  • Wraps runAsrTranscription with upload progress, heartbeat, and completion handling, mapping responses into success/empty/error/aborted outcomes.
  • Formats and logs file metadata, API endpoint, model, progress milestones, API errors, request failures, and abort events.
  • Normalizes ASR settings internally and reuses existing helpers like formatAsrApiErrorMessage and formatFileSize.
lib/local-transcription-run.ts
Refactor useTranscriptionFlow hook to delegate run lifecycle to the new local run module and narrow its responsibilities.
  • Introduce prepareRun and applyTranscriptionRunState helpers to reset UI shell and apply run patches to React state.
  • Replace direct runAsrTranscription usage with runLocalTranscription, wiring onState/onLog callbacks to React state and existing logging utilities.
  • Centralize AbortController management and loading state cleanup around the new run module, ensuring only the current run mutates state.
  • Switch API-key presence checks to hasAsrApiKey for both transcribe and import flows.
hooks/use-transcription-flow.ts
Add focused unit tests for local transcription run semantics while preserving lower-level XHR tests.
  • Create tests/unit/local-transcription-run.test.ts using a FakeXMLHttpRequest to simulate upload, success, error, network failure, and abort paths.
  • Assert emitted state patches and logs for start, progress, heartbeat, success, empty result, API error, request failure, and abort scenarios.
  • Keep tests/unit/asr-transcription.test.ts in place to continue validating request construction and upload details.
tests/unit/local-transcription-run.test.ts
tests/unit/asr-transcription.test.ts

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented Jun 9, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

@makoMakoGo, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 45 minutes and 1 second. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6b84a0b8-dbea-4b2a-a277-7c3cbca08158

📥 Commits

Reviewing files that changed from the base of the PR and between 2463631 and 320e148.

📒 Files selected for processing (3)
  • hooks/use-transcription-flow.ts
  • lib/local-transcription-run.ts
  • tests/unit/local-transcription-run.test.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/local-transcription-run-module

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the transcription flow by extracting the core ASR transcription logic from the useTranscriptionFlow hook into a dedicated helper function runLocalTranscription in lib/local-transcription-run.ts, accompanied by unit tests. The reviewer feedback highlights two key areas for improvement: first, adding a catch block back to the transcribe function in the hook to prevent unhandled promise rejections from unexpected runtime or callback errors; second, enhancing the robustness of the isAbortError helper to support environments where abort errors are standard Error objects rather than DOMException instances.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread hooks/use-transcription-flow.ts
Comment thread lib/local-transcription-run.ts Outdated

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 3 issues, and left some high level feedback:

  • In useTranscriptionFlow.transcribe, the result of runLocalTranscription is ignored; if the UI or error banners rely on setFlowError, consider mapping runLocalTranscription error states back into flowError to preserve the previous error‑handling behavior.
  • beginRun in useTranscriptionFlow is now unused after introducing prepareRun and runLocalTranscription; consider removing it (or inlining its remaining behavior) to avoid dead code.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `useTranscriptionFlow.transcribe`, the result of `runLocalTranscription` is ignored; if the UI or error banners rely on `setFlowError`, consider mapping `runLocalTranscription` error states back into `flowError` to preserve the previous error‑handling behavior.
- `beginRun` in `useTranscriptionFlow` is now unused after introducing `prepareRun` and `runLocalTranscription`; consider removing it (or inlining its remaining behavior) to avoid dead code.

## Individual Comments

### Comment 1
<location path="lib/local-transcription-run.ts" line_range="43-52" />
<code_context>
+  let state: LocalTranscriptionRunState = {
</code_context>
<issue_to_address>
**suggestion (performance):** Avoid emitting multiple synchronous state updates before the first await to reduce unnecessary re-renders.

`runLocalTranscription` currently calls `emitState(state)` and then `emitState({ statusMessage: '正在上传文件...' })` before any `await`, causing two near-identical `onState` callbacks and re-renders for React consumers. Instead, set `statusMessage: '正在上传文件...'` in the initial `state` or include it in the first `emitState` call so the initial render happens only once.

Suggested implementation:

```typescript
  let state: LocalTranscriptionRunState = {
    result: IDLE_TRANSCRIPTION_RESULT,
    uploadProgress: 0,
    status: 'processing',
    statusMessage: '正在上传文件...',
  }

```

```typescript
  emitState(state)

```

I assumed there is an initial `emitState(state)` followed by `emitState({ statusMessage: '正在上传文件...' })` as described in your comment. If the second call has slightly different text or is wrapped in additional logic, adjust the second SEARCH block to match the actual code and remove only that extra `emitState` invocation while keeping the first one.
</issue_to_address>

### Comment 2
<location path="lib/local-transcription-run.ts" line_range="33-34" />
<code_context>
+  kind: 'success' | 'empty' | 'error' | 'aborted'
+}
+
+const isAbortError = (error: unknown): boolean =>
+  error instanceof DOMException && error.name === 'AbortError'
+
+export const runLocalTranscription = async (
</code_context>
<issue_to_address>
**issue (bug_risk):** Guard against environments where DOMException is not defined when detecting abort errors.

`isAbortError` assumes `DOMException` is always defined, which can cause a `ReferenceError` in non-browser or older environments. Guard the check to avoid that runtime dependency, e.g.:

```ts
const isAbortError = (error: unknown): boolean =>
  typeof DOMException !== 'undefined' &&
  error instanceof DOMException &&
  (error as DOMException).name === 'AbortError'
```
</issue_to_address>

### Comment 3
<location path="tests/unit/local-transcription-run.test.ts" line_range="68" />
<code_context>
+  }
+}
+
+describe('runLocalTranscription', () => {
+  it('emits start, upload, heartbeat, and success state for a local ASR run', async () => {
+    const xhr = new FakeXMLHttpRequest()
</code_context>
<issue_to_address>
**suggestion (testing):** Consider adding a smoke test where `runLocalTranscription` is called without any callbacks to ensure optional handlers don’t cause runtime errors.

All current tests use `collectRunEvents`, so callbacks are always present. Since `LocalTranscriptionRunCallbacks` is optional, add a small case like `it('handles missing callbacks without throwing', ...)` that calls `runLocalTranscription(file, settings)` without the third argument and asserts the promise resolves to the expected success shape. This will catch regressions where `callbacks.onState`/`callbacks.onLog` are used without null-checks.

Suggested implementation:

```typescript
describe('runLocalTranscription', () => {
  it('handles missing callbacks without throwing', async () => {
    const resultPromise = runLocalTranscription(buildFile(), buildSettings())

    await expect(resultPromise).resolves.toEqual(expect.anything())
  })


```

If `runLocalTranscription` requires injected dependencies (e.g., a `FakeXMLHttpRequest` via an options argument) to run in tests, adapt this smoke test to match the pattern of the existing tests, for example:
1. Construct a `FakeXMLHttpRequest` and any required timing utilities (`now`, `setIntervalFn`, etc.).
2. Call `runLocalTranscription(buildFile(), buildSettings(), undefined, { /* test options mirroring other tests */ })` so that the callbacks parameter is explicitly `undefined` while still providing necessary options.
3. Drive the fake XHR to completion in the same way the success test does, if the promise does not resolve on its own.
Adjust the `expect` assertion to whatever “success” value the other tests expect (e.g., `expect.objectContaining({ status: 'success' })`) to keep the contract consistent across tests.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread lib/local-transcription-run.ts
Comment thread lib/local-transcription-run.ts Outdated
Comment thread tests/unit/local-transcription-run.test.ts
@makoMakoGo

Copy link
Copy Markdown
Owner Author

Bot review 处理记录:

  • Gemini 建议在 hook 外层恢复 catch:不采纳。runLocalTranscription 已处理预期内 ASR 错误;非预期 normalize/callback/runtime 错误应该暴露出来,避免把实现 bug 包成用户态“运行异常”。该线程已回复并 resolved。
  • Gemini 建议把 abort 判定扩大到任意 Error.name === "AbortError":不采纳。当前 abort 来源是 runAsrTranscription 明确构造的 DOMException("AbortError");扩大匹配会隐藏非预期错误。该线程已回复并 resolved。
  • Sourcery 关于首次 await 前重复 state patch 的建议已采纳:初始 state 直接使用 正在上传文件...,删除额外同步 emitState。
  • Sourcery 关于 DOMException 未定义的建议已采纳:增加 typeof DOMException !== "undefined" guard。
  • Sourcery 关于 optional callbacks 的测试建议已采纳:新增 handles missing callbacks without throwing。
  • Sourcery 高层提到 runLocalTranscription 返回值被忽略:这是误读,UI 状态通过 onState patch 落地,返回值主要作为 run-level contract 给测试使用。
  • Sourcery 高层提到 beginRun 未使用:这是误读,beginRun 仍用于远程导入的下载阶段。
  • CodeRabbit 因 stacked PR base 非默认分支跳过 review,是模板消息,无可执行意见。

验证:npm test -- --run tests/unit/local-transcription-run.test.ts tests/unit/asr-transcription.test.ts tests/unit/utils.test.ts、npm test、npm run build 均已通过。

@makoMakoGo
makoMakoGo changed the base branch from codex/runtime-settings-slices to main June 10, 2026 09:36
@makoMakoGo
makoMakoGo force-pushed the codex/local-transcription-run-module branch from b0e99f9 to 320e148 Compare June 10, 2026 09:38
@makoMakoGo
makoMakoGo merged commit d83bcb0 into main Jun 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant