VertexAIAPITests.swift 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  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 FirebaseCore
  15. import FirebaseVertexAI
  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 11.0, macCatalyst 15.0, tvOS 15.0, *)
  23. final class VertexAIAPITests: 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(role: "system", parts: [.text("Talk like a pirate.")])
  35. // Instantiate Vertex AI SDK - Default App
  36. let vertexAI = VertexAI.vertexAI()
  37. let _ = VertexAI.vertexAI(location: "my-location")
  38. // Instantiate Vertex AI SDK - Custom App
  39. let _ = VertexAI.vertexAI(app: app!)
  40. let _ = VertexAI.vertexAI(app: app!, location: "my-location")
  41. // Permutations without optional arguments.
  42. let _ = vertexAI.generativeModel(modelName: "gemini-1.0-pro")
  43. let _ = vertexAI.generativeModel(
  44. modelName: "gemini-1.0-pro",
  45. safetySettings: filters
  46. )
  47. let _ = vertexAI.generativeModel(
  48. modelName: "gemini-1.0-pro",
  49. generationConfig: config
  50. )
  51. let _ = vertexAI.generativeModel(
  52. modelName: "gemini-1.0-pro",
  53. systemInstruction: systemInstruction
  54. )
  55. // All arguments passed.
  56. let genAI = vertexAI.generativeModel(
  57. modelName: "gemini-1.0-pro",
  58. generationConfig: config, // Optional
  59. safetySettings: filters, // Optional
  60. systemInstruction: systemInstruction // Optional
  61. )
  62. // Full Typed Usage
  63. let pngData = Data() // ....
  64. let contents = [ModelContent(role: "user",
  65. parts: [
  66. .text("Is it a cat?"),
  67. .png(pngData),
  68. ])]
  69. do {
  70. let response = try await genAI.generateContent(contents)
  71. print(response.text ?? "Couldn't get text... check status")
  72. } catch {
  73. print("Error generating content: \(error)")
  74. }
  75. // Content input combinations.
  76. let _ = try await genAI.generateContent("Constant String")
  77. let str = "String Variable"
  78. let _ = try await genAI.generateContent(str)
  79. let _ = try await genAI.generateContent([str])
  80. let _ = try await genAI.generateContent(str, "abc", "def")
  81. let _ = try await genAI.generateContent(
  82. str,
  83. ModelContent.Part.fileData(mimetype: "image/jpeg", uri: "gs://test-bucket/image.jpg")
  84. )
  85. #if canImport(UIKit)
  86. _ = try await genAI.generateContent(UIImage())
  87. _ = try await genAI.generateContent([UIImage()])
  88. _ = try await genAI
  89. .generateContent([str, UIImage(), ModelContent.Part.text(str)])
  90. _ = try await genAI.generateContent(str, UIImage(), "def", UIImage())
  91. _ = try await genAI.generateContent([str, UIImage(), "def", UIImage()])
  92. _ = try await genAI.generateContent([ModelContent("def", UIImage()),
  93. ModelContent("def", UIImage())])
  94. #elseif canImport(AppKit)
  95. _ = try await genAI.generateContent(NSImage())
  96. _ = try await genAI.generateContent([NSImage()])
  97. _ = try await genAI.generateContent(str, NSImage(), "def", NSImage())
  98. _ = try await genAI.generateContent([str, NSImage(), "def", NSImage()])
  99. #endif
  100. // ThrowingPartsRepresentable combinations.
  101. let _ = ModelContent(parts: [.text(str)])
  102. let _ = ModelContent(role: "model", parts: [.text(str)])
  103. let _ = ModelContent(parts: "Constant String")
  104. let _ = ModelContent(parts: str)
  105. // Note: This requires the `try` for some reason. Casting to explicit [PartsRepresentable] also
  106. // doesn't work.
  107. let _ = try ModelContent(parts: [str])
  108. // Note: without `as [any ThrowingPartsRepresentable]` this will fail to compile with "Cannot
  109. // convert value of type 'String' to expected element type
  110. // 'Array<ModelContent.Part>.ArrayLiteralElement'. Not sure if there's a way we can get it to
  111. // work.
  112. let _ = try ModelContent(parts: [str, ModelContent.Part.data(
  113. mimetype: "foo",
  114. Data()
  115. )] as [any ThrowingPartsRepresentable])
  116. #if canImport(UIKit)
  117. _ = try ModelContent(role: "user", parts: UIImage())
  118. _ = try ModelContent(role: "user", parts: [UIImage()])
  119. // Note: without `as [any ThrowingPartsRepresentable]` this will fail to compile with "Cannot
  120. // convert
  121. // value of type `[Any]` to expected type `[any ThrowingPartsRepresentable]`. Not sure if
  122. // there's a
  123. // way we can get it to work.
  124. _ = try ModelContent(parts: [str, UIImage()] as [any ThrowingPartsRepresentable])
  125. // Alternatively, you can explicitly declare the type in a variable and pass it in.
  126. let representable2: [any ThrowingPartsRepresentable] = [str, UIImage()]
  127. _ = try ModelContent(parts: representable2)
  128. _ = try ModelContent(parts: [str, UIImage(),
  129. ModelContent.Part.text(str)] as [any ThrowingPartsRepresentable])
  130. #elseif canImport(AppKit)
  131. _ = try ModelContent(role: "user", parts: NSImage())
  132. _ = try ModelContent(role: "user", parts: [NSImage()])
  133. // Note: without `as [any ThrowingPartsRepresentable]` this will fail to compile with "Cannot
  134. // convert
  135. // value of type `[Any]` to expected type `[any ThrowingPartsRepresentable]`. Not sure if
  136. // there's a
  137. // way we can get it to work.
  138. _ = try ModelContent(parts: [str, NSImage()] as [any ThrowingPartsRepresentable])
  139. // Alternatively, you can explicitly declare the type in a variable and pass it in.
  140. let representable2: [any ThrowingPartsRepresentable] = [str, NSImage()]
  141. _ = try ModelContent(parts: representable2)
  142. _ =
  143. try ModelContent(parts: [str, NSImage(),
  144. ModelContent.Part.text(str)] as [any ThrowingPartsRepresentable])
  145. #endif
  146. // countTokens API
  147. let _: CountTokensResponse = try await genAI.countTokens("What color is the Sky?")
  148. #if canImport(UIKit)
  149. let _: CountTokensResponse = try await genAI.countTokens("What color is the Sky?",
  150. UIImage())
  151. let _: CountTokensResponse = try await genAI.countTokens([
  152. ModelContent("What color is the Sky?", UIImage()),
  153. ModelContent(UIImage(), "What color is the Sky?", UIImage()),
  154. ])
  155. #endif
  156. // Chat
  157. _ = genAI.startChat()
  158. _ = genAI.startChat(history: [ModelContent(parts: "abc")])
  159. }
  160. // Public API tests for GenerateContentResponse.
  161. func generateContentResponseAPI() {
  162. let response = GenerateContentResponse(candidates: [])
  163. let _: [CandidateResponse] = response.candidates
  164. let _: PromptFeedback? = response.promptFeedback
  165. // Usage Metadata
  166. guard let usageMetadata = response.usageMetadata else { fatalError() }
  167. let _: Int = usageMetadata.promptTokenCount
  168. let _: Int = usageMetadata.candidatesTokenCount
  169. let _: Int = usageMetadata.totalTokenCount
  170. // Computed Properties
  171. let _: String? = response.text
  172. let _: [FunctionCall] = response.functionCalls
  173. }
  174. // Result builder alternative
  175. /*
  176. let pngData = Data() // ....
  177. let contents = [GenAIContent(role: "user",
  178. parts: [
  179. .text("Is it a cat?"),
  180. .png(pngData)
  181. ])]
  182. // Turns into...
  183. let contents = GenAIContent {
  184. Role("user") {
  185. Text("Is this a cat?")
  186. Image(png: pngData)
  187. }
  188. }
  189. GenAIContent {
  190. ForEach(myInput) { input in
  191. Role(input.role) {
  192. input.contents
  193. }
  194. }
  195. }
  196. // Thoughts: this looks great from a code demo, but since I assume most content will be
  197. // user generated, the result builder may not be the best API.
  198. */
  199. }