6
6
using System . Threading . Tasks ;
7
7
#endif
8
8
using System . Runtime . CompilerServices ;
9
+ using System . Text ;
9
10
10
11
namespace Mscc . GenerativeAI
11
12
{
13
+ /// <summary>
14
+ /// This ChatSession object collects the messages sent and received, in its ChatSession.History attribute.
15
+ /// </summary>
12
16
public class ChatSession
13
17
{
14
18
private readonly GenerativeModel _model ;
15
19
private readonly GenerationConfig ? _generationConfig ;
16
20
private readonly List < SafetySetting > ? _safetySettings ;
17
21
private readonly List < Tool > ? _tools ;
22
+ private ContentResponse ? _lastSent ;
23
+ private ContentResponse ? _lastReceived ;
18
24
25
+ /// <summary>
26
+ /// The chat history.
27
+ /// </summary>
19
28
public List < ContentResponse > History { get ; set ; }
20
29
21
30
/// <summary>
22
- ///
31
+ /// Returns the last received ContentResponse
32
+ /// </summary>
33
+ public ContentResponse ? Last => _lastReceived ;
34
+
35
+ /// <summary>
36
+ /// Constructor to start a chat session with history.
23
37
/// </summary>
24
38
/// <param name="model"></param>
25
39
/// <param name="history"></param>
40
+ /// <param name="generationConfig">Optional. Configuration options for model generation and outputs.</param>
41
+ /// <param name="safetySettings">Optional. A list of unique SafetySetting instances for blocking unsafe content.</param>
42
+ /// <param name="tools">Optional. </param>
26
43
public ChatSession ( GenerativeModel model ,
27
44
List < ContentResponse > ? history = null ,
28
45
GenerationConfig ? generationConfig = null ,
@@ -37,38 +54,55 @@ public ChatSession(GenerativeModel model,
37
54
}
38
55
39
56
/// <summary>
40
- ///
57
+ /// Sends the conversation history with the added message and returns the model's response.
58
+ /// Appends the request and response to the conversation history.
41
59
/// </summary>
42
60
/// <param name="prompt"></param>
61
+ /// <param name="generationConfig">Optional. Overrides for the model's generation config.</param>
62
+ /// <param name="safetySettings">Optional. Overrides for the model's safety settings.</param>
43
63
/// <returns></returns>
44
- public async Task < GenerateContentResponse > SendMessage ( string prompt )
64
+ public async Task < GenerateContentResponse > SendMessage ( string prompt ,
65
+ GenerationConfig ? generationConfig = null ,
66
+ List < SafetySetting > ? safetySettings = null )
45
67
{
46
68
if ( prompt == null ) throw new ArgumentNullException ( nameof ( prompt ) ) ;
47
69
if ( string . IsNullOrEmpty ( prompt ) ) throw new ArgumentException ( prompt , nameof ( prompt ) ) ;
48
70
49
- History . Add ( new ContentResponse { Role = Role . User , Parts = new List < Part > { new Part { Text = prompt } } } ) ;
71
+ _lastSent = new ContentResponse
72
+ {
73
+ Role = Role . User , Parts = new List < Part > { new Part { Text = prompt } }
74
+ } ;
75
+ History . Add ( _lastSent ) ;
50
76
var request = new GenerateContentRequest
51
77
{
52
78
Contents = History . Select ( x =>
53
79
new Content { Role = x . Role , PartTypes = x . Parts }
54
80
) . ToList ( ) ,
55
- GenerationConfig = _generationConfig ,
56
- SafetySettings = _safetySettings ,
81
+ GenerationConfig = generationConfig ?? _generationConfig ,
82
+ SafetySettings = safetySettings ?? _safetySettings ,
57
83
Tools = _tools
58
84
} ;
59
85
60
86
var response = await _model . GenerateContent ( request ) ;
61
- History . Add ( new ContentResponse { Role = Role . Model , Parts = new List < Part > { new Part { Text = response . Text } } } ) ;
87
+ _lastReceived = new ContentResponse
88
+ {
89
+ Role = Role . Model , Parts = new List < Part > { new Part { Text = response . Text ?? string . Empty } }
90
+ } ;
91
+ History . Add ( _lastReceived ) ;
62
92
return response ;
63
93
}
64
94
65
95
/// <summary>
66
96
///
67
97
/// </summary>
68
98
/// <param name="content"></param>
99
+ /// <param name="generationConfig">Optional. Overrides for the model's generation config.</param>
100
+ /// <param name="safetySettings">Optional. Overrides for the model's safety settings.</param>
69
101
/// <param name="cancellationToken"></param>
70
102
/// <returns></returns>
71
- public async IAsyncEnumerable < GenerateContentResponse > SendMessageStream ( object content ,
103
+ public async IAsyncEnumerable < GenerateContentResponse > SendMessageStream ( object content ,
104
+ GenerationConfig ? generationConfig = null ,
105
+ List < SafetySetting > ? safetySettings = null ,
72
106
[ EnumeratorCancellation ] CancellationToken cancellationToken = default )
73
107
{
74
108
if ( content == null ) throw new ArgumentNullException ( nameof ( content ) ) ;
@@ -87,25 +121,60 @@ public async IAsyncEnumerable<GenerateContentResponse> SendMessageStream(object
87
121
parts = contentParts ;
88
122
}
89
123
90
- History . Add ( new ContentResponse { Role = role , Parts = parts } ) ;
124
+ _lastSent = new ContentResponse
125
+ {
126
+ Role = role , Parts = parts
127
+ } ;
128
+ History . Add ( _lastSent ) ;
91
129
var request = new GenerateContentRequest
92
130
{
93
131
Contents = History . Select ( x =>
94
132
new Content { Role = x . Role , PartTypes = x . Parts }
95
133
) . ToList ( ) ,
96
- GenerationConfig = _generationConfig ,
97
- SafetySettings = _safetySettings ,
134
+ GenerationConfig = generationConfig ?? _generationConfig ,
135
+ SafetySettings = safetySettings ?? _safetySettings ,
98
136
Tools = _tools
99
137
} ;
100
138
139
+ var fullText = new StringBuilder ( ) ;
101
140
var response = _model . GenerateContentStream ( request , cancellationToken ) ;
102
141
await foreach ( var item in response )
103
142
{
104
143
if ( cancellationToken . IsCancellationRequested )
105
144
yield break ;
106
- History . Add ( new ContentResponse { Role = Role . Model , Parts = item ? . Candidates ? [ 0 ] ? . Content ? . Parts } ) ;
145
+ fullText . Append ( item . Text ) ;
107
146
yield return item ;
108
147
}
148
+ _lastReceived = new ContentResponse
149
+ {
150
+ Role = Role . Model , Parts = new List < Part > { new Part { Text = fullText . ToString ( ) } }
151
+ } ;
152
+ History . Add ( _lastReceived ) ;
153
+ }
154
+
155
+ /// <summary>
156
+ /// Removes the last request/response pair from the chat history.
157
+ /// </summary>
158
+ /// <returns>Tuple with the last request/response pair.</returns>
159
+ public ( ContentResponse ? Sent , ContentResponse ? Received ) Rewind ( )
160
+ {
161
+ ( ContentResponse ? Sent , ContentResponse ? Received ) result ;
162
+ var position = History . Count - 2 ;
163
+
164
+ if ( _lastReceived is null )
165
+ {
166
+ var entries = History . GetRange ( position , 2 ) ;
167
+ result = ( entries . FirstOrDefault ( ) , entries . LastOrDefault ( ) ) ;
168
+ }
169
+ else
170
+ {
171
+ result = ( _lastSent , _lastReceived ) ;
172
+ _lastSent = null ;
173
+ _lastReceived = null ;
174
+ }
175
+
176
+ History . RemoveRange ( position , 2 ) ;
177
+ return result ;
109
178
}
110
179
}
111
180
}
0 commit comments