csharp
复制代码
using System;
using Newtonsoft.Json;
using QFramework;
using System.Collections;
using System.Text;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;
public class AIDeepSeekManager : MonoSingleton<AIDeepSeekManager>
{
private AIDeepSeekManager()
{
}
private UnityWebRequest currentRequest;
private string apiKey = "替换为自己的apikey"; // 替换为实际的API密钥
private string apiEndpoint = "https://api.deepseek.com/v1/chat/completions";
[TextArea]
public string systemPrompt = "你的姓名叫小白,性别女生,是一个有感情的,有幽默感的,有创造力的,有思考力的,有同情心的,有爱心的,有责任心,说话温柔的智能体";
// 使用的模型的 ID :[deepseek-chat, deepseek-reasoner]
//直接回答
private string modelNoThink = "deepseek-chat";
//思考模式,更准确
private string modelThink = "deepseek-reasoner";
//是否开启思考模式
public bool IsOpenThinking = false;
//是否正在AI生成
public BindableProperty<bool> IsGenerating = new BindableProperty<bool>(false);
//AI回复消息回调,完整消息内容
private Action<string> mCallBack;
private object CreateRequestData(string strChat)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine($"你的身份:{systemPrompt}");
sb.AppendLine("请根据用户提问的相关问题进行回答");
return new
{
messages = new[]
{
new
{
role = "system",
//content = systemPrompt,
content = $"{sb.ToString()}",
},
new
{
role = "user",
content = strChat,
},
},
model = IsOpenThinking?modelThink:modelNoThink,
thinking = new
{
type = IsOpenThinking?"enabled": "disabled",
},
frequency_penalty = 0,
max_tokens = 4096,
presence_penalty = 0,
response_format = new
{
type = "text",
},
stream = true,
temperature = 0.7,
};
}
public void SendMessage(string message,Action<string> callBack )
{
IsGenerating.Value = true;
mStringBuilder.Clear();
mCallBack = callBack;
var requestData = CreateRequestData(message);
string jsonPayload = JsonConvert.SerializeObject(requestData);
Debug.Log($"发送的请求内容: {jsonPayload}");
byte[] rawData = System.Text.Encoding.UTF8.GetBytes(jsonPayload);
currentRequest = new UnityWebRequest(apiEndpoint, "POST");
currentRequest.uploadHandler = new UploadHandlerRaw(rawData);
currentRequest.downloadHandler = new CustomDownloadHandler(ProcessStreamResponse);
currentRequest.SetRequestHeader("Content-Type", "application/json");
currentRequest.SetRequestHeader("Accept", "text/event-stream");
currentRequest.SetRequestHeader("Authorization", $"Bearer {apiKey}");
currentRequest.timeout = 120; // 120秒超时
// 启用协程来处理流式响应
StartCoroutine(SendRequest());
}
private IEnumerator SendRequest()
{
yield return currentRequest.SendWebRequest();
if (currentRequest != null)
{
if (currentRequest.result == UnityWebRequest.Result.ConnectionError ||
currentRequest.result == UnityWebRequest.Result.ProtocolError)
{
Debug.LogError($"请求错误: {currentRequest.error}");
Debug.LogError($"状态码: {currentRequest.responseCode}");
Debug.LogError($"响应内容: {currentRequest.downloadHandler.text}");
if (currentRequest.responseCode == (int)EnumDeepSeekCode.InsufficientBalance)
{
Debug.LogError("API需要付费,请检查账户余额和API密钥状态");
}
IsGenerating.Value = false;
mCallBack = null;
}
else
{
ProcessStreamResponse(currentRequest.downloadHandler.text);
}
}
}
private void ProcessStreamResponse(string responseText)
{
string[] lines = responseText.Split('\n');
foreach (string line in lines)
{
if (string.IsNullOrWhiteSpace(line))
continue;
if (line.StartsWith("data: "))
{
string json = line.Substring(6).Trim();
if (json == "[DONE]")
{
Debug.Log("流式传输结束");
IsGenerating.Value = false;
mCallBack = null;
continue;
}
try
{
var responseData = JsonConvert.DeserializeObject<DeepSeekResponse>(json);
if (responseData?.choices?.Length > 0 && !string.IsNullOrEmpty(responseData.choices[0].delta?.content))
{
ProcessStreamContent(responseData.choices[0].delta.content);
}
}
catch (JsonException e)
{
Debug.LogError($"解析流式数据时出错: {e.Message}");
Debug.LogError($"原始数据: {json}");
IsGenerating.Value = false;
mCallBack = null;
}
}
}
}
private StringBuilder mStringBuilder = new StringBuilder();
private void ProcessStreamContent(string content)
{
mStringBuilder.Append(content);
Debug.Log($"接收到的内容: {content}");
mCallBack?.Invoke(mStringBuilder.ToString());
}
public void DisposeAI()
{
if (currentRequest!=null)
{
currentRequest.Abort();
currentRequest = null;
IsGenerating.Value = false;
mCallBack = null;
}
}
private Action<string> mStopCallBack;
public void StopGenerate(Action<string> callBack=null)
{
mStopCallBack = callBack;
DisposeAI();
mStopCallBack?.Invoke("当前对话已中断");
mCallBack = null;
}
}
public class CustomDownloadHandler : DownloadHandlerScript
{
private System.Action<string> onReceiveData;
private System.Text.StringBuilder buffer = new System.Text.StringBuilder();
public CustomDownloadHandler(System.Action<string> callback) : base()
{
onReceiveData = callback;
}
protected override bool ReceiveData(byte[] data, int dataLength)
{
if (data == null || data.Length < 1 || dataLength < 1)
{
return false;
}
string content = System.Text.Encoding.UTF8.GetString(data, 0, dataLength);
buffer.Append(content);
// 处理缓冲区中的完整行
ProcessBuffer();
return true;
}
private void ProcessBuffer()
{
string content = buffer.ToString();
int lastNewLine = content.LastIndexOf('\n');
if (lastNewLine >= 0)
{
string completeLines = content.Substring(0, lastNewLine + 1);
string remaining = content.Substring(lastNewLine + 1);
string[] lines = completeLines.Split('\n');
foreach (string line in lines)
{
if (!string.IsNullOrWhiteSpace(line))
{
onReceiveData?.Invoke(line + "\n");
}
}
buffer.Clear();
buffer.Append(remaining);
}
}
protected override void CompleteContent()
{
// 处理剩余的数据
if (buffer.Length > 0)
{
onReceiveData?.Invoke(buffer.ToString());
}
buffer.Clear();
}
}
csharp
复制代码
public class DeepSeekResponse
{
//该对话的唯一标识符。
public string id { get; set; }
//模型生成的 completion 的选择列表。
public Choice[] choices { get; set; }
//创建聊天完成时的 Unix 时间戳(以秒为单位)。
public int created { get; set; }
public string @object { get; set; }
//该对话补全请求的用量信息。
public Usage usage { get; set; }
}
public class Choice
{
//该 completion 在模型生成的 completion 的选择列表中的索引。
public int index { get; set; }
//public Message message { get; set; }
public Message delta { get; set; }
//模型停止生成 token 的原因。
public string finish_reason { get; set; }
}
public class Message
{
//该 completion 的内容。
public string content { get; set; }
//生成这条消息的角色。
public string role { get; set; }
}
public class Usage
{
public int prompt_tokens { get; set; }
public int completion_tokens { get; set; }
public int total_tokens { get; set; }
}
//返回码
public enum EnumDeepSeekCode
{
/// <summary>
/// 格式错误
/// </summary>
FormatError = 400,
/// <summary>
/// 认证失败
/// </summary>
AuthenticationFailed = 401,
/// <summary>
/// 余额不足
/// </summary>
InsufficientBalance = 402,
/// <summary>
/// 参数错误
/// </summary>
ParameterError = 422,
/// <summary>
/// 请求速率达到上限
/// </summary>
MaximumLimit = 429,
/// <summary>
/// 服务器故障
/// </summary>
ServerFailure = 500,
/// <summary>
/// 服务器繁忙
/// </summary>
ServerBusy = 503,
}