天天看點

【開源】利用.NET開發第一個ChatGPT聊天系統

作者:IT技術資源愛好者

最近ChatGPT很火,借此機會給大家推薦一個利用C#開發的開源的ChatGPT聊天系統,話不多說,直接上主題。

準備

第一步:注冊OpenAI賬号

因為對大陸以及中國香港地區不開放,是以我們需要小小的科學一下。

來一個我就是參照着申請賬号的園子的文章:

https://www.cnblogs.com/chatgpt/p/how-to-register-chatgpt-in-china.html

當然手機那裡可以淘寶找,幾塊錢就能幫忙注冊手機,賬号裡面預設還有18美元餘額。

注意點:如果搭建了科學還是提示不對你的國家提供服務的話,嘗試清空浏覽器緩存或者打開浏覽器的無痕視窗。Chrome預設在右上角三個點打開就能找到“打開新的無痕式視窗”。

萬事具備,直接撸代碼

1.網頁擷取所需token和cookie

我們需要三個東西:UserAgent,CfClearance,Session_token

我們需要先打開ChatGPT官方網站:https://chat.openai.com/chat 然後按下F12打開浏覽器的開發者模式

UserAgent在網絡裡(隻需要複制UserAgent:後面的值):

【開源】利用.NET開發第一個ChatGPT聊天系統

CfClearance和Session_token在應用程式->cookie裡面

【開源】利用.NET開發第一個ChatGPT聊天系統

2.建立一個session用來表示一個會話

public OpenAISession(string session_token,string cfClearance,string userAgent)
{
    Session_token = session_token;
    CfClearance = cfClearance;
    UserAgent = userAgent;
    Headers = new Dictionary<string, string>();
    Cookies = new Dictionary<string, string>();
    Proxies = new Dictionary<string, string>();
}
           

Session可以重新整理自己的AccessToken和Session_token

public async Task RefreshSessionAsync()
{
    if (string.IsNullOrEmpty(Session_token))
    {
        throw new Exception("No tokens provided");
    }

    // Set cookies
    Cookies.Put("__Secure-next-auth.session-token", Session_token);
    Cookies.Put("cf_clearance", CfClearance);
    string cookiesString = GetCookiesString();
    Dictionary<string, string> map = new Dictionary<string, string>();
    Headers.Put("User-Agent", UserAgent);
    Headers.Put("cookie", cookiesString);
    Headers.Put("Cookie", cookiesString);

    var response = await GetAsync("https://chat.openai.com/api/auth/session");
    if (!response.IsSuccessStatusCode)
    {
        Console.WriteLine("err code: " + response.StatusCode);
        Console.WriteLine("cf_clearance: " + CfClearance);
        Console.WriteLine("token: " + Session_token);
        Console.WriteLine("userAgent: " + UserAgent);
        Console.WriteLine("請檢查以上參數是否正确,是否過期。");

        throw new Exception("無法擷取token!請重試");
    }

    try
    {
        string name = "__Secure-next-auth.session-token=";
        var cookies = response.Headers.GetValues("Set-Cookie");
        var stoken = cookies.FirstOrDefault(x => x.StartsWith(name));
        Session_token = stoken == null ? Session_token : stoken.Substring(name.Length, stoken.IndexOf(";") - name.Length);
        Cookies.Put("__Secure-next-auth.session-token", Session_token);
        var result = await response.Content.ReadAsStringAsync();
        AccessToken = JsonSerializer.Deserialize<Profile>(result, _jsonSerializerOptions)?.AccessToken;
        RefreshHeaders();
    }
    catch (Exception ex)
    {
        Console.WriteLine(#34;Error {nameof(RefreshSessionAsync)}:{ex}");
        throw new Exception(#34;Error {nameof(RefreshSessionAsync)}", ex);
    }
}
           

擷取到的最新的AccessToken更新到header裡,Session_token更新到cookie裡

private void RefreshHeaders()
{
    Headers.Put("Host", "chat.openai.com");
    Headers.Put("Accept", "text/event-stream");
    Headers.Put("Authorization", #34;Bearer {AccessToken}");
    Headers.Put("User-Agent", UserAgent);
    Headers.Put("X-Openai-Assistant-App-Id", string.Empty);
    Headers.Put("Connection", "close");
    Headers.Put("Accept-Language", "en-US,en;q=0.9");
    Headers.Put("Referer", "https://chat.openai.com/chat");
}

string name = "__Secure-next-auth.session-token=";
var cookies = response.Headers.GetValues("Set-Cookie");
var stoken = cookies.FirstOrDefault(x => x.StartsWith(name));
Session_token = stoken == null ? Session_token : stoken.Substring(name.Length, stoken.IndexOf(";") - name.Length);
Cookies.Put("__Secure-next-auth.session-token", Session_token);
           

3.建立機器人綁定一個會話

public Chatbot(OpenAISession openAISession)
{
    OpenAISession = openAISession;
    ResetConversation();
}

/// <summary>
/// 重置Conversation,開啟一個新的會話
/// </summary>
public void ResetConversation() 
{
    _conversationId = null;
    _parentMessageId = Guid.NewGuid().ToString();
}
           

如何保持上下文聊天以及多使用者隔離?

上下文聊天已經内置,會自動與機器人的回複進行關聯,當需要重新開啟一個對話的時候,可以調用ResetConversation,這樣對應的機器人對象發過去就是開啟了一個新的對話。

如何多使用者隔離?比如聯合微信機器人使用,可以将一個人或者一個群對應一個Chatbot對象,并且利用id與機器人做關聯。

當然這個_clientID需要使用者做唯一性管理

//可以作為隔離不同用戶端聊天上下文的憑據,即一個機器人綁定一個用戶端
//用戶端編号可以是,微信id,qq id,飛書id,亦或者自己開發的軟體的使用者id
private readonly string _clientID; 

public Chatbot(OpenAISession openAISession, string clientID)
{
    OpenAISession = openAISession;
    _clientID = clientID == null ? Guid.NewGuid().ToString() : clientID;
    ResetConversation();
}
           

最後構造對話對象,發送到對應api

public async Task<Reply> GetChatReplyAsync(string prompt)
{
    var conversation = new Conversation();
    conversation.Conversation_id = _conversationId;
    conversation.Parent_message_id = _parentMessageId;
    conversation.Messages = new Message[]
    {
        new Message()
        {
            Content = new Content
            {
                Parts = new string []{ prompt }
            }
        }
    };

    return await GetChatResponseAsync(conversation);
}

/// <summary>
/// 擷取響應
/// </summary>
/// <param name="conversation"></param>
/// <returns></returns>
/// <exception cref="Exception">伺服器傳回非200</exception>
private async Task<Reply> GetChatResponseAsync(Conversation conversation)
{
    using (var client = new HttpClient())
    {
        var response = await OpenAISession.PostAsync(_conversation, JsonSerializer.Serialize(conversation, _jsonSerializerOptions));
        if (!response.IsSuccessStatusCode)
        {
            throw new Exception(#34;Faild to request.StatusCode:{response.StatusCode}");
        }
        var msg = await response.Content.ReadAsStringAsync();
        var data = msg.Split("\n")?.ToList().Where(x => !string.IsNullOrEmpty(x) && !x.Contains("data: [DONE]")).LastOrDefault()?.Substring(5);
        var reply = JsonSerializer.Deserialize<Reply>(data, _jsonSerializerOptions);
        _conversationId = reply.Conversation_id;

        return reply;
    }
}
           

效果截圖(僅測試)

OpenAISession openAIOptions = new OpenAISession(Session_token, CfClearance, UserAgent);
await openAIOptions.RefreshSessionAsync();
Chatbot chatbot = new Chatbot(openAIOptions);
Console.WriteLine("用c++寫個冒泡查詢");
var reply = await chatbot.GetChatReplyAsync("用c++寫個冒泡查詢");
Console.WriteLine(reply.Message.Content.Parts.FirstOrDefault());
           
【開源】利用.NET開發第一個ChatGPT聊天系統

擷取源碼:關注我并私信回複:“ChatGPT聊天”。

歡迎點贊+轉發+關注!大家的支援是我分享最大的動力!!!

繼續閱讀