海口免费网站建站模板软文有哪些
又双叒叕很久不写博客,今天吐一口老曹。
一、为啥干这个
之前在修改OJ的时候,本着少修改多收益的原则,用Python写了一些DeepSeek的调用,真的很简单,用拉下来OpenAI按照官方文档复制粘贴就可以。接口文档页面(首次调用 API | DeepSeek API Docs)上至今有三种:curl(哦天哪,我在捣鼓ubuntu的时候好像用这个)、python(这个看着脸熟……当时敲的就是,那没事了)、node.js(dot是后加的,不然还真不认识)。
但是,随着需求越搞越多,顺手就祭起冷门编程语言VB.NET了。完成了各种远程多Judge服务器之后,发现".py"越看越不顺眼。于是乎,来吧NuGet一下……emmmmm……两下、三四五六下,He,Tui~~~
然后,再次祭起冷门语言VB.NET。因为之前就是多线程在搞一些队列呀、JudgeAPI呀,所以这个线程突然就顺手了。众所周知,我也不知道到底OpenAI支持多少参数,咱也搜不到,咱也不敢搜。所以,就比着能找到的就行了。并且,为了凑字数,成员定义的非常啰嗦:
Imports System
Imports System.Net.Http
Imports System.Text
Imports System.Threading.Tasks
Imports System.Text.Json
Imports System.Text.Json.Serialization
Imports System.Net
Imports System.ThreadingPublic Class DeepSeekClientPrivate ReadOnly _sharedHttpClient As HttpClientPrivate ReadOnly _apiKey As StringPrivate ReadOnly _apiBaseUrl As StringPrivate _model As String = "deepseek-chat"Private _temperature As Single = 0.1Private _maxTokens As Integer = 2048Private _top_p As Single = 0.2Private _stream As Boolean = False''' <summary>''' 初始化 DeepSeek 客户端(使用共享 HttpClient)''' </summary>''' <param name="sharedHttpClient">共享的 HttpClient 实例</param>''' <param name="apiKey">API 密钥</param>''' <param name="apiBaseUrl">API 基础地址 (可选,默认为官方地址)</param>Public Sub New(sharedHttpClient As HttpClient, apiKey As String, Optional apiBaseUrl As String = "https://api.deepseek.com/")If sharedHttpClient Is Nothing ThenThrow New ArgumentNullException(NameOf(sharedHttpClient))End IfIf String.IsNullOrWhiteSpace(apiKey) ThenThrow New ArgumentException("APIKey不能为空。", NameOf(apiKey))End If_sharedHttpClient = sharedHttpClient_apiKey = apiKey_apiBaseUrl = apiBaseUrl.TrimEnd("/"c)' 如果 HttpClient 还没有 Authorization 头,则添加If Not _sharedHttpClient.DefaultRequestHeaders.Contains("Authorization") Then_sharedHttpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {_apiKey}")End IfEnd Sub''' <summary>''' 设置模型名称''' </summary>Public Property Model As StringGetReturn _modelEnd GetSet(value As String)If String.IsNullOrWhiteSpace(value) ThenThrow New ArgumentException("模型名称不能为空。")End If_model = valueEnd SetEnd Property''' <summary>''' 设置温度参数 (0-2)''' </summary>Public Property Temperature As SingleGetReturn _temperatureEnd GetSet(value As Single)If value < 0 OrElse value > 2 ThenThrow New ArgumentOutOfRangeException(NameOf(Temperature), "温度值应在[0,2]区间")End If_temperature = valueEnd SetEnd Property''' <summary>''' 设置最大令牌数''' </summary>Public Property MaxTokens As IntegerGetReturn _maxTokensEnd GetSet(value As Integer)If value <= 0 ThenThrow New ArgumentOutOfRangeException(NameOf(MaxTokens), "最大Token数不应小于0。")End If_maxTokens = valueEnd SetEnd Property''' <summary>''' 生成多样性控制''' </summary>Public Property Top_p As SingleGetReturn _top_pEnd GetSet(value As Single)If value < 0 OrElse value > 1 ThenThrow New ArgumentOutOfRangeException(NameOf(Temperature), "Top_p应在[0,1]区间。")End If_top_p = valueEnd SetEnd Property''' <summary>''' 是否流式响应''' </summary>Public Property Stream As BooleanGetReturn _streamEnd GetSet(value As Boolean)_stream = valueEnd SetEnd Property''' <summary>''' 发送消息到 DeepSeek API 并获取响应''' </summary>''' <param name="userMessage">用户消息内容</param>''' <returns>API 响应内容</returns>Public Async Function SendMessageAsync(systemMessage As String, userMessage As String, timeout As TimeSpan) As Task(Of String)If String.IsNullOrWhiteSpace(systemMessage) ThenThrow New ArgumentException("系统消息不能为空。", NameOf(systemMessage))End IfIf String.IsNullOrWhiteSpace(userMessage) ThenThrow New ArgumentException("用户消息不能为空。", NameOf(userMessage))End IfIf timeout = Nothing ThenThrow New ArgumentException("超时时间不能为空。", NameOf(timeout))End If' 创建请求体对象Dim requestBody = New DeepSeekRequest With {.Model = _model,.Messages = New List(Of ChatMessage) From {New ChatMessage With {.Role = "system", .Content = systemMessage},New ChatMessage With {.Role = "user", .Content = userMessage}},.Temperature = _temperature,.MaxTokens = _maxTokens,.Top_p = Top_p,.Stream = False}' 使用 System.Text.Json 序列化Dim jsonContent = JsonSerializer.Serialize(requestBody)Dim content = New StringContent(jsonContent, Encoding.UTF8, "application/json")Try' 创建带有超时设置的请求Dim request = New HttpRequestMessage(HttpMethod.Post, $"{_apiBaseUrl}/chat/completions") With {.Content = content}' 使用 CancellationTokenSource 实现单次请求超时Using cts = New CancellationTokenSource(timeout)Dim response = Await _sharedHttpClient.SendAsync(request, cts.Token)Dim responseContent = Await response.Content.ReadAsStringAsync()If Not response.IsSuccessStatusCode ThenHandleApiError(response.StatusCode, responseContent)End If' 使用 System.Text.Json 反序列化Dim responseObject = JsonSerializer.Deserialize(Of DeepSeekResponse)(responseContent)Return responseObject?.Choices?.FirstOrDefault()?.Message?.ContentEnd UsingCatch ex As TaskCanceledException When Not ex.CancellationToken.IsCancellationRequestedThrow New TimeoutException("请求超时。", ex)Catch ex As OperationCanceledExceptionThrow New TimeoutException("由于超时,请求被取消。", ex)Catch ex As HttpRequestExceptionThrow New Exception("发送请求时出错。", ex)End TryEnd Function''' <summary>''' 处理 API 错误响应''' </summary>Private Sub HandleApiError(statusCode As HttpStatusCode, responseContent As String)Dim errorMessage As String = "发生未知错误"TryIf Not String.IsNullOrEmpty(responseContent) ThenDim errorResponse = JsonSerializer.Deserialize(Of DeepSeekErrorResponse)(responseContent)errorMessage = If(errorResponse?.Error?.Message, errorMessage)End IfCatch' 如果 JSON 解析失败,使用默认错误消息End TrySelect Case statusCodeCase HttpStatusCode.BadRequest ' 400Throw New DeepSeekApiException("错误请求:" & errorMessage, statusCode)Case HttpStatusCode.Unauthorized ' 401Throw New DeepSeekApiException("身份验证失败。请检查您的API密钥。", statusCode)Case HttpStatusCode.PaymentRequired ' 402Throw New DeepSeekApiException("余额不足。请给您的帐户充值。", statusCode)Case CType(422, HttpStatusCode) ' 422Throw New DeepSeekApiException("参数错误。" & errorMessage, statusCode)Case CType(429, HttpStatusCode) ' 429Throw New DeepSeekApiException("超出速率限制。请降低您的请求频率。", statusCode)Case HttpStatusCode.InternalServerError ' 500Throw New DeepSeekApiException("服务器错误。请稍后再试。", statusCode)Case HttpStatusCode.ServiceUnavailable ' 503Throw New DeepSeekApiException("服务器繁忙。请稍后再试。", statusCode)Case ElseThrow New DeepSeekApiException($"API 错误 ({statusCode}): {errorMessage}", statusCode)End SelectEnd Sub
End Class' 请求和响应数据模型
Public Class DeepSeekRequest<JsonPropertyName("model")>Public Property Model As String<JsonPropertyName("messages")>Public Property Messages As List(Of ChatMessage)<JsonPropertyName("temperature")>Public Property Temperature As Single<JsonPropertyName("top_p")>Public Property Top_p As Single<JsonPropertyName("max_tokens")>Public Property MaxTokens As Integer<JsonPropertyName("stream")>Public Property Stream As Boolean
End ClassPublic Class ChatMessage<JsonPropertyName("role")>Public Property Role As String<JsonPropertyName("content")>Public Property Content As String
End ClassPublic Class DeepSeekResponse<JsonPropertyName("choices")>Public Property Choices As List(Of Choice)
End ClassPublic Class Choice<JsonPropertyName("message")>Public Property Message As ChatMessage
End ClassPublic Class DeepSeekErrorResponse<JsonPropertyName("error")>Public Property [Error] As ApiError
End ClassPublic Class ApiError<JsonPropertyName("message")>Public Property Message As String<JsonPropertyName("type")>Public Property Type As String<JsonPropertyName("code")>Public Property Code As String
End Class''' <summary>
''' DeepSeek API 异常类
''' </summary>
Public Class DeepSeekApiExceptionInherits ExceptionPublic ReadOnly Property StatusCode As HttpStatusCodePublic Sub New(message As String, statusCode As HttpStatusCode)MyBase.New(message)Me.StatusCode = statusCodeEnd SubPublic Sub New(message As String, statusCode As HttpStatusCode, innerException As Exception)MyBase.New(message, innerException)Me.StatusCode = statusCodeEnd Sub
End Class
以上就是DeepSeek写的调用自己的代码(添加了几个属性、增加了几个参数、翻译了几段英文错误说明)之后的样子。
接下来就是调用咯:
' 全局共享的 HttpClientPrivate Shared ReadOnly HttpClientInstance As New HttpClient()Async Function TestDeepSeekClient(modeName As String, systemMessage As String, userMessage As String, timeOut As TimeSpan) As Task(Of (Boolean, String))Try' 初始化客户端(使用共享的 HttpClient)Dim apiKey = "sk-差点得去换APIKEY- -!!!"Dim client = New DeepSeekClient(HttpClientInstance, apiKey)' 自定义参数 (可选)client.Model = modeNameclient.Temperature = 0.1client.MaxTokens = 1024client.Top_p = 0.2client.Stream = False' 发送消息Dim response = Await client.SendMessageAsync(systemMessage, userMessage, timeOut)Return (True, response)Catch ex As DeepSeekApiExceptionReturn (False, $"API Error ({ex.StatusCode}): {ex.Message}")Catch ex As ExceptionReturn (False, $"Error: {ex.Message}")End TryEnd Function
最后,就是调用的调用:
Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click'"deepseek-chat" "deepseek-reasoner"Dim result = Await TestDeepSeekClient("deepseek-chat", "你是一个AI。", "你的名字是?", TimeSpan.FromSeconds(600))If result.Item1 ThenDebug.Print(result.Item2)ElseDebug.Print("发生错误:" & result.Item2)End IfDebug.Print("完成。")End Sub
好了,到此为止吧。