1+ using System . Text ;
2+ using System . Text . Json ;
3+ using System . Text . Json . Serialization ;
4+
5+ namespace FAST . AIProvider
6+ {
7+
8+ /// <summary>
9+ /// Deep Seek Provider
10+ /// Implementation of IAIProvider for Deep Seek models.
11+ /// </summary>
12+ public class DeepSeekProvider : IAIProvider , IAITraceableProvider
13+ {
14+ private const string BaseUrl = "https://api.deepseek.com/chat/completions" ;
15+ private const string DefaultModel = "deepseek-chat" ;
16+
17+ private readonly string _apiKey ;
18+ private readonly string _model ;
19+ private readonly HttpClient _httpClient ;
20+ private readonly List < Message > _messageHistory ;
21+ private string _systemPrompt ;
22+ private object _lastRawResponse ;
23+
24+ public bool IncludeSystemPrompt { get ; set ; } = true ;
25+
26+ public AITrace trace { get ; private set ; } = new ( ) ;
27+
28+ public DeepSeekProvider ( string apiKey , string model = DefaultModel )
29+ {
30+ if ( string . IsNullOrWhiteSpace ( apiKey ) )
31+ throw new ArgumentException ( "API key cannot be null or empty." , nameof ( apiKey ) ) ;
32+
33+ trace . model = model ;
34+ _apiKey = apiKey ;
35+ _model = string . IsNullOrWhiteSpace ( model ) ? DefaultModel : model ;
36+ _httpClient = new HttpClient ( ) ;
37+ _messageHistory = new List < Message > ( ) ;
38+ _systemPrompt = string . Empty ;
39+ }
40+
41+ public void SetSystemPrompt ( string systemPrompt )
42+ {
43+ _systemPrompt = systemPrompt ?? string . Empty ;
44+ }
45+
46+ public void ClearHistory ( )
47+ {
48+ _messageHistory . Clear ( ) ;
49+ }
50+
51+ public async Task < string > SendMessageAsync ( string message )
52+ {
53+ if ( string . IsNullOrWhiteSpace ( message ) )
54+ throw new ArgumentException ( "Message cannot be null or empty." , nameof ( message ) ) ;
55+
56+ // Add user message to history
57+ _messageHistory . Add ( new Message { Role = "user" , Content = message } ) ;
58+
59+ // Build messages array for API request
60+ var messages = new List < Message > ( ) ;
61+
62+ // Add system prompt if enabled and set
63+ if ( IncludeSystemPrompt && ! string . IsNullOrWhiteSpace ( _systemPrompt ) )
64+ {
65+ messages . Add ( new Message { Role = "system" , Content = _systemPrompt } ) ;
66+ }
67+
68+ // Add conversation history
69+ messages . AddRange ( _messageHistory ) ;
70+
71+ // Create request payload
72+ var requestPayload = new DeepSeekRequest
73+ {
74+ Model = _model ,
75+ Messages = messages ,
76+ Stream = false
77+ } ;
78+
79+ // Serialize request
80+ var jsonContent = JsonSerializer . Serialize ( requestPayload , new JsonSerializerOptions
81+ {
82+ PropertyNamingPolicy = JsonNamingPolicy . SnakeCaseLower ,
83+ DefaultIgnoreCondition = JsonIgnoreCondition . WhenWritingNull
84+ } ) ;
85+
86+ trace . request = jsonContent ;
87+
88+ var content = new StringContent ( jsonContent , Encoding . UTF8 , "application/json" ) ;
89+
90+ // Set authorization header
91+ var request = new HttpRequestMessage ( HttpMethod . Post , BaseUrl ) ;
92+ request . Headers . Add ( "Authorization" , $ "Bearer { _apiKey } ") ;
93+ request . Content = content ;
94+
95+ // Send request
96+ var response = await _httpClient . SendAsync ( request ) ;
97+ response . EnsureSuccessStatusCode ( ) ;
98+
99+ // Read and parse response
100+ var responseContent = await response . Content . ReadAsStringAsync ( ) ;
101+ trace . response = responseContent ;
102+
103+ var deepSeekResponse = JsonSerializer . Deserialize < DeepSeekResponse > ( responseContent , new JsonSerializerOptions
104+ {
105+ PropertyNamingPolicy = JsonNamingPolicy . SnakeCaseLower
106+ } ) ;
107+
108+ // Store raw response
109+ _lastRawResponse = deepSeekResponse ;
110+
111+ // Extract assistant message
112+ var assistantMessage = deepSeekResponse ? . Choices ? [ 0 ] ? . Message ? . Content ?? string . Empty ;
113+
114+ // Add assistant response to history
115+ _messageHistory . Add ( new Message { Role = "assistant" , Content = assistantMessage } ) ;
116+
117+ return assistantMessage ;
118+ }
119+
120+ #region Private Classes for JSON Serialization
121+
122+ private class Message
123+ {
124+ [ JsonPropertyName ( "role" ) ]
125+ public string Role { get ; set ; }
126+
127+ [ JsonPropertyName ( "content" ) ]
128+ public string Content { get ; set ; }
129+ }
130+
131+ private class DeepSeekRequest
132+ {
133+ [ JsonPropertyName ( "model" ) ]
134+ public string Model { get ; set ; }
135+
136+ [ JsonPropertyName ( "messages" ) ]
137+ public List < Message > Messages { get ; set ; }
138+
139+ [ JsonPropertyName ( "stream" ) ]
140+ public bool Stream { get ; set ; }
141+ }
142+
143+ private class DeepSeekResponse
144+ {
145+ [ JsonPropertyName ( "id" ) ]
146+ public string Id { get ; set ; }
147+
148+ [ JsonPropertyName ( "object" ) ]
149+ public string Object { get ; set ; }
150+
151+ [ JsonPropertyName ( "created" ) ]
152+ public long Created { get ; set ; }
153+
154+ [ JsonPropertyName ( "model" ) ]
155+ public string Model { get ; set ; }
156+
157+ [ JsonPropertyName ( "choices" ) ]
158+ public List < Choice > Choices { get ; set ; }
159+
160+ [ JsonPropertyName ( "usage" ) ]
161+ public Usage Usage { get ; set ; }
162+ }
163+
164+ private class Choice
165+ {
166+ [ JsonPropertyName ( "index" ) ]
167+ public int Index { get ; set ; }
168+
169+ [ JsonPropertyName ( "message" ) ]
170+ public Message Message { get ; set ; }
171+
172+ [ JsonPropertyName ( "finish_reason" ) ]
173+ public string FinishReason { get ; set ; }
174+ }
175+
176+ private class Usage
177+ {
178+ [ JsonPropertyName ( "prompt_tokens" ) ]
179+ public int PromptTokens { get ; set ; }
180+
181+ [ JsonPropertyName ( "completion_tokens" ) ]
182+ public int CompletionTokens { get ; set ; }
183+
184+ [ JsonPropertyName ( "total_tokens" ) ]
185+ public int TotalTokens { get ; set ; }
186+ }
187+
188+ #endregion
189+ }
190+ }
0 commit comments