diff --git a/FirebaseVertexAI/CHANGELOG.md b/FirebaseVertexAI/CHANGELOG.md index 21271329704..c904c0cfbc5 100644 --- a/FirebaseVertexAI/CHANGELOG.md +++ b/FirebaseVertexAI/CHANGELOG.md @@ -22,6 +22,9 @@ is now optional (`Int?`); it may be `null` in cases such as when a `GenerateContentRequest` contains only images or other non-text content. (#13721) +- [changed] **Breaking Change**: The `ImageConversionError` enum is no longer + public; image conversion errors are still reported as + `GenerateContentError.promptImageContentError`. (#13735) - [changed] The default request timeout is now 180 seconds instead of the platform-default value of 60 seconds for a `URLRequest`; this timeout may still be customized in `RequestOptions`. (#13722) diff --git a/FirebaseVertexAI/Sources/GenerateContentError.swift b/FirebaseVertexAI/Sources/GenerateContentError.swift index 5428223853f..b5b52d0acd5 100644 --- a/FirebaseVertexAI/Sources/GenerateContentError.swift +++ b/FirebaseVertexAI/Sources/GenerateContentError.swift @@ -17,12 +17,12 @@ import Foundation /// Errors that occur when generating content from a model. @available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public enum GenerateContentError: Error { - /// An error occurred when constructing the prompt. Examine the related error for details. - case promptImageContentError(underlying: ImageConversionError) - /// An internal error occurred. See the underlying error for more context. case internalError(underlying: Error) + /// An error occurred when constructing the prompt. Examine the related error for details. + case promptImageContentError(underlying: Error) + /// A prompt was blocked. See the response's `promptFeedback.blockReason` for more information. case promptBlocked(response: GenerateContentResponse) diff --git a/FirebaseVertexAI/Sources/PartsRepresentable+Image.swift b/FirebaseVertexAI/Sources/PartsRepresentable+Image.swift index 4e1dc2fea5e..6b2cc977889 100644 --- a/FirebaseVertexAI/Sources/PartsRepresentable+Image.swift +++ b/FirebaseVertexAI/Sources/PartsRepresentable+Image.swift @@ -24,29 +24,15 @@ private let imageCompressionQuality: CGFloat = 0.8 /// An enum describing failures that can occur when converting image types to model content data. /// For some image types like `CIImage`, creating valid model content requires creating a JPEG /// representation of the image that may not yet exist, which may be computationally expensive. -public enum ImageConversionError: Error { - /// The image that could not be converted. - public enum SourceImage { - #if canImport(UIKit) - case uiImage(UIImage) - #elseif canImport(AppKit) - case nsImage(NSImage) - #endif // canImport(UIKit) - case cgImage(CGImage) - #if canImport(CoreImage) - case ciImage(CIImage) - #endif // canImport(CoreImage) - } - +enum ImageConversionError: Error { /// The image (the receiver of the call `toModelContentParts()`) was invalid. case invalidUnderlyingImage /// A valid image destination could not be allocated. case couldNotAllocateDestination - /// JPEG image data conversion failed, accompanied by the original image, which may be an - /// instance of `NSImage`, `UIImage`, `CGImage`, or `CIImage`. - case couldNotConvertToJPEG(SourceImage) + /// JPEG image data conversion failed. + case couldNotConvertToJPEG } #if canImport(UIKit) @@ -55,7 +41,7 @@ public enum ImageConversionError: Error { extension UIImage: ThrowingPartsRepresentable { public func tryPartsValue() throws -> [ModelContent.Part] { guard let data = jpegData(compressionQuality: imageCompressionQuality) else { - throw ImageConversionError.couldNotConvertToJPEG(.uiImage(self)) + throw ImageConversionError.couldNotConvertToJPEG } return [ModelContent.Part.inlineData(mimetype: "image/jpeg", data)] } @@ -72,7 +58,7 @@ public enum ImageConversionError: Error { let bmp = NSBitmapImageRep(cgImage: cgImage) guard let data = bmp.representation(using: .jpeg, properties: [.compressionFactor: 0.8]) else { - throw ImageConversionError.couldNotConvertToJPEG(.nsImage(self)) + throw ImageConversionError.couldNotConvertToJPEG } return [ModelContent.Part.inlineData(mimetype: "image/jpeg", data)] } @@ -97,7 +83,7 @@ public enum ImageConversionError: Error { if CGImageDestinationFinalize(imageDestination) { return [.inlineData(mimetype: "image/jpeg", output as Data)] } - throw ImageConversionError.couldNotConvertToJPEG(.cgImage(self)) + throw ImageConversionError.couldNotConvertToJPEG } } #endif // !os(watchOS) @@ -118,7 +104,7 @@ public enum ImageConversionError: Error { if let jpegData = jpegData { return [.inlineData(mimetype: "image/jpeg", jpegData)] } - throw ImageConversionError.couldNotConvertToJPEG(.ciImage(self)) + throw ImageConversionError.couldNotConvertToJPEG } } #endif // canImport(CoreImage) diff --git a/FirebaseVertexAI/Tests/Unit/PartsRepresentableTests.swift b/FirebaseVertexAI/Tests/Unit/PartsRepresentableTests.swift index bd539d825a8..073f6582721 100644 --- a/FirebaseVertexAI/Tests/Unit/PartsRepresentableTests.swift +++ b/FirebaseVertexAI/Tests/Unit/PartsRepresentableTests.swift @@ -13,7 +13,6 @@ // limitations under the License. import CoreGraphics -import FirebaseVertexAI import XCTest #if canImport(UIKit) import UIKit @@ -24,6 +23,8 @@ import XCTest import CoreImage #endif // canImport(CoreImage) +@testable import FirebaseVertexAI + @available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) final class PartsRepresentableTests: XCTestCase { #if !os(watchOS) @@ -61,22 +62,13 @@ final class PartsRepresentableTests: XCTestCase { do { _ = try image.tryPartsValue() XCTFail("Expected model content from invalid image to error") - } catch { - guard let imageError = (error as? ImageConversionError) else { - XCTFail("Got unexpected error type: \(error)") - return - } - switch imageError { - case let .couldNotConvertToJPEG(source): - guard case let .ciImage(ciImage) = source else { - XCTFail("Unexpected image source: \(source)") - return - } - XCTAssertEqual(ciImage, image) - default: - XCTFail("Expected image conversion error, got \(imageError) instead") + } catch let imageError as ImageConversionError { + guard case .couldNotConvertToJPEG = imageError else { + XCTFail("Expected JPEG conversion error, got \(imageError) instead.") return } + } catch { + XCTFail("Got unexpected error type: \(error)") } } #endif // canImport(CoreImage) @@ -87,22 +79,13 @@ final class PartsRepresentableTests: XCTestCase { do { _ = try image.tryPartsValue() XCTFail("Expected model content from invalid image to error") - } catch { - guard let imageError = (error as? ImageConversionError) else { - XCTFail("Got unexpected error type: \(error)") - return - } - switch imageError { - case let .couldNotConvertToJPEG(source): - guard case let .uiImage(uiImage) = source else { - XCTFail("Unexpected image source: \(source)") - return - } - XCTAssertEqual(uiImage, image) - default: - XCTFail("Expected image conversion error, got \(imageError) instead") + } catch let imageError as ImageConversionError { + guard case .couldNotConvertToJPEG = imageError else { + XCTFail("Expected JPEG conversion error, got \(imageError) instead.") return } + } catch { + XCTFail("Got unexpected error type: \(error)") } }