加入收藏 | 设为首页 | 会员中心 | 我要投稿 威海站长网 (https://www.0631zz.cn/)- 科技、云服务器、分布式云、容器、中间件!
当前位置: 首页 > 综合聚焦 > 编程要点 > 资讯 > 正文

.NET MAUI赋能AI平台:打造ChatGPT多平台客户端的探索与实践

发布时间:2024-07-09 14:31:16 所属栏目:资讯 来源:DaWei
导读:   这篇文章给大家分享的是 .NET MAUI如何开发AI平台ChatGPT的客户端?。小编觉得挺实用的,因此分享给大家做个参考,文中的介绍得很详细,而要易于理解和学习,有需要的朋友可以参考,接下

  这篇文章给大家分享的是 .NET MAUI如何开发AI平台ChatGPT的客户端?。小编觉得挺实用的,因此分享给大家做个参考,文中的介绍得很详细,而要易于理解和学习,有需要的朋友可以参考,接下来就跟随小编一起了解看看吧。

  目录

  开发实战

  托盘图标(右键点击有 menu)

  WebView

  【重点】js 和 csharp 互相调用

  chatgpt 的开放 api 调用

  最近 chatgpt 很火,由于网页版本限制了 ip,还得必须开代理,用起来比较麻烦,所以我尝试用 maui 开发一个聊天小应用,结合 chatgpt 的开放 api 来实现(很多客户端使用网页版本接口用 cookie 的方式,有很多限制(如下图)总归不是很正规)。

  效果如下

  mac 端由于需要升级 macos13 才能开发调试,这部分我还没有完成,不过 maui 的控件是跨平台的,放在后续我升级系统再说。

  开发实战

  我是设想开发一个类似 jetbrains 的 ToolBox 应用一样,启动程序在桌面右下角出现托盘图标,点击图标弹出应用(风格在 windows mac 平台保持一致)

  需要实现的功能一览

  托盘图标(右键点击有 menu)

  webview(js 和 csharp 互相调用)

  聊天 SPA 页面(react 开发,build 后让 webview 展示)

  新建一个 maui 工程(vs2022)

  坑一:默认编译出来的 exe 是直接双击打不开的

  工程文件加上这个配置

  None

  true

  true

  以上修改后,编译出来的 exe 双击就可以打开了

  托盘图标(右键点击有 menu)

  启动时设置窗口不能改变大小,隐藏 titlebar, 让 Webview 控件占满整个窗口

  这里要根据平台不同实现不同了,windows 平台采用 winAPI 调用,具体看工程代码吧!

  WebView

  在 MainPage.xaml 添加控件

  对应的静态 html 等文件放在工程的 Resource\Raw 文件夹下 (整个文件夹里面默认是作为内嵌资源打包的,工程文件里面的如下配置起的作用)

  

  

  【重点】js 和 csharp 互相调用

  这部分我找了很多资料,最终参考了这个 demo,然后改进了下。

  主要原理是:

  js 调用 csharp 方法前先把数据存储在 localstorage 里

  然后 windows.location 切换特定的 url 发起调用,返回一个 promise,等待 csharp 的事件

  csharp 端监听 webview 的 Navigating 事件,异步进行下面处理

  根据 url 解析出来 localstorage 的 key

  然后 csharp 端调用 excutescript 根据 key 拿到 localstorage 的 value

  进行逻辑处理后返回通过事件分发到 js 端

  js 的调用封装如下:

  // 调用csharp的方法封装

  export default class CsharpMethod {

  constructor(command, data) {

  this.RequestPrefix = "request_csharp_";

  this.ResponsePrefix = "response_csharp_";

  // 唯一

  this.dataId = this.RequestPrefix + new Date().getTime();

  // 调用csharp的命令

  this.command = command;

  // 参数

  this.data = { command: command, data: !data ? '' : JSON.stringify(data), key: this.dataId }

  }

  // 调用csharp 返回promise

  call() {

  // 把data存储到localstorage中 目的是让csharp端获取参数

  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转换

  let realData = that.b64_to_utf8(resp);

  if (realData.startsWith('err:')) {

  reject(realData.substr(4));

  } else {

  resolve(realData);

  }

  } else {

  reject("unknown error :" + eventKey);

  }

  };

  // 注册监听回调(csharp端处理完发起的)

  window.addEventListener(eventKey, eventHandler);

  });

  // 改变location 发送给csharp端

  window.location = "/api/" + this.dataId;

  return promise;

  }

  // 转成base64 解决中文乱码

  utf8_to_b64(str) {

  return window.btoa(unescape(encodeURIComponent(str)));

  }

  // 从base64转过来 解决中文乱码

  b64_to_utf8(str) {

  return decodeURIComponent(escape(window.atob(str)));

  }

  }

  前端的使用方式

  import CsharpMethod from '../../services/api'

  // 发起调用csharp的chat事件函数

  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 的互相调用就很方便了。

  chatgpt 的开放 api 调用

  注册好 chatgpt 后可以申请一个 APIKEY。

  API 封装:

  public static async Task 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 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(responseBody);

  }

  调用方式

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

  完整代码参考~

  在学习 maui 的过程中,遇到问题我在 Microsoft Learn 提问,回答的效率很快,推荐大家试试看!

  点我了解更多 MAUI 相关资料~

  “ .NET MAUI如何开发AI平台ChatGPT的客户端?”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业技术相关的知识可以关注

(编辑:威海站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章