APITests.swift 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. // Copyright 2023 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. import FirebaseAI
  15. import FirebaseCore
  16. import XCTest
  17. #if canImport(AppKit)
  18. import AppKit // For NSImage extensions.
  19. #elseif canImport(UIKit)
  20. import UIKit // For UIImage extensions.
  21. #endif
  22. @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *)
  23. final class APITests: XCTestCase {
  24. func codeSamples() async throws {
  25. let app = FirebaseApp.app()
  26. let config = GenerationConfig(temperature: 0.2,
  27. topP: 0.1,
  28. topK: 16,
  29. candidateCount: 4,
  30. maxOutputTokens: 256,
  31. stopSequences: ["..."],
  32. responseMIMEType: "text/plain")
  33. let filters = [SafetySetting(harmCategory: .dangerousContent, threshold: .blockOnlyHigh)]
  34. let systemInstruction = ModelContent(
  35. role: "system",
  36. parts: TextPart("Talk like a pirate.")
  37. )
  38. let requestOptions = RequestOptions()
  39. let _ = RequestOptions(timeout: 30.0)
  40. // Instantiate Vertex AI SDK - Default App
  41. let vertexAI = FirebaseAI.vertexAI()
  42. let _ = FirebaseAI.vertexAI(location: "my-location")
  43. // Instantiate Vertex AI SDK - Custom App
  44. let _ = FirebaseAI.vertexAI(app: app!)
  45. let _ = FirebaseAI.vertexAI(app: app!, location: "my-location")
  46. // Permutations without optional arguments.
  47. let _ = vertexAI.generativeModel(modelName: "gemini-1.0-pro")
  48. let _ = vertexAI.generativeModel(
  49. modelName: "gemini-1.0-pro",
  50. safetySettings: filters
  51. )
  52. let _ = vertexAI.generativeModel(
  53. modelName: "gemini-1.0-pro",
  54. generationConfig: config
  55. )
  56. let _ = vertexAI.generativeModel(
  57. modelName: "gemini-1.0-pro",
  58. systemInstruction: systemInstruction
  59. )
  60. // All arguments passed.
  61. let genAI = vertexAI.generativeModel(
  62. modelName: "gemini-1.0-pro",
  63. generationConfig: config, // Optional
  64. safetySettings: filters, // Optional
  65. systemInstruction: systemInstruction, // Optional
  66. requestOptions: requestOptions // Optional
  67. )
  68. // Full Typed Usage
  69. let pngData = Data() // ....
  70. let contents = [ModelContent(
  71. role: "user",
  72. parts: [
  73. TextPart("Is it a cat?"),
  74. InlineDataPart(data: pngData, mimeType: "image/png"),
  75. ]
  76. )]
  77. do {
  78. let response = try await genAI.generateContent(contents)
  79. print(response.text ?? "Couldn't get text... check status")
  80. } catch {
  81. print("Error generating content: \(error)")
  82. }
  83. // Content input combinations.
  84. let _ = try await genAI.generateContent("Constant String")
  85. let str = "String Variable"
  86. let _ = try await genAI.generateContent(str)
  87. let _ = try await genAI.generateContent([str])
  88. let _ = try await genAI.generateContent(str, "abc", "def")
  89. let _ = try await genAI.generateContent(
  90. str,
  91. FileDataPart(uri: "gs://test-bucket/image.jpg", mimeType: "image/jpeg")
  92. )
  93. #if canImport(UIKit)
  94. _ = try await genAI.generateContent(UIImage())
  95. _ = try await genAI.generateContent([UIImage()])
  96. _ = try await genAI.generateContent([str, UIImage(), TextPart(str)])
  97. _ = try await genAI.generateContent(str, UIImage(), "def", UIImage())
  98. _ = try await genAI.generateContent([str, UIImage(), "def", UIImage()])
  99. _ = try await genAI.generateContent([ModelContent(parts: "def", UIImage()),
  100. ModelContent(parts: "def", UIImage())])
  101. #elseif canImport(AppKit)
  102. _ = try await genAI.generateContent(NSImage())
  103. _ = try await genAI.generateContent([NSImage()])
  104. _ = try await genAI.generateContent(str, NSImage(), "def", NSImage())
  105. _ = try await genAI.generateContent([str, NSImage(), "def", NSImage()])
  106. #endif
  107. // PartsRepresentable combinations.
  108. let _ = ModelContent(parts: [TextPart(str)])
  109. let _ = ModelContent(role: "model", parts: [TextPart(str)])
  110. let _ = ModelContent(parts: "Constant String")
  111. let _ = ModelContent(parts: str)
  112. let _ = ModelContent(parts: [str])
  113. let _ = ModelContent(parts: [str, InlineDataPart(data: Data(), mimeType: "foo")])
  114. #if canImport(UIKit)
  115. _ = ModelContent(role: "user", parts: UIImage())
  116. _ = ModelContent(role: "user", parts: [UIImage()])
  117. _ = ModelContent(parts: [str, UIImage()])
  118. // Note: without explicitly specifying`: [any PartsRepresentable]` this will fail to compile
  119. // below with "Cannot convert value of type `[Any]` to expected type `[any Part]`.
  120. let representable2: [any PartsRepresentable] = [str, UIImage()]
  121. _ = ModelContent(parts: representable2)
  122. _ = ModelContent(parts: [str, UIImage(), TextPart(str)])
  123. #elseif canImport(AppKit)
  124. _ = ModelContent(role: "user", parts: NSImage())
  125. _ = ModelContent(role: "user", parts: [NSImage()])
  126. _ = ModelContent(parts: [str, NSImage()])
  127. // Note: without explicitly specifying`: [any PartsRepresentable]` this will fail to compile
  128. // below with "Cannot convert value of type `[Any]` to expected type `[any Part]`.
  129. let representable2: [any PartsRepresentable] = [str, NSImage()]
  130. _ = ModelContent(parts: representable2)
  131. _ = ModelContent(parts: [str, NSImage(), TextPart(str)])
  132. #endif
  133. // countTokens API
  134. let _: CountTokensResponse = try await genAI.countTokens("What color is the Sky?")
  135. #if canImport(UIKit)
  136. let _: CountTokensResponse = try await genAI.countTokens("What color is the Sky?",
  137. UIImage())
  138. let _: CountTokensResponse = try await genAI.countTokens([
  139. ModelContent(parts: "What color is the Sky?", UIImage()),
  140. ModelContent(parts: UIImage(), "What color is the Sky?", UIImage()),
  141. ])
  142. #endif
  143. // Chat
  144. _ = genAI.startChat()
  145. _ = genAI.startChat(history: [ModelContent(parts: "abc")])
  146. }
  147. // Public API tests for GenerateContentResponse.
  148. func generateContentResponseAPI() {
  149. let response = GenerateContentResponse(candidates: [])
  150. let _: [Candidate] = response.candidates
  151. let _: PromptFeedback? = response.promptFeedback
  152. // Usage Metadata
  153. guard let usageMetadata = response.usageMetadata else { fatalError() }
  154. let _: Int = usageMetadata.promptTokenCount
  155. let _: Int = usageMetadata.candidatesTokenCount
  156. let _: Int = usageMetadata.totalTokenCount
  157. // Computed Properties
  158. let _: String? = response.text
  159. let _: [FunctionCallPart] = response.functionCalls
  160. }
  161. // Result builder alternative
  162. /*
  163. let pngData = Data() // ....
  164. let contents = [GenAIContent(role: "user",
  165. parts: [
  166. .text("Is it a cat?"),
  167. .png(pngData)
  168. ])]
  169. // Turns into...
  170. let contents = GenAIContent {
  171. Role("user") {
  172. Text("Is this a cat?")
  173. Image(png: pngData)
  174. }
  175. }
  176. GenAIContent {
  177. ForEach(myInput) { input in
  178. Role(input.role) {
  179. input.contents
  180. }
  181. }
  182. }
  183. // Thoughts: this looks great from a code demo, but since I assume most content will be
  184. // user generated, the result builder may not be the best API.
  185. */
  186. }