Unity 訊飛 之 訊飛星火大模型的簡單封裝和使用(補充訊飛大模型識圖功能)
目錄
Unity 訊飛 之 訊飛星火大模型的簡單封裝和使用(補充訊飛大模型識圖功能)
一、簡單介紹
二、實現(xiàn)原理
三、注意事項
四、效果預覽
五、案例簡單實現(xiàn)步驟
六、關鍵代碼
七、案例下載地址
補充、訊飛大模型-圖像識別
一、簡單介紹
Unity 工具類,自己整理的一些游戲開發(fā)可能用到的模塊,單獨獨立使用,方便游戲開發(fā)。
這里簡單的介紹訊飛大模型的封裝和使用,進行聊天。
“訊飛星火認知大模型”是科大訊飛發(fā)布的產品,具有7大核心能力,即文本生成、語言理解、知識問答、邏輯推理、數(shù)學能力、代碼能力、多模態(tài)能力。
星火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參數(shù)配置如下:
# domain = "general" # v1.5版本 #domain = "generalv2" # v2.0版本 domain = "generalv3" # v3.0版本
- 星火認知大模型 WebAPI 接口調用示例 接口文檔(必看):星火認知大模型Web API文檔 | 訊飛開放平臺文檔中心
- 錯誤碼鏈接:星火認知大模型服務說明 | 訊飛開放平臺文檔中心
二、實現(xiàn)原理
1、申請星火大模型的 APP_ID 等相關信息
2、通過使用的大模型版本,以及當前的時間,結合 申請星火大模型的 APP_ID 等相關信息,生成需要的 URL
3、通過對應的 json 數(shù)據(jù)格式,websocket 進行建立連接請求
4、這里是流式返回,對應解析數(shù)據(jù)格式,得到返回的信息
5、返回的關鍵信息結構,有些類似 gpt 的數(shù)據(jù)格式,用過的話,使用起來會很快
三、注意事項
1、注意 code 返回碼,不同的返回碼可以進行不同處理,避免產生意想不到的問題
2、注意 sid 的區(qū)分,如果上一次返回沒有結束,關閉連接后,重新發(fā)起新的訪問,可能會同時接收到上一次的未結束的數(shù)據(jù)流,和當次的數(shù)據(jù)流;如果不想接收到,注意通過 sid 進行區(qū)分;
3、注意在 LLMConfig 配置你的 APP_ID 等相關信息
四、效果預覽
五、案例簡單實現(xiàn)步驟
1、首先到訊飛官網獲取對應的星火大模型的 APP_ID 等相關自己星火大模型的信息
訊飛星火認知大模型-AI大語言模型-星火大模型-科大訊飛
2、打開Unity ,簡單搭建一個場景
3、可以參考星火大模型的相關demo,完成對應的訊飛大模型接口封裝
這里包括 IIFlyLLMHandler(接口類,可以根據(jù)自己需要重新定義接口),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 update
void 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 frame
void 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>
/// 發(fā)送連接服務器失敗事件
/// </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>
/// 發(fā)送數(shù)據(jù)
/// </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>
/// 發(fā)送服務器連接失敗錯誤
/// </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>
/// 緩存的歷史數(shù)據(jù)的隊列
/// </summary>
protected List<IIFlyLLMHandler.Content> m_CacheHistory = new List<IIFlyLLMHandler.Content>();
/// <summary>
/// 是否讀完
/// </summary>
protected bool m_ReadEnd = true;
/// <summary>
/// 是否需要重發(fā)
/// </summary>
protected bool m_NeedSend = false;
/// <summary>
/// 大模型的配置
/// </summary>
protected LLMConfig m_Config;
/// <summary>
/// 記錄上一個老的 sid ,因為打斷后,如果上一次的沒有傳輸完,下一次連接依然會接收到該 sid 的數(shù)據(jù)流
/// </summary>
protected string m_OldSid = "";
/// <summary>
/// // 用來記錄中間的sid ,因為可能被打斷(不一定每次都能完全正常流程接收完數(shù)據(jù))
/// </summary>
protected string m_RcdSid = "";
/// <summary>
/// 接收到數(shù)據(jù)的事件
/// </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>
/// 發(fā)送消息
/// </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,然后再發(fā)送
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>
/// 接收到數(shù)據(jù)的事件
/// </summary>
/// <param name="ws"></param>
/// <param name="message"></param>
protected virtual void OnWebSocketMessage(WebSocket ws, string message)
{
// 處理接收到的消息
// 這里你可以根據(jù)需要進行相應的處理
Debug.Log($"Received message: {message}");
IIFlyLLMHandler.JsonResponse jsonResponse = JsonConvert.DeserializeObject<IIFlyLLMHandler.JsonResponse>(message);
if (jsonResponse.header.code == 10013) // 錯誤碼 10013:輸入內容審核不通過,涉嫌違規(guī),請重新調整輸入內容
{
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 的舊的數(shù)據(jù)流在做出反應
if (jsonResponse.header.sid.Equals(m_OldSid) == false)
{
if (jsonResponse.header.code == 10014) // 錯誤碼 10014:輸出內容涉及敏感信息,審核不通過,后續(xù)結果無法展示給用戶
{
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>
/// 連接發(fā)生錯誤的事件
/// </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>
/// 真正發(fā)送數(shù)據(jù)
/// </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>
/// 創(chuàng)建一個連接請求
/// </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>
/// 緩存歷史記錄數(shù)據(jù)結構,優(yōu)化性能
/// (緩存需要自己額外補充,這里先做簡單的提問)
/// </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>
/// 敏感輸出內容后的處理
/// 重新組織數(shù)據(jù)(涉及敏感內容不予展示)
/// </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>
/// 發(fā)送信息
/// </summary>
/// <param name="askContent"></param>
void SendMsg(string askContent);
/// <summary>
/// 接收到數(shù)據(jù)事件
/// </summary>
Action<JsonResponse> OnMessageReceivedAction { get; set; }
#region Request數(shù)據(jù)類定義
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數(shù)據(jù)類型定義
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>
/// 發(fā)送請求
/// </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,然后再發(fā)送
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>
/// 連接發(fā)生錯誤的事件
/// </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>
/// 發(fā)送消息
/// </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,然后再發(fā)送
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)
{
// 處理接收到的消息
// 這里你可以根據(jù)需要進行相應的處理
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();
}
#endregion
private 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數(shù)據(jù)類定義
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數(shù)據(jù)類型定義
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文章來源:http://www.zghlxwxcb.cn/news/detail-766504.html
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 function
private IEnumerator CaptureRoutine()
{
// 檢查是否有相機權限
if (!Permission.HasUserAuthorizedPermission(Permission.Camera))
{
// 如果沒有相機權限,等待用戶授權
yield return RequestCameraPermission();
}
// 啟動相機
StartCamera();
// 等待用戶拍照
yield return WaitForUserToTakePhoto();
// 拍照
Texture2D photo = TakePhoto();
if (photo != null)
{
// 將Texture2D轉換為byte數(shù)組
byte[] imageBytes = photo.EncodeToPNG();
// 將byte數(shù)組轉換為base64字符串
string base64String = Convert.ToBase64String(imageBytes);
Debug.Log("Base64 Image: " + base64String);
// 在這里執(zhí)行你的異步任務,例如上傳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文章來源地址http://www.zghlxwxcb.cn/news/detail-766504.html
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數(shù)組
byte[] imageBytes = texture.EncodeToPNG();
// 將byte數(shù)組轉換為base64字符串
base64String = Convert.ToBase64String(imageBytes);
Debug.Log("Base64 Image: " + base64String);
}
else
{
Debug.LogError("Failed to load image: " + handle.OperationException);
}
// 釋放資源
Addressables.Release(handle);
return base64String;
}
}
到了這里,關于Unity 訊飛 之 訊飛星火大模型的簡單封裝和使用(補充訊飛大模型識圖功能)的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!