diff --git a/VoiceInk/Models/AIPrompts.swift b/VoiceInk/Models/AIPrompts.swift index 24505a8..c4e4533 100644 --- a/VoiceInk/Models/AIPrompts.swift +++ b/VoiceInk/Models/AIPrompts.swift @@ -13,14 +13,16 @@ enum AIPrompts { static let assistantMode = """ - Give a helpful and informative response to the user's query. Use information from the section if directly related to the user's query. - Remember to: - 1. ALWAYS provide ONLY the direct answer to the user's query. - 2. NEVER add any introductory text like "Here is the corrected text:", "Transcript:", "Sure, here's that:", or anything similar. - 3. NEVER add any disclaimers or additional information that was not explicitly asked for, unless it's a crucial clarification tied to the direct answer. - 4. NEVER add sign-offs or closing text like "Let me know if you need any more adjustments!", or anything like that. - 5. Your response must be directly address the user's request. - 6. Maintain a friendly, casual tone. + You are a powerful AI assistant. Your primary goal is to provide a direct, clean, and unadorned response to the user's request from the . + + YOUR RESPONSE MUST BE PURE. This means: + - NO commentary. + - NO introductory phrases like "Here is the result:" or "Sure, here's the text:". + - NO concluding remarks or sign-offs like "Let me know if you need anything else!". + - NO markdown formatting (like ```) unless it is essential for the response format (e.g., code). + - ONLY provide the direct answer or the modified text that was requested. + + Use the information within the section as the primary material to work with when the user's request implies it. Your main instruction is always the user's . """ diff --git a/VoiceInk/Services/AIEnhancementService.swift b/VoiceInk/Services/AIEnhancementService.swift index 34048a7..14a4a8d 100644 --- a/VoiceInk/Services/AIEnhancementService.swift +++ b/VoiceInk/Services/AIEnhancementService.swift @@ -126,6 +126,17 @@ class AIEnhancementService: ObservableObject { } private func getSystemMessage(for mode: EnhancementPrompt) -> String { + let selectedText = SelectedTextService.fetchSelectedText() + + if let activePrompt = activePrompt, + activePrompt.id == PredefinedPrompts.assistantPromptId, + let selectedText = selectedText, !selectedText.isEmpty { + + let selectedTextContext = "\n\nSelected Text: \(selectedText)" + let contextSection = "\n\n\(AIPrompts.contextInstructions)\n\n\(selectedTextContext)\n" + return activePrompt.promptText + contextSection + } + let clipboardContext = if useClipboardContext, let clipboardText = NSPasteboard.general.string(forType: .string), !clipboardText.isEmpty { diff --git a/VoiceInk/Services/SelectedTextService.swift b/VoiceInk/Services/SelectedTextService.swift new file mode 100644 index 0000000..97a66c3 --- /dev/null +++ b/VoiceInk/Services/SelectedTextService.swift @@ -0,0 +1,51 @@ +import Foundation +import AppKit + +class SelectedTextService { + static func fetchSelectedText() -> String? { + guard let frontmostApp = NSWorkspace.shared.frontmostApplication, + frontmostApp.bundleIdentifier != "com.prakashjoshipax.VoiceInk" else { + return nil + } + + let systemWideElement = AXUIElementCreateSystemWide() + var focusedElement: CFTypeRef? + + guard AXUIElementCopyAttributeValue(systemWideElement, kAXFocusedUIElementAttribute as CFString, &focusedElement) == .success, + let element = focusedElement else { + return nil + } + + return findSelectedText(in: element as! AXUIElement) + } + + private static func findSelectedText(in element: AXUIElement) -> String? { + var selectedTextValue: CFTypeRef? + if AXUIElementCopyAttributeValue(element, kAXSelectedTextAttribute as CFString, &selectedTextValue) == .success { + if let selectedText = selectedTextValue as? String, !selectedText.isEmpty { + return selectedText + } + } + + // Fallback for apps that use kAXValueAttribute for selected text (like some Electron apps) + var value: CFTypeRef? + if AXUIElementCopyAttributeValue(element, kAXValueAttribute as CFString, &value) == .success { + if let selectedText = value as? String, !selectedText.isEmpty { + return selectedText + } + } + + var children: CFTypeRef? + if AXUIElementCopyAttributeValue(element, kAXChildrenAttribute as CFString, &children) == .success { + if let axChildren = children as? [AXUIElement] { + for child in axChildren { + if let foundText = findSelectedText(in: child) { + return foundText + } + } + } + } + + return nil + } +} \ No newline at end of file