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

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参数配置如下:

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

  • 星火认知大模型 WebAPI 接口调用示例 接口文档(必看):星火认知大模型Web API文档 | 讯飞开放平台文档中心
  • 错误码链接:星火认知大模型服务说明 | 讯飞开放平台文档中心

二、实现原理

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

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;public class TestIFlyLLMHandler : MonoBehaviour
{public Text TagrgetText;public InputField TagrgetInputField;public Button TagrgetButton;List<string> m_StrLst = new List<string>() { "你是谁","最近天气"};IIFlyLLMHandler m_Handler;// Start is called before the first frame updatevoid Start(){m_Handler = new IFlyLLMHandler();m_Handler.Initialized();TagrgetText.text = "";m_Handler.OnMessageReceivedAction = (jsonResponse) => { TagrgetText.text += jsonResponse.payload.choices.text[0].content; };TagrgetButton.onClick.AddListener(() => {TagrgetText.text = "";m_Handler.SendMsg(TagrgetInputField.text);});}// Update is called once per framevoid Update(){if (Input.anyKeyDown) {//m_Handler.SendMsg(m_StrLst[Random.Range(0,m_StrLst.Count)]);}}
}

2、IFlyLLMHandler

using BestHTTP.WebSocket;
using System;
using UnityEngine;/// <summary>
/// 使用讯飞大模型
/// </summary>
public class IFlyLLMHandler : BaseIFlyLLMHandler
{#region Data/// <summary>/// 发送连接服务器失败事件/// </summary>int m_TimerServerAccessFailure = -1;const float INTERVAL_TIME_SEND_SERVER_ACCESS_FAILURE = 4.0f;#endregion#region interface function/// <summary>/// 初始化/// </summary>public override void Initialized(){base.Initialized();}/// <summary>/// 发送数据/// </summary>/// <param name="askContent"></param>public override void SendMsg(string askContent){try{CacheHistory(askContent);Connect();}catch (Exception e){Debug.LogError($"e.ToString() {e.ToString()}\ne.Message {e.Message}");}}#endregion#region Websocket回调/// <summary>/// 建立连接事件/// </summary>/// <param name="ws"></param>protected override void OnWebSocketOpen(WebSocket ws){Debug.Log("WebSocket Connected!");Send();}/// <summary>/// 连接错误信息/// </summary>/// <param name="ws"></param>/// <param name="ex"></param>protected override void OnWebSocketError(WebSocket ws, Exception ex){base.OnWebSocketError(ws, ex);SendServerAccessFailure(1005);}/// <summary>/// 连接关闭事件/// </summary>/// <param name="ws"></param>/// <param name="code"></param>/// <param name="message"></param>protected override void OnWebSocketClosed(WebSocket ws, ushort code, string message){base.OnWebSocketClosed(ws, code, message);SendServerAccessFailure(code);}#endregion#region private function/// <summary>/// 发送服务器连接失败错误/// </summary>/// <param name="code"></param>private void SendServerAccessFailure(UInt16 code){if (code == 1005) // 连接失败错误码{if (m_TimerServerAccessFailure != -1) return;m_TimerServerAccessFailure = Timer.Instance.Post2Scale((index) => {Debug.Log("[BubbleChatUseIFlyLLMHandler] SendServerAccessFailure");m_TimerServerAccessFailure = -1;}, INTERVAL_TIME_SEND_SERVER_ACCESS_FAILURE);}}#endregion
}

3、BaseIFlyLLMHandler

using Newtonsoft.Json;
using System;
using UnityEngine;
using System.Text;
using BestHTTP.WebSocket;
using System.Collections.Generic;/*** 星火认知大模型 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*//// <summary>
/// 讯飞大模型基类
/// </summary>
public class BaseIFlyLLMHandler : IIFlyLLMHandler
{#region Data/// <summary>/// WebSocket/// </summary>protected WebSocket m_WebSocket;/// <summary>/// 缓存的历史数据的队列/// </summary>protected List<IIFlyLLMHandler.Content> m_CacheHistory = new List<IIFlyLLMHandler.Content>();/// <summary>/// 是否读完/// </summary>protected bool m_ReadEnd = true;/// <summary>/// 是否需要重发/// </summary>protected bool m_NeedSend = false;/// <summary>/// 大模型的配置/// </summary>protected LLMConfig m_Config;/// <summary>/// 记录上一个老的 sid ,因为打断后,如果上一次的没有传输完,下一次连接依然会接收到该 sid 的数据流/// </summary>protected string m_OldSid = "";/// <summary>/// // 用来记录中间的sid ,因为可能被打断(不一定每次都能完全正常流程接收完数据)/// </summary>protected string m_RcdSid = ""; /// <summary>/// 接收到数据的事件/// </summary>public Action<IIFlyLLMHandler.JsonResponse> OnMessageReceivedAction { get; set; }#endregion#region interface function/// <summary>/// 初始化/// </summary>public virtual void Initialized(){m_Config = new LLMConfig();}/// <summary>/// 连接/// </summary>public virtual void Connect(){if (m_WebSocket != null){Close();}string authUrl = GetAuthUrl();string url = authUrl.Replace("http://", "ws://").Replace("https://", "wss://");m_WebSocket = new WebSocket(new Uri(url));m_WebSocket.OnOpen += OnWebSocketOpen;m_WebSocket.OnMessage += OnWebSocketMessage;m_WebSocket.OnError += OnWebSocketError;m_WebSocket.OnClosed += OnWebSocketClosed;m_WebSocket.Open();}/// <summary>/// 关闭/// </summary>public virtual void Close(){m_OldSid = m_RcdSid;m_WebSocket?.Close();m_WebSocket = null;}/// <summary>/// 重置/// </summary>public virtual void Reset(){m_CacheHistory.Clear();}/// <summary>/// 发送消息/// </summary>/// <param name="history"></param>public virtual void SendMsg(string askContent){try{CacheHistory(askContent);if (m_WebSocket != null && m_WebSocket.IsOpen){if (m_ReadEnd){Send();}else{//中断websocket,然后再发送Close();m_NeedSend = true;}}else{m_NeedSend = true;Connect();}}catch (Exception e){Debug.LogError(e.Message);}}#endregion#region Websocket回调/// <summary>/// 建立连接的事件/// </summary>/// <param name="ws"></param>protected virtual void OnWebSocketOpen(WebSocket ws){Debug.Log("WebSocket Connected!");if (m_NeedSend) Send();}/// <summary>/// 接收到数据的事件/// </summary>/// <param name="ws"></param>/// <param name="message"></param>protected virtual void OnWebSocketMessage(WebSocket ws, string message){// 处理接收到的消息// 这里你可以根据需要进行相应的处理Debug.Log($"Received message: {message}");IIFlyLLMHandler.JsonResponse jsonResponse = JsonConvert.DeserializeObject<IIFlyLLMHandler.JsonResponse>(message);if (jsonResponse.header.code == 10013) // 错误码 10013:输入内容审核不通过,涉嫌违规,请重新调整输入内容{Debug.LogError($"OnWebSocketMessage message {jsonResponse.header.message} ");}else{Debug.Log($"OnWebSocketMessage m_OldSid {m_OldSid}, jsonResponse.header.sid {jsonResponse.header.sid} jsonResponse.header.code {jsonResponse.header.code}");// 判断不是上一次的 sid 的旧的数据流在做出反应if (jsonResponse.header.sid.Equals(m_OldSid) == false){if (jsonResponse.header.code == 10014) // 错误码 10014:输出内容涉及敏感信息,审核不通过,后续结果无法展示给用户{jsonResponse=GetHandleJsonResponse(jsonResponse);}OnMessageReceivedAction?.Invoke(jsonResponse);m_RcdSid = jsonResponse.header.sid;}}if (jsonResponse.payload.choices.status == 0){Debug.Log("Get First IFlyLLM Response");}if (jsonResponse.payload.choices.status == 2){m_ReadEnd = true;Debug.Log("Get Last IFlyLLM Response");m_OldSid = jsonResponse.header.sid;}}/// <summary>/// 连接发生错误的事件/// </summary>/// <param name="ws"></param>/// <param name="ex"></param>protected virtual void OnWebSocketError(WebSocket ws, Exception ex){Debug.LogError($"WebSocket Error: {ex.Message}");}/// <summary>/// 连接关闭的事件/// </summary>/// <param name="ws"></param>/// <param name="code"></param>/// <param name="message"></param>protected virtual void OnWebSocketClosed(WebSocket ws, UInt16 code, string message){Debug.LogFormat("WebSocket Closed!: code={0}, msg={1}", code, message);}#endregion#region protected function/// <summary>/// 真正发送数据/// </summary>protected virtual void Send(){m_NeedSend = false;m_ReadEnd = false;IIFlyLLMHandler.JsonRequest request = CreateRequest();string jsonString = JsonConvert.SerializeObject(request);Debug.LogError(jsonString);m_WebSocket?.Send(jsonString);}/// <summary>/// 创建一个连接请求/// </summary>/// <returns></returns>protected virtual IIFlyLLMHandler.JsonRequest CreateRequest(){return new IIFlyLLMHandler.JsonRequest{header = new IIFlyLLMHandler.Header{app_id = m_Config.IFLY_APPID,uid = Guid.NewGuid().ToString().Substring(0, 10)},parameter = new IIFlyLLMHandler.Parameter{chat = new IIFlyLLMHandler.Chat{domain = "generalv3",temperature = 0.01,max_tokens = 480}},payload = new IIFlyLLMHandler.Payload{message = new IIFlyLLMHandler.Message{text = m_CacheHistory}}};}/// <summary>/// 缓存历史记录数据结构,优化性能/// (缓存需要自己额外补充,这里先做简单的提问)/// </summary>protected virtual void CacheHistory(string askContent){m_CacheHistory.Clear();IIFlyLLMHandler.Content content = new IIFlyLLMHandler.Content();content.role = "user";content.content = askContent;m_CacheHistory.Add(content);}/// <summary>/// 敏感输出内容后的处理/// 重新组织数据(涉及敏感内容不予展示)/// </summary>/// <param name="jsonResponse"></param>/// <returns></returns>protected virtual IIFlyLLMHandler.JsonResponse GetHandleJsonResponse(IIFlyLLMHandler.JsonResponse jsonResponse) {int status = 2;IIFlyLLMHandler.HeaderResponse header = new IIFlyLLMHandler.HeaderResponse() { code = 0, message = "Success", sid = jsonResponse.header.sid, status = status };IIFlyLLMHandler.Text text = new IIFlyLLMHandler.Text() {content="***(涉及敏感内容不予展示)。",role= "assistant",index=0 };List<IIFlyLLMHandler.Text> textlst = new List<IIFlyLLMHandler.Text>();textlst.Add(text);IIFlyLLMHandler.Choices choices = new IIFlyLLMHandler.Choices() { status= status, seq=999,text=textlst};IIFlyLLMHandler.PayloadResponse payload = new IIFlyLLMHandler.PayloadResponse() { choices=choices};IIFlyLLMHandler.JsonResponse reorganizingInformationJRspn = new IIFlyLLMHandler.JsonResponse() {header=header,payload=payload };return reorganizingInformationJRspn;}#endregion#region 字符串操作/// <summary>/// 生成得到授权的 URL /// </summary>/// <returns></returns>private string GetAuthUrl(){string date = DateTime.UtcNow.ToString("r");Uri uri = new Uri(m_Config.IFLY_HOST_URL);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(m_Config.IFLY_API_SECRET, builder.ToString());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);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;}/// <summary>/// HMACsha256 /// </summary>/// <param name="apiSecretIsKey"></param>/// <param name="buider"></param>/// <returns></returns>private 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);}#endregion}

4、IIFlyLLMHandler

using System;
using System.Collections.Generic;/// <summary>
/// 讯飞大模型接口类
/// </summary>
public interface IIFlyLLMHandler
{/// <summary>/// 初始化/// </summary>void Initialized();/// <summary>/// 连接/// </summary>void Connect();/// <summary>/// 关闭连接/// </summary>void Close();/// <summary>/// 重置/// </summary>void Reset();/// <summary>/// 发送信息/// </summary>/// <param name="askContent"></param>void SendMsg(string askContent);/// <summary>/// 接收到数据事件/// </summary>Action<JsonResponse> OnMessageReceivedAction { get; set; }#region Request数据类定义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<Content> text { get; set; }}public class Content{public string role { get; set; }public string content { get; set; }}#endregion#region Response数据类型定义public class JsonResponse{public HeaderResponse header { get; set; }public PayloadResponse payload { get; set; }}public class HeaderResponse{public int code { get; set; }public string message { get; set; }public string sid { get; set; }public int status { get; set; }}public class PayloadResponse{public Choices choices { get; set; }}public class Choices{public int status { get; set; }public int seq { get; set; }public List<Text> text { get; set; }}public class Text{public string content { get; set; }public string role { get; set; }public int index { get; set; }}#endregion
}

5、LLMConfig

public class LLMConfig
{#region 讯飞/// <summary>/// 应用APPID(必须为webapi类型应用,并开通星火认知大模型授权)/// </summary>public readonly string IFLY_APPID = "YOUR_IFLY_APPID";/// <summary>/// 接口密钥(webapi类型应用开通星火认知大模型后,控制台--我的应用---星火认知大模型---相应服务的apikey)/// </summary>public readonly string IFLY_API_SECRET = "YOUR_IFLY_API_SECRET";/// <summary>/// 接口密钥(webapi类型应用开通星火认知大模型后,控制台--我的应用---星火认知大模型---相应服务的apisecret)/// </summary>public readonly string IFLY_API_KEY = "YOUR_IFLY_API_KEY";/// <summary>/// 讯飞大模型访问地址/// </summary>public readonly string IFLY_HOST_URL = "https://spark-api.xf-yun.com/v3.1/chat";/// <summary>/// 讯飞图像识别/// </summary>public readonly string IFLY_IMAGE_RECOGNIZE_URL = "wss://spark-api.cn-huabei-1.xf-yun.com/v2.1/image";#endregion
}

6、AutoReConnectIFlyLLMHandler

using BestHTTP.WebSocket;
using System;
using UnityEngine;/// <summary>
/// 带自动重连的讯飞大模型访问
/// </summary>
public class AutoReConnectIFlyLLMHandler : BaseIFlyLLMHandler
{#region Data/// <summary>/// m_ReconnectTimerId :自动重连的 TimerId/// </summary>int m_ReconnectTimerId = -1;/// <summary>/// m_ReconnectDelay :  自动重连的 时间/// </summary>float m_ReconnectDelay = 0.5f;#endregion#region interface function/// <summary>/// 初始化/// </summary>public override void Initialized(){base.Initialized();Connect();}/// <summary>/// 关闭连接/// </summary>public override void Close(){CancelReconnectTimer();base.Close();}/// <summary>/// 自动重连/// </summary>internal void AutoReconnect(){Connect();}/// <summary>/// 发送请求/// </summary>/// <param name="askContent"></param>public override void SendMsg(string askContent){try{CacheHistory(askContent);if (m_WebSocket != null && m_WebSocket.IsOpen){if (m_ReadEnd){Send();}else{//中断websocket,然后再发送Close();m_NeedSend = true;}}else{m_NeedSend = true;}}catch (Exception e){Debug.LogError(e.Message);}}#endregion#region Websocket回调/// <summary>/// 关闭连接事件/// </summary>/// <param name="ws"></param>/// <param name="code"></param>/// <param name="message"></param>protected override void OnWebSocketClosed(WebSocket ws, ushort code, string message){base.OnWebSocketClosed(ws, code, message);RunReconnectTimer();}/// <summary>/// 连接发生错误的事件/// </summary>/// <param name="ws"></param>/// <param name="ex"></param>protected override void OnWebSocketError(WebSocket ws, Exception ex){base.OnWebSocketError(ws, ex);RunReconnectTimer();}#endregion#region 计时器/// <summary>/// 计时自动重新连接/// </summary>private void RunReconnectTimer(){Debug.Log($"Scheduling reconnect in {m_ReconnectDelay} seconds...");CancelReconnectTimer();m_ReconnectTimerId = Timer.Instance.Post2Really((v) => { AutoReconnect(); }, m_ReconnectDelay);}/// <summary>/// 取消重新连接计时/// </summary>private void CancelReconnectTimer(){if (m_ReconnectTimerId != -1){Timer.Instance.Cancel(m_ReconnectTimerId);m_ReconnectTimerId = -1;}}#endregion
}

七、案例下载地址

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

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

1、IFlyLLMImageHandler

using UnityEngine;
using System;
using System.Text;
using Newtonsoft.Json;
using BestHTTP.WebSocket;
using System.Collections.Generic;public class IFlyLLMImageHandler 
{private WebSocket m_WebSocket;private int m_ReconnectTimerId = -1;private float m_ReconnectDelay = 0.5f;private List<Content> m_CacheHistory = new List<Content>();public Action<JsonResponse> OnMessageReceivedAction;private bool m_ReadEnd = true;private bool m_NeedSend = false;private LLMConfig m_Config;public void Initialized(){m_Config = new LLMConfig();Connect();}/// <summary>/// 连接/// </summary>public void Connect(){if (m_WebSocket != null){Close();}string authUrl = GetAuthUrl();string url = authUrl.Replace("http://", "ws://").Replace("https://", "wss://");m_WebSocket = new WebSocket(new Uri(url));m_WebSocket.OnOpen += OnWebSocketOpen;m_WebSocket.OnMessage += OnWebSocketMessage;m_WebSocket.OnError += OnWebSocketError;m_WebSocket.OnClosed += OnWebSocketClosed;m_WebSocket.Open();}/// <summary>/// 关闭/// </summary>public void Close(){CancelReconnectTimer();m_WebSocket?.Close();m_WebSocket = null;}public void Reset(){m_CacheHistory.Clear();}/// <summary>/// 自动重连/// </summary>private void AutoReconnect(){Connect();}/// <summary>/// 发送消息/// </summary>/// <param name="history"></param>public void SendMsg(string base64,string ask){try{ImageDataAsk(base64, ask);if (m_WebSocket != null && m_WebSocket.IsOpen){if (m_ReadEnd){Send();}else{//中断websocket,然后再发送Close();m_NeedSend = true;}}else{m_NeedSend = true;}}catch (Exception e){Debug.LogError(e.Message);}}private void Send(){m_NeedSend = false;m_ReadEnd = false;JsonRequest request = CreateRequest();string jsonString = JsonConvert.SerializeObject(request);Debug.LogError(jsonString);m_WebSocket?.Send(jsonString);}#region Websocket回调private void OnWebSocketOpen(WebSocket ws){Debug.Log("WebSocket Connected!");if (m_NeedSend) Send();}private void OnWebSocketMessage(WebSocket ws, string message){// 处理接收到的消息// 这里你可以根据需要进行相应的处理Debug.Log($"Received message: {message}");JsonResponse jsonResponse = JsonConvert.DeserializeObject<IFlyLLMImageHandler.JsonResponse>(message);OnMessageReceivedAction?.Invoke(jsonResponse);if (jsonResponse.payload.choices.status == 0){Debug.Log("Get First IFlyLLM Response");}if (jsonResponse.payload.choices.status == 2){m_ReadEnd = true;Debug.Log("Get Last IFlyLLM Response");}}private void OnWebSocketError(WebSocket ws, Exception ex){Debug.LogError($"WebSocket Error: {ex.Message}");RunReconnectTimer();}private void OnWebSocketClosed(WebSocket ws, UInt16 code, string message){Debug.LogFormat("WebSocket Closed!: code={0}, msg={1}", code, message);RunReconnectTimer();}#endregionprivate JsonRequest CreateRequest(){return new JsonRequest{header = new Header{app_id = m_Config.IFLY_APPID,uid = Guid.NewGuid().ToString().Substring(0, 10)},parameter = new Parameter{chat = new Chat{domain = "general",temperature = 0.5,top_k= 4,max_tokens = 2048,auditing = "default"}},payload = new Payload{message = new Message{text = m_CacheHistory}}};}private void ImageDataAsk(string base64,string ask) {m_CacheHistory.Clear();Content content = new Content();content.role = "user";content.content = base64;content.content_type = "image";m_CacheHistory.Add(content);content = new Content();content.role = "user";content.content = ask;content.content_type = "text";m_CacheHistory.Add(content);}#region 计时器private void RunReconnectTimer(){Debug.Log($"Scheduling reconnect in {m_ReconnectDelay} seconds...");CancelReconnectTimer();m_ReconnectTimerId = Timer.Instance.Post2Really((v) => { AutoReconnect(); }, m_ReconnectDelay);}private void CancelReconnectTimer(){if (m_ReconnectTimerId != -1){Timer.Instance.Cancel(m_ReconnectTimerId);m_ReconnectTimerId = -1;}}#endregion#region 字符串操作private string GetAuthUrl(){string date = DateTime.UtcNow.ToString("r");Uri uri = new Uri(m_Config.IFLY_IMAGE_RECOGNIZE_URL);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(m_Config.IFLY_API_SECRET, builder.ToString());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);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;}private 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);}#endregion#region Request数据类定义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 top_k { get; set; }public int max_tokens { get; set; }public string auditing { get; set; }}public class Payload{public Message message { get; set; }}public class Message{public List<Content> text { get; set; }}public class Content{public string role { get; set; }public string content { get; set; }public string content_type { get; set; }}#endregion#region Response数据类型定义public class JsonResponse{public HeaderResponse header { get; set; }public PayloadResponse payload { get; set; }}public class HeaderResponse{public int code { get; set; }public string message { get; set; }public string sid { get; set; }public int status { get; set; }}public class PayloadResponse{public Choices choices { get; set; }public Usage usage { get; set; }}public class Choices{public int status { get; set; }public int seq { get; set; }public List<Text> text { get; set; }}public class Text{public string content { get; set; }public string role { get; set; }public int index { get; set; }}public class Usage{public UsageText text { get; set; }}public class UsageText { public int completion_tokens { get; set; }public int question_tokens { get; set; }public int prompt_tokens { get; set; }public int total_tokens { get; set; }}#endregion
}

2、TestIFlyLLMImageHandler


using UnityEngine;public class TestIFlyLLMImageHandler : Singleton<TestIFlyLLMImageHandler>
{public void Test() {IFlyLLMImageHandler imageHandler = new IFlyLLMImageHandler();imageHandler.Initialized();imageHandler.OnMessageReceivedAction += (str) => {Debug.Log(" TestIFlyLLMImageHandler OnMessageReceivedAction " + str.payload.choices.text[0].content);};CameraCaptureImageForBase64.Instance.OnGetBase64ImageSuccess = (base64) =>{imageHandler.SendMsg(base64, "这是什么,尽可能详细的回答");};CameraCaptureImageForBase64.Instance.OnGetBase64ImageFailed = async (str) =>{string base64 = await ImageLoader.Instance.LoadImageAndConvertToBase64();imageHandler.SendMsg(base64, "这是什么,尽可能详细的回答");};CameraCaptureImageForBase64.Instance.CaptureImage();}
}

3、CameraCaptureImageForBase64


using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Android;/// <summary>
/// 打开 Camera  捕捉图片,获取图片 base64 信息
/// </summary>
public class CameraCaptureImageForBase64 : MonoSingleton<CameraCaptureImageForBase64>
{#region data/// <summary>/// 获取图片成功事件/// </summary>public Action<string> OnGetBase64ImageSuccess;/// <summary>/// 获取图片失败事件/// </summary>public Action<string> OnGetBase64ImageFailed;private WebCamTexture webcamTexture; // 用于获取相机图像private Coroutine m_Coroutine;#endregion/// <summary>/// 捕捉图片/// </summary>public void CaptureImage(){m_Coroutine = StartCoroutine(CaptureRoutine());}/// <summary>/// 停止捕捉/// </summary>public void StopCapture(){if (m_Coroutine!=null){StopCoroutine(m_Coroutine);m_Coroutine = null;}}#region private functionprivate IEnumerator CaptureRoutine(){// 检查是否有相机权限if (!Permission.HasUserAuthorizedPermission(Permission.Camera)){// 如果没有相机权限,等待用户授权yield return RequestCameraPermission();}// 启动相机StartCamera();// 等待用户拍照yield return WaitForUserToTakePhoto();// 拍照Texture2D photo = TakePhoto();if (photo != null){// 将Texture2D转换为byte数组byte[] imageBytes = photo.EncodeToPNG();// 将byte数组转换为base64字符串string base64String = Convert.ToBase64String(imageBytes);Debug.Log("Base64 Image: " + base64String);// 在这里执行你的异步任务,例如上传base64图片到服务器OnGetBase64ImageSuccess?.Invoke(base64String);}else {OnGetBase64ImageFailed?.Invoke("capture image failed.");}// 停止相机StopCamera();}private IEnumerator RequestCameraPermission(){// 请求相机权限Permission.RequestUserPermission(Permission.Camera);// 等待用户授权yield return new WaitUntil(() => Permission.HasUserAuthorizedPermission(Permission.Camera));}private void StartCamera(){// 获取可用的相机设备WebCamDevice[] devices = WebCamTexture.devices;if (devices.Length > 0){// 使用第一个相机设备webcamTexture = new WebCamTexture(devices[0].name);webcamTexture.Play();}else{Debug.LogError("No camera device available.");OnGetBase64ImageFailed?.Invoke("No camera device available.");}}private IEnumerator WaitForUserToTakePhoto(){// 可以其他按键操作拍照// 这里直接等到若干秒yield return new WaitForSecondsRealtime(0.1f);}private Texture2D TakePhoto(){if (webcamTexture != null && webcamTexture.isPlaying){Texture2D photo = new Texture2D(webcamTexture.width, webcamTexture.height);photo.SetPixels(webcamTexture.GetPixels());photo.Apply();return photo;}return null;}private void StopCamera(){if (webcamTexture != null && webcamTexture.isPlaying){webcamTexture.Stop();}}#endregion
}

4、ImageLoader


using System;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;public class ImageLoader : Singleton<ImageLoader>
{[SerializeField] private string imageAddress = "车"; // 设置为你图片在Addressables中的地址public async Task<string> LoadImageAndConvertToBase64(){string base64String = string.Empty;// 使用Addressables加载图片AsyncOperationHandle<Texture2D> handle = Addressables.LoadAssetAsync<Texture2D>(imageAddress);// 等待加载完成await handle.Task;if (handle.Status == AsyncOperationStatus.Succeeded){Texture2D texture = handle.Result;// 将Texture2D转换为byte数组byte[] imageBytes = texture.EncodeToPNG();// 将byte数组转换为base64字符串base64String = Convert.ToBase64String(imageBytes);Debug.Log("Base64 Image: " + base64String);}else{Debug.LogError("Failed to load image: " + handle.OperationException);}// 释放资源Addressables.Release(handle);return base64String;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/169273.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【外贸干货】领英客户开发与营销的六个策略方向

领英(LinkedIn)已经成为外贸营销人员&#xff0c;尤其是B2B外贸营销人员&#xff0c;一个重要且有效的社交媒体平台。 相比于其他社交媒体平台&#xff0c;领英(LinkedIn)在增加流量、产生高质量的潜在客户和建立思想领导力方面有着独有的优势。 因为领英(LinkedIn)不仅仅是获…

Harmony开发 eTs公共样式抽取

Harmony系统开发使用eTs开发过程中对于样式相同且重复使用的样式可以抽取成公共样式循环利用&#xff0c;类似于android的style样式。 import router from ohos.router import cryptoFramework from ohos.security.cryptoFramework; import prompt from system.prompt class L…

【LLM_04】自然语言处理基础_2

一、神经网络1、循环神经网络&#xff08;RNN&#xff09;2、门控循环单元&#xff08;GRU&#xff09;3、长短期记忆网络&#xff08;LSTM&#xff09;4、双向RNN5、卷积神经网络&#xff08;CNN&#xff09; 二、注意力机制1、注意力机制原理介绍2、注意力机制的各种变式3、注…

保护您的IP地址:预防IP地址盗用的关键措施

随着互联网的发展&#xff0c;IP地址作为标识互联网设备的重要元素&#xff0c;成为网络通信的基石。然而&#xff0c;IP地址盗用威胁正不断增加&#xff0c;可能导致敏感信息泄露、未经授权的访问和网络攻击。本文将介绍一些有效的方法&#xff0c;以帮助组织和个人预防IP地址…

Acrel-2000电力监控系统在上海大世界保护修缮工程项目中的应用

摘要&#xff1a;安科瑞生产厂家1876150/-6237黄安南 介绍上海大世界电力监控系统&#xff0c;采用智能电力仪表采集配电现场的各种电参量和开关信号。系统采用现场就地组网的方式&#xff0c;组网后通过现场总线通讯并远传至后台&#xff0c;通过Acrel-2000型电力监控系统实现…

Vue与UserEcharts、DataV的协同

文章目录 引言一、Vue.js简介二、ECharts和UserEcharts1.ECharts简介2.UserEcharts&#xff1a;Vue和ECharts的结合 三、DataV简介四、Vue与DataV的结合1.DataV的Vue插件2.Vue和DataV的数据交互 结论我是将军&#xff0c;我一直都在&#xff0c;。&#xff01; 引言 接着上一篇…

ubuntu22.04 arrch64版在线安装java环境

脚本 #安装java#!/bin/bashif type -p java; thenecho "Java has been installed."else#2.Installed Java , must install wgetwget -c https://repo.huaweicloud.com/java/jdk/8u151-b12/jdk-8u151-linux-arm64-vfp-hflt.tar.gz;tar -zxvf ./jdk-8u151-linux-arm6…

【数据分享】我国12.5米分辨率的山体阴影数据(免费获取)

地形数据&#xff0c;也叫DEM数据&#xff0c;是我们在各项研究中最常使用的数据之一。之前我们分享过源于NASA地球科学数据网站发布的12.5米分辨率DEM地形数据&#xff0c;这个DEM数据的优点是精度高&#xff01;基于该数据我们处理得到12.5米分辨率的坡度数据&#xff08;以上…

外贸分享|如何从外贸小白成长为大咖?这10件事值得你坚持做

外贸成功不是一朝一夕的事&#xff0c;而是需要有充分的准备和持续的努力。作为一位有着丰富经验的外贸人员&#xff0c;我总结了成功的秘诀&#xff0c;分享了一个优秀的外贸人应该做好的10项工作。 1 找不到客户怎么办&#xff1f; 有很多各种各样的原因值得思考&#xff1a…

【数字图像处理】均值滤波与中值滤波

在数字图像处理中,均值滤波和中值滤波是常见的空间域处理方法,可以用于过滤图像中的噪声。本文主要介绍数字图像均值滤波与中值滤波的基本原理,并记录在紫光同创 PGL22G FPGA 平台的布署与实现过程。 目录 1. 均值滤波与中值滤波 2. FPGA 布署与实现 2.1 功能与指标定义

基于减法平均算法优化概率神经网络PNN的分类预测 - 附代码

基于减法平均算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于减法平均算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于减法平均优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神…

Python----函数的参数----形参(定义函数时编写的),实参(调用函数时传递的)

在函数定义与调用时&#xff0c;我们可以根据自己的需求来实现参数的传递。在Python中&#xff0c;函数的参数一共有两种形式&#xff1a;① 形参 ② 实参 形参&#xff1a;在函数定义时&#xff0c;所 编写 的参数就称之为 形式参数 实参&#xff1a;在函数调用时&#…

Spring Boot配置文件 Spring日志文件相关的知识

在上文中&#xff0c;小编带领大家创建了一个Spring Boot项目&#xff0c;并且成功的执行了第一个SPring Boot项目&#xff08;在网页上运行hello world&#xff09; 那么&#xff0c;本文的主要作用便是带领大家走进&#xff1a;Spring Boot配置文件 && Spring日志文件…

flutter之graphic图表自定义tooltip

renderer graphic中tooltip的TooltipGuide类提供了renderer方法&#xff0c;接收三个参数Size类型&#xff0c;Offset类型&#xff0c;Map<int, Tuple>类型。可查到的文档是真的少&#xff0c;所以只能在源码中扒拉例子&#xff0c;做符合需求的修改。 官方github示例 …

枚举与应用

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 枚举简介 枚举是一种特…

CentOS 7 使用异步网络框架Libevent

CentOS 7 安装Libevent库 libevent github地址&#xff1a;https://github.com/libevent/libevent 步骤1&#xff1a;首先&#xff0c;你需要下载libevent的源代码。你可以从github或者源代码官方网站下载。并上传至/usr/local/source_code/ 步骤2&#xff1a;下载完成后&…

C语言 - 基础

C 语言 1. Hello World #include <stdio.h>int main(int argc, const char *argv[]) {printf("hello world\n");return 0; }注意: 所有的标点符号必须在英文状态下输入单词不要写错注意空格 创建 C语言 程序步骤&#xff1a; 1、创建一个文档&#xff0c;以…

Springboot 南阳旅游平台-计算机毕设 附源码 31829

Springboot 南阳旅游平台 目 录 摘要 1 绪论 1.1 研究背景 1.2 研究意义 1.3 论文结构与章节安排 2 南阳旅游平台系统分析 2.1 可行性分析 2.1.1 技术可行性分析 2.1.2 经济可行性分析 2.1.3 法律可行性分析 2.2 系统功能分析 2.2.1 功能性分析 2.2.2 非功能性分析…

芙蓉花 欣赏

芙蓉&#xff08;Hibiscus mutabilis Linn&#xff09;是一种锦葵科、木槿属植物原名&#xff1a;木芙蓉&#xff0c;别名&#xff1a;芙蓉花、拒霜花、木莲、地芙蓉、华木、酒醉芙蓉。其花或白或粉或赤&#xff0c;皎若芙蓉出水&#xff0c;艳似菡萏展瓣&#xff0c;故有“芙蓉…

Ubuntu服务器/工作站常见故障修复记录

日常写代码写方案文档&#xff0c;偶尔遇上服务器出现问题的时候&#xff0c;也需要充当一把运维工程师&#xff0c;此帖用来记录服务器报错的一些解决方案&#xff0c;仅供参考&#xff01; 文章目录 一、服务器简介二、机箱拆解三、基本操作3.1 F2进入BIOS3.2 F12进入Boot Me…