C#实现deepseek API调用软件开发(仅学过C语言版)
本文将详细介绍一个使用C# WinForms和DeepSeek API构建的聊天助手应用程序的实现原理和功能。这个程序实现了与AI的实时对话、思考过程可视化以及对话历史记录等功能。
本人纯外行,非常感兴趣业余时间玩一玩,欢迎各位大佬提各种建议及想法。
当前功能:
实现API调用并进行多轮对话及思考链输出,并在本地存储对话内容。
聊天框:展示对话过程及思考链。
输入框:输入想发送的内容
button1:发送输入框内容,并触发对话将返回内容呈现到聊天框
button2:清空对话内容并重启对话
下一步实现功能:
对于不同用户,不同需求进行对话,本地对话历史调用。
(仅展示最新版本,一步一步过来的苦就不多说了。全程靠deepseek输出代码实现软件功能,包括以下绝大部分内容,不要骂我)
DeepSeek API聊天助手实现教程
本文将详细介绍一个使用C# WinForms和DeepSeek API构建的聊天助手应用程序的实现原理和功能。这个程序实现了与AI的实时对话、思考过程可视化以及对话历史记录等功能。
功能概述
该应用程序主要实现以下功能:
-
用户输入消息并发送
-
实时显示AI的思考过程和最终回复
-
保存完整对话历史到CSV文件
-
清除对话历史
-
支持回车键发送消息
核心代码解析
1. 初始化与类成员
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private List<dynamic> conversationHistory = new List<dynamic>();
-
conversationHistory
:动态列表,用于存储完整的对话历史(用户消息和AI回复) -
构造函数初始化窗体组件
2. 发送消息与API交互
private async void button1_Click(object sender, EventArgs e)
{
string userMessage = textBox2.Text;
textBox1.AppendText($"用户: {userMessage}{Environment.NewLine}{Environment.NewLine}");
conversationHistory.Add(new
{
role = "user",
content = userMessage
});
功能:
-
获取用户输入的消息
-
在聊天框中显示用户消息
-
将用户消息添加到对话历史
var baseurl = "https://api.deepseek.com";
var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer your-api-key");
var requestDate = new
{
model = "deepseek-reasoner",
messages = conversationHistory.ToArray(),
max_tokens = 1000,
return_reasoning = true,
stream = true
};
(这里要说一下,"Bearer your-api-key"为deepseek上自己创建的API,需要自己申请。。。。。前面没搞懂代码的时候搜了半天)
功能:
-
设置DeepSeek API端点
-
创建HTTP客户端并添加授权头
-
构建请求参数:
-
指定AI模型
-
包含完整对话历史
-
限制最大token数
-
要求返回思考过程
-
启用流式响应
-
textBox1.AppendText($"DeepSeek 正在思考...{Environment.NewLine}");
int thinkingHeaderEnd = textBox1.TextLength;
string reasoningSeparator = $"----------";
textBox1.AppendText(reasoningSeparator + Environment.NewLine);
int reasoningStartPos = textBox1.TextLength;
int lastReasoningPos = reasoningStartPos;
功能:
-
在聊天框中显示"正在思考"提示
-
记录当前文本位置,用于后续插入思考过程
-
添加分隔线区分不同内容区域
var response = await client.PostAsync($"{baseurl}/v1/chat/completions", content);
var stream = await response.Content.ReadAsStreamAsync();
var reader = new StreamReader(stream);
bool isReasoningComplete = false;
string currentAnswer = "";
while (!reader.EndOfStream)
{
var line = await reader.ReadLineAsync();
// 处理流式响应...
}
功能:
-
发送API请求并获取流式响应
-
逐行处理API返回的数据
-
使用标志位区分思考过程和最终回复
this.Invoke((Action)(() =>
{
// 处理思考链
if (!string.IsNullOrEmpty(deltaReasoning))
{
textBox1.Select(lastReasoningPos, 0);
textBox1.SelectedText = deltaReasoning;
lastReasoningPos += deltaReasoning.Length;
}
// 切换到答案输出
if (!isReasoningComplete && string.IsNullOrEmpty(deltaReasoning))
{
isReasoningComplete = true;
textBox1.AppendText($"{Environment.NewLine}----------------------{Environment.NewLine}");
textBox1.AppendText("Deepseek:" + Environment.NewLine);
}
// 处理答案
if (!string.IsNullOrEmpty(deltaContent))
{
currentAnswer += deltaContent;
textBox1.AppendText(deltaContent);
textBox1.ScrollToCaret();
}
}));
功能:
-
思考过程处理:将AI的思考内容实时插入到指定位置
-
内容切换:当思考过程结束时添加分隔线并显示回复标题
-
答案处理:流式显示AI的最终回复
-
自动滚动到最新内容
private void SaveConversationToCsv()
{
string documentsPath = @"E:\deepseekcc1\deepseek0610";
string fileName = $"DeepSeek_Conversation_{DateTime.Now:yyyyMMdd}.csv";
string filePath = Path.Combine(documentsPath, fileName);
var csvContent = new StringBuilder();
if (!File.Exists(filePath))
{
csvContent.AppendLine("Timestamp,Role,Content");
}
foreach (var message in conversationHistory)
{
string role = message.role;
string content = message.content.Replace("\"", "\"\"");
string timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
csvContent.AppendLine($"\"{timestamp}\",\"{role}\",\"{content}\"");
}
File.AppendAllText(filePath, csvContent.ToString(), Encoding.UTF8);
}
(存储路径为第一条)
功能:
-
按日期生成CSV文件名
-
首次创建文件时添加标题行
-
转义特殊字符(如双引号)
-
添加时间戳、角色和内容三列
-
追加保存到文件
// 回车键发送
private void textBox2_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
e.SuppressKeyPress = true;
button1.PerformClick();
}
}
// 清除历史
private void button2_Click(object sender, EventArgs e)
{
conversationHistory.Clear();
textBox1.Text = "对话历史已清除" + Environment.NewLine + Environment.NewLine;
}
功能:
-
支持回车键发送消息(阻止默认提示音)
-
一键清除对话历史和聊天框内容
(哈哈哈deepseek给自己写的亮点)
技术亮点
-
流式响应处理:实时显示AI的思考过程和回复,提升用户体验
-
动态文本插入:精确定位插入点实现不同内容区域的区分显示
-
对话历史管理:完整记录并保存所有交互内容
-
异常处理:完善的错误处理机制确保程序稳定性
-
线程安全:使用Invoke确保跨线程UI操作安全
使用场景
这个聊天助手适用于:
-
教育学习:解答学习问题,展示解题思路
-
编程辅助:提供代码建议和解释
-
内容创作:帮助生成和优化文本内容
-
研究分析:展示思考过程增强可信度
-
个人助手:日常问答和信息查询
(附上代码)
private async void button1_Click(object sender, EventArgs e)
{
string userMessage = textBox2.Text;
textBox1.AppendText($"用户: {userMessage}{Environment.NewLine}{Environment.NewLine}");
conversationHistory.Add(new
{
role = "user",
content = userMessage
});
var baseurl = "https://api.deepseek.com";
var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer sk-ab----你创建的API--------");
var requestDate = new
{
model = "deepseek-reasoner",
//maxTokens:100,
messages = conversationHistory.ToArray(),
max_tokens = 1000, // 设置最大token数
return_reasoning = true,
stream = true
};
var jsonContent = JsonConvert.SerializeObject(requestDate);
var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
//初始化UI显示
textBox1.AppendText($"DeepSeek 正在思考...{Environment.NewLine}");
int thinkingHeaderEnd = textBox1.TextLength;
//添加明确的分隔标记(使用唯一标识符)
string reasoningSeparator = $"----------";
textBox1.AppendText(reasoningSeparator + Environment.NewLine);
int reasoningStartPos = textBox1.TextLength; // 精确记录思考链开始位置
int lastReasoningPos = reasoningStartPos;
try
{
var response = await client.PostAsync($"{baseurl}/v1/chat/completions", content);
var stream = await response.Content.ReadAsStreamAsync();
var reader = new StreamReader(stream);
bool isReasoningComplete = false; // 标记思考过程是否完成;
//string currentReasoning = ""; // 当前累积的思考内容
string currentAnswer = "";
StringBuilder reasoningBuilder = new StringBuilder();
StringBuilder answerBuilder = new StringBuilder();
while (!reader.EndOfStream)
{
var line = await reader.ReadLineAsync();
if (string.IsNullOrWhiteSpace(line) || !line.StartsWith("data:"))
continue;
var eventData = line.Substring("data:".Length).Trim();
if (eventData == "[DONE]") // Fix: Ensure the loop breaks only when "[DONE]" is encountered
break;
dynamic chunk = JsonConvert.DeserializeObject(eventData);
string deltaReasoning = chunk.choices[0]?.delta?.reasoning_content;
string deltaContent = chunk.choices[0]?.delta?.content;
this.Invoke((Action)(() =>
{
//处理思考链(追加模式)
if (!string.IsNullOrEmpty(deltaReasoning))
{
textBox1.Select(lastReasoningPos, 0);
textBox1.SelectedText = deltaReasoning;
lastReasoningPos += deltaReasoning.Length;
}
//切换到答案输出
if (!isReasoningComplete && string.IsNullOrEmpty(deltaReasoning))
{
isReasoningComplete = true;
textBox1.AppendText($"{Environment.NewLine}----------------------{Environment.NewLine}");
textBox1.AppendText("Deepseek:" + Environment.NewLine);
}
//处理答案(追加模式)
if (!string.IsNullOrEmpty(deltaContent))
{
currentAnswer += deltaContent;
textBox1.AppendText(deltaContent);
textBox1.ScrollToCaret();
}
}));
}
conversationHistory.Add(new
{
role = "assistant",
content = currentAnswer
});
}
catch (Exception ex)
{
this.Invoke((Action)(() =>
{
textBox1.AppendText($"{Environment.NewLine}错误: {ex.Message}{Environment.NewLine}");
}));
}
finally
{
this.Invoke((Action)(() =>
{
textBox2.Text = "";
textBox1.AppendText($"{Environment.NewLine}----------------------{Environment.NewLine}");
SaveConversationToCsv();
}));
}
}
有什么创意都可以提喔,嘻嘻。deepseek应该都能实现的。
下面两周有空的话应该会更新一版能够调用不同本地的历史记录。
后面还想扩展成能够导入图片、PPT和Word并进行分析的。
本人是做机器视觉的,后期发展会偏向图像识别、AOI检测相关,到时候可能就嵌入到其他二次开发的视觉系统上。(就是不知道能不能行)
更多推荐
所有评论(0)