不用第三方库调用DeepSeek

又双叒叕很久不写博客,今天吐一口老曹。

一、为啥干这个

        之前在修改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.Threading

Public Class DeepSeekClient
    Private ReadOnly _sharedHttpClient As HttpClient
    Private ReadOnly _apiKey As String
    Private ReadOnly _apiBaseUrl As String
    Private _model As String = "deepseek-chat"
    Private _temperature As Single = 0.1
    Private _maxTokens As Integer = 2048
    Private _top_p As Single = 0.2
    Private _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 Then
            Throw New ArgumentNullException(NameOf(sharedHttpClient))
        End If
        If String.IsNullOrWhiteSpace(apiKey) Then
            Throw 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 If
    End Sub

    ''' <summary>
    ''' 设置模型名称
    ''' </summary>
    Public Property Model As String
        Get
            Return _model
        End Get
        Set(value As String)
            If String.IsNullOrWhiteSpace(value) Then
                Throw New ArgumentException("模型名称不能为空。")
            End If
            _model = value
        End Set
    End Property

    ''' <summary>
    ''' 设置温度参数 (0-2)
    ''' </summary>
    Public Property Temperature As Single
        Get
            Return _temperature
        End Get
        Set(value As Single)
            If value < 0 OrElse value > 2 Then
                Throw New ArgumentOutOfRangeException(NameOf(Temperature), "温度值应在[0,2]区间")
            End If
            _temperature = value
        End Set
    End Property

    ''' <summary>
    ''' 设置最大令牌数
    ''' </summary>
    Public Property MaxTokens As Integer
        Get
            Return _maxTokens
        End Get
        Set(value As Integer)
            If value <= 0 Then
                Throw New ArgumentOutOfRangeException(NameOf(MaxTokens), "最大Token数不应小于0。")
            End If
            _maxTokens = value
        End Set
    End Property

    ''' <summary>
    ''' 生成多样性控制
    ''' </summary>
    Public Property Top_p As Single
        Get
            Return _top_p
        End Get
        Set(value As Single)
            If value < 0 OrElse value > 1 Then
                Throw New ArgumentOutOfRangeException(NameOf(Temperature), "Top_p应在[0,1]区间。")
            End If
            _top_p = value
        End Set
    End Property

    ''' <summary>
    ''' 是否流式响应
    ''' </summary>
    Public Property Stream As Boolean
        Get
            Return _stream
        End Get
        Set(value As Boolean)
            _stream = value
        End Set
    End 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) Then
            Throw New ArgumentException("系统消息不能为空。", NameOf(systemMessage))
        End If
        If String.IsNullOrWhiteSpace(userMessage) Then
            Throw New ArgumentException("用户消息不能为空。", NameOf(userMessage))
        End If
        If timeout = Nothing Then
            Throw 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 Then
                    HandleApiError(response.StatusCode, responseContent)
                End If

                ' 使用 System.Text.Json 反序列化
                Dim responseObject = JsonSerializer.Deserialize(Of DeepSeekResponse)(responseContent)
                Return responseObject?.Choices?.FirstOrDefault()?.Message?.Content
            End Using
        Catch ex As TaskCanceledException When Not ex.CancellationToken.IsCancellationRequested
            Throw New TimeoutException("请求超时。", ex)
        Catch ex As OperationCanceledException
            Throw New TimeoutException("由于超时,请求被取消。", ex)
        Catch ex As HttpRequestException
            Throw New Exception("发送请求时出错。", ex)
        End Try
    End Function

    ''' <summary>
    ''' 处理 API 错误响应
    ''' </summary>
    Private Sub HandleApiError(statusCode As HttpStatusCode, responseContent As String)
        Dim errorMessage As String = "发生未知错误"

        Try
            If Not String.IsNullOrEmpty(responseContent) Then
                Dim errorResponse = JsonSerializer.Deserialize(Of DeepSeekErrorResponse)(responseContent)
                errorMessage = If(errorResponse?.Error?.Message, errorMessage)
            End If
        Catch
            ' 如果 JSON 解析失败,使用默认错误消息
        End Try

        Select Case statusCode
            Case HttpStatusCode.BadRequest ' 400
                Throw New DeepSeekApiException("错误请求:" & errorMessage, statusCode)
            Case HttpStatusCode.Unauthorized ' 401
                Throw New DeepSeekApiException("身份验证失败。请检查您的API密钥。", statusCode)
            Case HttpStatusCode.PaymentRequired ' 402
                Throw New DeepSeekApiException("余额不足。请给您的帐户充值。", statusCode)
            Case CType(422, HttpStatusCode) ' 422
                Throw New DeepSeekApiException("参数错误。" & errorMessage, statusCode)
            Case CType(429, HttpStatusCode) ' 429
                Throw New DeepSeekApiException("超出速率限制。请降低您的请求频率。", statusCode)
            Case HttpStatusCode.InternalServerError ' 500
                Throw New DeepSeekApiException("服务器错误。请稍后再试。", statusCode)
            Case HttpStatusCode.ServiceUnavailable ' 503
                Throw New DeepSeekApiException("服务器繁忙。请稍后再试。", statusCode)
            Case Else
                Throw New DeepSeekApiException($"API 错误 ({statusCode}): {errorMessage}", statusCode)
        End Select
    End 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 Class

Public Class ChatMessage
    <JsonPropertyName("role")>
    Public Property Role As String

    <JsonPropertyName("content")>
    Public Property Content As String
End Class

Public Class DeepSeekResponse
    <JsonPropertyName("choices")>
    Public Property Choices As List(Of Choice)
End Class

Public Class Choice
    <JsonPropertyName("message")>
    Public Property Message As ChatMessage
End Class

Public Class DeepSeekErrorResponse
    <JsonPropertyName("error")>
    Public Property [Error] As ApiError
End Class

Public 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 DeepSeekApiException
    Inherits Exception

    Public ReadOnly Property StatusCode As HttpStatusCode

    Public Sub New(message As String, statusCode As HttpStatusCode)
        MyBase.New(message)
        Me.StatusCode = statusCode
    End Sub

    Public Sub New(message As String, statusCode As HttpStatusCode, innerException As Exception)
        MyBase.New(message, innerException)
        Me.StatusCode = statusCode
    End Sub
End Class

        以上就是DeepSeek写的调用自己的代码(添加了几个属性、增加了几个参数、翻译了几段英文错误说明)之后的样子。

        接下来就是调用咯:

    ' 全局共享的 HttpClient
    Private 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 = modeName
            client.Temperature = 0.1
            client.MaxTokens = 1024
            client.Top_p = 0.2
            client.Stream = False
            ' 发送消息
            Dim response = Await client.SendMessageAsync(systemMessage, userMessage, timeOut)
            Return (True, response)
        Catch ex As DeepSeekApiException
            Return (False, $"API Error ({ex.StatusCode}): {ex.Message}")
        Catch ex As Exception
            Return (False, $"Error: {ex.Message}")
        End Try
    End 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 Then
            Debug.Print(result.Item2)
        Else
            Debug.Print("发生错误:" & result.Item2)
        End If
        Debug.Print("完成。")
    End Sub

        好了,到此为止吧。

内容概要:本文介绍了基于贝叶斯优化的CNN-LSTM混合神经网络在时间序列预测中的应用,并提供了完整的Matlab代码实现。该模型结合了卷积神经网络(CNN)在特征提取方面的优势与长短期记忆网络(LSTM)在处理时序依赖问题上的强大能力,形成一种高效的混合预测架构。通过贝叶斯优化算法自动调参,提升了模型的预测精度与泛化能力,适用于风电、光伏、负荷、交通流等多种复杂非线性系统的预测任务。文中还展示了模型训练流程、参数优化机制及实际预测效果分析,突出其在科研与工程应用中的实用性。; 适合人群:具备一定机器学习基基于贝叶斯优化CNN-LSTM混合神经网络预测(Matlab代码实现)础和Matlab编程经验的高校研究生、科研人员及从事预测建模的工程技术人员,尤其适合关注深度学习与智能优化算法结合应用的研究者。; 使用场景及目标:①解决各类时间序列预测问题,如能源出力预测、电力负荷预测、环境数据预测等;②学习如何将CNN-LSTM模型与贝叶斯优化相结合,提升模型性能;③掌握Matlab环境下深度学习模型搭建与超参数自动优化的技术路线。; 阅读建议:建议读者结合提供的Matlab代码进行实践操作,重点关注贝叶斯优化模块与混合神经网络结构的设计逻辑,通过调整数据集和参数加深对模型工作机制的理解,同时可将其框架迁移至其他预测场景中验证效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

清晨曦月

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值