Update AI Enhancement Service: Remove retry logic and fix unused error logging
This commit is contained in:
parent
0b79f71946
commit
a4356e7fb8
@ -53,7 +53,6 @@ class AIEnhancementService: ObservableObject {
|
|||||||
|
|
||||||
private let aiService: AIService
|
private let aiService: AIService
|
||||||
private let screenCaptureService: ScreenCaptureService
|
private let screenCaptureService: ScreenCaptureService
|
||||||
private let maxRetries = 3
|
|
||||||
private let baseTimeout: TimeInterval = 10
|
private let baseTimeout: TimeInterval = 10
|
||||||
private let rateLimitInterval: TimeInterval = 1.0
|
private let rateLimitInterval: TimeInterval = 1.0
|
||||||
private var lastRequestTime: Date?
|
private var lastRequestTime: Date?
|
||||||
@ -166,7 +165,7 @@ class AIEnhancementService: ObservableObject {
|
|||||||
return systemMessage
|
return systemMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
private func makeRequest(text: String, mode: EnhancementPrompt, retryCount: Int = 0) async throws -> String {
|
private func makeRequest(text: String, mode: EnhancementPrompt) async throws -> String {
|
||||||
guard isConfigured else {
|
guard isConfigured else {
|
||||||
throw EnhancementError.notConfigured
|
throw EnhancementError.notConfigured
|
||||||
}
|
}
|
||||||
@ -200,80 +199,6 @@ class AIEnhancementService: ObservableObject {
|
|||||||
try await waitForRateLimit()
|
try await waitForRateLimit()
|
||||||
|
|
||||||
switch aiService.selectedProvider {
|
switch aiService.selectedProvider {
|
||||||
case .gemini:
|
|
||||||
let baseEndpoint = "https://generativelanguage.googleapis.com/v1beta/models"
|
|
||||||
let model = aiService.currentModel
|
|
||||||
let fullURL = "\(baseEndpoint)/\(model):generateContent"
|
|
||||||
|
|
||||||
var urlComponents = URLComponents(string: fullURL)!
|
|
||||||
urlComponents.queryItems = [URLQueryItem(name: "key", value: aiService.apiKey)]
|
|
||||||
|
|
||||||
guard let url = urlComponents.url else {
|
|
||||||
throw EnhancementError.invalidResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
var request = URLRequest(url: url)
|
|
||||||
request.httpMethod = "POST"
|
|
||||||
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
||||||
request.timeoutInterval = baseTimeout * pow(2.0, Double(retryCount))
|
|
||||||
|
|
||||||
let requestBody: [String: Any] = [
|
|
||||||
"contents": [
|
|
||||||
[
|
|
||||||
"parts": [
|
|
||||||
["text": systemMessage],
|
|
||||||
["text": formattedText]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"generationConfig": [
|
|
||||||
"temperature": 0.3,
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
request.httpBody = try? JSONSerialization.data(withJSONObject: requestBody)
|
|
||||||
|
|
||||||
do {
|
|
||||||
let (data, response) = try await URLSession.shared.data(for: request)
|
|
||||||
|
|
||||||
guard let httpResponse = response as? HTTPURLResponse else {
|
|
||||||
throw EnhancementError.invalidResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
switch httpResponse.statusCode {
|
|
||||||
case 200:
|
|
||||||
guard let jsonResponse = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
|
|
||||||
let candidates = jsonResponse["candidates"] as? [[String: Any]],
|
|
||||||
let firstCandidate = candidates.first,
|
|
||||||
let content = firstCandidate["content"] as? [String: Any],
|
|
||||||
let parts = content["parts"] as? [[String: Any]],
|
|
||||||
let firstPart = parts.first,
|
|
||||||
let enhancedText = firstPart["text"] as? String else {
|
|
||||||
throw EnhancementError.enhancementFailed
|
|
||||||
}
|
|
||||||
|
|
||||||
let filteredText = AIEnhancementOutputFilter.filter(enhancedText.trimmingCharacters(in: .whitespacesAndNewlines))
|
|
||||||
return filteredText
|
|
||||||
|
|
||||||
case 401:
|
|
||||||
throw EnhancementError.authenticationFailed
|
|
||||||
case 429:
|
|
||||||
throw EnhancementError.rateLimitExceeded
|
|
||||||
case 500...599:
|
|
||||||
throw EnhancementError.serverError
|
|
||||||
default:
|
|
||||||
throw EnhancementError.apiError
|
|
||||||
}
|
|
||||||
} catch let error as EnhancementError {
|
|
||||||
throw error
|
|
||||||
} catch {
|
|
||||||
if retryCount < maxRetries {
|
|
||||||
try await Task.sleep(nanoseconds: UInt64(pow(2.0, Double(retryCount)) * 1_000_000_000))
|
|
||||||
return try await makeRequest(text: text, mode: mode, retryCount: retryCount + 1)
|
|
||||||
}
|
|
||||||
throw EnhancementError.networkError
|
|
||||||
}
|
|
||||||
|
|
||||||
case .anthropic:
|
case .anthropic:
|
||||||
let requestBody: [String: Any] = [
|
let requestBody: [String: Any] = [
|
||||||
"model": aiService.currentModel,
|
"model": aiService.currentModel,
|
||||||
@ -289,7 +214,7 @@ class AIEnhancementService: ObservableObject {
|
|||||||
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
||||||
request.addValue(aiService.apiKey, forHTTPHeaderField: "x-api-key")
|
request.addValue(aiService.apiKey, forHTTPHeaderField: "x-api-key")
|
||||||
request.addValue("2023-06-01", forHTTPHeaderField: "anthropic-version")
|
request.addValue("2023-06-01", forHTTPHeaderField: "anthropic-version")
|
||||||
request.timeoutInterval = baseTimeout * pow(2.0, Double(retryCount))
|
request.timeoutInterval = baseTimeout
|
||||||
request.httpBody = try? JSONSerialization.data(withJSONObject: requestBody)
|
request.httpBody = try? JSONSerialization.data(withJSONObject: requestBody)
|
||||||
|
|
||||||
do {
|
do {
|
||||||
@ -320,14 +245,11 @@ class AIEnhancementService: ObservableObject {
|
|||||||
default:
|
default:
|
||||||
throw EnhancementError.apiError
|
throw EnhancementError.apiError
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch let error as EnhancementError {
|
} catch let error as EnhancementError {
|
||||||
throw error
|
throw error
|
||||||
} catch {
|
} catch {
|
||||||
if retryCount < maxRetries {
|
throw EnhancementError.customError(error.localizedDescription)
|
||||||
try await Task.sleep(nanoseconds: UInt64(pow(2.0, Double(retryCount)) * 1_000_000_000))
|
|
||||||
return try await makeRequest(text: text, mode: mode, retryCount: retryCount + 1)
|
|
||||||
}
|
|
||||||
throw EnhancementError.networkError
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -336,7 +258,7 @@ class AIEnhancementService: ObservableObject {
|
|||||||
request.httpMethod = "POST"
|
request.httpMethod = "POST"
|
||||||
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
||||||
request.addValue("Bearer \(aiService.apiKey)", forHTTPHeaderField: "Authorization")
|
request.addValue("Bearer \(aiService.apiKey)", forHTTPHeaderField: "Authorization")
|
||||||
request.timeoutInterval = baseTimeout * pow(2.0, Double(retryCount))
|
request.timeoutInterval = baseTimeout
|
||||||
|
|
||||||
let messages: [[String: Any]] = [
|
let messages: [[String: Any]] = [
|
||||||
["role": "system", "content": systemMessage],
|
["role": "system", "content": systemMessage],
|
||||||
@ -347,8 +269,6 @@ class AIEnhancementService: ObservableObject {
|
|||||||
"model": aiService.currentModel,
|
"model": aiService.currentModel,
|
||||||
"messages": messages,
|
"messages": messages,
|
||||||
"temperature": 0.3,
|
"temperature": 0.3,
|
||||||
"frequency_penalty": 0.0,
|
|
||||||
"presence_penalty": 0.0,
|
|
||||||
"stream": false
|
"stream": false
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -361,8 +281,7 @@ class AIEnhancementService: ObservableObject {
|
|||||||
throw EnhancementError.invalidResponse
|
throw EnhancementError.invalidResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
switch httpResponse.statusCode {
|
if httpResponse.statusCode == 200 {
|
||||||
case 200:
|
|
||||||
guard let jsonResponse = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
|
guard let jsonResponse = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
|
||||||
let choices = jsonResponse["choices"] as? [[String: Any]],
|
let choices = jsonResponse["choices"] as? [[String: Any]],
|
||||||
let firstChoice = choices.first,
|
let firstChoice = choices.first,
|
||||||
@ -373,25 +292,15 @@ class AIEnhancementService: ObservableObject {
|
|||||||
|
|
||||||
let filteredText = AIEnhancementOutputFilter.filter(enhancedText.trimmingCharacters(in: .whitespacesAndNewlines))
|
let filteredText = AIEnhancementOutputFilter.filter(enhancedText.trimmingCharacters(in: .whitespacesAndNewlines))
|
||||||
return filteredText
|
return filteredText
|
||||||
|
} else {
|
||||||
case 401:
|
let errorString = String(data: data, encoding: .utf8) ?? "Could not decode error response."
|
||||||
throw EnhancementError.authenticationFailed
|
throw EnhancementError.customError("HTTP \(httpResponse.statusCode): \(errorString)")
|
||||||
case 429:
|
|
||||||
throw EnhancementError.rateLimitExceeded
|
|
||||||
case 500...599:
|
|
||||||
throw EnhancementError.serverError
|
|
||||||
default:
|
|
||||||
throw EnhancementError.apiError
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch let error as EnhancementError {
|
} catch let error as EnhancementError {
|
||||||
throw error
|
throw error
|
||||||
} catch {
|
} catch {
|
||||||
if retryCount < maxRetries {
|
throw EnhancementError.customError(error.localizedDescription)
|
||||||
try await Task.sleep(nanoseconds: UInt64(pow(2.0, Double(retryCount)) * 1_000_000_000))
|
|
||||||
return try await makeRequest(text: text, mode: mode, retryCount: retryCount + 1)
|
|
||||||
}
|
|
||||||
throw EnhancementError.networkError
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -400,26 +309,14 @@ class AIEnhancementService: ObservableObject {
|
|||||||
let startTime = Date()
|
let startTime = Date()
|
||||||
let enhancementPrompt: EnhancementPrompt = .transcriptionEnhancement
|
let enhancementPrompt: EnhancementPrompt = .transcriptionEnhancement
|
||||||
|
|
||||||
var retryCount = 0
|
do {
|
||||||
while retryCount < maxRetries {
|
let result = try await makeRequest(text: text, mode: enhancementPrompt)
|
||||||
do {
|
let endTime = Date()
|
||||||
let result = try await makeRequest(text: text, mode: enhancementPrompt, retryCount: retryCount)
|
let duration = endTime.timeIntervalSince(startTime)
|
||||||
let duration = Date().timeIntervalSince(startTime)
|
return (result, duration)
|
||||||
return (result, duration)
|
} catch {
|
||||||
} catch let error as EnhancementError {
|
throw error
|
||||||
if shouldRetry(error: error, retryCount: retryCount) {
|
|
||||||
retryCount += 1
|
|
||||||
let delaySeconds = getRetryDelay(for: retryCount)
|
|
||||||
try await Task.sleep(nanoseconds: UInt64(delaySeconds * 1_000_000_000))
|
|
||||||
continue
|
|
||||||
} else {
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
throw EnhancementError.maxRetriesExceeded
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func captureScreenContext() async {
|
func captureScreenContext() async {
|
||||||
@ -457,21 +354,6 @@ class AIEnhancementService: ObservableObject {
|
|||||||
selectedPromptId = prompt.id
|
selectedPromptId = prompt.id
|
||||||
}
|
}
|
||||||
|
|
||||||
private func shouldRetry(error: EnhancementError, retryCount: Int) -> Bool {
|
|
||||||
guard retryCount < maxRetries - 1 else { return false }
|
|
||||||
|
|
||||||
switch error {
|
|
||||||
case .rateLimitExceeded, .serverError:
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func getRetryDelay(for retryCount: Int) -> TimeInterval {
|
|
||||||
return retryCount == 1 ? 1.0 : 2.0
|
|
||||||
}
|
|
||||||
|
|
||||||
private func initializePredefinedPrompts() {
|
private func initializePredefinedPrompts() {
|
||||||
let predefinedTemplates = PredefinedPrompts.createDefaultPrompts()
|
let predefinedTemplates = PredefinedPrompts.createDefaultPrompts()
|
||||||
|
|
||||||
@ -506,7 +388,7 @@ enum EnhancementError: Error {
|
|||||||
case serverError
|
case serverError
|
||||||
case apiError
|
case apiError
|
||||||
case networkError
|
case networkError
|
||||||
case maxRetriesExceeded
|
case customError(String)
|
||||||
}
|
}
|
||||||
|
|
||||||
extension EnhancementError: LocalizedError {
|
extension EnhancementError: LocalizedError {
|
||||||
@ -530,8 +412,8 @@ extension EnhancementError: LocalizedError {
|
|||||||
return "AI provider API error. Please try again."
|
return "AI provider API error. Please try again."
|
||||||
case .networkError:
|
case .networkError:
|
||||||
return "Network connection failed. Check your internet."
|
return "Network connection failed. Check your internet."
|
||||||
case .maxRetriesExceeded:
|
case .customError(let message):
|
||||||
return "Enhancement failed after multiple attempts."
|
return message
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -22,7 +22,7 @@ enum AIProvider: String, CaseIterable {
|
|||||||
case .groq:
|
case .groq:
|
||||||
return "https://api.groq.com/openai/v1/chat/completions"
|
return "https://api.groq.com/openai/v1/chat/completions"
|
||||||
case .gemini:
|
case .gemini:
|
||||||
return "https://generativelanguage.googleapis.com/v1beta/models"
|
return "https://generativelanguage.googleapis.com/v1beta/openai/chat/completions"
|
||||||
case .anthropic:
|
case .anthropic:
|
||||||
return "https://api.anthropic.com/v1/messages"
|
return "https://api.anthropic.com/v1/messages"
|
||||||
case .openAI:
|
case .openAI:
|
||||||
@ -291,8 +291,6 @@ class AIService: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch selectedProvider {
|
switch selectedProvider {
|
||||||
case .gemini:
|
|
||||||
verifyGeminiAPIKey(key, completion: completion)
|
|
||||||
case .anthropic:
|
case .anthropic:
|
||||||
verifyAnthropicAPIKey(key, completion: completion)
|
verifyAnthropicAPIKey(key, completion: completion)
|
||||||
case .elevenLabs:
|
case .elevenLabs:
|
||||||
@ -370,49 +368,6 @@ class AIService: ObservableObject {
|
|||||||
}.resume()
|
}.resume()
|
||||||
}
|
}
|
||||||
|
|
||||||
private func verifyGeminiAPIKey(_ key: String, completion: @escaping (Bool) -> Void) {
|
|
||||||
let baseEndpoint = "https://generativelanguage.googleapis.com/v1beta/models"
|
|
||||||
let model = currentModel
|
|
||||||
let fullURL = "\(baseEndpoint)/\(model):generateContent"
|
|
||||||
|
|
||||||
var urlComponents = URLComponents(string: fullURL)!
|
|
||||||
urlComponents.queryItems = [URLQueryItem(name: "key", value: key)]
|
|
||||||
|
|
||||||
guard let url = urlComponents.url else {
|
|
||||||
completion(false)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var request = URLRequest(url: url)
|
|
||||||
request.httpMethod = "POST"
|
|
||||||
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
||||||
|
|
||||||
let testBody: [String: Any] = [
|
|
||||||
"contents": [
|
|
||||||
[
|
|
||||||
"parts": [
|
|
||||||
["text": "test"]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
request.httpBody = try? JSONSerialization.data(withJSONObject: testBody)
|
|
||||||
|
|
||||||
URLSession.shared.dataTask(with: request) { data, response, error in
|
|
||||||
if let error = error {
|
|
||||||
completion(false)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if let httpResponse = response as? HTTPURLResponse {
|
|
||||||
completion(httpResponse.statusCode == 200)
|
|
||||||
} else {
|
|
||||||
completion(false)
|
|
||||||
}
|
|
||||||
}.resume()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func verifyElevenLabsAPIKey(_ key: String, completion: @escaping (Bool) -> Void) {
|
private func verifyElevenLabsAPIKey(_ key: String, completion: @escaping (Bool) -> Void) {
|
||||||
let url = URL(string: "https://api.elevenlabs.io/v1/user")!
|
let url = URL(string: "https://api.elevenlabs.io/v1/user")!
|
||||||
|
|
||||||
|
|||||||
@ -294,7 +294,7 @@ class WhisperState: NSObject, ObservableObject {
|
|||||||
let newTranscription = Transcription(
|
let newTranscription = Transcription(
|
||||||
text: originalText,
|
text: originalText,
|
||||||
duration: actualDuration,
|
duration: actualDuration,
|
||||||
enhancedText: "Enhancement failed: \(error.localizedDescription)",
|
enhancedText: "Enhancement failed: \(error)",
|
||||||
audioFileURL: url.absoluteString,
|
audioFileURL: url.absoluteString,
|
||||||
transcriptionModelName: model.displayName,
|
transcriptionModelName: model.displayName,
|
||||||
transcriptionDuration: transcriptionDuration
|
transcriptionDuration: transcriptionDuration
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user