-
-
Notifications
You must be signed in to change notification settings - Fork 53
AI Enhancements #64
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
AI Enhancements #64
Conversation
WalkthroughThis update introduces AI-powered transcription enhancement to the Hex application, primarily by integrating local large language models (LLMs) through Ollama. New client logic and UI components are added to enable users to configure and use AI enhancement, including model selection, prompt customization, and response style adjustment. The transcription flow is updated to optionally pass results through the AI enhancement pipeline, with state and error handling for the asynchronous process. Settings and state management are extended to support these features, and new localization keys are added for the updated UI. Pasteboard and recording logic receive minor improvements and optimizations. Changes
Sequence Diagram(s)AI Enhancement Flow in TranscriptionsequenceDiagram
participant User
participant AppView
participant TranscriptionFeature
participant AIEnhancementClient
participant Ollama
User->>AppView: Starts transcription
AppView->>TranscriptionFeature: Begin recording/transcribing
TranscriptionFeature->>TranscriptionFeature: Process audio, produce transcript
TranscriptionFeature->>TranscriptionFeature: Check if AI enhancement enabled
alt Enhancement enabled
TranscriptionFeature->>AIEnhancementClient: enhance(transcript, model, options, progress)
AIEnhancementClient->>Ollama: POST /api/generate
Ollama-->>AIEnhancementClient: Enhanced text
AIEnhancementClient-->>TranscriptionFeature: Return enhanced text
TranscriptionFeature->>TranscriptionFeature: Store enhanced transcript
else Enhancement disabled
TranscriptionFeature->>TranscriptionFeature: Store original transcript
end
TranscriptionFeature-->>AppView: Update UI with final transcript
AI Enhancement Settings InitializationsequenceDiagram
participant User
participant AIEnhancementView
participant AIEnhancementFeature
participant AIEnhancementClient
participant Ollama
User->>AIEnhancementView: Opens AI Enhancement settings
AIEnhancementView->>AIEnhancementFeature: .task action
AIEnhancementFeature->>AIEnhancementClient: isOllamaAvailable()
AIEnhancementClient->>Ollama: GET /api/tags
Ollama-->>AIEnhancementClient: Model list or error
AIEnhancementClient-->>AIEnhancementFeature: Availability and models
AIEnhancementFeature-->>AIEnhancementView: Update models, status
Poem
Tip ⚡️ Faster reviews with caching
Enjoy the performance boost—your workflow just got faster. ✨ Finishing Touches
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🔭 Outside diff range comments (1)
Localizable.xcstrings (1)
38-670: 🛠️ Refactor suggestionNew localization keys added without comments or translations.
The file has been updated with numerous new localization keys related to the AI enhancement feature, but they lack comments explaining their context and translations for other supported languages like German.
For consistency with existing localization keys in the file, consider adding:
- Comments explaining where and how each string is used
- Translations for the supported languages (particularly German, which appears to be supported)
This will ensure a consistent experience for users across all supported languages.
🧹 Nitpick comments (14)
Hex/Models/HexSettings.swift (1)
126-160: Efficient caching implementation for HexSettings.The caching mechanism for HexSettings is a good performance optimization to reduce disk I/O. Setting a 5-second expiration is a reasonable balance between performance and freshness.
However, there's a minor issue in the variable declaration:
-private var cachedSettings: HexSettings? = nil +private var cachedSettings: HexSettings?Since Swift initializes optionals to nil by default, the explicit nil initialization is redundant.
🧰 Tools
🪛 SwiftLint (0.57.0)
[Warning] 127-127: Initializing an optional variable with nil is redundant
(redundant_optional_initialization)
Hex/Features/Settings/AIEnhancementFeature.swift (2)
21-21: Remove redundant optional initialization
errorMessageis declared as an optional, which isnilby default. Initialising it explicitly adds noise and triggers the SwiftLint warning you saw.-var errorMessage: String? = nil +var errorMessage: String?🧰 Tools
🪛 SwiftLint (0.57.0)
[Warning] 21-21: Initializing an optional variable with nil is redundant
(redundant_optional_initialization)
24-26: Consider hoistingdefaultAIModelto astatic letBecause
defaultAIModelnever varies per‐instance, astaticconstant is marginally cheaper and communicates intent more clearly:-// Computed property for convenient access to the default model -var defaultAIModel: String { - "gemma3" -} +static let defaultAIModel = "gemma3"You can then reference it with
State.defaultAIModel.
This is purely stylistic, feel free to ignore if you prefer the current form.Hex/Features/Transcription/TranscriptionFeature.swift (2)
60-61: UnusedaiEnhancementcancel ID
CancelID.aiEnhancementis declared but never used in a.cancellable(id:)call.
If you intentionally removed cancellation to avoid premature termination, consider deleting the enum case altogether (or re-introduce the ID in.run {}via.cancellable(id: CancelID.aiEnhancement)).This keeps the enum in sync with real usage and avoids confusion for future maintainers.
51-54:aiEnhancementErroraction is never dispatchedThe catch-block in
enhanceWithAIsends.aiEnhancementResult(result)instead of.aiEnhancementError. Either:
- Remove the unused case to simplify the reducer, or
- Emit the dedicated error action to handle/report enhancement failures separately.
Aligning intent and implementation prevents dead code paths.
Hex/Clients/PasteboardClient.swift (2)
60-64: Remove now-unused static tracking properties
savedChangeCountandsavedPasteboardNameare written insavePasteboardStatebut never read elsewhere after the refactor. They can be deleted to reduce clutter:-// Stores the previous pasteboard owner change count -private static var savedChangeCount: Int = 0 -// Stores the previous pasteboard contents name for tracking -private static var savedPasteboardName: String?
94-109: Return value ofwriteObjectsshould be checked
NSPasteboard.writeObjects(_:)returnsBoolindicating success.
Silently ignoring a failure may leave the pasteboard empty, causing data loss on restore.-if let items = backupPasteboard.pasteboardItems { - backupPasteboard.writeObjects(items) +if let items = backupPasteboard.pasteboardItems, + !items.isEmpty { + let ok = backupPasteboard.writeObjects(items) + if !ok { + print("⚠️ Failed to write items to backup pasteboard") + } }Hex/Clients/AIEnhancementClient.swift (7)
1-11: Header block includes an unusual creator attribution.The file header indicates it was created by "Claude AI" which is unusual for source code files. Consider changing this to reflect the actual developer or your team name for consistency with other files in the project.
12-14: Consider using OllamaKit directly as suggested by the comment.The commented-out code suggests a future enhancement to use OllamaKit directly. This could provide better integration with Ollama and potentially simplify the code by leveraging an official or community-maintained client library rather than implementing the API integration manually.
Would you like me to research if OllamaKit exists and provide implementation guidelines for integrating it?
96-101: Replace magic number with a named constant.The check
text.count > 5uses a hardcoded value. This would be clearer as a named constant.+ // Minimum text length required for enhancement + private let minimumTextLengthForEnhancement = 5 + /// Enhances text using a local AI model func enhance(text: String, model: String, options: EnhancementOptions, progressCallback: @escaping (Progress) -> Void) async throws -> String { // Skip if the text is empty or too short - guard !text.isEmpty, text.count > 5 else { + guard !text.isEmpty, text.count > minimumTextLengthForEnhancement else { print("[AIEnhancementClientLive] Text too short for enhancement, returning original") return text }
115-116: Use localized error messages instead of hardcoded strings.Error messages are hardcoded in English. Since your app supports localization (as seen in the Localizable.xcstrings file), consider using localized strings for error messages.
- throw NSError(domain: "AIEnhancementClient", code: -5, - userInfo: [NSLocalizedDescriptionKey: "Ollama is not available. Please ensure it's running."]) + throw NSError(domain: "AIEnhancementClient", code: -5, + userInfo: [NSLocalizedDescriptionKey: NSLocalizedString("Ollama is not available. Please ensure it's running.", comment: "Error when Ollama service is unavailable")])
214-252: Consider making temperature and token limits part of the EnhancementOptions validation.The limits for temperature and token count are enforced in the enhancement method rather than in the EnhancementOptions struct itself.
Consider validating these parameters in the EnhancementOptions initializer instead, ensuring that invalid values cannot be created in the first place:
struct EnhancementOptions { /// The prompt to send to the AI model for text enhancement var prompt: String /// Temperature controls randomness: lower values (0.1-0.3) are more precise, /// higher values (0.7-1.0) give more creative/varied results var temperature: Double /// Maximum number of tokens to generate in the response var maxTokens: Int + // Valid ranges for parameters + private static let minTemperature = 0.1 + private static let maxTemperature = 1.0 + private static let minTokens = 100 + private static let maxTokens = 2000 + /// Default prompt for enhancing transcribed text with clear instructions static let defaultPrompt = """ // [existing prompt] """ /// Default enhancement options for transcribed text static let `default` = EnhancementOptions( prompt: defaultPrompt, temperature: 0.3, maxTokens: 1000 ) /// Custom initialization with sensible defaults init(prompt: String = defaultPrompt, temperature: Double = 0.3, maxTokens: Int = 1000) { self.prompt = prompt - self.temperature = temperature - self.maxTokens = maxTokens + self.temperature = max(Self.minTemperature, min(Self.maxTemperature, temperature)) + self.maxTokens = max(Self.minTokens, min(Self.maxTokens, maxTokens)) } }Then in the
enhanceWithOllamamethod:- // Build request parameters with appropriate defaults - let temperature = max(0.1, min(1.0, options.temperature)) // Ensure valid range - let maxTokens = max(100, min(2000, options.maxTokens)) // Reasonable limits let requestDict: [String: Any] = [ "model": model, "prompt": fullPrompt, - "temperature": temperature, - "max_tokens": maxTokens, + "temperature": options.temperature, + "max_tokens": options.maxTokens, "stream": false, "system": "You are an AI that improves transcribed text while preserving meaning." ]
139-141: Consider making the Ollama API endpoint configurable.The Ollama API endpoint is hardcoded in multiple places. Consider making it configurable, either through a configuration file or an environment variable, to support different setups.
class AIEnhancementClientLive { + // MARK: - Configuration + + private let ollamaBaseURL: String + + init(ollamaBaseURL: String = "http://localhost:11434") { + self.ollamaBaseURL = ollamaBaseURL + } // MARK: - Public Methods // ... existing code ... /// Checks if Ollama is available on the system func isOllamaAvailable() async -> Bool { // Simple check - try to connect to Ollama's API endpoint do { - var request = URLRequest(url: URL(string: "http://localhost:11434/api/version")!) + var request = URLRequest(url: URL(string: "\(ollamaBaseURL)/api/version")!) request.timeoutInterval = 5.0 // Longer timeout for more reliabilityAnd similarly update the other hardcoded URLs.
Also applies to: 179-180, 225-229
99-131: Consider using a proper logging framework instead of print statements.The code uses
os.logor a third-party solution that supports different log levels and better formatting.Here's how you might use
os.loginstead:+import os class AIEnhancementClientLive { + // MARK: - Logging + + private let logger = Logger(subsystem: "com.yourcompany.Hex", category: "AIEnhancement") // MARK: - Public Methods /// Enhances text using a local AI model func enhance(text: String, model: String, options: EnhancementOptions, progressCallback: @escaping (Progress) -> Void) async throws -> String { // Skip if the text is empty or too short guard !text.isEmpty, text.count > 5 else { - print("[AIEnhancementClientLive] Text too short for enhancement, returning original") + logger.debug("Text too short for enhancement, returning original") return text } let progress = Progress(totalUnitCount: 100) progressCallback(progress) - print("[AIEnhancementClientLive] Starting text enhancement with model: \(model)") - print("[AIEnhancementClientLive] Text to enhance (\(text.count) chars): \"\(text.prefix(50))...\"") + logger.debug("Starting text enhancement with model: \(model)") + logger.debug("Text to enhance (\(text.count) chars): \"\(text.prefix(50))...\"")
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
Hex/Clients/AIEnhancementClient.swift(1 hunks)Hex/Clients/PasteboardClient.swift(2 hunks)Hex/Clients/RecordingClient.swift(2 hunks)Hex/Clients/TranscriptionClient.swift(1 hunks)Hex/Features/App/AppFeature.swift(3 hunks)Hex/Features/Settings/AIEnhancementFeature.swift(1 hunks)Hex/Features/Settings/AIEnhancementView.swift(1 hunks)Hex/Features/Settings/SettingsFeature.swift(5 hunks)Hex/Features/Settings/SettingsView.swift(1 hunks)Hex/Features/Transcription/TranscriptionFeature.swift(6 hunks)Hex/Features/Transcription/TranscriptionIndicatorView.swift(8 hunks)Hex/Models/HexSettings.swift(5 hunks)Localizable.xcstrings(17 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
Hex/Features/Settings/AIEnhancementView.swift (1)
Hex/Clients/AIEnhancementClient.swift (1)
isOllamaAvailable(136-159)
Hex/Clients/AIEnhancementClient.swift (1)
Hex/Clients/TranscriptionClient.swift (1)
getAvailableModels(198-200)
Hex/Features/Transcription/TranscriptionFeature.swift (1)
Hex/Clients/AIEnhancementClient.swift (1)
enhance(96-133)
🪛 SwiftLint (0.57.0)
Hex/Models/HexSettings.swift
[Warning] 127-127: Initializing an optional variable with nil is redundant
(redundant_optional_initialization)
Hex/Features/Settings/AIEnhancementFeature.swift
[Warning] 21-21: Initializing an optional variable with nil is redundant
(redundant_optional_initialization)
🔇 Additional comments (41)
Hex/Models/HexSettings.swift (6)
20-25: The AI enhancement settings are well organized and properly integrated.The new settings for disabling auto-capitalization and AI enhancement options are properly added to the struct with appropriate defaults. The naming is clear and descriptive.
42-46: Good practice adding corresponding CodingKeys entries.All the new properties have corresponding CodingKeys, which ensures proper JSON coding/decoding consistency.
62-67: Well-structured initializer parameters.New parameters added to the initializer with appropriate default values that match the property defaults.
82-86: Proper initializer implementation.All new properties are correctly initialized from the parameters.
116-122: Proper decoder handling for new properties.The custom decoder correctly handles all new properties with appropriate default values if they are missing from the encoded data.
168-168: Good implementation of caching in the SharedReaderKey.The update to use the cached settings is a nice optimization and maintains the same functionality.
Hex/Features/Settings/SettingsView.swift (1)
221-226: Well-integrated UI control for the new auto-capitalization setting.The toggle is properly bound to the HexSettings property and includes clear descriptive text and an appropriate icon. It's consistently styled with other toggles in the General section.
Hex/Features/App/AppFeature.swift (3)
18-18: Good addition of the AI enhancement tab.The new
aiEnhancementcase is properly added to the ActiveTab enum.
84-90: Well-structured UI integration for the AI enhancement feature.The new AI Enhancement button is implemented consistently with other navigation items, using the same pattern for button styling and tagging.
110-112: Good integration of AIEnhancementView in the detail view.The AIEnhancementView is properly scoped to the settings.aiEnhancement state and action, following the established pattern.
Hex/Clients/RecordingClient.swift (2)
384-384: Good improvement: Usingletfor immutable allocation.The change from
vartoletfordeviceNamePtris good practice since it's only initialized once and never modified after allocation. This ensures immutability and prevents accidental modifications.
562-583: Nice optimization to throttle meter updates.This implementation adds intelligent throttling for meter updates, which:
- Reduces UI updates for imperceptible changes (< 0.05 for average, < 0.1 for peak)
- Only forces updates every ~500ms (5 updates at 100ms intervals)
- Improves performance and reduces resource usage while maintaining responsiveness
+ var lastMeter = Meter(averagePower: 0, peakPower: 0) + var updateCount = 0 + + // Only emit if there's a significant change, or every ~5 updates (500ms) + let significantChange = abs(currentMeter.averagePower - lastMeter.averagePower) > 0.05 || + abs(currentMeter.peakPower - lastMeter.peakPower) > 0.1 + + if significantChange || updateCount >= 5 { + meterContinuation.yield(currentMeter) + lastMeter = currentMeter + updateCount = 0 + } else { + updateCount += 1 + }Hex/Features/Settings/SettingsFeature.swift (5)
39-40: Well-structured integration of AIEnhancementFeature.The AI enhancement feature is properly added as a property in the State struct, following the existing pattern for feature composition.
67-68: Consistent action enum extension.The new action case for AI enhancement follows the established pattern in this reducer.
83-85: Good use of Scope for feature composition.The
AIEnhancementFeatureis correctly scoped within the main reducer, ensuring proper separation of concerns.
112-123: Performance improvement for device refresh.Two smart optimizations:
- Extended refresh interval from 120 to 180 seconds to reduce resource usage
- Added conditional refresh that only runs when app is active AND settings panel is visible
This will improve battery life and reduce unnecessary background processing.
298-300: Consistent handling of sub-feature actions.The
.aiEnhancementaction handler follows the established pattern for delegating to the scoped sub-reducer.Hex/Features/Transcription/TranscriptionIndicatorView.swift (6)
17-17: Well-integrated new enhancing status.The new
enhancingcase is correctly added to the Status enum with a dedicated green color to visually distinguish it from other statuses.Also applies to: 24-24
33-33: Consistent styling for enhancing status.The
enhancingstatus is properly handled in all styling computations (background, stroke, and inner shadow), maintaining visual consistency with existing states.Also applies to: 44-44, 55-55
68-68: Complete visual integration of enhancing state.The enhancement state is thoroughly implemented in:
- Shadow effects with appropriate opacity levels
- Glow effects using the green color
- Animation effects with a dedicated counter variable
This provides a cohesive visual experience for the new state.
Also applies to: 108-117, 128-131
133-147: Optimized animation with consolidated task.Excellent optimization to use a single animation task for both
transcribingandenhancingstates instead of separate tasks. The code:
- Only runs animation when needed (status check)
- Updates the correct counter based on current status
- Maintains the same timing for animations (0.3s)
This reduces resource usage while providing the same visual feedback.
150-151: Clear tooltip behavior for distinct states.Good decision to explicitly limit the "Model prewarming..." tooltip to only appear for the
prewarmingstate, keeping the UI clean during enhancement.
178-178: Complete preview with all states.Adding the
enhancingstatus to the preview ensures developers can test and verify all possible visual states.Hex/Features/Settings/AIEnhancementView.swift (7)
11-54: Well-structured AIEnhancementView with conditional sections.The view is well-organized with:
- Logical section grouping
- Conditional rendering based on feature enablement and Ollama availability
- Appropriate task initialization for data loading
- Clear section headers and explanatory footers
The form style and binding to the store follow SwiftUI best practices.
59-119: Informative connection status view for better user experience.The connection status view provides:
- Clear visual alert with appropriate icon and styling
- Detailed setup instructions with bullet points
- Actionable buttons for downloading Ollama and checking connection
- Proper spacing and visual hierarchy
This helps users understand what's needed to make the feature work.
122-156: Good activation toggle with status feedback.The toggle implementation:
- Properly uses
withLockfor thread-safe settings updates- Triggers Ollama availability check when enabled
- Shows connection status indicator when connected
- Has clear explanatory text
I appreciate the visual indicator (green dot) when connected.
159-258: Complete model selection UI with all possible states.The model selection section handles all states gracefully:
- Loading state with progress indicator
- Error state with message
- Empty state with helpful link
- Normal state with proper picker
The refresh button and explanatory footer provide good UX.
261-316: Well-designed temperature control with clear visual cues.The temperature slider implementation:
- Shows precise numeric value
- Uses clear label indicators for "Precision" vs "Creativity"
- Has appropriate range (0-1) and step (0.05)
- Updates settings thread-safely with
withLock- Includes explanatory text about the impact of different values
319-400: Versatile prompt configuration with expandable editing.The prompt section offers a good balance of simplicity and power:
- Collapsed view shows preview with limited lines
- Expandable view provides full editing capability
- Reset button to restore defaults
- Monospaced font in editor for better code/prompt editing
- Different footer text based on expanded state
The animation for expanding/collapsing is a nice touch.
402-413: Reusable bullet point helper for consistent formatting.Good extraction of the bullet point rendering into a helper function for consistent styling and reuse throughout the view.
Hex/Clients/AIEnhancementClient.swift (6)
18-27: Good use of dependency injection pattern with TCA.The
AIEnhancementClientstructure effectively uses the@DependencyClientmacro for dependency injection, providing clear method signatures with sensible defaults. This follows the TCA pattern well and enables easy testing through dependency substitution.
30-70: Well-designed options struct with clear documentation.The
EnhancementOptionsstruct is well-designed with:
- Clear documentation for each property
- Appropriate default values
- A detailed default prompt with specific instructions
- Clean initialization with sensible defaults
This makes the API both easy to use with defaults and flexible for custom configurations.
136-159: Good implementation of Ollama availability check.The
isOllamaAvailablemethod is well-implemented with:
- Appropriate timeout settings
- Clear logging
- Proper error handling that defaults to false when errors occur
- Status code validation
- Useful debug information
This should provide reliable detection of the Ollama service.
162-209: Well-structured model fetching implementation.The
getAvailableModelsmethod provides a comprehensive implementation:
- Clean nested structure for JSON decoding
- Proper error handling at each step
- Appropriate timeout settings
- Result sorting for better UX
- Detailed error messages with error propagation
This will provide reliable model listing functionality.
92-134: Well-structured error handling and progress reporting in the enhancement logic.The
enhancemethod contains robust error handling and progress reporting:
- Checks for Ollama availability before proceeding
- Propagates errors appropriately
- Reports progress at key points in the process
- Logs useful diagnostic information
- Returns the original text when enhancement fails or isn't possible
This helps ensure a good user experience even when things go wrong.
214-329: Comprehensive implementation of text enhancement via Ollama API.The
enhanceWithOllamamethod provides a thorough implementation:
- Input validation
- Well-constructed prompt format
- Parameter validation
- Proper HTTP request setup
- Comprehensive error handling with descriptive messages
- Progress reporting at multiple stages
- Response parsing and cleanup
- Fallback to original text when needed
The implementation should provide reliable enhancement functionality with good error recovery.
Localizable.xcstrings (5)
203-207: New auto-capitalization feature strings.The addition of "Disable auto-capitalization" and "Disable automatic capitalization in transcriptions" strings aligns with the PR objective mentioning the new
disableAutoCapitalizationsetting. This provides the necessary UI text for the feature mentioned in the PR summary.
38-40: AI Enhancement feature localization keys added.The addition of "AI Enhancement" and related description strings properly supports the new AI enhancement feature mentioned in the PR objectives. These strings provide the necessary UI text for the feature described in the PR summary.
Also applies to: 259-261, 672-673
422-432: Ollama status indicator strings added.The Ollama connection status strings ("Ollama Connected", "Ollama Not Connected", "Ollama Status") provide clear feedback to users about the connection state for the AI enhancement feature, which is important for user experience when integrating with an external service.
152-153: Response style configuration strings added.The strings related to "Creativity", "Precision", and "Response Style" along with explanatory text provide user-friendly controls for configuring the AI enhancement's behavior, allowing users to tailor the enhancement process to their needs.
Also applies to: 367-368, 492-493, 526-527
262-263: Enhancement prompt customization strings added.The strings for "Enhancement Prompt", prompt editing instructions, and "Reset to Default" provide users with the ability to customize how the AI enhances their transcriptions, offering flexibility while maintaining the option to revert to defaults.
Also applies to: 371-372, 523-524, 655-656
| import ComposableArchitecture | ||
| import SwiftUI | ||
|
|
||
| struct AIEnhancementView: View { | ||
| @Bindable var store: StoreOf<AIEnhancementFeature> | ||
| @State private var showExpandedPrompt = false | ||
| @State private var isHoveringModelSelect = false | ||
|
|
||
| var body: some View { | ||
| Form { | ||
| // Activation Section (Always show this first) | ||
| Section { | ||
| activationToggle | ||
| } header: { | ||
| Text("AI Enhancement") | ||
| } footer: { | ||
| Text("Enable AI to improve transcription quality by fixing grammar, formatting, and errors.") | ||
| .foregroundColor(.secondary.opacity(0.7)) | ||
| .font(.caption) | ||
| } | ||
|
|
||
| // Only show other settings if AI enhancement is enabled | ||
| if store.hexSettings.useAIEnhancement { | ||
| // Connection Status Section (only if AI enhancement is enabled) | ||
| if !store.isOllamaAvailable { | ||
| Section { | ||
| connectionStatusView | ||
| } header: { | ||
| Text("Ollama Status") | ||
| } | ||
| } | ||
|
|
||
| // Model Selection Section | ||
| modelSelectionSection | ||
|
|
||
| // Temperature Control Section | ||
| temperatureSection | ||
|
|
||
| // Prompt Configuration Section | ||
| promptSection | ||
| } | ||
| } | ||
| .formStyle(.grouped) | ||
| .task { | ||
| await store.send(.task).finish() | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Verify ability to detect Ollama timeout issues.
The current implementation relies on the AIEnhancementClient's availability check, but there might be edge cases where Ollama appears available but becomes unresponsive during actual usage.
🏁 Script executed:
#!/bin/bash
# Check the timeout handling in AIEnhancementClient's isOllamaAvailable method
# Look for timeout configuration in AIEnhancementClient
rg -A 2 "timeoutInterval" --glob "**/*EnhancementClient*"
# Check error handling for connection issues
rg -A 5 "try await" --glob "**/*EnhancementClient*"Length of output: 3778
🏁 Script executed:
#!/bin/bash
# Extract the isOllamaAvailable implementation
rg -A20 "func isOllamaAvailable" --glob "Hex/Clients/AIEnhancementClient.swift"
echo "--------------------------------------------------"
# Extract the generation call (enhanceWithOllama) implementation
rg -A20 "func enhanceWithOllama" --glob "Hex/Clients/AIEnhancementClient.swift"Length of output: 4135
Handle Ollama timeouts and connectivity failures during enhancement
Although isOllamaAvailable() uses a 5 s timeout and returns false on error, the actual generation call in enhanceWithOllama(…) (60 s timeout) simply propagates any thrown error. This means the UI may think Ollama is available but then hang or crash on a timeout. We need to:
• Add explicit error handling around the URLSession call in enhanceWithOllama to catch timeouts and other network errors, then translate them into a user‐facing state (e.g. mark Ollama unavailable, show an error banner).
• In your feature reducer (or wherever .enhance is called), catch enhancement errors and dispatch an action to recheck availability or present an alert.
Example diff in AIEnhancementClient.swift:
// generation call
- let (data, response) = try await URLSession.shared.data(for: request)
+ let (data, response): (Data, URLResponse)
+ do {
+ (data, response) = try await URLSession.shared.data(for: request)
+ } catch {
+ // Treat timeouts and connectivity issues as “Ollama unavailable”
+ print("[AIEnhancementClientLive] Generation failed: \(error.localizedDescription)")
+ throw NSError(domain: "AIEnhancementClient",
+ code: -1001, // NSURLErrorTimedOut or similar
+ userInfo: [NSLocalizedDescriptionKey: "Ollama is unresponsive"])
+ }And in your reducer:
- Catch the thrown error from
enhance, send a new.ollamaBecameUnavailableaction. - In response, re-run
isOllamaAvailable()and display an alert if still down.
This ensures the user never hits a silent timeout and always sees a clear “Ollama unavailable” state.
Committable suggestion skipped: line range outside the PR's diff.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
Hex/Features/Transcription/TranscriptionFeature.swift (1)
396-435:⚠️ Potential issueCompile-time error – missing argument labels when calling
enhance
AIEnhancementClient.enhanceexpects external labelstext:model:options:, but the call is missing them.-let enhancedText = try await aiEnhancement.enhance(result, model, options) { _ in } +let enhancedText = try await aiEnhancement.enhance( + text: result, + model: model, + options: options +) { _ in }
🧹 Nitpick comments (2)
Hex/Features/Transcription/TranscriptionFeature.swift (2)
433-435: Consider documenting the cancellation decision more clearly.The code avoids making the AI enhancement cancellable due to potential issues. This reasoning should be better documented for future maintainers to understand the rationale.
// Don't make this cancellable to avoid premature cancellation // This may have been causing the issue with the enhancement being cancelled +// Note: AI enhancement operations may take longer than typical network operations. +// Making this cancellable was causing the enhancement to be prematurely cancelled when +// another action was dispatched or when the user interacted with the UI.
534-540: Commented-out code needs explanation.The decision not to cancel AI enhancement during the cancel flow should be better documented.
// Don't cancel AI enhancement as it might cause issues -// .cancel(id: CancelID.aiEnhancement), +// AI enhancement is intentionally not cancelled here because: +// 1. It might be near completion when cancelled, wasting processing +// 2. It can cause race conditions with result handling +// .cancel(id: CancelID.aiEnhancement),
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
Hex.xcodeproj/project.pbxproj(6 hunks)Hex/Clients/AIEnhancementClient.swift(1 hunks)Hex/Clients/RecordingClient.swift(2 hunks)Hex/Clients/TranscriptionClient.swift(4 hunks)Hex/Features/Settings/SettingsFeature.swift(5 hunks)Hex/Features/Transcription/TranscriptionFeature.swift(8 hunks)
✅ Files skipped from review due to trivial changes (1)
- Hex.xcodeproj/project.pbxproj
🚧 Files skipped from review as they are similar to previous changes (4)
- Hex/Clients/RecordingClient.swift
- Hex/Features/Settings/SettingsFeature.swift
- Hex/Clients/TranscriptionClient.swift
- Hex/Clients/AIEnhancementClient.swift
🔇 Additional comments (8)
Hex/Features/Transcription/TranscriptionFeature.swift (8)
22-22: State tracking addition looks good.Adding the
isEnhancingstate flag properly tracks when AI enhancement is active, maintaining consistency with other state flags in the struct.
50-55: Well-structured action cases for AI enhancement flow.The new action cases properly handle all aspects of the AI enhancement flow, including state management, results, errors, and Ollama availability.
62-62: Cancel ID for AI enhancement added correctly.This addition follows the established pattern for other cancellable operations in the codebase.
70-70: Dependency injection properly implemented.The
aiEnhancementdependency is correctly injected following the established pattern.
120-154: Well-implemented AI enhancement action handlers.The implementation checks for Ollama connectivity issues specifically and triggers availability rechecks when needed. Good error handling and logging.
357-391: Good conditional flow for AI enhancement.The transcription result handler now intelligently routes the result through AI enhancement when enabled, with proper state management.
438-460: AI enhancement result handler looks good.The handler properly resets state and finalizes the transcript similarly to the original flow.
582-583: Good UI state prioritization for enhancing status.The status logic correctly prioritizes showing the enhancing status before transcribing or recording states.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🔭 Outside diff range comments (1)
Hex/Features/Transcription/TranscriptionFeature.swift (1)
158-164: 🛠️ Refactor suggestionUpdate cancel guard condition to include
isEnhancingThe cancel handler has a guard condition that only runs if
isRecordingorisTranscribingare true, but it doesn't checkisEnhancing. This might lead to inconsistencies if cancel is triggered during enhancement.Update the guard condition to include all relevant states:
case .cancel: // Only cancel if we're in the middle of recording or transcribing - guard state.isRecording || state.isTranscribing else { + guard state.isRecording || state.isTranscribing || state.isEnhancing else { return .none } return handleCancel(&state)
♻️ Duplicate comments (1)
Hex/Features/Transcription/TranscriptionFeature.swift (1)
423-425:⚠️ Potential issueMissing argument labels in
enhancemethod callThe
AIEnhancementClient.enhancemethod likely requires argument labels (text:model:options:), but they're omitted here.The call should include the external parameter labels to prevent compilation errors:
-let enhancedText = try await aiEnhancement.enhance(result, model, options) { progress in +let enhancedText = try await aiEnhancement.enhance( + text: result, + model: model, + options: options +) { progress in // Optional: Could update UI with progress information here if needed }🧰 Tools
🪛 SwiftLint (0.57.0)
[Warning] 423-423: Unused parameter in a closure should be replaced with _
(unused_closure_parameter)
🧹 Nitpick comments (1)
Hex/Features/Transcription/TranscriptionFeature.swift (1)
423-425: Unused closure parameters flagged by static analysisThere are two instances of unused parameters in closures that should be replaced with
_as recommended by SwiftLint.Apply these changes:
// In recheckOllamaAvailability handler -return .run { send in +return .run { _ in // In enhanceWithAI method -let enhancedText = try await aiEnhancement.enhance(...) { progress in +let enhancedText = try await aiEnhancement.enhance(...) { _ inAlso applies to: 147-148
🧰 Tools
🪛 SwiftLint (0.57.0)
[Warning] 423-423: Unused parameter in a closure should be replaced with _
(unused_closure_parameter)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
Hex/Features/Transcription/TranscriptionFeature.swift(8 hunks)
🧰 Additional context used
🪛 SwiftLint (0.57.0)
Hex/Features/Transcription/TranscriptionFeature.swift
[Warning] 147-147: Unused parameter in a closure should be replaced with _
(unused_closure_parameter)
[Warning] 423-423: Unused parameter in a closure should be replaced with _
(unused_closure_parameter)
🔇 Additional comments (1)
Hex/Features/Transcription/TranscriptionFeature.swift (1)
435-437: Uncancellable AI enhancement operationThe AI enhancement effect is deliberately not made cancellable (with a comment explaining it avoids premature cancellation), but this creates inconsistency with the cancel handler which resets the
isEnhancingstate flag without actually cancelling the operation.This could lead to a situation where the UI shows enhancement is not happening (after cancel), but the enhancement is still running in the background. Consider the implications:
- What happens if the enhancement completes after cancellation?
- Could this lead to unexpected state or race conditions?
You might need additional safeguards in
handleAIEnhancementto check if the operation was cancelled before applying the result.
| return .run { send in | ||
| let isAvailable = await aiEnhancement.isOllamaAvailable() | ||
| if !isAvailable { | ||
| // Could dispatch to a UI state to show an alert or notification | ||
| print("[TranscriptionFeature] Ollama is not available. AI enhancement is disabled.") | ||
| // Here you would typically update UI state to show an alert | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Incomplete handling of Ollama unavailability
The rechecking logic detects Ollama unavailability but only logs it without updating any UI state or taking corrective action. Users won't be notified of the issue.
Consider updating to actually dispatch an action that updates the UI when Ollama is unavailable:
case .recheckOllamaAvailability:
// Recheck if Ollama is available and update UI accordingly
return .run { send in
let isAvailable = await aiEnhancement.isOllamaAvailable()
if !isAvailable {
// Could dispatch to a UI state to show an alert or notification
print("[TranscriptionFeature] Ollama is not available. AI enhancement is disabled.")
// Here you would typically update UI state to show an alert
+ await send(.someActionToShowOllamaUnavailableAlert)
}
}🏁 Script executed:
#!/bin/bash
# Verify if there's any UI state or user notification mechanism implemented elsewhere
# Look for UI alerts or notifications related to Ollama availability
rg -A 3 -B 3 "Ollama.*not available|ollamaUnavailable" --glob "*.swift"Length of output: 2932
Dispatch a UI action in TranscriptionFeature for Ollama unavailability
The .recheckOllamaAvailability branch only logs the error but doesn’t surface it to the user. Your Settings view already shows a message when store.isOllamaAvailable is false—do the same in Transcription:
• File: Hex/Features/Transcription/TranscriptionFeature.swift (Lines 147–154)
• Add a new action in TranscriptionAction, e.g. .ollamaUnavailable
• Update the reducer:
case .recheckOllamaAvailability:
return .run { send in
let isAvailable = await aiEnhancement.isOllamaAvailable()
if !isAvailable {
print("[TranscriptionFeature] Ollama is not available. AI enhancement is disabled.")
+ await send(.ollamaUnavailable)
}
}• Handle .ollamaUnavailable in the reducer to set a UI flag (e.g. state.showOllamaAlert = true)
• In TranscriptionView, bind an Alert to state.showOllamaAlert, similar to AIEnhancementView.swift
This ensures users receive an immediate notification when Ollama can’t be reached.
Committable suggestion skipped: line range outside the PR's diff.
🧰 Tools
🪛 SwiftLint (0.57.0)
[Warning] 147-147: Unused parameter in a closure should be replaced with _
(unused_closure_parameter)
|
i want this!! |
|
@0ni-x4 motivated me to finish this. will get it going!! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (4)
Hex/Features/Transcription/TranscriptionFeature.swift (4)
154-162: Missing UI feedback for Ollama unavailability.The rechecking logic detects Ollama unavailability but only logs it without updating any UI state or taking corrective action. Users won't be notified of the issue.
#!/bin/bash # Verify if there's any UI state update or user notification mechanism implemented elsewhere # Look for UI alerts or notifications related to Ollama availability rg -A 3 -B 3 "Ollama.*not available|ollamaUnavailable" --glob "*.swift"🧰 Tools
🪛 SwiftLint (0.57.0)
[Warning] 155-155: Unused parameter in a closure should be replaced with _
(unused_closure_parameter)
579-581: Potential UI state inconsistency with commented cancellation code.The cancel handler resets the
isEnhancingstate but explicitly avoids cancelling the AI enhancement effect. This creates a visual/UI inconsistency where the UI indicates cancellation but the operation continues in the background.Consider these options:
- Make the AI enhancement cancellable and actually cancel it
- Add state tracking to ignore enhancement results if cancel was requested
- Document this behavior clearly for future maintainers
// Don't cancel AI enhancement as it might cause issues // .cancel(id: CancelID.aiEnhancement), + // TODO: This creates a potential inconsistency - the UI shows cancellation + // but enhancement continues in background. Consider implementing a safer + // cancellation approach or state tracking to ignore late results.
138-147:⚠️ Potential issueIncomplete error handling in AI enhancement.
The comment states "For other errors, just use the original transcription," but the code returns
.nonewhich doesn't actually restore or use the original transcription result. When a non-Ollama error occurs, the transcription might be lost.case let .aiEnhancementError(error): // Check if this is an Ollama connectivity error let nsError = error as NSError if nsError.domain == "AIEnhancementClient" && (nsError.code == -1001 || nsError.localizedDescription.contains("Ollama")) { print("AI Enhancement error due to Ollama connectivity: \(error)") return .send(.ollamaBecameUnavailable) } else { // For other errors, just use the original transcription print("AI Enhancement error: \(error)") - return .none + // Pass the original transcription result through + return .send(.transcriptionResult(result)) }
433-475:⚠️ Potential issueIncorrect parameter passing in AI enhancement call.
The
enhancemethod is called without parameter labels, butAIEnhancementClient.enhancerequires external labels (text:,model:,options:).- let enhancedText = try await aiEnhancement.enhance(result, model, options) { progress in + let enhancedText = try await aiEnhancement.enhance( + text: result, + model: model, + options: options + ) { progress in🧰 Tools
🪛 SwiftLint (0.57.0)
[Warning] 461-461: Unused parameter in a closure should be replaced with _
(unused_closure_parameter)
🧹 Nitpick comments (1)
Hex/Features/Transcription/TranscriptionFeature.swift (1)
461-461: Unused parameter in closure.The
progressparameter in the closure is unused. Replace it with_to avoid the SwiftLint warning.- let enhancedText = try await aiEnhancement.enhance(result, model, options) { progress in + let enhancedText = try await aiEnhancement.enhance(result, model, options) { _ in🧰 Tools
🪛 SwiftLint (0.57.0)
[Warning] 461-461: Unused parameter in a closure should be replaced with _
(unused_closure_parameter)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
Hex/Clients/KeyEventMonitorClient.swift(3 hunks)Hex/Clients/PasteboardClient.swift(2 hunks)Hex/Clients/RecordingClient.swift(2 hunks)Hex/Features/Transcription/TranscriptionFeature.swift(10 hunks)Hex/Features/Transcription/TranscriptionIndicatorView.swift(7 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- Hex/Features/Transcription/TranscriptionIndicatorView.swift
🧰 Additional context used
🧬 Code Graph Analysis (1)
Hex/Features/Transcription/TranscriptionFeature.swift (3)
Hex/Clients/AIEnhancementClient.swift (2)
isOllamaAvailable(136-159)enhance(96-133)Hex/Clients/RecordingClient.swift (1)
observeAudioLevel(621-623)Hex/Clients/TranscriptionClient.swift (1)
transcribe(206-247)
🪛 SwiftLint (0.57.0)
Hex/Features/Transcription/TranscriptionFeature.swift
[Warning] 155-155: Unused parameter in a closure should be replaced with _
(unused_closure_parameter)
[Warning] 185-185: Initializing an optional variable with nil is redundant
(redundant_optional_initialization)
[Warning] 461-461: Unused parameter in a closure should be replaced with _
(unused_closure_parameter)
🔇 Additional comments (19)
Hex/Clients/KeyEventMonitorClient.swift (2)
11-36: Well-designed thread safety implementation for Sauce library.This new
SafeSauceenum provides an excellent thread-safe wrapper around Sauce library calls, effectively preventing_dispatch_assert_queue_failerrors. The implementation correctly handles the case when code is already on the main thread versus when it needs to dispatch.
47-47: Good use of the thread-safe wrapper.The
KeyEventinitializer now correctly uses the thread-safe wrapper to prevent potential crashes from background thread access.Hex/Clients/RecordingClient.swift (2)
384-384: Appropriate use ofletfor immutable pointer allocation.Changed from
vartoletwhich is correct since this pointer doesn't need to be mutable after allocation.
562-612: Excellent adaptive throttling for audio metering.The implementation adds sophisticated adaptive throttling that:
- Adjusts sampling intervals based on activity level (80-150ms)
- Only emits updates when there are significant changes
- Has smart fallbacks to ensure UI responsiveness
This will reduce CPU usage and improve battery life while maintaining responsive UI feedback.
Hex/Clients/PasteboardClient.swift (6)
68-92: Efficient pasteboard backup implementation.This new approach using NSPasteboard's native capabilities is more efficient than manually copying data items. The use of a unique temporary pasteboard is elegant and avoids potential data loss issues.
95-109: Clean pasteboard restoration with proper cleanup.The restoration process correctly handles the pasteboard state and cleans up the temporary pasteboard to avoid memory leaks.
112-115: Good practice keeping the legacy method with a warning.Maintaining backward compatibility while clearly marking this method as deprecated will help with future code maintenance.
164-166: Smart conditional pasteboard backup.Only saving the pasteboard state when clipboard retention is disabled is a good optimization that avoids unnecessary work.
180-211: Thread-safe key code retrieval and efficient event posting.The thread safety check and main thread dispatching for key code retrieval aligns with the improvements in
KeyEventMonitorClient. Using autoreleasepool for the event posting sequence ensures proper resource management.
222-229: Appropriate delay and cleanup handling.Adding a delay before restoration gives the paste operation time to complete, and wrapping the restoration in an autoreleasepool helps with memory management.
Hex/Features/Transcription/TranscriptionFeature.swift (9)
22-22: Good addition of enhancing state tracking.Adding the
isEnhancingstate variable allows proper UI feedback during the AI enhancement process.
50-56: Well-defined actions for AI enhancement flow.The new actions clearly separate different aspects of the AI enhancement process, promoting a clean state management approach.
70-70: Added AI enhancement dependency.Correctly added the dependency to access AI enhancement functionality.
89-97: Optimized audio level update logic.The conditional update based on significant changes is a good optimization that reduces unnecessary state updates and UI refreshes.
183-214: Excellent audio meter update optimization.The rate limiting and significance threshold for audio meter updates will reduce UI updates and improve performance, especially during quieter periods.
🧰 Tools
🪛 SwiftLint (0.57.0)
[Warning] 185-185: Initializing an optional variable with nil is redundant
(redundant_optional_initialization)
375-375: Good integration of HexSettings with transcription client.Passing the settings to the transcription client enables features like disabling auto-capitalization.
394-429: Well-structured conditional AI enhancement.The transcription result handler now correctly branches based on user settings, either proceeding to AI enhancement or finalizing the transcription directly. The code properly extracts necessary settings values.
477-500: Complete AI enhancement result handling.The implementation correctly updates all relevant state variables and proceeds to finalize the recording with the enhanced transcript.
622-623: Good UI status prioritization.Prioritizing the
.enhancingstate in the UI status logic ensures users get appropriate feedback during the AI enhancement process.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
Hex/Features/Transcription/TranscriptionFeature.swift (1)
466-509: 🛠️ Refactor suggestionFix argument labels in AIEnhancement.enhance call.
The code bypasses Swift's argument labels by directly accessing the enhance method. This is error-prone and less readable.
- // Access the raw value directly to avoid argument label issues - let enhanceMethod = aiEnhancement.enhance - let enhancedText = try await enhanceMethod(result, model, options) { progress in + // Use proper argument labels for better readability and type safety + let enhancedText = try await aiEnhancement.enhance( + text: result, + model: model, + options: options + ) { progress in🧰 Tools
🪛 SwiftLint (0.57.0)
[Warning] 495-495: Unused parameter in a closure should be replaced with _
(unused_closure_parameter)
🧹 Nitpick comments (2)
Hex/Features/Transcription/TranscriptionFeature.swift (2)
234-242: Enhance meter update with for-where pattern.Consider using a Swift for-where pattern to simplify the conditional meter updates.
- for await meter in await recording.observeAudioLevel() { - // Check if we should send this update - if await rateLimiter.shouldUpdate(meter: meter) { - // The Effect.run captures its function as @Sendable, so we're already on an appropriate context - // for sending actions. ComposableArchitecture handles dispatching to the main thread as needed. - await send(.audioLevelUpdated(meter)) - } + for await meter in await recording.observeAudioLevel() where await rateLimiter.shouldUpdate(meter: meter) { + // The Effect.run captures its function as @Sendable, so we're already on an appropriate context + // for sending actions. ComposableArchitecture handles dispatching to the main thread as needed. + await send(.audioLevelUpdated(meter))🧰 Tools
🪛 SwiftLint (0.57.0)
[Warning] 239-239:
whereclauses are preferred over a singleifinside afor(for_where)
495-495: Replace unused closure parameter with underscore.The progress parameter in the closure is unused and should be replaced with an underscore.
- let enhancedText = try await enhanceMethod(result, model, options) { progress in + let enhancedText = try await enhanceMethod(result, model, options) { _ in🧰 Tools
🪛 SwiftLint (0.57.0)
[Warning] 495-495: Unused parameter in a closure should be replaced with _
(unused_closure_parameter)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
Hex.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved(2 hunks)Hex/Features/Transcription/TranscriptionFeature.swift(10 hunks)
✅ Files skipped from review due to trivial changes (1)
- Hex.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
🧰 Additional context used
🪛 SwiftLint (0.57.0)
Hex/Features/Transcription/TranscriptionFeature.swift
[Warning] 239-239: where clauses are preferred over a single if inside a for
(for_where)
[Warning] 201-201: Initializing an optional variable with nil is redundant
(redundant_optional_initialization)
[Warning] 495-495: Unused parameter in a closure should be replaced with _
(unused_closure_parameter)
[Warning] 618-618: TODOs should be resolved (Consider implementing a safer ...)
(todo)
🔇 Additional comments (16)
Hex/Features/Transcription/TranscriptionFeature.swift (16)
22-23: State management for tracking AI enhancement progress looks good.The new
isEnhancingstate properly tracks when AI enhancement is active, providing a clear separation between transcription and enhancement states.
27-27: Well-designed fallback mechanism for transcription.Using
pendingTranscriptionas a fallback storage is an excellent approach to ensure the original transcription is preserved in case of AI enhancement failures.
51-56: Comprehensive action enumeration for AI enhancement flow.The action cases cover all necessary states for the AI enhancement flow including state changes, results, error handling, and Ollama availability checks.
63-63: LGTM: New cancellation ID added for AI enhancement.Properly defines a cancellation ID for the AI enhancement operation.
71-71: LGTM: Dependency injection for AI enhancement client.Correctly uses dependency injection for the AI enhancement client following TCA patterns.
90-98: Optimized meter updates improve UI performance.The optimization to only update the meter when there's a significant change or during active recording reduces unnecessary UI updates.
131-133: Clean state management for AI enhancement status.Simple and direct state management for the enhancing state.
135-136: Proper handling of AI enhancement results.Correctly delegates to a helper method to handle successful AI enhancement results.
161-178: Properly implemented Ollama availability rechecking.Correctly handles the case when Ollama becomes unavailable, showing an error to the user.
198-232: Well-implemented actor for meter rate limiting.The
MeterRateLimiteractor is a good implementation for Swift concurrency. It safely manages state and implements an adaptive threshold for meter updates.🧰 Tools
🪛 SwiftLint (0.57.0)
[Warning] 201-201: Initializing an optional variable with nil is redundant
(redundant_optional_initialization)
404-404: LGTM: Updated transcription call with settings parameter.Properly passes the settings to respect configuration options like
disableAutoCapitalization.
424-460: Well-designed enhancement decision flow.Good conditional logic to determine whether AI enhancement should be applied based on user settings.
512-535: LGTM: Proper AI enhancement result handling.The handler correctly updates all relevant state properties and proceeds with storing the transcript.
609-620: Addressed cancellation concerns with detailed comment.The code intentionally avoids canceling AI enhancement operations to prevent Ollama API issues. The comment clearly explains the trade-off and plans for future improvements.
🧰 Tools
🪛 SwiftLint (0.57.0)
[Warning] 618-618: TODOs should be resolved (Consider implementing a safer ...)
(todo)
662-673: LGTM: Updated status logic with enhancement state.The status logic correctly prioritizes showing the enhancing state when active.
138-159:Details
✅ Verification successful
Consider improving error recovery flow to avoid false positives.
The error handling correctly identifies Ollama connectivity issues, but there's a potential edge case where
pendingTranscriptionmight be nil, which would result in empty text being processed.
🏁 Script executed:
#!/bin/bash # Check if there are cases where pendingTranscription could be nil when error handling is triggered # Look for places where pendingTranscription is set to nil rg "pendingTranscription = nil" --type swift # Look for places where aiEnhancementError action is sent without setting pendingTranscription rg "send\(\.aiEnhancementError" --type swift -A 10 -B 10Length of output: 2321
To confirm where and how
pendingTranscriptionis set, let’s list all usages in the reducer around that property:
🏁 Script executed:
#!/bin/bash rg "pendingTranscription" -n Hex/Features/Transcription/TranscriptionFeature.swift -A 5 -B 5Length of output: 2204
Error recovery flow is safe—no
pendingTranscriptionnil scenario
state.pendingTranscriptionis set at line 429 before the AI enhancement call.- It’s only cleared on success at line 519, so in the
.aiEnhancementErrorcase it will always be non-nil.- The
?? ""fallback further guards against any unexpected nil, preventing crashes.No further changes needed.
|
Let me know when you're ready for a final review :D This looks like it's gonna be great! |
|
Super pumped for this @plyght this will unlock lot 🙌 |
|
@lkeude96 appreciate it! sorry it's taking a while to finish... there's some performance issues :/ @kitlangton actually would be great if you could take a look and help me diagnose why the spinner wheel is super laggy! |
|
I understand, I might be asking for more, is there an option to add another bigger model that supports my 48 gig MacBook Pro M4 other than Ollama |
|
@VipinReddy all https://ollama.com models will be supported for the text enhancement. |
|
Super excited about this! |
|
Cmon, really looking forward to this! |
|
@kitlangton would love your help on this to fix the performance of the bubble when transcribing, etc. I've seen that you'd like to reduce redundancy and too many options in settings. please let me know what you'd like me to fix, change, etc here, before merging. I will fix the merge conflicts! |
|
buzzin for this! |
@kitlangton
This pull request introduces significant enhancements and fixes across multiple areas of the codebase, including the addition of a new AI enhancement feature, improvements to pasteboard handling, and updates to existing functionalities. Below is a breakdown of the most important changes grouped by theme:
New Feature: AI Enhancement
AIEnhancementClientinHex/Clients/AIEnhancementClient.swift, which provides functionality for enhancing transcribed text using local AI models like Ollama. This includes methods for checking model availability, retrieving available models, and performing text enhancement with detailed options.aiEnhancementtab in the app's UI by updatingAppFeatureandAppViewto include the AI enhancement feature. This includes a new button and navigation logic. [1] [2] [3]Improvements to Pasteboard Handling
savePasteboardStateinPasteboardClientLiveto limit the number of pasteboard items saved (to 5) and restrict the size of saved data (to 1MB per item) to reduce memory usage.pasteWithClipboardmethod to conditionally save the pasteboard state only when necessary, added delays for better system processing, and ensured proper restoration of the pasteboard state. [1] [2]Updates to Transcription Functionality
TranscriptionClientLiveto respect a newdisableAutoCapitalizationsetting fromhex_settings.json. If this setting is enabled, transcribed text will remain in lowercase.Build Configuration Changes
CODE_SIGN_IDENTITYfor macOS builds inHex.xcodeproj/project.pbxprojto"-"to simplify code signing during development. [1] [2]Minor Fixes
RecordingClientLiveto useletinstead ofvarfor thedeviceNamePtrallocation to ensure immutability.Summary by CodeRabbit
New Features
Enhancements
User Interface
Localization
Performance