9
9
using System . Threading ;
10
10
using System . Threading . Tasks ;
11
11
#endif
12
+ using System . Diagnostics ;
12
13
using System . Net ;
13
14
using System . Net . Http . Headers ;
14
15
using System . Runtime . CompilerServices ;
@@ -29,11 +30,12 @@ public class GenerativeModel
29
30
private readonly bool _useHeaderApiKey ;
30
31
private readonly bool _useHeaderProjectId ;
31
32
private readonly string _model ;
32
- private readonly string _apiKey ;
33
- private readonly string _projectId ;
34
- private readonly string _region ;
33
+ private readonly string ? _apiKey ;
34
+ private readonly string ? _projectId ;
35
+ private readonly string ? _region ;
35
36
private readonly string _publisher = "google" ;
36
37
private readonly JsonSerializerOptions _options ;
38
+ private string ? _accessToken ;
37
39
private List < SafetySetting > ? _safetySettings ;
38
40
private GenerationConfig ? _generationConfig ;
39
41
private List < Tool > ? _tools ;
@@ -109,16 +111,20 @@ private string Method
109
111
}
110
112
}
111
113
112
- // Todo: Remove after ADC has been added.
113
- private string _accessToken ;
114
+ /// <summary>
115
+ /// Returns the name of the model.
116
+ /// </summary>
117
+ /// <returns>Name of the model.</returns>
118
+ public string Name => _model ;
114
119
115
- public string AccessToken
120
+ public string ? AccessToken
116
121
{
117
122
get => _accessToken ;
118
123
set
119
124
{
120
125
_accessToken = value ;
121
- Client . DefaultRequestHeaders . Authorization = new AuthenticationHeaderValue ( "Bearer" , _accessToken ) ;
126
+ if ( value != null )
127
+ Client . DefaultRequestHeaders . Authorization = new AuthenticationHeaderValue ( "Bearer" , _accessToken ) ;
122
128
}
123
129
}
124
130
@@ -128,10 +134,28 @@ public string AccessToken
128
134
public GenerativeModel ( )
129
135
{
130
136
_options = DefaultJsonSerializerOptions ( ) ;
131
- // GOOGLE_APPLICATION_CREDENTIALS
132
- // Linux, macOS: $HOME /.config / gcloud / application_default_credentials.json
133
- // Windows: % APPDATA %\gcloud\application_default_credentials.json
134
- //var credentials = GoogleCredential.FromFile(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "gcloud", "application_default_credentials.json"))
137
+ _model = Environment . GetEnvironmentVariable ( "GOOGLE_AI_MODEL" ) ??
138
+ Model . Gemini10Pro ;
139
+ _apiKey = Environment . GetEnvironmentVariable ( "GOOGLE_API_KEY" ) ;
140
+ _projectId = Environment . GetEnvironmentVariable ( "GOOGLE_PROJECT_ID" ) ;
141
+ _region = Environment . GetEnvironmentVariable ( "GOOGLE_REGION" ) ;
142
+ AccessToken = Environment . GetEnvironmentVariable ( "GOOGLE_ACCESS_TOKEN" ) ??
143
+ GetAccessTokenFromAdc ( ) ;
144
+
145
+ var credentialsFile =
146
+ Environment . GetEnvironmentVariable ( "GOOGLE_APPLICATION_CREDENTIALS" ) ??
147
+ Environment . GetEnvironmentVariable ( "GOOGLE_WEB_CREDENTIALS" ) ??
148
+ Path . Combine ( Environment . GetFolderPath ( Environment . SpecialFolder . ApplicationData ) , "gcloud" ,
149
+ "application_default_credentials.json" ) ;
150
+ if ( File . Exists ( credentialsFile ) )
151
+ {
152
+ using ( var stream = new FileStream ( credentialsFile , FileMode . Open , FileAccess . Read ) )
153
+ {
154
+ var json = JsonSerializer . DeserializeAsync < JsonElement > ( stream , _options ) . Result ;
155
+ _projectId ??= json . GetValue ( "quota_project_id" ) ??
156
+ json . GetValue ( "project_id" ) ;
157
+ }
158
+ } //var credentials = GoogleCredential.FromFile()
135
159
}
136
160
137
161
// Todo: Add parameters for GenerationConfig, SafetySettings, Transport? and Tools
@@ -142,15 +166,15 @@ public GenerativeModel()
142
166
/// <param name="model">Model to use (default: "gemini-pro")</param>
143
167
/// <param name="generationConfig"></param>
144
168
/// <param name="safetySettings"></param>
145
- public GenerativeModel ( string apiKey = "" ,
146
- string model = Model . GeminiPro ,
169
+ public GenerativeModel ( string ? apiKey = null ,
170
+ string ? model = null ,
147
171
GenerationConfig ? generationConfig = null ,
148
172
List < SafetySetting > ? safetySettings = null ) : this ( )
149
173
{
150
- _apiKey = apiKey ;
151
- _model = model . Sanitize ( ) ;
152
- _generationConfig = generationConfig ;
153
- _safetySettings = safetySettings ;
174
+ _apiKey = apiKey ?? _apiKey ;
175
+ _model = model . SanitizeModelName ( ) ?? _model ;
176
+ _generationConfig ?? = generationConfig ;
177
+ _safetySettings ?? = safetySettings ;
154
178
155
179
if ( ! string . IsNullOrEmpty ( apiKey ) )
156
180
{
@@ -179,7 +203,7 @@ internal GenerativeModel(string projectId, string region,
179
203
_useVertexAi = true ;
180
204
_projectId = projectId ;
181
205
_region = region ;
182
- _model = model . Sanitize ( ) ;
206
+ _model = model . SanitizeModelName ( ) ;
183
207
_generationConfig = generationConfig ;
184
208
_safetySettings = safetySettings ;
185
209
@@ -521,15 +545,6 @@ public async Task<CountTokensResponse> CountTokens(List<IPart>? parts)
521
545
return await CountTokens ( request ) ;
522
546
}
523
547
524
- /// <summary>
525
- /// Returns the name of the model.
526
- /// </summary>
527
- /// <returns>Name of the model.</returns>
528
- public string Name ( )
529
- {
530
- return _model ;
531
- }
532
-
533
548
// Todo: Implementation missing
534
549
/// <summary>
535
550
/// Starts a chat session.
@@ -627,5 +642,79 @@ internal JsonSerializerOptions DefaultJsonSerializerOptions()
627
642
628
643
return options ;
629
644
}
645
+
646
+ private string GetAccessTokenFromAdc ( )
647
+ {
648
+ if ( System . Runtime . InteropServices . RuntimeInformation . IsOSPlatform ( System . Runtime . InteropServices . OSPlatform . Windows ) )
649
+ {
650
+ return RunExternalExe ( "cmd.exe" , "/c gcloud auth application-default print-access-token" ) . TrimEnd ( ) ;
651
+ }
652
+ else
653
+ {
654
+ return RunExternalExe ( "gcloud" , "auth application-default print-access-token" ) . TrimEnd ( ) ;
655
+ }
656
+ }
657
+
658
+ private string RunExternalExe ( string filename , string arguments = null )
659
+ {
660
+ var process = new Process ( ) ;
661
+
662
+ process . StartInfo . FileName = filename ;
663
+ if ( ! string . IsNullOrEmpty ( arguments ) )
664
+ {
665
+ process . StartInfo . Arguments = arguments ;
666
+ }
667
+
668
+ process . StartInfo . CreateNoWindow = true ;
669
+ process . StartInfo . WindowStyle = ProcessWindowStyle . Hidden ;
670
+ process . StartInfo . UseShellExecute = false ;
671
+
672
+ process . StartInfo . RedirectStandardError = true ;
673
+ process . StartInfo . RedirectStandardOutput = true ;
674
+ var stdOutput = new StringBuilder ( ) ;
675
+ process . OutputDataReceived += ( sender , args ) => stdOutput . AppendLine ( args . Data ) ; // Use AppendLine rather than Append since args.Data is one line of output, not including the newline character.
676
+
677
+ string stdError = null ;
678
+ try
679
+ {
680
+ process . Start ( ) ;
681
+ process . BeginOutputReadLine ( ) ;
682
+ stdError = process . StandardError . ReadToEnd ( ) ;
683
+ process . WaitForExit ( ) ;
684
+ }
685
+ catch ( Exception e )
686
+ {
687
+ throw new Exception ( "OS error while executing " + Format ( filename , arguments ) + ": " + e . Message , e ) ;
688
+ }
689
+
690
+ if ( process . ExitCode == 0 )
691
+ {
692
+ return stdOutput . ToString ( ) ;
693
+ }
694
+ else
695
+ {
696
+ var message = new StringBuilder ( ) ;
697
+
698
+ if ( ! string . IsNullOrEmpty ( stdError ) )
699
+ {
700
+ message . AppendLine ( stdError ) ;
701
+ }
702
+
703
+ if ( stdOutput . Length != 0 )
704
+ {
705
+ message . AppendLine ( "Std output:" ) ;
706
+ message . AppendLine ( stdOutput . ToString ( ) ) ;
707
+ }
708
+
709
+ throw new Exception ( Format ( filename , arguments ) + " finished with exit code = " + process . ExitCode + ": " + message ) ;
710
+ }
711
+ }
712
+
713
+ private string Format ( string filename , string arguments )
714
+ {
715
+ return "'" + filename +
716
+ ( ( string . IsNullOrEmpty ( arguments ) ) ? string . Empty : " " + arguments ) +
717
+ "'" ;
718
+ }
630
719
}
631
720
}
0 commit comments