Skip to content

Commit 70f3450

Browse files
author
aafent
committed
DeepSeek AI Provider Added
1 parent 30693d2 commit 70f3450

4 files changed

Lines changed: 226 additions & 4 deletions

File tree

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
rem
2+
AiPROVIDER manProvider, deepseek, *
3+
AiPROVIDER womanProvider, gemini,*
4+
AiSESSION man, manProvider, "Act as a 22-year-old man named Johnny.
5+
Your goal is to make the woman you are talking to start a social conversesion.
6+
For each prompt, you will generate only one reply to her."
7+
8+
AiSESSION woman, womanProvider, "Act as a 26-year-old woman named Anna.
9+
Your goal is to drive the man you are talking to a social conversesion.
10+
For each prompt, you will generate only one reply to him."
11+
12+
let times=0
13+
let manReponse="Hi what is your name?"
14+
15+
loop:
16+
let times=times+1
17+
18+
print "John: "+manReponse
19+
AiPROMPT woman, womanResponse, manReponse
20+
print "Anna: "+womanResponse
21+
22+
AiPROMPT man, manReponse, womanResponse
23+
print ""
24+
25+
if times < 5 then goto loop
26+
27+
halt
28+

FAST.FBasic.InteractiveConsole/Tests/aichat.bas

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
rem
22

3-
AiPROVIDER prov, test, *
3+
AiPROVIDER prov, deepseek, *
44
AiSESSION chat, prov, "You are an Oceanographer. Provide clear and concise responses, no more that 100 words."
55

66
AiPROMPT chat, resp, "What is the whale? reply with up to 20 words"
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
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+
}

FAST.FBasicInterpreter/Libraries/FBasicAIChat.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace FAST.FBasicInterpreter
66
AIChat:
77
Statements:
88
9-
AIPROVIDER provider_name, OPENAI|CLAUDE|GEMINI|HUGGINGFACE|TEST, *|model :: setup a AI provider and a model. Use * for the default model.
9+
AIPROVIDER provider_name, OPENAI|CLAUDE|GEMINI|HUGGINGFACE|DEEPSEEK|TEST, *|model :: setup a AI provider and a model. Use * for the default model.
1010
AISESSION session_name, provider_name, system_prompt :: initialize an AI session topic.
1111
AIPROMPT session_name, variable_response, prompt :: Send a prompt over a session and store the response at a variable
1212
AISETPROVIDER session_name, provider_name :: Change the initial provider
@@ -24,7 +24,7 @@ public void InstallAll(IInterpreter interpreter)
2424

2525
private static void AIPROVIDER(IInterpreter interpreter)
2626
{
27-
// Syntax: AIPROVIDER provider_name, OPENAI|CLAUDE|GEMINI|HUGGINGFACE|TEST, *|model
27+
// Syntax: AIPROVIDER provider_name, OPENAI|CLAUDE|GEMINI|HUGGINGFACE|DEEPSEEK|TEST, *|model
2828
//
2929
interpreter.Match(Token.Identifier);
3030
string name = interpreter.lex.Identifier;
@@ -75,8 +75,12 @@ private static void AIPROVIDER(IInterpreter interpreter)
7575
case "HUGGINGFACE":
7676
provider = string.IsNullOrEmpty(aiModel)?new HuggingFaceProvider(apiKey):new HuggingFaceProvider(apiKey, aiModel);
7777
break;
78+
case "DEEPSEEK":
79+
provider = string.IsNullOrEmpty(aiModel) ? new DeepSeekProvider(apiKey) : new DeepSeekProvider(apiKey, aiModel);
80+
break;
81+
7882
default:
79-
interpreter.Error("AIChat", Errors.E106_ExpectingKeyword(providerNameToUse, "Expected: CLAUDE,GEMINI or HUGGINGFACE") );
83+
interpreter.Error("AIChat", Errors.E106_ExpectingKeyword(providerNameToUse, "Expected: CLAUDE,GEMINI,OPENAI,DEEPSEEK,HUGGINGFACE or TEST") );
8084
return;
8185
}
8286

0 commit comments

Comments
 (0)