Unity接入火山引擎/豆包大模型文生图,实现AI绘画

1.访问火山引擎

2.注册后实名信息

3.产品—火山方舟—视觉大模型。找到对应模型,开通或者免费领取体验资源

4.点击查看详情—立即使用,按步骤获取产品密钥

5.打开unity 新建脚本(以下为主要方法,构建请求体后创建签名及认证)

 IEnumerator GenerateImage()
    {
        long timestamp = GetTimestamp();
        string method = "POST"; // 请求方法,固定为POST,可根据实际情况调整
        string path = ""; // 这里假设你的请求路径是/generate,需根据实际API调整
        string contentType = "application/json"; // 根据请求体内容类型设置

        // 构建请求的JSON格式数据,按照文档里请求格式要求填充各参数
        ImageGenerationRequest requestData = new ImageGenerationRequest
        {
            req_key = "high_aes_general_v20_L",
            prompt = InputField.text,
            model_version = "general_v2.0_L",
            req_schedule_conf = "general_v20_9B_rephraser",
            seed = -1,
            scale = 3.5f,
            ddim_steps = 16,
            width = 512,
            height = 512,
            use_sr = true,
            return_url = false,
            logo_info = new LogoInfo
            {
                add_logo = false,
                position = 0,
                language = 0,
                opacity = 0.3f,
                logo_text_content = "这里是明水印内容"
            }
        };
        string requestBody = JsonUtility.ToJson(requestData);

        // 生成签名
        string signature = GenerateSignature(timestamp, accessKey, secretKey, method, path, contentType, requestBody);
        //string signature = "1caf8e82d88a9fc8f094f6d800616522e7c78f23f7e4ee568625b9b825e15eb0";
        //Debug.Log(signature);
        UnityWebRequest request = new UnityWebRequest(apiUrl, method);
        byte[] bodyRaw = Encoding.UTF8.GetBytes(requestBody);
        request.uploadHandler = (UploadHandler)new UploadHandlerRaw(bodyRaw);
        request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();

        // 设置Content-Type请求头
        request.SetRequestHeader("Content-Type", contentType);

        //设置Host请求头,从API请求地址中提取主机部分
        //string host = new Uri(apiUrl).Host;
        // request.SetRequestHeader("host", host);

        // 设置X-Date请求头,使用获取到的时间戳转换后的格式
        string xDate = GetFormattedXDate(timestamp);
        request.SetRequestHeader("X-Date", xDate);

        // 计算并设置X-Content-Sha256请求头,对请求体内容计算SHA256哈希值
        string xContentSha256 = HashSHA256(bodyRaw);
        request.SetRequestHeader("X-Content-Sha256", xContentSha256);
        Debug.Log(xContentSha256);

        // 构建并设置Authorization请求头,包含签名等认证信息
        string credentialScope = $"{xDate.Substring(0, 8)}/{region}/{service}/request";
        string authorizationHeader = $"HMAC-SHA256 Credential={accessKey}/{credentialScope}, SignedHeaders=host;x-content-sha256;x-date, Signature={signature}";


        request.SetRequestHeader("Authorization", authorizationHeader);


        yield return request.SendWebRequest();

        // 按照新的方式判断请求结果,使用isDone和isNetworkError、isHttpError属性来替代原来的.result属性判断
        if (request.isDone)
        {
            // 解析返回的JSON数据,获取图片相关内容并处理显示(按文档返回格式要求操作)
            string responseJson = request.downloadHandler.text;
            Debug.Log(responseJson);
            ImageGenerationResponse response = JsonUtility.FromJson<ImageGenerationResponse>(responseJson);
            if (response.data.binary_data_base64 != null && response.data.binary_data_base64.Count > 0)
            {
                byte[] imageBytes = System.Convert.FromBase64String(response.data.binary_data_base64[0]);
                Texture2D texture = new Texture2D(2, 2);
                texture.LoadImage(imageBytes);
                Sprite sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f));
                resultImage.sprite = sprite;
            }
            else
            {
                Debug.LogError("没有获取到有效的图片数据");
            }
        }
        else
        {
            Debug.LogError("请求出错: " + request.error);
        }
    }

6.效果

贴个源代码,就一个脚本,换成你自己申请的sk,ak即可

using UnityEngine;
using UnityEngine.Networking;
using System.Collections;
using System.Text;
using UnityEngine.UI;
using System.Collections.Generic;
using System;
using System.Security.Cryptography;
using System.Linq;

// 定义请求参数对应的结构体,按照文档里请求格式要求来组织数据
[System.Serializable]
public struct ImageGenerationRequest
{
    public string req_key;
    public string prompt;
    public string model_version;
    public string req_schedule_conf;
    public int seed;
    public float scale;
    public int ddim_steps;
    public int width;
    public int height;
    public bool use_sr;
    public bool return_url;
    public LogoInfo logo_info;
}

// 定义请求里logo相关信息的结构体
[System.Serializable]
public struct LogoInfo
{
    public bool add_logo;
    public int position;
    public int language;
    public float opacity;
    public string logo_text_content;
}

// 定义返回数据对应的结构体,按照文档里返回格式要求来解析响应内容
[System.Serializable]
public struct ImageGenerationResponse
{
    public int code;
    public ResponseData data;
    public string message;
    public string request_id;
    public int status;
    public string time_elapsed;
}

[System.Serializable]
public struct ResponseData
{
    public AlgorithmBaseResp algorithm_base_resp;
    public List<string> binary_data_base64;
    public string pe_result;
    public string predict_tags_result;
    public string rephraser_result;
    public string request_id;
}

[System.Serializable]
public struct AlgorithmBaseResp
{
    public int status_code;
    public string status_message;
}

public class TextToImage : MonoBehaviour
{
    // 火山引擎文生图服务的API请求地址,替换为你申请到的真实地址
    public string apiUrl = "https://your-volcengine-api-url.com/generate";
    // 你的火山引擎应用的访问密钥,根据实际申请填写
    public string accessKey = "your-access-key";
    // 你的火山引擎应用的秘密密钥,根据实际申请填写
    public string secretKey = "your-secret-key";
    // 用于输入文生图的文本提示,比如描述画面内容等
    public string textPrompt = "美丽的自然风光";
    // 用于展示生成图片的Unity UI的Image组件,在场景中挂载并赋值到此处
    public Image resultImage;
    // 火山引擎服务对应的区域,需替换为实际使用的区域名称
    private string region = "cn-north-1";
    // 火山引擎服务对应的服务名称,需替换为实际的服务名称(比如文生图相关服务的名称)
    private string service = "cv";

    // 获取时间戳,用于请求签名等操作(按常见的时间戳生成方式示例)
    private long GetTimestamp()
    {
        System.DateTime startTime = System.DateTime.Now.ToUniversalTime();
        return (long)(startTime - new System.DateTime(1970, 1, 1, 0, 0, 0, System.DateTimeKind.Utc)).TotalSeconds;
    }

    // 生成签名,按照火山引擎要求完善后的签名算法
    private string GenerateSignature(long timestamp, string accessKey, string secretKey, string method, string path, string contentType, string requestBody)
    {
        // 假设这里有对应的区域和服务名称变量,需要根据实际情况正确赋值

        // 第一步:获取格式化后的X-Date,格式为YYYYMMDD'T'HHmmss'Z',用于后续多处时间相关的标识
        string xDate = GetFormattedXDate(timestamp);

        // 第二步:构建规范请求字符串(CanonicalRequest)
        StringBuilder canonicalRequestBuilder = new StringBuilder();

        // 1. 添加请求方法(HTTPRequestMethod),按照文档要求转换为大写
        canonicalRequestBuilder.Append(method.ToUpper()).Append("\n");

        // 2. 添加规范化URI(CanonicalURI)
        // 根据文档,如果URI为空,使用"/"作为绝对路径;若不为空,需按照RFC3986规范进行编码
        string canonicalURI;
        if (string.IsNullOrEmpty(path))
        {
            canonicalURI = "/";
        }
        else
        {
            canonicalURI = System.Web.HttpUtility.UrlEncode(path, System.Text.Encoding.UTF8);
        }
        canonicalRequestBuilder.Append(canonicalURI).Append("\n");


        canonicalRequestBuilder.Append("Action=CVProcess&Version=2022-08-31").Append("\n");

        // 4. 添加规范化请求头(CanonicalHeaders)
        // 遍历要参与签名的请求头,将请求头名称转换为小写,去除值的前后空格,然后按照“名称:值\n”的格式添加到构建器中
        // 注意最后要额外添加一个换行符,确保格式符合文档要求,且host和x-date如果存在于请求头中则必选参与签名计算
        StringBuilder canonicalHeadersBuilder = new StringBuilder();
        AddCanonicalHeader(canonicalHeadersBuilder, "host", new Uri(apiUrl).Host);
        AddCanonicalHeader(canonicalHeadersBuilder, "x-content-sha256", HashSHA256(Encoding.UTF8.GetBytes(requestBody)));
        AddCanonicalHeader(canonicalHeadersBuilder, "x-date", xDate);
        // AddCanonicalHeader(canonicalHeadersBuilder, "content-type", contentType);
        string canonicalHeaders = canonicalHeadersBuilder.ToString() + "\n";
        canonicalRequestBuilder.Append(canonicalHeaders);

        // 5. 添加参与签名的请求头列表(SignedHeaders)
        // 将参与签名的请求头名称转换为小写并用“;”连接,确保顺序正确且包含host和x-date(如果存在),用于后续签名计算中明确参与的请求头
        string signedHeaders = "host;x-content-sha256;x-date";
        canonicalRequestBuilder.Append(signedHeaders).Append("\n");
        // 6. 添加请求体哈希值(HexEncode(Hash(RequestPayload)))
        // 计算请求体的哈希值(使用SHA256算法),并将结果转换为十六进制编码后添加到规范请求字符串中
        canonicalRequestBuilder.Append(HashSHA256(Encoding.UTF8.GetBytes(requestBody)));

        string canonicalRequest = canonicalRequestBuilder.ToString();
        Debug.Log(canonicalRequest);

        // 第三步:计算规范请求的哈希值(HexEncode(Hash(CanonicalRequest)))
        string hashedCanonicalRequest = HashSHA256(Encoding.UTF8.GetBytes(canonicalRequest));

        // 第四步:构建凭证范围字符串(CredentialScope)
        // 按照文档要求,取X-Date中的日期部分(前8位),与region、service和固定的“request”字符串拼接,用于界定签名的有效范围
        string shortDate = xDate.Substring(0, 8);
        string credentialScope = $"{shortDate}/{region}/{service}/request";

        // 第五步:构建待签名字符串(StringToSign)
        string stringToSign = $"HMAC-SHA256\n{xDate}\n{credentialScope}\n{hashedCanonicalRequest}";
        Debug.Log(stringToSign);
        // 第六步:计算签名密钥(kSigning)
        // 通过多层HMAC计算,使用秘密密钥(secretKey)和相关的日期、区域、服务信息逐步派生得到签名密钥
        byte[] secretKeyBytes = Encoding.UTF8.GetBytes(secretKey);
        byte[] kDate = HmacSha256(secretKeyBytes, shortDate);
        byte[] kRegion = HmacSha256(kDate, region);
        byte[] kService = HmacSha256(kRegion, service);
        byte[] kSigning = HmacSha256(kService, "request");

        // 第七步:计算签名(Signature)
        // 使用派生得到的签名密钥(kSigning)和待签名字符串(StringToSign)进行HMAC计算,然后将结果转换为十六进制编码

        byte[] signatureBytes = HmacSha256(kSigning, stringToSign);
        string signature = ByteArrayToHexString(signatureBytes);
        return signature;
    }

    // 辅助方法,用于添加规范化的请求头到构建器中
    private void AddCanonicalHeader(StringBuilder builder, string headerName, string headerValue)
    {
        builder.Append(headerName.ToLower()).Append(":").Append(headerValue.Trim()).Append("\n");
    }

    // 辅助方法,执行HMAC-SHA256计算,返回字节数组结果
    private byte[] HmacSha256(byte[] key, string data)
    {
        using (HMACSHA256 hmac = new HMACSHA256(key))
        {
            return hmac.ComputeHash(Encoding.UTF8.GetBytes(data));
        }
    }

    // 辅助方法,将字节数组转换为十六进制编码的字符串
    private string ByteArrayToHexString(byte[] bytes)
    {
        StringBuilder hex = new StringBuilder(bytes.Length * 2);
        foreach (byte b in bytes)
        {
            hex.AppendFormat("{0:x2}", b);
        }
        return hex.ToString();
    }

    // 辅助方法,用于将时间戳转换为符合要求的X-Date格式字符串
    private string GetFormattedXDate(long timestamp)
    {
        DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeSeconds(timestamp).ToUniversalTime();
        return dateTimeOffset.ToString("yyyyMMdd'T'HHmmss'Z'");
    }

    // 计算字节数组的SHA256哈希值,并返回十六进制字符串表示
    private string HashSHA256(byte[] content)
    {
        using (SHA256 sha256Hash = SHA256.Create())
        {
            byte[] hashBytes = sha256Hash.ComputeHash(content);
            StringBuilder sb = new StringBuilder();
            for (int i = 0, n = hashBytes.Length; i < n; i++)
            {
                sb.Append(hashBytes[i].ToString("x2"));
            }
            return sb.ToString();
        }
    }

    IEnumerator GenerateImage()
    {
        long timestamp = GetTimestamp();
        string method = "POST"; // 请求方法,固定为POST,可根据实际情况调整
        string path = ""; // 这里假设你的请求路径是/generate,需根据实际API调整
        string contentType = "application/json"; // 根据请求体内容类型设置

        // 构建请求的JSON格式数据,按照文档里请求格式要求填充各参数
        ImageGenerationRequest requestData = new ImageGenerationRequest
        {
            req_key = "high_aes_general_v20_L",
            prompt = textPrompt,
            model_version = "general_v2.0_L",
            req_schedule_conf = "general_v20_9B_rephraser",
            seed = -1,
            scale = 3.5f,
            ddim_steps = 16,
            width = 512,
            height = 512,
            use_sr = true,
            return_url = true,
            logo_info = new LogoInfo
            {
                add_logo = false,
                position = 0,
                language = 0,
                opacity = 0.3f,
                logo_text_content = "这里是明水印内容"
            }
        };
        string requestBody = JsonUtility.ToJson(requestData);

        // 生成签名
        string signature = GenerateSignature(timestamp, accessKey, secretKey, method, path, contentType, requestBody);
        //string signature = "1caf8e82d88a9fc8f094f6d800616522e7c78f23f7e4ee568625b9b825e15eb0";
        //Debug.Log(signature);
        UnityWebRequest request = new UnityWebRequest(apiUrl, method);
        byte[] bodyRaw = Encoding.UTF8.GetBytes(requestBody);
        request.uploadHandler = (UploadHandler)new UploadHandlerRaw(bodyRaw);
        request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();

        // 设置Content-Type请求头
        request.SetRequestHeader("Content-Type", contentType);

        //设置Host请求头,从API请求地址中提取主机部分
        //string host = new Uri(apiUrl).Host;
       // request.SetRequestHeader("host", host);

        // 设置X-Date请求头,使用获取到的时间戳转换后的格式
        string xDate = GetFormattedXDate(timestamp);
        request.SetRequestHeader("X-Date", xDate);

        // 计算并设置X-Content-Sha256请求头,对请求体内容计算SHA256哈希值
        string xContentSha256 = HashSHA256(bodyRaw);
        request.SetRequestHeader("X-Content-Sha256", xContentSha256);
        Debug.Log(xContentSha256);

        // 构建并设置Authorization请求头,包含签名等认证信息
        string credentialScope = $"{xDate.Substring(0, 8)}/{region}/{service}/request";
        string authorizationHeader = $"HMAC-SHA256 Credential={accessKey}/{credentialScope}, SignedHeaders=host;x-content-sha256;x-date, Signature={signature}";


        request.SetRequestHeader("Authorization", authorizationHeader);
     

        yield return request.SendWebRequest();

        // 按照新的方式判断请求结果,使用isDone和isNetworkError、isHttpError属性来替代原来的.result属性判断
        if (request.isDone)
        {
            //
            // 解析返回的JSON数据,获取图片相关内容并处理显示(按文档返回格式要求操作)
            string responseJson = request.downloadHandler.text;
            Debug.Log(responseJson);
            ImageGenerationResponse response = JsonUtility.FromJson<ImageGenerationResponse>(responseJson);
            Debug.Log(response.data.binary_data_base64.Count);
            if (response.data.binary_data_base64 != null && response.data.binary_data_base64.Count > 0)
            {
                byte[] imageBytes = System.Convert.FromBase64String(response.data.binary_data_base64[0]);
                Texture2D texture = new Texture2D(2, 2);
                texture.LoadImage(imageBytes);
                Sprite sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f));
                resultImage.sprite = sprite;
            }
            else
            {
                Debug.LogError("没有获取到有效的图片数据");
            }
        }
        else
        {
            Debug.LogError("请求出错: " + request.error);
        }
    }

    public void StartImageGeneration()
    {
        StartCoroutine(GenerateImage());
    }

    private void Start()
    {
        StartImageGeneration();
    }
}

评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值