@@ -23,25 +23,28 @@ import VertexAITestApp
23
23
24
24
@Suite ( . serialized)
25
25
struct GenerateContentIntegrationTests {
26
- static let vertexV1Config = APIConfig ( service: . vertexAI, version: . v1)
27
- static let vertexV1BetaConfig = APIConfig ( service: . vertexAI, version: . v1beta)
28
- static let developerV1BetaConfig = APIConfig (
29
- service: . developer( endpoint: . generativeLanguage) ,
30
- version: . v1beta
26
+ static let vertexV1Config =
27
+ InstanceConfig ( apiConfig: APIConfig ( service: . vertexAI, version: . v1) )
28
+ static let vertexV1BetaConfig =
29
+ InstanceConfig ( apiConfig: APIConfig ( service: . vertexAI, version: . v1beta) )
30
+ static let developerV1Config = InstanceConfig (
31
+ appName: FirebaseAppNames . spark,
32
+ apiConfig: APIConfig (
33
+ service: . developer( endpoint: . generativeLanguage) , version: . v1
34
+ )
35
+ )
36
+ static let developerV1BetaConfig = InstanceConfig (
37
+ appName: FirebaseAppNames . spark,
38
+ apiConfig: APIConfig (
39
+ service: . developer( endpoint: . generativeLanguage) , version: . v1beta
40
+ )
31
41
)
42
+ static let allConfigs =
43
+ [ vertexV1Config, vertexV1BetaConfig, developerV1Config, developerV1BetaConfig]
32
44
33
45
// Set temperature, topP and topK to lowest allowed values to make responses more deterministic.
34
- static let generationConfig = GenerationConfig (
35
- temperature: 0.0 ,
36
- topP: 0.0 ,
37
- topK: 1 ,
38
- responseMIMEType: " text/plain "
39
- )
40
- static let systemInstruction = ModelContent (
41
- role: " system " ,
42
- parts: " You are a friendly and helpful assistant. "
43
- )
44
- static let safetySettings = [
46
+ let generationConfig = GenerationConfig ( temperature: 0.0 , topP: 0.0 , topK: 1 )
47
+ let safetySettings = [
45
48
SafetySetting ( harmCategory: . harassment, threshold: . blockLowAndAbove) ,
46
49
SafetySetting ( harmCategory: . hateSpeech, threshold: . blockLowAndAbove) ,
47
50
SafetySetting ( harmCategory: . sexuallyExplicit, threshold: . blockLowAndAbove) ,
@@ -64,9 +67,13 @@ struct GenerateContentIntegrationTests {
64
67
storage = Storage . storage ( )
65
68
}
66
69
67
- @Test ( arguments: [ vertexV1Config, vertexV1BetaConfig, developerV1BetaConfig] )
68
- func generateContent( _ apiConfig: APIConfig ) async throws {
69
- let model = GenerateContentIntegrationTests . model ( apiConfig: apiConfig)
70
+ @Test ( arguments: allConfigs)
71
+ func generateContent( _ config: InstanceConfig ) async throws {
72
+ let model = VertexAI . componentInstance ( config) . generativeModel (
73
+ modelName: ModelNames . gemini2FlashLite,
74
+ generationConfig: generationConfig,
75
+ safetySettings: safetySettings
76
+ )
70
77
let prompt = " Where is Google headquarters located? Answer with the city name only. "
71
78
72
79
let response = try await model. generateContent ( prompt)
@@ -75,9 +82,9 @@ struct GenerateContentIntegrationTests {
75
82
#expect( text == " Mountain View " )
76
83
77
84
let usageMetadata = try #require( response. usageMetadata)
78
- #expect( usageMetadata. promptTokenCount == 21 )
85
+ #expect( usageMetadata. promptTokenCount == 13 )
79
86
#expect( usageMetadata. candidatesTokenCount. isEqual ( to: 3 , accuracy: tokenCountAccuracy) )
80
- #expect( usageMetadata. totalTokenCount. isEqual ( to: 24 , accuracy: tokenCountAccuracy) )
87
+ #expect( usageMetadata. totalTokenCount. isEqual ( to: 16 , accuracy: tokenCountAccuracy) )
81
88
#expect( usageMetadata. promptTokensDetails. count == 1 )
82
89
let promptTokensDetails = try #require( usageMetadata. promptTokensDetails. first)
83
90
#expect( promptTokensDetails. modality == . text)
@@ -88,31 +95,45 @@ struct GenerateContentIntegrationTests {
88
95
#expect( candidatesTokensDetails. tokenCount == usageMetadata. candidatesTokenCount)
89
96
}
90
97
91
- static func model( apiConfig: APIConfig ) -> GenerativeModel {
92
- return instance ( apiConfig: apiConfig) . generativeModel (
93
- modelName: " gemini-2.0-flash " ,
94
- generationConfig: generationConfig,
98
+ @Test (
99
+ " Generate an enum and provide a system instruction " ,
100
+ arguments: [
101
+ vertexV1Config,
102
+ vertexV1BetaConfig,
103
+ /* System instructions are not supported on the v1 Developer API. */
104
+ developerV1BetaConfig,
105
+ ]
106
+ )
107
+ func generateContentEnum( _ config: InstanceConfig ) async throws {
108
+ let model = VertexAI . componentInstance ( config) . generativeModel (
109
+ modelName: ModelNames . gemini2FlashLite,
110
+ generationConfig: GenerationConfig (
111
+ responseMIMEType: " text/x.enum " , // Not supported on the v1 Developer API
112
+ responseSchema: . enumeration( values: [ " Red " , " Green " , " Blue " ] )
113
+ ) ,
95
114
safetySettings: safetySettings,
96
- tools: [ ] ,
97
- toolConfig: . init( functionCallingConfig: . none( ) ) ,
98
- systemInstruction: systemInstruction
115
+ tools: [ ] , // Not supported on the v1 Developer API
116
+ toolConfig: . init( functionCallingConfig: . none( ) ) , // Not supported on the v1 Developer API
117
+ systemInstruction: ModelContent ( role : " system " , parts : " Always pick blue. " )
99
118
)
100
- }
119
+ let prompt = " What is your favourite colour? "
101
120
102
- // TODO(andrewheard): Move this helper to a file in the Utilities folder.
103
- static func instance( apiConfig: APIConfig ) -> VertexAI {
104
- switch apiConfig. service {
105
- case . vertexAI:
106
- return VertexAI . vertexAI ( app: nil , location: " us-central1 " , apiConfig: apiConfig)
107
- case . developer:
108
- return VertexAI . vertexAI ( app: nil , location: nil , apiConfig: apiConfig)
109
- }
110
- }
111
- }
121
+ let response = try await model. generateContent ( prompt)
122
+
123
+ let text = try #require( response. text) . trimmingCharacters ( in: . whitespacesAndNewlines)
124
+ #expect( text == " Blue " )
112
125
113
- // TODO(andrewheard): Move this extension to a file in the Utilities folder.
114
- extension Numeric where Self: Strideable , Self. Stride. Magnitude: Comparable {
115
- func isEqual( to other: Self , accuracy: Self . Stride ) -> Bool {
116
- return distance ( to: other) . magnitude < accuracy. magnitude
126
+ let usageMetadata = try #require( response. usageMetadata)
127
+ #expect( usageMetadata. promptTokenCount == 14 )
128
+ #expect( usageMetadata. candidatesTokenCount. isEqual ( to: 1 , accuracy: tokenCountAccuracy) )
129
+ #expect( usageMetadata. totalTokenCount. isEqual ( to: 15 , accuracy: tokenCountAccuracy) )
130
+ #expect( usageMetadata. promptTokensDetails. count == 1 )
131
+ let promptTokensDetails = try #require( usageMetadata. promptTokensDetails. first)
132
+ #expect( promptTokensDetails. modality == . text)
133
+ #expect( promptTokensDetails. tokenCount == usageMetadata. promptTokenCount)
134
+ #expect( usageMetadata. candidatesTokensDetails. count == 1 )
135
+ let candidatesTokensDetails = try #require( usageMetadata. candidatesTokensDetails. first)
136
+ #expect( candidatesTokensDetails. modality == . text)
137
+ #expect( candidatesTokensDetails. tokenCount == usageMetadata. candidatesTokenCount)
117
138
}
118
139
}
0 commit comments