国产成人精品久久免费动漫-国产成人精品天堂-国产成人精品区在线观看-国产成人精品日本-a级毛片无码免费真人-a级毛片毛片免费观看久潮喷

您的位置:首頁技術(shù)文章
文章詳情頁

使用 .NET MAUI 開發(fā) ChatGPT 客戶端的流程

瀏覽:112日期:2022-06-09 08:58:56
目錄
  • 開發(fā)實(shí)戰(zhàn)
    • 托盤圖標(biāo)(右鍵點(diǎn)擊有 menu)
    • WebView
    • 【重點(diǎn)】js 和 csharp 互相調(diào)用
    • chatgpt 的開放 api 調(diào)用

最近 chatgpt 很火,由于網(wǎng)頁版本限制了 ip,還得必須開代理,用起來比較麻煩,所以我嘗試用 maui 開發(fā)一個(gè)聊天小應(yīng)用,結(jié)合 chatgpt 的開放 api 來實(shí)現(xiàn)(很多客戶端使用網(wǎng)頁版本接口用 cookie 的方式,有很多限制(如下圖)總歸不是很正規(guī))。

效果如下

mac 端由于需要升級(jí) macos13 才能開發(fā)調(diào)試,這部分我還沒有完成,不過 maui 的控件是跨平臺(tái)的,放在后續(xù)我升級(jí)系統(tǒng)再說。

開發(fā)實(shí)戰(zhàn)

我是設(shè)想開發(fā)一個(gè)類似 jetbrains 的 ToolBox 應(yīng)用一樣,啟動(dòng)程序在桌面右下角出現(xiàn)托盤圖標(biāo),點(diǎn)擊圖標(biāo)彈出應(yīng)用(風(fēng)格在 windows mac 平臺(tái)保持一致)

需要實(shí)現(xiàn)的功能一覽

  • 托盤圖標(biāo)(右鍵點(diǎn)擊有 menu)
  • webview(js 和 csharp 互相調(diào)用)
  • 聊天 SPA 頁面(react 開發(fā),build 后讓 webview 展示)

新建一個(gè) maui 工程(vs2022)

坑一:默認(rèn)編譯出來的 exe 是直接雙擊打不開的

工程文件加上這個(gè)配置

<WindowsPackageType>None</WindowsPackageType><WindowsAppSDKSelfContained Condition=""$(IsUnpackaged)" == "true"">true</WindowsAppSDKSelfContained><SelfContained Condition=""$(IsUnpackaged)" == "true"">true</SelfContained>

以上修改后,編譯出來的 exe 雙擊就可以打開了

托盤圖標(biāo)(右鍵點(diǎn)擊有 menu)

啟動(dòng)時(shí)設(shè)置窗口不能改變大小,隱藏 titlebar, 讓 Webview 控件占滿整個(gè)窗口

這里要根據(jù)平臺(tái)不同實(shí)現(xiàn)不同了,windows 平臺(tái)采用 winAPI 調(diào)用,具體看工程代碼吧!

WebView

在 MainPage.xaml 添加控件

對(duì)應(yīng)的靜態(tài) html 等文件放在工程的 Resource\Raw 文件夾下 (整個(gè)文件夾里面默認(rèn)是作為內(nèi)嵌資源打包的,工程文件里面的如下配置起的作用)

<!-- Raw Assets (also remove the "Resources\Raw" prefix) --><MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />

【重點(diǎn)】js 和 csharp 互相調(diào)用

這部分我找了很多資料,最終參考了這個(gè) demo,然后改進(jìn)了下。

主要原理是:

  • js 調(diào)用 csharp 方法前先把數(shù)據(jù)存儲(chǔ)在 localstorage 里
  • 然后 windows.location 切換特定的 url 發(fā)起調(diào)用,返回一個(gè) promise,等待 csharp 的事件
  • csharp 端監(jiān)聽 webview 的 Navigating 事件,異步進(jìn)行下面處理
  • 根據(jù) url 解析出來 localstorage 的 key
  • 然后 csharp 端調(diào)用 excutescript 根據(jù) key 拿到 localstorage 的 value
  • 進(jìn)行邏輯處理后返回通過事件分發(fā)到 js 端

js 的調(diào)用封裝如下:

// 調(diào)用csharp的方法封裝export default class CsharpMethod {  constructor(command, data) {    this.RequestPrefix = "request_csharp_";    this.ResponsePrefix = "response_csharp_";    // 唯一    this.dataId = this.RequestPrefix + new Date().getTime();    // 調(diào)用csharp的命令    this.command = command;    // 參數(shù)    this.data = { command: command, data: !data ? "" : JSON.stringify(data), key: this.dataId }  }   // 調(diào)用csharp 返回promise  call() {    // 把data存儲(chǔ)到localstorage中 目的是讓csharp端獲取參數(shù)    localStorage.setItem(this.dataId, this.utf8_to_b64(JSON.stringify(this.data)));    let eventKey = this.dataId.replace(this.RequestPrefix, this.ResponsePrefix);    let that = this;    const promise = new Promise(function (resolve, reject) {      const eventHandler = function (e) {window.removeEventListener(eventKey, eventHandler);let resp = e.newValue;if (resp) {  // 從base64轉(zhuǎn)換  let realData = that.b64_to_utf8(resp);  if (realData.startsWith("err:")) {    reject(realData.substr(4));  } else {    resolve(realData);  }} else {  reject("unknown error :" + eventKey);}      };      // 注冊(cè)監(jiān)聽回調(diào)(csharp端處理完發(fā)起的)      window.addEventListener(eventKey, eventHandler);    });    // 改變location 發(fā)送給csharp端    window.location = "/api/" + this.dataId;    return promise;  }   // 轉(zhuǎn)成base64 解決中文亂碼  utf8_to_b64(str) {    return window.btoa(unescape(encodeURIComponent(str)));  }  // 從base64轉(zhuǎn)過來 解決中文亂碼  b64_to_utf8(str) {    return decodeURIComponent(escape(window.atob(str)));  } }

前端的使用方式

import CsharpMethod from "../../services/api" // 發(fā)起調(diào)用csharp的chat事件函數(shù)const method = new CsharpMethod("chat", {msg: message});method.call() // call返回promise.then(data =>{  // 拿到csharp端的返回后展示  onMessageHandler({    message: data,    username: "Robot",    type: "chat_message"  });}).catch(err =>  {    alert(err);});

csharp 端的處理:

這么封裝后,js 和 csharp 的互相調(diào)用就很方便了。

chatgpt 的開放 api 調(diào)用

注冊(cè)好 chatgpt 后可以申請(qǐng)一個(gè) APIKEY。

API 封裝:

  public static async Task<CompletionsResponse> GetResponseDataAsync(string prompt){    // Set up the API URL and API key    string apiUrl = "https://api.openai.com/v1/completions";     // Get the request body JSON    decimal temperature = decimal.Parse(Setting.Temperature, CultureInfo.InvariantCulture);    int maxTokens = int.Parse(Setting.MaxTokens, CultureInfo.InvariantCulture);    string requestBodyJson = GetRequestBodyJson(prompt, temperature, maxTokens);     // Send the API request and get the response data    return await SendApiRequestAsync(apiUrl, Setting.ApiKey, requestBodyJson);} private static string GetRequestBodyJson(string prompt, decimal temperature, int maxTokens){    // Set up the request body    var requestBody = new CompletionsRequestBody    {Model = "text-davinci-003",Prompt = prompt,Temperature = temperature,MaxTokens = maxTokens,TopP = 1.0m,FrequencyPenalty = 0.0m,PresencePenalty = 0.0m,N = 1,Stop = "[END]",    };     // Create a new JsonSerializerOptions object with the IgnoreNullValues and IgnoreReadOnlyProperties properties set to true    var serializerOptions = new JsonSerializerOptions    {IgnoreNullValues = true,IgnoreReadOnlyProperties = true,    };     // Serialize the request body to JSON using the JsonSerializer.Serialize method overload that takes a JsonSerializerOptions parameter    return JsonSerializer.Serialize(requestBody, serializerOptions);} private static async Task<CompletionsResponse> SendApiRequestAsync(string apiUrl, string apiKey, string requestBodyJson){    // Create a new HttpClient for making the API request    using HttpClient client = new HttpClient();     // Set the API key in the request headers    client.DefaultRequestHeaders.Add("Authorization", "Bearer " + apiKey);     // Create a new StringContent object with the JSON payload and the correct content type    StringContent content = new StringContent(requestBodyJson, Encoding.UTF8, "application/json");     // Send the API request and get the response    HttpResponseMessage response = await client.PostAsync(apiUrl, content);     // Deserialize the response    var responseBody = await response.Content.ReadAsStringAsync();     // Return the response data    return JsonSerializer.Deserialize<CompletionsResponse>(responseBody);}

調(diào)用方式

 var reply = await ChatService.GetResponseDataAsync("xxxxxxxxxx");

在學(xué)習(xí) maui 的過程中,遇到問題我在 Microsoft Learn 提問,回答的效率很快,推薦大家試試看!

到此這篇關(guān)于使用 .NET MAUI 開發(fā) ChatGPT 客戶端的文章就介紹到這了,更多相關(guān).NET MAUI 開發(fā) ChatGPT 內(nèi)容請(qǐng)搜索以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持!

標(biāo)簽: ASP.NET
主站蜘蛛池模板: 日日噜噜噜夜夜爽爽狠狠69 | 久久久久琪琪去精品色村长 | 免费老外的毛片清高 | 欧美 亚洲 另类 自拍 在线 | 免费一级性片 | 千涩成人网 | 日本一线一区二区三区免费视频 | 国产精品18久久久久久久久久 | 国产成人精品一区二区三在线观看 | 国产精品视频一区二区猎奇 | 蕾丝视频永久在线入口香蕉 | 久久看精品 | 欧美成人在线免费观看 | 国产精品路边足疗店按摩 | 国产亚洲精品线观看77 | 黄页美女 | 99久久精品免费看国产免费 | 国产三级a三级三级三级 | 久久国产免费一区二区三区 | 亚洲国产成人久久三区 | 中文字幕亚洲高清综合 | 日韩一品在线播放视频一品免费 | 免费无毒 | 色婷婷国产精品欧美毛片 | 日本欧美一区二区 | 欧美人性影片免费看 | 国产91精品露脸国语对白 | 乱码一区| 91成人免费观看 | 欧美满嘴射 | 免费的特黄特色大片在线观看 | 欧美无极品 | 免费福利入口在线观看 | a毛片免费| 免费看成人www的网站软件 | 久久精品国产99久久 | 亚洲欧美在线观看视频 | 欧美1| 国产a国产片国产 | 久久精品国产6699国产精 | 15—17女人毛片|