基于AI大文本模型的智慧对话开发设计及C#源码实现,实现智能文本改写与智慧对话

慈云数据 5个月前 (06-15) 技术支持 58 0

文章目录

  • 1.AI 大模型发展现状
  • 2.基于AI服务的智慧对话开发
    • 2.1 大模型API选择
    • 2.2 基于C#的聊天界面开发
    • 2.3 星火大模型API接入
    • 2.4 优化开发界面与显示逻辑
    • 3.源码工程Demo及相关软件下载
    • 参考文献

      1.AI 大模型发展现状

      端午假期几天,关注到国内的AI大模型厂商近乎疯狂地打起了价格战,这边阿里云刚宣布降价97%,那边百度就宣布两款模型全面免费,好不热闹!据不完全统计,国内已有7家大模型企业“参战”,包括字节跳动、阿里云、百度、腾讯云互联网大厂,智谱AI、深度求索等AI创企,以及垂直赛道头部玩家科大讯飞,纷纷争夺“最便宜”“最高性价比”大模型这块蛋糕。

      在这里插入图片描述

      ▲国内大模型厂商参与价格战情况(智东西制表,统计于2024年5月27日)

      总的来看,各大厂商对降价原因的解释无外乎以下几点:技术突破了,推理成本降低了;为开发者兜底,降低大模型的使用门槛;提升产品竞争力,积累客户。但大模型价格战对产业的影响具有两面性,既能够促使产业格局变化和商业模式创新,也为开发者带来机遇,有利于爆款应用的开发和大模型私有化部署。

      2.基于AI服务的智慧对话开发

      由于工作关系,涉及到相关文字材料的编制,对于某些材料,选用baidu的文心一言或者Aliyun的通义千问对于简单的工作来说可以提升部分效率,但是基于网页端还是存在一些限制,于是计划假期间利用C#语言+VS2015的win界面开发优势,配合大模型API实现快速的文本改写、文字降重以及智慧对话的功能

      2.1 大模型API选择

      选择讯飞星火大模型,其SparkLite免费为开发者开放,且不限tokens和有效期,提供各类开发的Demo源码,对于新手开发的话也比较友好。

      在这里插入图片描述

      2.2 基于C#的聊天界面开发

      聊天界面开发计划基于Panel、RichTextBox、Button、PictureBox组成。其中Button主要负责模拟发送。

      在这里插入图片描述

      值得说明的是:Panel部分的聊天窗口由设计如下控件组成,且要支持右键菜单的复制和全选的功能,方便获取消息内容。

      功能控件
      头像PictureBox
      昵称Label
      发送时间Label
      信息详情RichTextBox
      右键菜单ContextMenuStrip

      实现的效果如下:

      在这里插入图片描述

      主窗体源码如下:

      using System;
      using System.Collections.Generic;
      using System.ComponentModel;
      using System.Data;
      using System.Drawing;
      using System.Linq;
      using System.Text;
      using System.Threading.Tasks;
      using System.Windows.Forms;
      namespace WindowsFormsApplication1
      {
          public partial class Form1 : Form
          {
              public Form1()
              {
                  InitializeComponent();
              }
              //新建聊天控件全局变量
              ChatBubble tsps_chat;
              private void button1_Click(object sender, EventArgs e)
              {
                  Image touxiang = (WindowsFormsApplication1.Properties.Resources._001);
                  Image touxiang2 = (WindowsFormsApplication1.Properties.Resources._002);
                  //发送
                  tsps_chat.AddMsg(touxiang2,
                      richTextBox1.Text, ChatBubble.MsgPlace.Right, "测试");
                  //模拟接收
                  tsps_chat.AddMsg(touxiang,
                      "你好,我有一个帽衫...",ChatBubble.MsgPlace.Left,"TSPS");
                 
              }
              private void Form1_Load(object sender, EventArgs e)
              {
                  panel1.VerticalScroll.Visible = true;
                  panel1.AutoScroll = true;
                  Font ft = new Font("黑体", 12, Font.Style & ~FontStyle.Italic);
                  //创建新的聊天窗口(传入panel和font)
                  tsps_chat = new ChatBubble(panel1, ft);
              }
          }
      }
      

      Panel相关代码如下:

      using System;
      using System.Collections.Generic;
      using System.Drawing;
      using System.Linq;
      using System.Text;
      using System.Threading.Tasks;
      using System.Windows.Forms;
      namespace WindowsFormsApplication1
      {
          /// 
          /// 聊天窗口展示类
          /// 
          class Class1
          {
          }
          class ChatBubble
          {
              /// 
              /// 生成菜单项
              /// 
              /// 
              /// 
              /// 
              private ToolStripMenuItem GetMenuItem(string txt, Image img)
              {
                  ToolStripMenuItem menuItem = new ToolStripMenuItem();
                  menuItem.Text = txt;
                  menuItem.Image = img;
                  return menuItem;
              }
              /// 
              /// 菜单项事件响应
              /// 
              /// 
              /// 
              private void toolStripMenuItem_Click(object sender, ToolStripItemClickedEventArgs e)
              {
                  //ToolStripMenuItem menuSend = sender as ToolStripMenuItem;
                  //string selectText = ((RichTextBox)menuSend.).SelectedText;
                  //MessageBox.Show(menu.Text);
                  //获取对应控件的值
                  ContextMenuStrip menu_now = (ContextMenuStrip)sender;
                  RichTextBox tb = ((RichTextBox)(menu_now).SourceControl);
                  if (((ContextMenuStrip)sender).Items[0] == e.ClickedItem)//全选
                  {
                      tb.Focus();//设置先焦点定位到当前活动的RichTextBox,
                      tb.SelectAll();
                  }
                  else if (((ContextMenuStrip)sender).Items[1] == e.ClickedItem)//复制
                  {
                     
                      Clipboard.SetDataObject(tb.SelectedText);
                  }
              }
              
              public ChatBubble(Panel panel, Font font)
              {
                  if (panel.Controls.Count != 0) throw new Exception("指定Panel控件不为空!");
                  ChatPlace = panel;
                  BubbleFont = font;
                  Context_caidan = new ContextMenuStrip();
                  MsgMaxLength = panel.Width - (6 * 4 + 35*2 );    // 其中, 四个6为 图片与(容器以及消息文本框)的距离 ,两个35为两侧图片的大小.
                  //右键菜单编辑
                  Context_caidan.Items.Add("全选");//添加到右键菜单
                  Context_caidan.Items.Add("复制");//添加到右键菜单
                  //绑定消息
                  Context_caidan.ItemClicked += new ToolStripItemClickedEventHandler(toolStripMenuItem_Click);//添加事件
                  //Control.ContextMenuStrip = Context_caidan;
              }
              readonly Panel ChatPlace;
              readonly Font BubbleFont;
              readonly ContextMenuStrip Context_caidan;//右键复制菜单
              int NowY = 7;
              readonly int MsgMaxLength;
              public enum MsgPlace
              {
                  Left,
                  Right
              }              // 气泡创建的位置
              /// 
              /// 根据文本内容设置textbox高度等属性
              /// 
              /// 
              private void SettxtHeight(RichTextBox textBox1,string showString)
              {
                  //属性
                  textBox1.Text = showString;
                  textBox1.Multiline = true;
                  textBox1.WordWrap = true;
                  textBox1.Font = BubbleFont;
                  textBox1.Width = MsgMaxLength;
                  textBox1.BorderStyle = BorderStyle.None;
                  textBox1.ContextMenuStrip = Context_caidan;//为文本框添加右键菜单
                  textBox1.ReadOnly = true;
                  //尺寸参数
                  int txtHeight = 22;//设置单行的行高
                  int MaxLineCount = 20;//设置最大行数
                  Size size = TextRenderer.MeasureText(textBox1.Text, textBox1.Font);
                  int itxtLine = size.Width / textBox1.Width + textBox1.Lines.Count() + 1;
                  if (itxtLine > MaxLineCount) { itxtLine = MaxLineCount; }
                  itxtLine -= 1;
                  textBox1.Height = txtHeight * itxtLine;
                  
                  
              }
              public void AddMsg(Image Photo, string Text, MsgPlace Place, string Name)
              {
                  if (ChatPlace.Controls.Count > 4*51) //仅保留近51条消息
                  {
                      ChatPlace.Controls.Clear();
                      NowY = 7;
                  }
                  if (ChatPlace.Controls.Count != 0)
                  {
                      NowY = ChatPlace.Controls[ChatPlace.Controls.Count - 2].Location.Y
                          + ChatPlace.Controls[ChatPlace.Controls.Count - 1].Height + 35;//间隔控制
                  }
                  
                  PictureBox photo = new PictureBox();                // 头像
                  Label nickname = new Label();                       // 昵称
                  Label sendtime = new Label();
                  // Label msg = new Label();
                  RichTextBox msg = new RichTextBox();
                  
                  
                  photo.Size = new Size(35, 35);
                  photo.SizeMode = PictureBoxSizeMode.StretchImage;
                  photo.Image = Photo;
                  nickname.AutoSize = true;
                  nickname.MaximumSize = new Size(0, 0);
                  nickname.Font = BubbleFont;
                  nickname.Text = Name;
                  //获取当前时间
                  string timenow = System.DateTime.Now.ToString("T");
                  sendtime.AutoSize = true;
                  sendtime.MaximumSize = new Size(0, 0);
                  sendtime.Font = BubbleFont;
                  sendtime.Text = timenow;
                  //msg.AutoSize = true;
                  //msg.Font = BubbleFont;
                  //msg.MaximumSize = new Size(MsgMaxLength, 0);
                  // msg.Text = Text;
                  //msg.BorderStyle = BorderStyle.None;
                  SettxtHeight(msg,Text);//自动调整文本框大小
                 
                  ChatPlace.Controls.Add(nickname);
                  ChatPlace.Controls.Add(sendtime);
                  ChatPlace.Controls.Add(photo);
                  ChatPlace.Controls.Add(msg);
                  if (Place == MsgPlace.Left)
                  {
                      msg.BackColor = Color.LightGreen;
                      photo.Location = new Point(7, NowY);
                      sendtime.Location = new Point(ChatPlace.Width/2-45, NowY);
                      nickname.Location = new Point(photo.Location.X + photo.Width + 6, NowY);
                      msg.Location = new Point(nickname.Location.X, NowY + nickname.Size.Height);
                  }
                  else
                  {
                      msg.BackColor = Color.LightSkyBlue;
                      photo.Location = new Point(ChatPlace.Width - 7 - 35 - 10, NowY);
                      sendtime.Location = new Point(ChatPlace.Width/2 -45 , NowY);
                      nickname.Location = new Point(photo.Location.X - 7 - nickname.Width - 17, NowY);
                      msg.Location = new Point(photo.Location.X - msg.Width - 10, NowY + nickname.Size.Height);
                      // 这里的减去10是除去滚动条的宽度
                  }
                  //panel滚动条到最下方
                  Point newPoint = new Point(0, ChatPlace.Height - ChatPlace.AutoScrollPosition.Y);
                  ChatPlace.AutoScrollPosition = newPoint;
              }
          }        // 简易聊天气泡
      }
      

      2.3 星火大模型API接入

      使用如下C#代码接入讯飞星火大模型API

      using System;
      using System.Collections.Generic;
      using System.IO;
      using System.Linq;
      using System.Net;
      using System.Security.Cryptography;
      using System.Text;
      using System.Threading.Tasks;
      using System.Collections;
      using Newtonsoft.Json;
      using System.Net.WebSockets;
      using System.Threading;
      using Newtonsoft.Json.Linq;
      using System.Text.Json;
      /**
       * 星火认知大模型 WebAPI 接口调用示例 接口文档(必看):https://www.xfyun.cn/doc/spark/Web.html
       * 错误码链接:https://www.xfyun.cn/doc/spark/%E6%8E%A5%E5%8F%A3%E8%AF%B4%E6%98%8E.html (code返回错误码时必看)
       * @author iflytek
       */
      namespace Webiat
      {
          class Program
          {
              static ClientWebSocket webSocket0;
              static CancellationToken cancellation;
              // 应用APPID(必须为webapi类型应用,并开通星火认知大模型授权)
              const string x_appid = "XXXXXXXX";
              // 接口key(webapi类型应用开通星火认知大模型后,控制台--我的应用---星火认知大模型---相应服务的apikey)
              const string api_secret = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
              // 接口密钥(webapi类型应用开通星火认知大模型后,控制台--我的应用---星火认知大模型---相应服务的apisecret)
              const string api_key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
              static string hostUrl = "https://spark-api.xf-yun.com/v1.1/chat";
              async public static void Tasker()
              {
                  
                  string authUrl = GetAuthUrl();
                  string url = authUrl.Replace("http://", "ws://").Replace("https://", "wss://");
                  using (webSocket0 = new ClientWebSocket())
                  {
                      try
                      {
                          await webSocket0.ConnectAsync(new Uri(url), cancellation);
                          JsonRequest request = new JsonRequest();
                          request.header = new Header()
                                          {
                                              app_id = x_appid,
                                              uid = "12345"
                                          };
                          request.parameter = new Parameter()
                                              {
                                                  chat = new Chat()
                                                  {
       domain = "general",//模型领域,默认为星火通用大模型
       temperature = 0.5,//温度采样阈值,用于控制生成内容的随机性和多样性,值越大多样性越高;范围(0,1)
       max_tokens = 1024,//生成内容的最大长度,范围(0,4096)
                                                  }
                                              };
                          request.payload = new Payload()
                                              {
                                                  message = new Message()
                                                  {
       text = new List
       {
           new Content() { role = "user", content = "你是谁" },
           // new Content() { role = "assistant", content = "....." }, // AI的历史回答结果,这里省略了具体内容,可以根据需要添加更多历史对话信息和最新问题的内容。
       }
                                                  }
                                              };
                          string jsonString = JsonConvert.SerializeObject(request);
                          //连接成功,开始发送数据
                          
                          var frameData2 = System.Text.Encoding.UTF8.GetBytes(jsonString.ToString());
                          
                          webSocket0.SendAsync(new ArraySegment(frameData2), WebSocketMessageType.Text, true, cancellation);
                         
                          // 接收流式返回结果进行解析
                          byte[] receiveBuffer = new byte[1024];
                          WebSocketReceiveResult result = await webSocket0.ReceiveAsync(new ArraySegment(receiveBuffer), cancellation);
                          String resp = "";
                          while (!result.CloseStatus.HasValue)
                          {
                              if (result.MessageType == WebSocketMessageType.Text)
                              {
                                  string receivedMessage = Encoding.UTF8.GetString(receiveBuffer, 0, result.Count);
                                  //将结果构造为json
                                  
                                  JObject jsonObj = JObject.Parse(receivedMessage);
                                  int code = (int)jsonObj["header"]["code"];
                                  
                                  
                                  if(0==code){
                                      int status = (int)jsonObj["payload"]["choices"]["status"];
                                      
                                      JArray textArray = (JArray)jsonObj["payload"]["choices"]["text"];
                                      string content = (string)textArray[0]["content"];
                                      resp += content;
                                      if(status != 2){
                                          Console.WriteLine($"已接收到数据: {receivedMessage}");
                                      }
                                      else{
                                          Console.WriteLine($"最后一帧: {receivedMessage}");
                                          int totalTokens = (int)jsonObj["payload"]["usage"]["text"]["total_tokens"];
                                          Console.WriteLine($"整体返回结果: {resp}");
                                          Console.WriteLine($"本次消耗token数: {totalTokens}");
                                          break;
                                      }
                                  }else{
                                      Console.WriteLine($"请求报错: {receivedMessage}");
                                  }
                                      
                              }
                              else if (result.MessageType == WebSocketMessageType.Close)
                              {
                                  Console.WriteLine("已关闭WebSocket连接");
                                  break;
                              }
                              result = await webSocket0.ReceiveAsync(new ArraySegment(receiveBuffer), cancellation);
                          }
                      }
                      catch (Exception e)
                      {
                          Console.WriteLine(e.Message);
                      }
                  }
              }
              // 返回code为错误码时,请查询https://www.xfyun.cn/document/error-code解决方案
              static string GetAuthUrl()
              {
                  string date = DateTime.UtcNow.ToString("r");
                  Uri uri = new Uri(hostUrl);
                  StringBuilder builder = new StringBuilder("host: ").Append(uri.Host).Append("\n").//
                                          Append("date: ").Append(date).Append("\n").//
                                          Append("GET ").Append(uri.LocalPath).Append(" HTTP/1.1");
                  string sha = HMACsha256(api_secret, builder.ToString());
                  string authorization = string.Format("api_key=\"{0}\", algorithm=\"{1}\", headers=\"{2}\", signature=\"{3}\"", api_key, "hmac-sha256", "host date request-line", sha);
                  //System.Web.HttpUtility.UrlEncode
                  string NewUrl = "https://" + uri.Host + uri.LocalPath;
                  string path1 = "authorization" + "=" + Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(authorization));
                  date = date.Replace(" ", "%20").Replace(":", "%3A").Replace(",", "%2C");
                  string path2 = "date" + "=" + date;
                  string path3 = "host" + "=" + uri.Host;
                  NewUrl = NewUrl + "?" + path1 + "&" + path2 + "&" + path3;
                  return NewUrl;
              }
      
              public static string HMACsha256(string apiSecretIsKey, string buider)
              {
                  byte[] bytes = System.Text.Encoding.UTF8.GetBytes(apiSecretIsKey);
                  System.Security.Cryptography.HMACSHA256 hMACSHA256 = new System.Security.Cryptography.HMACSHA256(bytes);
                  byte[] date = System.Text.Encoding.UTF8.GetBytes(buider);
                  date = hMACSHA256.ComputeHash(date);
                  hMACSHA256.Clear();
                  return Convert.ToBase64String(date);
              }
              
              
              static void Main(string[] args)
              {
                  Tasker();
                  Console.ReadLine();
              }
          }
      }
      //构造请求体
      public class JsonRequest
      {
          public Header header { get; set; }
          public Parameter parameter { get; set; }
          public Payload payload { get; set; }
      }
      public class Header
      {
          public string app_id { get; set; }
          public string uid { get; set; }
      }
      public class Parameter
      {
          public Chat chat { get; set; }
      }
      public class Chat
      {
          public string domain { get; set; }
          public double temperature { get; set; }
          public int max_tokens { get; set; }
      }
      public class Payload
      {
          public Message message { get; set; }
      }
      public class Message
      {
          public List text { get; set; }
      }
      public class Content
      {
          public string role { get; set; }
          public string content { get; set; }
      }
      

      2.4 优化开发界面与显示逻辑

      最终调整了实时显示以及界面展示逻辑如下效果

      1.获取的数据可以实时显示并自动调整控件大小;

      2.可以正常通过按钮进行交互控制;

      3.增加进度条用于显示实时状态;

      4.支持个人的账号登录。

      请添加图片描述

      请添加图片描述

      3.源码工程Demo及相关软件下载

      下载1:讯飞星火大模型C#接入Demo

      下载2: C#聊天窗口界面Demo开发

      下载3: 打包好的程序,可直接使用: TSPS V32程序,支持讯飞大模型等API接入、论文降重、文本改写、智慧AI对话 或 蓝奏云下载

      注:对于上述(3)中打包的程序,若程序打开时显示“Window已保护你的电脑”可以:

      1.点击弹窗的“更多信息”

      2.点击仍要运行

      3.在弹窗中点击“是”即可打开

      参考文献

      https://www.thepaper.cn/newsDetail_forward_27521760

      https://blog.csdn.net/qq_20051033/article/details/104889215?spm=1001.2014.3001.5506

      请添加图片描述

微信扫一扫加客服

微信扫一扫加客服

点击启动AI问答
Draggable Icon