Skip to content

Add context-aware transcription and dynamic ChatGPT models - #1016

Merged
SeoFood merged 3 commits into
mainfrom
seofood/openai-context-aware-transcription
Jul 28, 2026
Merged

Add context-aware transcription and dynamic ChatGPT models#1016
SeoFood merged 3 commits into
mainfrom
seofood/openai-context-aware-transcription

Conversation

@SeoFood

@SeoFood SeoFood commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Context

OpenAI announced two new transcription models: gpt-transcribe and gpt-live-transcribe. This PR adds both models to the OpenAI plugin using the existing plugin SDK contracts and keeps the host compatibility floor unchanged.

The local development smoke also exposed that ChatGPT Login's Refresh button returned a hard-coded model snapshot instead of requesting the account-specific Codex catalog. The current Codex catalog includes GPT-5.6 Sol, Terra, and Luna, so this PR now uses the same dynamic /backend-api/codex/models?client_version=... contract as Codex. Future visible models can therefore appear after refresh without another plugin update.

Official references:

What changed

  • Add a private capability table for file/realtime routing, context-aware fields, response formats, and translation support.
  • Add gpt-transcribe as the default only when no model selection has been persisted; existing selections remain unchanged.
  • Send gpt-transcribe requests through /v1/audio/transcriptions with M4A-to-WAV fallback, context, sanitized ordered keywords, ordered language hints, and detected-language parsing.
  • Add gpt-live-transcribe to the existing WebSocket transcription path with context, keywords, language hints, and configurable delay.
  • Keep gpt-realtime-whisper and existing REST model payloads unchanged.
  • Block Translate locally for every model except whisper-1 before any network request.
  • Dynamically fetch the ChatGPT/Codex model catalog with the OAuth access token and ChatGPT-Account-ID, then honor server visibility and priority.
  • Cache the fetched ChatGPT catalog per account, preserve a still-available selected model, and keep the previous cache or fallback when refresh fails.
  • Refresh ChatGPT models when settings open and after login/import, while retaining the manual Refresh action.
  • Keep a current GPT-5.6 fallback for offline use without removing legacy selections until a successful server refresh replaces the fallback.
  • Add context and live-delay settings with localized UI copy.
  • Bump the OpenAI plugin manifest to 1.3.0 while keeping minHostVersion: 1.5.0 and SDK compatibility v1.

Test plan

  • swift test --package-path TypeWhisperPluginSDK --filter OpenAIPluginTests (39 tests)
  • xcodebuild -project TypeWhisper.xcodeproj -scheme OpenAIPlugin -configuration Release CODE_SIGNING_ALLOWED=NO build
  • /Users/marco/Projects/typewhisper-dev-tools/build-typewhisper-plugin-dev.sh --run OpenAIPlugin /Users/marco/.codex/worktrees/c7bc/typewhisper-mac
  • Verify the installed bundle is Apple Development signed and contains manifest version 1.3.0.
  • Verify all newly referenced SDK symbols already exist in the v1.5.0 host tag.
  • Run an account-scoped live Codex model-catalog smoke: HTTP 200 with gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, gpt-5.4, gpt-5.4-mini, and gpt-5.3-codex-spark.
  • Run a real gpt-transcribe API smoke with context, multiple language hints, and dictionary terms.
  • Run a real gpt-live-transcribe API smoke with delay low, partial updates, and a final committed result.
  • Restart with a persisted legacy transcription selection and verify it remains selected.
  • Run a successful whisper-1 translation and verify a GPT transcription model is blocked locally with Translate requires Whisper 1.

The real transcription API checks remain required before merge. Merge and plugin release are separate approval gates.

Summary by CodeRabbit

  • New Features
    • Added transcription context, language hints, dictionary terms, and a selectable live transcription delay.
    • Enabled context-aware transcription for both file and realtime streaming.
    • Refreshed ChatGPT model discovery with account-scoped caching and improved model availability after login/import.
    • Updated multilingual UI text (German and Japanese) for the new transcription options and tiers.
    • Added translation support limited to Whisper 1.
  • Bug Fixes
    • Improved request validation, retry behavior, and error handling to prevent incorrect model fallbacks.

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 997f901b-bbc1-40a3-a93f-e961e34afb27

📥 Commits

Reviewing files that changed from the base of the PR and between 0350cd7 and a67bfef.

📒 Files selected for processing (1)
  • TypeWhisperPluginSDK/Plugins/OpenAIPlugin/OpenAIPlugin.swift
🚧 Files skipped from review as they are similar to previous changes (1)
  • TypeWhisperPluginSDK/Plugins/OpenAIPlugin/OpenAIPlugin.swift

📝 Walkthrough

Walkthrough

The OpenAI plugin adds context-aware file and realtime transcription, configurable live delay, account-scoped ChatGPT model discovery and caching, new settings and localized text, expanded tests, and a manifest version update to 1.3.0.

Changes

OpenAI transcription and ChatGPT model enhancement

Layer / File(s) Summary
Context-aware transcription flow
TypeWhisperPluginSDK/Plugins/OpenAIPlugin/OpenAIPlugin.swift, TypeWhisperPluginSDK/Plugins/OpenAIPlugin/Tests/OpenAIPluginTests.swift
Model capabilities select legacy or context-aware file/realtime transports, normalize language and dictionary hints, support transcription context, and validate translation support.
Realtime session configuration
TypeWhisperPluginSDK/Plugins/OpenAIPlugin/OpenAIPlugin.swift
Realtime sessions build configuration-based updates containing model IDs, fallback language, context hints, keywords, and live delay.
ChatGPT model catalog and account cache
TypeWhisperPluginSDK/Plugins/OpenAIPlugin/OpenAIPlugin.swift, TypeWhisperPluginSDK/Plugins/OpenAIPlugin/Tests/OpenAIPluginTests.swift
ChatGPT authentication fetches Codex models, caches them by OAuth account, restores matching catalogs, and preserves fallback selection on refresh failure.
Settings, localization, and release validation
TypeWhisperPluginSDK/Plugins/OpenAIPlugin/OpenAIPlugin.swift, TypeWhisperPluginSDK/Plugins/OpenAIPlugin/Localizable.xcstrings, TypeWhisperPluginSDK/Plugins/OpenAIPlugin/manifest.json, TypeWhisperPluginSDK/Plugins/OpenAIPlugin/Tests/OpenAIPluginTests.swift
Settings expose context and live delay, new German and Japanese strings are added, test helpers support multipart assertions, and the manifest version changes to 1.3.0.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant OpenAIPlugin
  participant TranscriptionClient
  participant RealtimeSession
  participant CodexModelsEndpoint
  OpenAIPlugin->>TranscriptionClient: submit context-aware file transcription
  OpenAIPlugin->>RealtimeSession: create configured live transcription
  RealtimeSession-->>OpenAIPlugin: return transcript result
  OpenAIPlugin->>CodexModelsEndpoint: fetch account-scoped ChatGPT models
  CodexModelsEndpoint-->>OpenAIPlugin: return model catalog
Loading

Possibly related PRs

Suggested labels: enhancement, area: UI, area: dictation

Poem

I’m a rabbit with notes in my burrow tonight,
Context and live delay now hop into sight.
Models bloom fresh from the Codex stream,
Localized strings make the settings gleam.
Tests thump their paws: the flows are right!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: context-aware transcription plus dynamic ChatGPT model discovery.
Description check ✅ Passed The description covers the main changes and includes a test plan, though it uses Context/What changed instead of a dedicated Summary heading.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch seofood/openai-context-aware-transcription

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.

@SeoFood SeoFood changed the title Add context-aware OpenAI transcription models Add context-aware transcription and dynamic ChatGPT models Jul 28, 2026
@SeoFood
SeoFood marked this pull request as ready for review July 28, 2026 19:57
@coderabbitai coderabbitai Bot added area: dictation Related to recording and transcription area: UI Related to user interface and settings enhancement New feature or request labels Jul 28, 2026

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🧹 Nitpick comments (2)
TypeWhisperPluginSDK/Plugins/OpenAIPlugin/Tests/OpenAIPluginTests.swift (1)

257-257: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

SwiftLint flags the String(decoding:as:) conversions (Lines 257, 309, 362, 363, 402, 561).

optional_data_string_conversion prefers the failable initializer; consider a small helper so the rule is satisfied in one place.

♻️ Suggested helper
private static func bodyString(_ data: Data) throws -> String {
    try XCTUnwrap(String(bytes: data, encoding: .utf8))
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@TypeWhisperPluginSDK/Plugins/OpenAIPlugin/Tests/OpenAIPluginTests.swift` at
line 257, Replace the flagged String(decoding:as:) conversions in
OpenAIPluginTests with a shared throwing bodyString helper that uses
String(bytes:encoding:) and XCTUnwrap; update all listed request-body assertions
to call this helper while preserving their existing error propagation.

Source: Linters/SAST tools

TypeWhisperPluginSDK/Plugins/OpenAIPlugin/OpenAIPlugin.swift (1)

707-709: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Capability decisions are re-derived from hard-coded model IDs in three places. OpenAITranscriptionModelCapability is the intended single source of truth for transport, context-aware hints, and realtime behavior, but three sites bypass it and compare against specific model IDs, so adding a model to the capability table would silently produce wrong requests or a missing control.

  • TypeWhisperPluginSDK/Plugins/OpenAIPlugin/OpenAIPlugin.swift#L707-L709: replace the modelID == gptLiveTranscribeModelID check with OpenAITranscriptionModelCapability.capability(for: modelID)?.usesContextAwareHints ?? false.
  • TypeWhisperPluginSDK/Plugins/OpenAIPlugin/OpenAIPlugin.swift#L2084-L2093: pass capability.modelInfo.id into contextAwareFileTranscriptionClient.transcribe(...) instead of letting the client hard-code gptTranscribeModelID at Line 800.
  • TypeWhisperPluginSDK/Plugins/OpenAIPlugin/OpenAIPlugin.swift#L3197-L3210: gate the live delay picker on transcriptionModelIsRealtime + transcriptionModelUsesContextAwareHints rather than selectedModel == liveModelId.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@TypeWhisperPluginSDK/Plugins/OpenAIPlugin/OpenAIPlugin.swift` around lines
707 - 709, Use OpenAITranscriptionModelCapability as the single source of truth
for all capability decisions: in
TypeWhisperPluginSDK/Plugins/OpenAIPlugin/OpenAIPlugin.swift:707-709, update
usesContextAwareHints to call capability(for:) and return usesContextAwareHints
with a false fallback; at 2084-2093, pass capability.modelInfo.id to
contextAwareFileTranscriptionClient.transcribe; at 3197-3210, gate the live
delay picker using transcriptionModelIsRealtime and
transcriptionModelUsesContextAwareHints instead of selectedModel and a
hard-coded live model ID.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@TypeWhisperPluginSDK/Plugins/OpenAIPlugin/Localizable.xcstrings`:
- Around line 148-163: Update the transcription context field in
OpenAIPlugin.swift around TextField("Describe the recording topic, setting, or
relevant context.", ...) so its label resolves from the plugin localization
bundle instead of the main app bundle. Use an explicitly bundled localized Text
or LocalizedStringResource, or pass the resolved localized string into
TextField, while preserving the existing binding and vertical-axis behavior.

In `@TypeWhisperPluginSDK/Plugins/OpenAIPlugin/OpenAIPlugin.swift`:
- Around line 3045-3060: Update OpenAIChatGPTModel.isVisibleInPicker to use a
denylist: return false only when visibility lowercases to "hide" or "hidden",
and true for nil and all other values, including "list".

---

Nitpick comments:
In `@TypeWhisperPluginSDK/Plugins/OpenAIPlugin/OpenAIPlugin.swift`:
- Around line 707-709: Use OpenAITranscriptionModelCapability as the single
source of truth for all capability decisions: in
TypeWhisperPluginSDK/Plugins/OpenAIPlugin/OpenAIPlugin.swift:707-709, update
usesContextAwareHints to call capability(for:) and return usesContextAwareHints
with a false fallback; at 2084-2093, pass capability.modelInfo.id to
contextAwareFileTranscriptionClient.transcribe; at 3197-3210, gate the live
delay picker using transcriptionModelIsRealtime and
transcriptionModelUsesContextAwareHints instead of selectedModel and a
hard-coded live model ID.

In `@TypeWhisperPluginSDK/Plugins/OpenAIPlugin/Tests/OpenAIPluginTests.swift`:
- Line 257: Replace the flagged String(decoding:as:) conversions in
OpenAIPluginTests with a shared throwing bodyString helper that uses
String(bytes:encoding:) and XCTUnwrap; update all listed request-body assertions
to call this helper while preserving their existing error propagation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 1d13c044-6841-4aac-82c9-d0041d3f00bd

📥 Commits

Reviewing files that changed from the base of the PR and between ac77759 and 0350cd7.

📒 Files selected for processing (4)
  • TypeWhisperPluginSDK/Plugins/OpenAIPlugin/Localizable.xcstrings
  • TypeWhisperPluginSDK/Plugins/OpenAIPlugin/OpenAIPlugin.swift
  • TypeWhisperPluginSDK/Plugins/OpenAIPlugin/Tests/OpenAIPluginTests.swift
  • TypeWhisperPluginSDK/Plugins/OpenAIPlugin/manifest.json

Comment thread TypeWhisperPluginSDK/Plugins/OpenAIPlugin/Localizable.xcstrings
Comment thread TypeWhisperPluginSDK/Plugins/OpenAIPlugin/OpenAIPlugin.swift
@SeoFood
SeoFood merged commit 179e778 into main Jul 28, 2026
13 checks passed
@SeoFood
SeoFood deleted the seofood/openai-context-aware-transcription branch July 28, 2026 20:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: dictation Related to recording and transcription area: UI Related to user interface and settings enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant