当前位置:   article > 正文

Unity 讯飞 之 讯飞星火大模型的简单封装和使用(补充讯飞大模型识图功能)_大模型的url怎么获取

大模型的url怎么获取

Unity 讯飞 之 讯飞星火大模型的简单封装和使用(补充讯飞大模型识图功能)

目录

Unity 讯飞 之 讯飞星火大模型的简单封装和使用(补充讯飞大模型识图功能)

一、简单介绍

二、实现原理

三、注意事项

四、效果预览

五、案例简单实现步骤

六、关键代码

七、案例下载地址

补充、讯飞大模型-图像识别


一、简单介绍

Unity 工具类,自己整理的一些游戏开发可能用到的模块,单独独立使用,方便游戏开发

这里简单的介绍讯飞大模型的封装和使用,进行聊天。

“讯飞星火认知大模型”是科大讯飞发布的产品,具有7大核心能力,即文本生成、语言理解、知识问答、逻辑推理、数学能力、代码能力、多模态能力。

星火v1.5、v2.0地址: http://spark-api.xf-yun.com/v1/completions

星火v3.0地址: http://spark-api.xf-yun.com/v3/completions

星火v1.5和v2.0使用的是同一个URL,domain参数配置如下:

  1. # domain = "general" # v1.5版本
  2. #domain = "generalv2" # v2.0版本
  3. domain = "generalv3" # v3.0版本

二、实现原理

1、申请星火大模型的 APP_ID 等相关信息

2、通过使用的大模型版本,以及当前的时间,结合 申请星火大模型的 APP_ID 等相关信息,生成需要的 URL

3、通过对应的 json 数据格式,websocket 进行建立连接请求

4、这里是流式返回,对应解析数据格式,得到返回的信息

5、返回的关键信息结构,有些类似 gpt 的数据格式,用过的话,使用起来会很快

三、注意事项

1、注意 code 返回码,不同的返回码可以进行不同处理,避免产生意想不到的问题

2、注意 sid 的区分,如果上一次返回没有结束,关闭连接后,重新发起新的访问,可能会同时接收到上一次的未结束的数据流,和当次的数据流;如果不想接收到,注意通过 sid 进行区分;

3、注意在 LLMConfig 配置你的 APP_ID 等相关信息

四、效果预览

五、案例简单实现步骤

1、首先到讯飞官网获取对应的星火大模型的 APP_ID 等相关自己星火大模型的信息

讯飞星火认知大模型-AI大语言模型-星火大模型-科大讯飞

2、打开Unity ,简单搭建一个场景

3、可以参考星火大模型的相关demo,完成对应的讯飞大模型接口封装

这里包括 IIFlyLLMHandler(接口类,可以根据自己需要重新定义接口),BaseIFlyLLMHandler(基类),IFlyLLMHandler(基本的讯飞接口大模型类),AutoReConnectIFlyLLMHandler(待自动重连的讯飞接口大模型类)

4、完成对应接口的封装之后,添加一个简单的测试类 TestIFlyLLMHandler

5、把 TestIFlyLLMHandler  添加到场景中,比对应赋值

6、运行结果如上

六、关键代码

1、TestIFlyLLMHandler

  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. using UnityEngine.UI;
  4. public class TestIFlyLLMHandler : MonoBehaviour
  5. {
  6. public Text TagrgetText;
  7. public InputField TagrgetInputField;
  8. public Button TagrgetButton;
  9. List<string> m_StrLst = new List<string>() {
  10. "你是谁",
  11. "最近天气"
  12. };
  13. IIFlyLLMHandler m_Handler;
  14. // Start is called before the first frame update
  15. void Start()
  16. {
  17. m_Handler = new IFlyLLMHandler();
  18. m_Handler.Initialized();
  19. TagrgetText.text = "";
  20. m_Handler.OnMessageReceivedAction = (jsonResponse) => { TagrgetText.text += jsonResponse.payload.choices.text[0].content; };
  21. TagrgetButton.onClick.AddListener(() => {
  22. TagrgetText.text = "";
  23. m_Handler.SendMsg(TagrgetInputField.text);
  24. });
  25. }
  26. // Update is called once per frame
  27. void Update()
  28. {
  29. if (Input.anyKeyDown) {
  30. //m_Handler.SendMsg(m_StrLst[Random.Range(0,m_StrLst.Count)]);
  31. }
  32. }
  33. }

2、IFlyLLMHandler

  1. using BestHTTP.WebSocket;
  2. using System;
  3. using UnityEngine;
  4. /// <summary>
  5. /// 使用讯飞大模型
  6. /// </summary>
  7. public class IFlyLLMHandler : BaseIFlyLLMHandler
  8. {
  9. #region Data
  10. /// <summary>
  11. /// 发送连接服务器失败事件
  12. /// </summary>
  13. int m_TimerServerAccessFailure = -1;
  14. const float INTERVAL_TIME_SEND_SERVER_ACCESS_FAILURE = 4.0f;
  15. #endregion
  16. #region interface function
  17. /// <summary>
  18. /// 初始化
  19. /// </summary>
  20. public override void Initialized()
  21. {
  22. base.Initialized();
  23. }
  24. /// <summary>
  25. /// 发送数据
  26. /// </summary>
  27. /// <param name="askContent"></param>
  28. public override void SendMsg(string askContent)
  29. {
  30. try
  31. {
  32. CacheHistory(askContent);
  33. Connect();
  34. }
  35. catch (Exception e)
  36. {
  37. Debug.LogError($"e.ToString() {e.ToString()}\ne.Message {e.Message}");
  38. }
  39. }
  40. #endregion
  41. #region Websocket回调
  42. /// <summary>
  43. /// 建立连接事件
  44. /// </summary>
  45. /// <param name="ws"></param>
  46. protected override void OnWebSocketOpen(WebSocket ws)
  47. {
  48. Debug.Log("WebSocket Connected!");
  49. Send();
  50. }
  51. /// <summary>
  52. /// 连接错误信息
  53. /// </summary>
  54. /// <param name="ws"></param>
  55. /// <param name="ex"></param>
  56. protected override void OnWebSocketError(WebSocket ws, Exception ex)
  57. {
  58. base.OnWebSocketError(ws, ex);
  59. SendServerAccessFailure(1005);
  60. }
  61. /// <summary>
  62. /// 连接关闭事件
  63. /// </summary>
  64. /// <param name="ws"></param>
  65. /// <param name="code"></param>
  66. /// <param name="message"></param>
  67. protected override void OnWebSocketClosed(WebSocket ws, ushort code, string message)
  68. {
  69. base.OnWebSocketClosed(ws, code, message);
  70. SendServerAccessFailure(code);
  71. }
  72. #endregion
  73. #region private function
  74. /// <summary>
  75. /// 发送服务器连接失败错误
  76. /// </summary>
  77. /// <param name="code"></param>
  78. private void SendServerAccessFailure(UInt16 code)
  79. {
  80. if (code == 1005) // 连接失败错误码
  81. {
  82. if (m_TimerServerAccessFailure != -1) return;
  83. m_TimerServerAccessFailure = Timer.Instance.Post2Scale((index) => {
  84. Debug.Log("[BubbleChatUseIFlyLLMHandler] SendServerAccessFailure");
  85. m_TimerServerAccessFailure = -1;
  86. }, INTERVAL_TIME_SEND_SERVER_ACCESS_FAILURE);
  87. }
  88. }
  89. #endregion
  90. }

3、BaseIFlyLLMHandler

  1. using Newtonsoft.Json;
  2. using System;
  3. using UnityEngine;
  4. using System.Text;
  5. using BestHTTP.WebSocket;
  6. using System.Collections.Generic;
  7. /**
  8. * 星火认知大模型 WebAPI 接口调用示例 接口文档(必看):https://www.xfyun.cn/doc/spark/Web.html
  9. * 错误码链接:https://www.xfyun.cn/doc/spark/%E6%8E%A5%E5%8F%A3%E8%AF%B4%E6%98%8E.html (code返回错误码时必看)
  10. * @author iflytek
  11. */
  12. /// <summary>
  13. /// 讯飞大模型基类
  14. /// </summary>
  15. public class BaseIFlyLLMHandler : IIFlyLLMHandler
  16. {
  17. #region Data
  18. /// <summary>
  19. /// WebSocket
  20. /// </summary>
  21. protected WebSocket m_WebSocket;
  22. /// <summary>
  23. /// 缓存的历史数据的队列
  24. /// </summary>
  25. protected List<IIFlyLLMHandler.Content> m_CacheHistory = new List<IIFlyLLMHandler.Content>();
  26. /// <summary>
  27. /// 是否读完
  28. /// </summary>
  29. protected bool m_ReadEnd = true;
  30. /// <summary>
  31. /// 是否需要重发
  32. /// </summary>
  33. protected bool m_NeedSend = false;
  34. /// <summary>
  35. /// 大模型的配置
  36. /// </summary>
  37. protected LLMConfig m_Config;
  38. /// <summary>
  39. /// 记录上一个老的 sid ,因为打断后,如果上一次的没有传输完,下一次连接依然会接收到该 sid 的数据流
  40. /// </summary>
  41. protected string m_OldSid = "";
  42. /// <summary>
  43. /// // 用来记录中间的sid ,因为可能被打断(不一定每次都能完全正常流程接收完数据)
  44. /// </summary>
  45. protected string m_RcdSid = "";
  46. /// <summary>
  47. /// 接收到数据的事件
  48. /// </summary>
  49. public Action<IIFlyLLMHandler.JsonResponse> OnMessageReceivedAction { get; set; }
  50. #endregion
  51. #region interface function
  52. /// <summary>
  53. /// 初始化
  54. /// </summary>
  55. public virtual void Initialized()
  56. {
  57. m_Config = new LLMConfig();
  58. }
  59. /// <summary>
  60. /// 连接
  61. /// </summary>
  62. public virtual void Connect()
  63. {
  64. if (m_WebSocket != null)
  65. {
  66. Close();
  67. }
  68. string authUrl = GetAuthUrl();
  69. string url = authUrl.Replace("http://", "ws://").Replace("https://", "wss://");
  70. m_WebSocket = new WebSocket(new Uri(url));
  71. m_WebSocket.OnOpen += OnWebSocketOpen;
  72. m_WebSocket.OnMessage += OnWebSocketMessage;
  73. m_WebSocket.OnError += OnWebSocketError;
  74. m_WebSocket.OnClosed += OnWebSocketClosed;
  75. m_WebSocket.Open();
  76. }
  77. /// <summary>
  78. /// 关闭
  79. /// </summary>
  80. public virtual void Close()
  81. {
  82. m_OldSid = m_RcdSid;
  83. m_WebSocket?.Close();
  84. m_WebSocket = null;
  85. }
  86. /// <summary>
  87. /// 重置
  88. /// </summary>
  89. public virtual void Reset()
  90. {
  91. m_CacheHistory.Clear();
  92. }
  93. /// <summary>
  94. /// 发送消息
  95. /// </summary>
  96. /// <param name="history"></param>
  97. public virtual void SendMsg(string askContent)
  98. {
  99. try
  100. {
  101. CacheHistory(askContent);
  102. if (m_WebSocket != null && m_WebSocket.IsOpen)
  103. {
  104. if (m_ReadEnd)
  105. {
  106. Send();
  107. }
  108. else
  109. {
  110. //中断websocket,然后再发送
  111. Close();
  112. m_NeedSend = true;
  113. }
  114. }
  115. else
  116. {
  117. m_NeedSend = true;
  118. Connect();
  119. }
  120. }
  121. catch (Exception e)
  122. {
  123. Debug.LogError(e.Message);
  124. }
  125. }
  126. #endregion
  127. #region Websocket回调
  128. /// <summary>
  129. /// 建立连接的事件
  130. /// </summary>
  131. /// <param name="ws"></param>
  132. protected virtual void OnWebSocketOpen(WebSocket ws)
  133. {
  134. Debug.Log("WebSocket Connected!");
  135. if (m_NeedSend) Send();
  136. }
  137. /// <summary>
  138. /// 接收到数据的事件
  139. /// </summary>
  140. /// <param name="ws"></param>
  141. /// <param name="message"></param>
  142. protected virtual void OnWebSocketMessage(WebSocket ws, string message)
  143. {
  144. // 处理接收到的消息
  145. // 这里你可以根据需要进行相应的处理
  146. Debug.Log($"Received message: {message}");
  147. IIFlyLLMHandler.JsonResponse jsonResponse = JsonConvert.DeserializeObject<IIFlyLLMHandler.JsonResponse>(message);
  148. if (jsonResponse.header.code == 10013) // 错误码 10013:输入内容审核不通过,涉嫌违规,请重新调整输入内容
  149. {
  150. Debug.LogError($"OnWebSocketMessage message {jsonResponse.header.message} ");
  151. }
  152. else
  153. {
  154. Debug.Log($"OnWebSocketMessage m_OldSid {m_OldSid}, jsonResponse.header.sid {jsonResponse.header.sid} jsonResponse.header.code {jsonResponse.header.code}");
  155. // 判断不是上一次的 sid 的旧的数据流在做出反应
  156. if (jsonResponse.header.sid.Equals(m_OldSid) == false)
  157. {
  158. if (jsonResponse.header.code == 10014) // 错误码 10014:输出内容涉及敏感信息,审核不通过,后续结果无法展示给用户
  159. {
  160. jsonResponse=GetHandleJsonResponse(jsonResponse);
  161. }
  162. OnMessageReceivedAction?.Invoke(jsonResponse);
  163. m_RcdSid = jsonResponse.header.sid;
  164. }
  165. }
  166. if (jsonResponse.payload.choices.status == 0)
  167. {
  168. Debug.Log("Get First IFlyLLM Response");
  169. }
  170. if (jsonResponse.payload.choices.status == 2)
  171. {
  172. m_ReadEnd = true;
  173. Debug.Log("Get Last IFlyLLM Response");
  174. m_OldSid = jsonResponse.header.sid;
  175. }
  176. }
  177. /// <summary>
  178. /// 连接发生错误的事件
  179. /// </summary>
  180. /// <param name="ws"></param>
  181. /// <param name="ex"></param>
  182. protected virtual void OnWebSocketError(WebSocket ws, Exception ex)
  183. {
  184. Debug.LogError($"WebSocket Error: {ex.Message}");
  185. }
  186. /// <summary>
  187. /// 连接关闭的事件
  188. /// </summary>
  189. /// <param name="ws"></param>
  190. /// <param name="code"></param>
  191. /// <param name="message"></param>
  192. protected virtual void OnWebSocketClosed(WebSocket ws, UInt16 code, string message)
  193. {
  194. Debug.LogFormat("WebSocket Closed!: code={0}, msg={1}", code, message);
  195. }
  196. #endregion
  197. #region protected function
  198. /// <summary>
  199. /// 真正发送数据
  200. /// </summary>
  201. protected virtual void Send()
  202. {
  203. m_NeedSend = false;
  204. m_ReadEnd = false;
  205. IIFlyLLMHandler.JsonRequest request = CreateRequest();
  206. string jsonString = JsonConvert.SerializeObject(request);
  207. Debug.LogError(jsonString);
  208. m_WebSocket?.Send(jsonString);
  209. }
  210. /// <summary>
  211. /// 创建一个连接请求
  212. /// </summary>
  213. /// <returns></returns>
  214. protected virtual IIFlyLLMHandler.JsonRequest CreateRequest()
  215. {
  216. return new IIFlyLLMHandler.JsonRequest
  217. {
  218. header = new IIFlyLLMHandler.Header
  219. {
  220. app_id = m_Config.IFLY_APPID,
  221. uid = Guid.NewGuid().ToString().Substring(0, 10)
  222. },
  223. parameter = new IIFlyLLMHandler.Parameter
  224. {
  225. chat = new IIFlyLLMHandler.Chat
  226. {
  227. domain = "generalv3",
  228. temperature = 0.01,
  229. max_tokens = 480
  230. }
  231. },
  232. payload = new IIFlyLLMHandler.Payload
  233. {
  234. message = new IIFlyLLMHandler.Message
  235. {
  236. text = m_CacheHistory
  237. }
  238. }
  239. };
  240. }
  241. /// <summary>
  242. /// 缓存历史记录数据结构,优化性能
  243. /// (缓存需要自己额外补充,这里先做简单的提问)
  244. /// </summary>
  245. protected virtual void CacheHistory(string askContent)
  246. {
  247. m_CacheHistory.Clear();
  248. IIFlyLLMHandler.Content content = new IIFlyLLMHandler.Content();
  249. content.role = "user";
  250. content.content = askContent;
  251. m_CacheHistory.Add(content);
  252. }
  253. /// <summary>
  254. /// 敏感输出内容后的处理
  255. /// 重新组织数据(涉及敏感内容不予展示)
  256. /// </summary>
  257. /// <param name="jsonResponse"></param>
  258. /// <returns></returns>
  259. protected virtual IIFlyLLMHandler.JsonResponse GetHandleJsonResponse(IIFlyLLMHandler.JsonResponse jsonResponse) {
  260. int status = 2;
  261. IIFlyLLMHandler.HeaderResponse header = new IIFlyLLMHandler.HeaderResponse() { code = 0, message = "Success", sid = jsonResponse.header.sid, status = status };
  262. IIFlyLLMHandler.Text text = new IIFlyLLMHandler.Text() {content="***(涉及敏感内容不予展示)。",role= "assistant",index=0 };
  263. List<IIFlyLLMHandler.Text> textlst = new List<IIFlyLLMHandler.Text>();
  264. textlst.Add(text);
  265. IIFlyLLMHandler.Choices choices = new IIFlyLLMHandler.Choices() { status= status, seq=999,text=textlst};
  266. IIFlyLLMHandler.PayloadResponse payload = new IIFlyLLMHandler.PayloadResponse() { choices=choices};
  267. IIFlyLLMHandler.JsonResponse reorganizingInformationJRspn = new IIFlyLLMHandler.JsonResponse() {header=header,payload=payload };
  268. return reorganizingInformationJRspn;
  269. }
  270. #endregion
  271. #region 字符串操作
  272. /// <summary>
  273. /// 生成得到授权的 URL
  274. /// </summary>
  275. /// <returns></returns>
  276. private string GetAuthUrl()
  277. {
  278. string date = DateTime.UtcNow.ToString("r");
  279. Uri uri = new Uri(m_Config.IFLY_HOST_URL);
  280. StringBuilder builder = new StringBuilder("host: ").Append(uri.Host).Append("\n").//
  281. Append("date: ").Append(date).Append("\n").//
  282. Append("GET ").Append(uri.LocalPath).Append(" HTTP/1.1");
  283. string sha = HMACsha256(m_Config.IFLY_API_SECRET, builder.ToString());
  284. string authorization = string.Format("api_key=\"{0}\", algorithm=\"{1}\", headers=\"{2}\", signature=\"{3}\"", m_Config.IFLY_API_KEY, "hmac-sha256", "host date request-line", sha);
  285. string NewUrl = "https://" + uri.Host + uri.LocalPath;
  286. string path1 = "authorization" + "=" + Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(authorization));
  287. date = date.Replace(" ", "%20").Replace(":", "%3A").Replace(",", "%2C");
  288. string path2 = "date" + "=" + date;
  289. string path3 = "host" + "=" + uri.Host;
  290. NewUrl = NewUrl + "?" + path1 + "&" + path2 + "&" + path3;
  291. return NewUrl;
  292. }
  293. /// <summary>
  294. /// HMACsha256
  295. /// </summary>
  296. /// <param name="apiSecretIsKey"></param>
  297. /// <param name="buider"></param>
  298. /// <returns></returns>
  299. private string HMACsha256(string apiSecretIsKey, string buider)
  300. {
  301. byte[] bytes = System.Text.Encoding.UTF8.GetBytes(apiSecretIsKey);
  302. System.Security.Cryptography.HMACSHA256 hMACSHA256 = new System.Security.Cryptography.HMACSHA256(bytes);
  303. byte[] date = System.Text.Encoding.UTF8.GetBytes(buider);
  304. date = hMACSHA256.ComputeHash(date);
  305. hMACSHA256.Clear();
  306. return Convert.ToBase64String(date);
  307. }
  308. #endregion
  309. }

4、IIFlyLLMHandler

  1. using System;
  2. using System.Collections.Generic;
  3. /// <summary>
  4. /// 讯飞大模型接口类
  5. /// </summary>
  6. public interface IIFlyLLMHandler
  7. {
  8. /// <summary>
  9. /// 初始化
  10. /// </summary>
  11. void Initialized();
  12. /// <summary>
  13. /// 连接
  14. /// </summary>
  15. void Connect();
  16. /// <summary>
  17. /// 关闭连接
  18. /// </summary>
  19. void Close();
  20. /// <summary>
  21. /// 重置
  22. /// </summary>
  23. void Reset();
  24. /// <summary>
  25. /// 发送信息
  26. /// </summary>
  27. /// <param name="askContent"></param>
  28. void SendMsg(string askContent);
  29. /// <summary>
  30. /// 接收到数据事件
  31. /// </summary>
  32. Action<JsonResponse> OnMessageReceivedAction { get; set; }
  33. #region Request数据类定义
  34. public class JsonRequest
  35. {
  36. public Header header { get; set; }
  37. public Parameter parameter { get; set; }
  38. public Payload payload { get; set; }
  39. }
  40. public class Header
  41. {
  42. public string app_id { get; set; }
  43. public string uid { get; set; }
  44. }
  45. public class Parameter
  46. {
  47. public Chat chat { get; set; }
  48. }
  49. public class Chat
  50. {
  51. public string domain { get; set; }
  52. public double temperature { get; set; }
  53. public int max_tokens { get; set; }
  54. }
  55. public class Payload
  56. {
  57. public Message message { get; set; }
  58. }
  59. public class Message
  60. {
  61. public List<Content> text { get; set; }
  62. }
  63. public class Content
  64. {
  65. public string role { get; set; }
  66. public string content { get; set; }
  67. }
  68. #endregion
  69. #region Response数据类型定义
  70. public class JsonResponse
  71. {
  72. public HeaderResponse header { get; set; }
  73. public PayloadResponse payload { get; set; }
  74. }
  75. public class HeaderResponse
  76. {
  77. public int code { get; set; }
  78. public string message { get; set; }
  79. public string sid { get; set; }
  80. public int status { get; set; }
  81. }
  82. public class PayloadResponse
  83. {
  84. public Choices choices { get; set; }
  85. }
  86. public class Choices
  87. {
  88. public int status { get; set; }
  89. public int seq { get; set; }
  90. public List<Text> text { get; set; }
  91. }
  92. public class Text
  93. {
  94. public string content { get; set; }
  95. public string role { get; set; }
  96. public int index { get; set; }
  97. }
  98. #endregion
  99. }

5、LLMConfig

  1. public class LLMConfig
  2. {
  3. #region 讯飞
  4. /// <summary>
  5. /// 应用APPID(必须为webapi类型应用,并开通星火认知大模型授权)
  6. /// </summary>
  7. public readonly string IFLY_APPID = "YOUR_IFLY_APPID";
  8. /// <summary>
  9. /// 接口密钥(webapi类型应用开通星火认知大模型后,控制台--我的应用---星火认知大模型---相应服务的apikey)
  10. /// </summary>
  11. public readonly string IFLY_API_SECRET = "YOUR_IFLY_API_SECRET";
  12. /// <summary>
  13. /// 接口密钥(webapi类型应用开通星火认知大模型后,控制台--我的应用---星火认知大模型---相应服务的apisecret)
  14. /// </summary>
  15. public readonly string IFLY_API_KEY = "YOUR_IFLY_API_KEY";
  16. /// <summary>
  17. /// 讯飞大模型访问地址
  18. /// </summary>
  19. public readonly string IFLY_HOST_URL = "https://spark-api.xf-yun.com/v3.1/chat";
  20. /// <summary>
  21. /// 讯飞图像识别
  22. /// </summary>
  23. public readonly string IFLY_IMAGE_RECOGNIZE_URL = "wss://spark-api.cn-huabei-1.xf-yun.com/v2.1/image";
  24. #endregion
  25. }

6、AutoReConnectIFlyLLMHandler

  1. using BestHTTP.WebSocket;
  2. using System;
  3. using UnityEngine;
  4. /// <summary>
  5. /// 带自动重连的讯飞大模型访问
  6. /// </summary>
  7. public class AutoReConnectIFlyLLMHandler : BaseIFlyLLMHandler
  8. {
  9. #region Data
  10. /// <summary>
  11. /// m_ReconnectTimerId :自动重连的 TimerId
  12. /// </summary>
  13. int m_ReconnectTimerId = -1;
  14. /// <summary>
  15. /// m_ReconnectDelay : 自动重连的 时间
  16. /// </summary>
  17. float m_ReconnectDelay = 0.5f;
  18. #endregion
  19. #region interface function
  20. /// <summary>
  21. /// 初始化
  22. /// </summary>
  23. public override void Initialized()
  24. {
  25. base.Initialized();
  26. Connect();
  27. }
  28. /// <summary>
  29. /// 关闭连接
  30. /// </summary>
  31. public override void Close()
  32. {
  33. CancelReconnectTimer();
  34. base.Close();
  35. }
  36. /// <summary>
  37. /// 自动重连
  38. /// </summary>
  39. internal void AutoReconnect()
  40. {
  41. Connect();
  42. }
  43. /// <summary>
  44. /// 发送请求
  45. /// </summary>
  46. /// <param name="askContent"></param>
  47. public override void SendMsg(string askContent)
  48. {
  49. try
  50. {
  51. CacheHistory(askContent);
  52. if (m_WebSocket != null && m_WebSocket.IsOpen)
  53. {
  54. if (m_ReadEnd)
  55. {
  56. Send();
  57. }
  58. else
  59. {
  60. //中断websocket,然后再发送
  61. Close();
  62. m_NeedSend = true;
  63. }
  64. }
  65. else
  66. {
  67. m_NeedSend = true;
  68. }
  69. }
  70. catch (Exception e)
  71. {
  72. Debug.LogError(e.Message);
  73. }
  74. }
  75. #endregion
  76. #region Websocket回调
  77. /// <summary>
  78. /// 关闭连接事件
  79. /// </summary>
  80. /// <param name="ws"></param>
  81. /// <param name="code"></param>
  82. /// <param name="message"></param>
  83. protected override void OnWebSocketClosed(WebSocket ws, ushort code, string message)
  84. {
  85. base.OnWebSocketClosed(ws, code, message);
  86. RunReconnectTimer();
  87. }
  88. /// <summary>
  89. /// 连接发生错误的事件
  90. /// </summary>
  91. /// <param name="ws"></param>
  92. /// <param name="ex"></param>
  93. protected override void OnWebSocketError(WebSocket ws, Exception ex)
  94. {
  95. base.OnWebSocketError(ws, ex);
  96. RunReconnectTimer();
  97. }
  98. #endregion
  99. #region 计时器
  100. /// <summary>
  101. /// 计时自动重新连接
  102. /// </summary>
  103. private void RunReconnectTimer()
  104. {
  105. Debug.Log($"Scheduling reconnect in {m_ReconnectDelay} seconds...");
  106. CancelReconnectTimer();
  107. m_ReconnectTimerId = Timer.Instance.Post2Really((v) => { AutoReconnect(); }, m_ReconnectDelay);
  108. }
  109. /// <summary>
  110. /// 取消重新连接计时
  111. /// </summary>
  112. private void CancelReconnectTimer()
  113. {
  114. if (m_ReconnectTimerId != -1)
  115. {
  116. Timer.Instance.Cancel(m_ReconnectTimerId);
  117. m_ReconnectTimerId = -1;
  118. }
  119. }
  120. #endregion
  121. }

七、案例下载地址

https://download.csdn.net/download/u014361280/88565465

补充、讯飞大模型-图像识别

1、IFlyLLMImageHandler

  1. using UnityEngine;
  2. using System;
  3. using System.Text;
  4. using Newtonsoft.Json;
  5. using BestHTTP.WebSocket;
  6. using System.Collections.Generic;
  7. public class IFlyLLMImageHandler
  8. {
  9. private WebSocket m_WebSocket;
  10. private int m_ReconnectTimerId = -1;
  11. private float m_ReconnectDelay = 0.5f;
  12. private List<Content> m_CacheHistory = new List<Content>();
  13. public Action<JsonResponse> OnMessageReceivedAction;
  14. private bool m_ReadEnd = true;
  15. private bool m_NeedSend = false;
  16. private LLMConfig m_Config;
  17. public void Initialized()
  18. {
  19. m_Config = new LLMConfig();
  20. Connect();
  21. }
  22. /// <summary>
  23. /// 连接
  24. /// </summary>
  25. public void Connect()
  26. {
  27. if (m_WebSocket != null)
  28. {
  29. Close();
  30. }
  31. string authUrl = GetAuthUrl();
  32. string url = authUrl.Replace("http://", "ws://").Replace("https://", "wss://");
  33. m_WebSocket = new WebSocket(new Uri(url));
  34. m_WebSocket.OnOpen += OnWebSocketOpen;
  35. m_WebSocket.OnMessage += OnWebSocketMessage;
  36. m_WebSocket.OnError += OnWebSocketError;
  37. m_WebSocket.OnClosed += OnWebSocketClosed;
  38. m_WebSocket.Open();
  39. }
  40. /// <summary>
  41. /// 关闭
  42. /// </summary>
  43. public void Close()
  44. {
  45. CancelReconnectTimer();
  46. m_WebSocket?.Close();
  47. m_WebSocket = null;
  48. }
  49. public void Reset()
  50. {
  51. m_CacheHistory.Clear();
  52. }
  53. /// <summary>
  54. /// 自动重连
  55. /// </summary>
  56. private void AutoReconnect()
  57. {
  58. Connect();
  59. }
  60. /// <summary>
  61. /// 发送消息
  62. /// </summary>
  63. /// <param name="history"></param>
  64. public void SendMsg(string base64,string ask)
  65. {
  66. try
  67. {
  68. ImageDataAsk(base64, ask);
  69. if (m_WebSocket != null && m_WebSocket.IsOpen)
  70. {
  71. if (m_ReadEnd)
  72. {
  73. Send();
  74. }
  75. else
  76. {
  77. //中断websocket,然后再发送
  78. Close();
  79. m_NeedSend = true;
  80. }
  81. }
  82. else
  83. {
  84. m_NeedSend = true;
  85. }
  86. }
  87. catch (Exception e)
  88. {
  89. Debug.LogError(e.Message);
  90. }
  91. }
  92. private void Send()
  93. {
  94. m_NeedSend = false;
  95. m_ReadEnd = false;
  96. JsonRequest request = CreateRequest();
  97. string jsonString = JsonConvert.SerializeObject(request);
  98. Debug.LogError(jsonString);
  99. m_WebSocket?.Send(jsonString);
  100. }
  101. #region Websocket回调
  102. private void OnWebSocketOpen(WebSocket ws)
  103. {
  104. Debug.Log("WebSocket Connected!");
  105. if (m_NeedSend) Send();
  106. }
  107. private void OnWebSocketMessage(WebSocket ws, string message)
  108. {
  109. // 处理接收到的消息
  110. // 这里你可以根据需要进行相应的处理
  111. Debug.Log($"Received message: {message}");
  112. JsonResponse jsonResponse = JsonConvert.DeserializeObject<IFlyLLMImageHandler.JsonResponse>(message);
  113. OnMessageReceivedAction?.Invoke(jsonResponse);
  114. if (jsonResponse.payload.choices.status == 0)
  115. {
  116. Debug.Log("Get First IFlyLLM Response");
  117. }
  118. if (jsonResponse.payload.choices.status == 2)
  119. {
  120. m_ReadEnd = true;
  121. Debug.Log("Get Last IFlyLLM Response");
  122. }
  123. }
  124. private void OnWebSocketError(WebSocket ws, Exception ex)
  125. {
  126. Debug.LogError($"WebSocket Error: {ex.Message}");
  127. RunReconnectTimer();
  128. }
  129. private void OnWebSocketClosed(WebSocket ws, UInt16 code, string message)
  130. {
  131. Debug.LogFormat("WebSocket Closed!: code={0}, msg={1}", code, message);
  132. RunReconnectTimer();
  133. }
  134. #endregion
  135. private JsonRequest CreateRequest()
  136. {
  137. return new JsonRequest
  138. {
  139. header = new Header
  140. {
  141. app_id = m_Config.IFLY_APPID,
  142. uid = Guid.NewGuid().ToString().Substring(0, 10)
  143. },
  144. parameter = new Parameter
  145. {
  146. chat = new Chat
  147. {
  148. domain = "general",
  149. temperature = 0.5,
  150. top_k= 4,
  151. max_tokens = 2048,
  152. auditing = "default"
  153. }
  154. },
  155. payload = new Payload
  156. {
  157. message = new Message
  158. {
  159. text = m_CacheHistory
  160. }
  161. }
  162. };
  163. }
  164. private void ImageDataAsk(string base64,string ask) {
  165. m_CacheHistory.Clear();
  166. Content content = new Content();
  167. content.role = "user";
  168. content.content = base64;
  169. content.content_type = "image";
  170. m_CacheHistory.Add(content);
  171. content = new Content();
  172. content.role = "user";
  173. content.content = ask;
  174. content.content_type = "text";
  175. m_CacheHistory.Add(content);
  176. }
  177. #region 计时器
  178. private void RunReconnectTimer()
  179. {
  180. Debug.Log($"Scheduling reconnect in {m_ReconnectDelay} seconds...");
  181. CancelReconnectTimer();
  182. m_ReconnectTimerId = Timer.Instance.Post2Really((v) => { AutoReconnect(); }, m_ReconnectDelay);
  183. }
  184. private void CancelReconnectTimer()
  185. {
  186. if (m_ReconnectTimerId != -1)
  187. {
  188. Timer.Instance.Cancel(m_ReconnectTimerId);
  189. m_ReconnectTimerId = -1;
  190. }
  191. }
  192. #endregion
  193. #region 字符串操作
  194. private string GetAuthUrl()
  195. {
  196. string date = DateTime.UtcNow.ToString("r");
  197. Uri uri = new Uri(m_Config.IFLY_IMAGE_RECOGNIZE_URL);
  198. StringBuilder builder = new StringBuilder("host: ").Append(uri.Host).Append("\n").//
  199. Append("date: ").Append(date).Append("\n").//
  200. Append("GET ").Append(uri.LocalPath).Append(" HTTP/1.1");
  201. string sha = HMACsha256(m_Config.IFLY_API_SECRET, builder.ToString());
  202. string authorization = string.Format("api_key=\"{0}\", algorithm=\"{1}\", headers=\"{2}\", signature=\"{3}\"", m_Config.IFLY_API_KEY, "hmac-sha256", "host date request-line", sha);
  203. string NewUrl = "https://" + uri.Host + uri.LocalPath;
  204. string path1 = "authorization" + "=" + Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(authorization));
  205. date = date.Replace(" ", "%20").Replace(":", "%3A").Replace(",", "%2C");
  206. string path2 = "date" + "=" + date;
  207. string path3 = "host" + "=" + uri.Host;
  208. NewUrl = NewUrl + "?" + path1 + "&" + path2 + "&" + path3;
  209. return NewUrl;
  210. }
  211. private string HMACsha256(string apiSecretIsKey, string buider)
  212. {
  213. byte[] bytes = System.Text.Encoding.UTF8.GetBytes(apiSecretIsKey);
  214. System.Security.Cryptography.HMACSHA256 hMACSHA256 = new System.Security.Cryptography.HMACSHA256(bytes);
  215. byte[] date = System.Text.Encoding.UTF8.GetBytes(buider);
  216. date = hMACSHA256.ComputeHash(date);
  217. hMACSHA256.Clear();
  218. return Convert.ToBase64String(date);
  219. }
  220. #endregion
  221. #region Request数据类定义
  222. public class JsonRequest
  223. {
  224. public Header header { get; set; }
  225. public Parameter parameter { get; set; }
  226. public Payload payload { get; set; }
  227. }
  228. public class Header
  229. {
  230. public string app_id { get; set; }
  231. public string uid { get; set; }
  232. }
  233. public class Parameter
  234. {
  235. public Chat chat { get; set; }
  236. }
  237. public class Chat
  238. {
  239. public string domain { get; set; }
  240. public double temperature { get; set; }
  241. public int top_k { get; set; }
  242. public int max_tokens { get; set; }
  243. public string auditing { get; set; }
  244. }
  245. public class Payload
  246. {
  247. public Message message { get; set; }
  248. }
  249. public class Message
  250. {
  251. public List<Content> text { get; set; }
  252. }
  253. public class Content
  254. {
  255. public string role { get; set; }
  256. public string content { get; set; }
  257. public string content_type { get; set; }
  258. }
  259. #endregion
  260. #region Response数据类型定义
  261. public class JsonResponse
  262. {
  263. public HeaderResponse header { get; set; }
  264. public PayloadResponse payload { get; set; }
  265. }
  266. public class HeaderResponse
  267. {
  268. public int code { get; set; }
  269. public string message { get; set; }
  270. public string sid { get; set; }
  271. public int status { get; set; }
  272. }
  273. public class PayloadResponse
  274. {
  275. public Choices choices { get; set; }
  276. public Usage usage { get; set; }
  277. }
  278. public class Choices
  279. {
  280. public int status { get; set; }
  281. public int seq { get; set; }
  282. public List<Text> text { get; set; }
  283. }
  284. public class Text
  285. {
  286. public string content { get; set; }
  287. public string role { get; set; }
  288. public int index { get; set; }
  289. }
  290. public class Usage
  291. {
  292. public UsageText text { get; set; }
  293. }
  294. public class UsageText {
  295. public int completion_tokens { get; set; }
  296. public int question_tokens { get; set; }
  297. public int prompt_tokens { get; set; }
  298. public int total_tokens { get; set; }
  299. }
  300. #endregion
  301. }

2、TestIFlyLLMImageHandler

  1. using UnityEngine;
  2. public class TestIFlyLLMImageHandler : Singleton<TestIFlyLLMImageHandler>
  3. {
  4. public void Test() {
  5. IFlyLLMImageHandler imageHandler = new IFlyLLMImageHandler();
  6. imageHandler.Initialized();
  7. imageHandler.OnMessageReceivedAction += (str) => {
  8. Debug.Log(" TestIFlyLLMImageHandler OnMessageReceivedAction " + str.payload.choices.text[0].content);
  9. };
  10. CameraCaptureImageForBase64.Instance.OnGetBase64ImageSuccess = (base64) =>
  11. {
  12. imageHandler.SendMsg(base64, "这是什么,尽可能详细的回答");
  13. };
  14. CameraCaptureImageForBase64.Instance.OnGetBase64ImageFailed = async (str) =>
  15. {
  16. string base64 = await ImageLoader.Instance.LoadImageAndConvertToBase64();
  17. imageHandler.SendMsg(base64, "这是什么,尽可能详细的回答");
  18. };
  19. CameraCaptureImageForBase64.Instance.CaptureImage();
  20. }
  21. }

3、CameraCaptureImageForBase64

  1. using System;
  2. using System.Collections;
  3. using UnityEngine;
  4. using UnityEngine.Android;
  5. /// <summary>
  6. /// 打开 Camera 捕捉图片,获取图片 base64 信息
  7. /// </summary>
  8. public class CameraCaptureImageForBase64 : MonoSingleton<CameraCaptureImageForBase64>
  9. {
  10. #region data
  11. /// <summary>
  12. /// 获取图片成功事件
  13. /// </summary>
  14. public Action<string> OnGetBase64ImageSuccess;
  15. /// <summary>
  16. /// 获取图片失败事件
  17. /// </summary>
  18. public Action<string> OnGetBase64ImageFailed;
  19. private WebCamTexture webcamTexture; // 用于获取相机图像
  20. private Coroutine m_Coroutine;
  21. #endregion
  22. /// <summary>
  23. /// 捕捉图片
  24. /// </summary>
  25. public void CaptureImage()
  26. {
  27. m_Coroutine = StartCoroutine(CaptureRoutine());
  28. }
  29. /// <summary>
  30. /// 停止捕捉
  31. /// </summary>
  32. public void StopCapture()
  33. {
  34. if (m_Coroutine!=null)
  35. {
  36. StopCoroutine(m_Coroutine);
  37. m_Coroutine = null;
  38. }
  39. }
  40. #region private function
  41. private IEnumerator CaptureRoutine()
  42. {
  43. // 检查是否有相机权限
  44. if (!Permission.HasUserAuthorizedPermission(Permission.Camera))
  45. {
  46. // 如果没有相机权限,等待用户授权
  47. yield return RequestCameraPermission();
  48. }
  49. // 启动相机
  50. StartCamera();
  51. // 等待用户拍照
  52. yield return WaitForUserToTakePhoto();
  53. // 拍照
  54. Texture2D photo = TakePhoto();
  55. if (photo != null)
  56. {
  57. // 将Texture2D转换为byte数组
  58. byte[] imageBytes = photo.EncodeToPNG();
  59. // 将byte数组转换为base64字符串
  60. string base64String = Convert.ToBase64String(imageBytes);
  61. Debug.Log("Base64 Image: " + base64String);
  62. // 在这里执行你的异步任务,例如上传base64图片到服务器
  63. OnGetBase64ImageSuccess?.Invoke(base64String);
  64. }
  65. else {
  66. OnGetBase64ImageFailed?.Invoke("capture image failed.");
  67. }
  68. // 停止相机
  69. StopCamera();
  70. }
  71. private IEnumerator RequestCameraPermission()
  72. {
  73. // 请求相机权限
  74. Permission.RequestUserPermission(Permission.Camera);
  75. // 等待用户授权
  76. yield return new WaitUntil(() => Permission.HasUserAuthorizedPermission(Permission.Camera));
  77. }
  78. private void StartCamera()
  79. {
  80. // 获取可用的相机设备
  81. WebCamDevice[] devices = WebCamTexture.devices;
  82. if (devices.Length > 0)
  83. {
  84. // 使用第一个相机设备
  85. webcamTexture = new WebCamTexture(devices[0].name);
  86. webcamTexture.Play();
  87. }
  88. else
  89. {
  90. Debug.LogError("No camera device available.");
  91. OnGetBase64ImageFailed?.Invoke("No camera device available.");
  92. }
  93. }
  94. private IEnumerator WaitForUserToTakePhoto()
  95. {
  96. // 可以其他按键操作拍照
  97. // 这里直接等到若干秒
  98. yield return new WaitForSecondsRealtime(0.1f);
  99. }
  100. private Texture2D TakePhoto()
  101. {
  102. if (webcamTexture != null && webcamTexture.isPlaying)
  103. {
  104. Texture2D photo = new Texture2D(webcamTexture.width, webcamTexture.height);
  105. photo.SetPixels(webcamTexture.GetPixels());
  106. photo.Apply();
  107. return photo;
  108. }
  109. return null;
  110. }
  111. private void StopCamera()
  112. {
  113. if (webcamTexture != null && webcamTexture.isPlaying)
  114. {
  115. webcamTexture.Stop();
  116. }
  117. }
  118. #endregion
  119. }

4、ImageLoader

  1. using System;
  2. using System.Threading.Tasks;
  3. using UnityEngine;
  4. using UnityEngine.AddressableAssets;
  5. using UnityEngine.ResourceManagement.AsyncOperations;
  6. public class ImageLoader : Singleton<ImageLoader>
  7. {
  8. [SerializeField] private string imageAddress = "车"; // 设置为你图片在Addressables中的地址
  9. public async Task<string> LoadImageAndConvertToBase64()
  10. {
  11. string base64String = string.Empty;
  12. // 使用Addressables加载图片
  13. AsyncOperationHandle<Texture2D> handle = Addressables.LoadAssetAsync<Texture2D>(imageAddress);
  14. // 等待加载完成
  15. await handle.Task;
  16. if (handle.Status == AsyncOperationStatus.Succeeded)
  17. {
  18. Texture2D texture = handle.Result;
  19. // 将Texture2D转换为byte数组
  20. byte[] imageBytes = texture.EncodeToPNG();
  21. // 将byte数组转换为base64字符串
  22. base64String = Convert.ToBase64String(imageBytes);
  23. Debug.Log("Base64 Image: " + base64String);
  24. }
  25. else
  26. {
  27. Debug.LogError("Failed to load image: " + handle.OperationException);
  28. }
  29. // 释放资源
  30. Addressables.Release(handle);
  31. return base64String;
  32. }
  33. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/77521
推荐阅读
相关标签
  

闽ICP备14008679号