diff --git a/Package.swift b/Package.swift index 8402e52..041b6c9 100644 --- a/Package.swift +++ b/Package.swift @@ -23,6 +23,7 @@ let package = Package( .iOS(.v11), .macOS(.v10_13), .macCatalyst(.v13), + .watchOS(.v4) ], products: [ .library( diff --git a/Sources/GoogleAI/Chat.swift b/Sources/GoogleAI/Chat.swift index 6549df4..ebb9c65 100644 --- a/Sources/GoogleAI/Chat.swift +++ b/Sources/GoogleAI/Chat.swift @@ -16,7 +16,7 @@ import Foundation /// An object that represents a back-and-forth chat with a model, capturing the history and saving /// the context in memory between each message sent. -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, *) +@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, watchOS 7.0, *) public class Chat { private let model: GenerativeModel @@ -84,7 +84,7 @@ public class Chat { /// and response will be added to the history. If unsuccessful, history will remain unchanged. /// - Parameter parts: The new content to send as a single chat message. /// - Returns: A stream containing the model's response or an error if an error occurred. - @available(macOS 12.0, *) + @available(macOS 12.0, watchOS 8.0, *) public func sendMessageStream(_ parts: any ThrowingPartsRepresentable...) -> AsyncThrowingStream { return try sendMessageStream([ModelContent(parts: parts)]) @@ -94,7 +94,7 @@ public class Chat { /// and response will be added to the history. If unsuccessful, history will remain unchanged. /// - Parameter content: The new content to send as a single chat message. /// - Returns: A stream containing the model's response or an error if an error occurred. - @available(macOS 12.0, *) + @available(macOS 12.0, watchOS 8.0, *) public func sendMessageStream(_ content: @autoclosure () throws -> [ModelContent]) -> AsyncThrowingStream { let resolvedContent: [ModelContent] @@ -188,4 +188,4 @@ public class Chat { return ModelContent(role: "user", parts: content.parts) } } -} +} \ No newline at end of file diff --git a/Sources/GoogleAI/CountTokensRequest.swift b/Sources/GoogleAI/CountTokensRequest.swift index d8bfc0e..3c5de5f 100644 --- a/Sources/GoogleAI/CountTokensRequest.swift +++ b/Sources/GoogleAI/CountTokensRequest.swift @@ -47,4 +47,4 @@ extension CountTokensRequest: Encodable { } @available(iOS 15.0, macOS 11.0, macCatalyst 15.0, *) -extension CountTokensResponse: Decodable {} +extension CountTokensResponse: Decodable {} \ No newline at end of file diff --git a/Sources/GoogleAI/Errors.swift b/Sources/GoogleAI/Errors.swift index 35e7e6b..d534343 100644 --- a/Sources/GoogleAI/Errors.swift +++ b/Sources/GoogleAI/Errors.swift @@ -186,4 +186,4 @@ enum RPCErrorMessage: String { enum InvalidCandidateError: Error { case emptyContent(underlyingError: Error) case malformedContent(underlyingError: Error) -} +} \ No newline at end of file diff --git a/Sources/GoogleAI/FunctionCalling.swift b/Sources/GoogleAI/FunctionCalling.swift index 57130eb..ca88246 100644 --- a/Sources/GoogleAI/FunctionCalling.swift +++ b/Sources/GoogleAI/FunctionCalling.swift @@ -292,4 +292,4 @@ extension FunctionCallingConfig.Mode: Encodable {} extension ToolConfig: Encodable {} -extension FunctionResponse: Encodable {} +extension FunctionResponse: Encodable {} \ No newline at end of file diff --git a/Sources/GoogleAI/GenerateContentError.swift b/Sources/GoogleAI/GenerateContentError.swift index 055928e..63f18b2 100644 --- a/Sources/GoogleAI/GenerateContentError.swift +++ b/Sources/GoogleAI/GenerateContentError.swift @@ -15,7 +15,7 @@ import Foundation /// Errors that occur when generating content from a model. -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, *) +@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, watchOS 7.0, *) public enum GenerateContentError: Error { /// An error occurred when constructing the prompt. Examine the related error for details. case promptImageContentError(underlying: ImageConversionError) @@ -41,4 +41,4 @@ public enum GenerateContentError: Error { /// - Important: The API is only available in /// [specific regions](https://ai.google.dev/available_regions#available_regions). case unsupportedUserLocation -} +} \ No newline at end of file diff --git a/Sources/GoogleAI/GenerateContentRequest.swift b/Sources/GoogleAI/GenerateContentRequest.swift index c360583..49ba5e8 100644 --- a/Sources/GoogleAI/GenerateContentRequest.swift +++ b/Sources/GoogleAI/GenerateContentRequest.swift @@ -41,7 +41,7 @@ extension GenerateContentRequest: Encodable { } } -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, *) +@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, watchOS 7.0, *) extension GenerateContentRequest: GenerativeAIRequest { typealias Response = GenerateContentResponse @@ -53,4 +53,4 @@ extension GenerateContentRequest: GenerativeAIRequest { return URL(string: "\(modelURL):generateContent")! } } -} +} \ No newline at end of file diff --git a/Sources/GoogleAI/GenerateContentResponse.swift b/Sources/GoogleAI/GenerateContentResponse.swift index 04c41f7..27a3e17 100644 --- a/Sources/GoogleAI/GenerateContentResponse.swift +++ b/Sources/GoogleAI/GenerateContentResponse.swift @@ -15,7 +15,7 @@ import Foundation /// The model's response to a generate content request. -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, *) +@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, watchOS 7.0, *) public struct GenerateContentResponse { /// Token usage metadata for processing the generate content request. public struct UsageMetadata { @@ -188,7 +188,7 @@ public struct PromptFeedback { // MARK: - Codable Conformances -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, *) +@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, watchOS 7.0, *) extension GenerateContentResponse: Decodable { enum CodingKeys: CodingKey { case candidates @@ -222,7 +222,7 @@ extension GenerateContentResponse: Decodable { } } -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, *) +@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, watchOS 7.0, *) extension GenerateContentResponse.UsageMetadata: Decodable { enum CodingKeys: CodingKey { case promptTokenCount @@ -312,7 +312,7 @@ extension Citation: Decodable { } } -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, *) +@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, watchOS 7.0, *) extension FinishReason: Decodable { public init(from decoder: Decoder) throws { let value = try decoder.singleValueContainer().decode(String.self) @@ -327,7 +327,7 @@ extension FinishReason: Decodable { } } -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, *) +@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, watchOS 7.0, *) extension PromptFeedback.BlockReason: Decodable { public init(from decoder: Decoder) throws { let value = try decoder.singleValueContainer().decode(String.self) @@ -364,4 +364,4 @@ extension PromptFeedback: Decodable { safetyRatings = [] } } -} +} \ No newline at end of file diff --git a/Sources/GoogleAI/GenerationConfig.swift b/Sources/GoogleAI/GenerationConfig.swift index c4bd37c..f173b87 100644 --- a/Sources/GoogleAI/GenerationConfig.swift +++ b/Sources/GoogleAI/GenerationConfig.swift @@ -107,4 +107,4 @@ public struct GenerationConfig { // MARK: - Codable Conformances @available(iOS 15.0, macOS 11.0, macCatalyst 15.0, *) -extension GenerationConfig: Encodable {} +extension GenerationConfig: Encodable {} \ No newline at end of file diff --git a/Sources/GoogleAI/GenerativeAIRequest.swift b/Sources/GoogleAI/GenerativeAIRequest.swift index d468576..dd9693c 100644 --- a/Sources/GoogleAI/GenerativeAIRequest.swift +++ b/Sources/GoogleAI/GenerativeAIRequest.swift @@ -41,4 +41,4 @@ public struct RequestOptions { self.timeout = timeout self.apiVersion = apiVersion } -} +} \ No newline at end of file diff --git a/Sources/GoogleAI/GenerativeAIService.swift b/Sources/GoogleAI/GenerativeAIService.swift index ed0a6df..adafb47 100644 --- a/Sources/GoogleAI/GenerativeAIService.swift +++ b/Sources/GoogleAI/GenerativeAIService.swift @@ -14,7 +14,7 @@ import Foundation -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, *) +@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, watchOS 7.0, *) struct GenerativeAIService { /// Gives permission to talk to the backend. private let apiKey: String @@ -52,7 +52,7 @@ struct GenerativeAIService { return try parseResponse(T.Response.self, from: data) } - @available(macOS 12.0, *) + @available(macOS 12.0, watchOS 8.0, *) func loadRequestStream(request: T) -> AsyncThrowingStream { return AsyncThrowingStream { continuation in @@ -161,6 +161,7 @@ struct GenerativeAIService { return urlRequest } + @available(watchOS 7.0, *) private func httpResponse(urlResponse: URLResponse) throws -> HTTPURLResponse { // Verify the status code is 200 guard let response = urlResponse as? HTTPURLResponse else { @@ -209,6 +210,7 @@ struct GenerativeAIService { } } + @available(watchOS 7.0, *) private func parseResponse(_ type: T.Type, from data: Data) throws -> T { do { return try JSONDecoder().decode(type, from: data) @@ -222,6 +224,7 @@ struct GenerativeAIService { } #if DEBUG + @available(watchOS 7.0, *) private func cURLCommand(from request: URLRequest) -> String { var returnValue = "curl " if let allHeaders = request.allHTTPHeaderFields { @@ -251,4 +254,4 @@ struct GenerativeAIService { """) } #endif // DEBUG -} +} \ No newline at end of file diff --git a/Sources/GoogleAI/GenerativeAISwift.swift b/Sources/GoogleAI/GenerativeAISwift.swift index 0eb6253..52d0557 100644 --- a/Sources/GoogleAI/GenerativeAISwift.swift +++ b/Sources/GoogleAI/GenerativeAISwift.swift @@ -24,4 +24,4 @@ public enum GenerativeAISwift { public static let version = "0.5.4" /// The Google AI backend endpoint URL. static let baseURL = "https://generativelanguage.googleapis.com" -} +} \ No newline at end of file diff --git a/Sources/GoogleAI/GenerativeModel.swift b/Sources/GoogleAI/GenerativeModel.swift index fc9c985..d4ebdf5 100644 --- a/Sources/GoogleAI/GenerativeModel.swift +++ b/Sources/GoogleAI/GenerativeModel.swift @@ -16,7 +16,7 @@ import Foundation /// A type that represents a remote multimodal model (like Gemini), with the ability to generate /// content based on various input types. -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, *) +@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, watchOS 7.0, *) public final class GenerativeModel { // The prefix for a model resource in the Gemini API. private static let modelResourcePrefix = "models/" @@ -220,7 +220,7 @@ public final class GenerativeModel { /// for conforming types). /// - Returns: A stream wrapping content generated by the model or a ``GenerateContentError`` /// error if an error occurred. - @available(macOS 12.0, *) + @available(macOS 12.0, watchOS 8.0, *) public func generateContentStream(_ parts: any ThrowingPartsRepresentable...) -> AsyncThrowingStream { return try generateContentStream([ModelContent(parts: parts)]) @@ -231,7 +231,7 @@ public final class GenerativeModel { /// - Parameter content: The input(s) given to the model as a prompt. /// - Returns: A stream wrapping content generated by the model or a ``GenerateContentError`` /// error if an error occurred. - @available(macOS 12.0, *) + @available(macOS 12.0, watchOS 8.0, *) public func generateContentStream(_ content: @autoclosure () throws -> [ModelContent]) -> AsyncThrowingStream { let evaluatedContent: [ModelContent] @@ -373,4 +373,4 @@ public final class GenerativeModel { @available(iOS 15.0, macOS 11.0, macCatalyst 15.0, *) public enum CountTokensError: Error { case internalError(underlying: Error) -} +} \ No newline at end of file diff --git a/Sources/GoogleAI/JSONValue.swift b/Sources/GoogleAI/JSONValue.swift index 5ce52cd..df87be7 100644 --- a/Sources/GoogleAI/JSONValue.swift +++ b/Sources/GoogleAI/JSONValue.swift @@ -93,4 +93,4 @@ extension JSONValue: Encodable { } } -extension JSONValue: Equatable {} +extension JSONValue: Equatable {} \ No newline at end of file diff --git a/Sources/GoogleAI/Logging.swift b/Sources/GoogleAI/Logging.swift index 458c34e..16ffe24 100644 --- a/Sources/GoogleAI/Logging.swift +++ b/Sources/GoogleAI/Logging.swift @@ -15,7 +15,7 @@ import Foundation import OSLog -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, *) +@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, watchOS 7.0, *) struct Logging { /// Subsystem that should be used for all Loggers. static let subsystem = "com.google.generative-ai" @@ -53,4 +53,4 @@ struct Logging { return Logger(.disabled) } }() -} +} \ No newline at end of file diff --git a/Sources/GoogleAI/ModelContent.swift b/Sources/GoogleAI/ModelContent.swift index 979c406..81471d9 100644 --- a/Sources/GoogleAI/ModelContent.swift +++ b/Sources/GoogleAI/ModelContent.swift @@ -188,4 +188,4 @@ extension ModelContent.Part: Codable { )) } } -} +} \ No newline at end of file diff --git a/Sources/GoogleAI/PartsRepresentable+Image.swift b/Sources/GoogleAI/PartsRepresentable+Image.swift index 052a004..9dd8f76 100644 --- a/Sources/GoogleAI/PartsRepresentable+Image.swift +++ b/Sources/GoogleAI/PartsRepresentable+Image.swift @@ -19,6 +19,11 @@ import UniformTypeIdentifiers import AppKit // For NSImage extensions. #endif +#if os(watchOS) + import ImageIO + import CoreGraphics +#endif + private let imageCompressionQuality: CGFloat = 0.8 /// An enum describing failures that can occur when converting image types to model content data. @@ -38,7 +43,7 @@ public enum ImageConversionError: Error { #if canImport(UIKit) /// Enables images to be representable as ``ThrowingPartsRepresentable``. - @available(iOS 15.0, macOS 11.0, macCatalyst 15.0, *) + @available(iOS 15.0, macOS 11.0, macCatalyst 15.0, watchOS 8.0, *) extension UIImage: ThrowingPartsRepresentable { public func tryPartsValue() throws -> [ModelContent.Part] { guard let data = jpegData(compressionQuality: imageCompressionQuality) else { @@ -50,7 +55,7 @@ public enum ImageConversionError: Error { #elseif canImport(AppKit) /// Enables images to be representable as ``ThrowingPartsRepresentable``. - @available(iOS 15.0, macOS 11.0, macCatalyst 15.0, *) + @available(iOS 15.0, macOS 11.0, macCatalyst 15.0, watchOS 8.0, *) extension NSImage: ThrowingPartsRepresentable { public func tryPartsValue() throws -> [ModelContent.Part] { guard let cgImage = cgImage(forProposedRect: nil, context: nil, hints: nil) else { @@ -67,7 +72,7 @@ public enum ImageConversionError: Error { #endif /// Enables `CGImages` to be representable as model content. -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, *) +@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, watchOS 9.0, *) extension CGImage: ThrowingPartsRepresentable { public func tryPartsValue() throws -> [ModelContent.Part] { let output = NSMutableData() @@ -88,6 +93,7 @@ extension CGImage: ThrowingPartsRepresentable { } /// Enables `CIImages` to be representable as model content. +#if !os(watchOS) @available(iOS 15.0, macOS 11.0, macCatalyst 15.0, *) extension CIImage: ThrowingPartsRepresentable { public func tryPartsValue() throws -> [ModelContent.Part] { @@ -105,3 +111,4 @@ extension CIImage: ThrowingPartsRepresentable { throw ImageConversionError.couldNotConvertToJPEG(self) } } +#endif diff --git a/Sources/GoogleAI/PartsRepresentable.swift b/Sources/GoogleAI/PartsRepresentable.swift index 05ba0d9..5251b47 100644 --- a/Sources/GoogleAI/PartsRepresentable.swift +++ b/Sources/GoogleAI/PartsRepresentable.swift @@ -63,4 +63,4 @@ extension String: PartsRepresentable { public var partsValue: [ModelContent.Part] { return [.text(self)] } -} +} \ No newline at end of file diff --git a/Sources/GoogleAI/Safety.swift b/Sources/GoogleAI/Safety.swift index d2adc4a..d8b5d7c 100644 --- a/Sources/GoogleAI/Safety.swift +++ b/Sources/GoogleAI/Safety.swift @@ -143,7 +143,7 @@ public struct SafetySetting { // MARK: - Codable Conformances -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, *) +@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, watchOS 7.0, *) extension SafetyRating.HarmProbability: Codable { public init(from decoder: Decoder) throws { let value = try decoder.singleValueContainer().decode(String.self) @@ -164,7 +164,7 @@ extension SafetyRating: Decodable {} @available(iOS 15.0, macOS 11.0, macCatalyst 15.0, *) extension SafetyFeedback: Decodable {} -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, *) +@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, watchOS 7.0, *) extension SafetySetting.HarmCategory: Codable { public init(from decoder: Decoder) throws { let value = try decoder.singleValueContainer().decode(String.self) @@ -179,7 +179,7 @@ extension SafetySetting.HarmCategory: Codable { } } -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, *) +@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, watchOS 7.0, *) extension SafetySetting.BlockThreshold: Codable { public init(from decoder: Decoder) throws { let value = try decoder.singleValueContainer().decode(String.self) @@ -195,4 +195,4 @@ extension SafetySetting.BlockThreshold: Codable { } @available(iOS 15.0, macOS 11.0, macCatalyst 15.0, *) -extension SafetySetting: Codable {} +extension SafetySetting: Codable {} \ No newline at end of file