当前位置: 首页 > news >正文

接入提供方的AI

查看文档

具体文档不能放上来,但是总之涉及到的东西就是

  1. 基本的请求头:
    1. App-Key
    2. Request-Timestamp:13位毫秒级
    3. Signature-Headers:参与签名的header列表
    4. Request-Uuid:随机一个id
    5. Reqeust-Signature:计算出的签名
      Pasted image 20250815140548.pngPasted image 20250815140652.png
      Pasted image 20250815140709.pngPasted image 20250815140734.pngPasted image 20250815140752.png
      有点像java还是javascript,不认识。总归能看懂点意思。
      反正一个函数一个函数实现。

开始实现签名-签名的底层运算

  1. 第一个合并签名太容易弄了。
//.h
static FString GetStringToSign(const FString& RequestMethod, const FString& RequestBodyMD5, const FString& RequestHeadersToSign, const FString& RequestUrlToSign);
//.cpp
FString UAPI::GetStringToSign(const FString& RequestMethod, const FString& RequestBodyMD5, const FString& RequestHeadersToSign, const FString& RequestUrlToSign)
{return RequestMethod + TEXT("\n") + RequestBodyMD5 + TEXT("\n") + RequestHeadersToSign + RequestUrlToSign;
}
  1. 不好,是加密
    因为CPP的基本操作是造轮子,所以没有给md5加密库,base64编码库,以及hash256加密库;为什么我会这么觉得,因为我要吃玉米卷了。【精神恍惚,精神崩溃,呆滞ing】。
    1. 找网上的第三方cpp头文件,某些网安领域的专业人士开源的源码。能满足需求这里一口气把所有的源码配置都弄上来。Pasted image 20250815145905.png这这里的加密库Hashlib是我自己到处找到的一批能满足需求的源码,有的从github下下来,有的从csdn上拷过来,反正我是直接看他们的引导文档,和引导用的main函试着跑的,跑下来对的上提供的签名样例,我就把.h和.cpp文件分拆到这个Hashlib里了。Pasted image 20250815150643.png
    2. 然后修改build.cs:注意hashilib里的build.cs没有用,删掉也无大碍,这个Hashlib.Build.cs的作用就是能让Pasted image 20250815150953.pngPasted image 20250815151118.png,额,让我们在VS创建UE的C++类的时候,多一个模块。做更高程度的封装肯定要这个,但是我tm都不用get方法了,也没打算现在接语音,所以就不封装成插件之类的东西了,应该是叫插件或者模块啥的吧?算不重要。
    3. 编写项目对应的build.cs文件,项目也是一个模块,不然刚才的模块列表不会有。什么?你不懂C#?我也不动,反正我也不用写c#,这个build.cs文件里我只用会4个函数就够用了。
      1. 第一个Console.WriteLine($"-------------------【HashilibPath:{HashilibPath}】----------------------");这个函数拿来print,这样Pasted image 20250815152244.png就能知道什么路径是被order了的了。
      2. 第二个string HashilibPath = Path.Combine(ModuleDirectory,"Hashlib");类似于python的os库path操作,反正我python看得懂。
      3. 第三个PublicIncludePaths.AddRange(new string[]{Path.Combine(HashilibPath,"include/")//Path.Combine(ThirdPartyPath, "Hashlib", "include")});看不懂,总之就是用指定路径让ue能定位到这个里面的.h头文件的。
public class SeaAPI : ModuleRules
{public SeaAPI(ReadOnlyTargetRules       Target) : base(Target){PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore","HeadMountedDisplay","HTTP","Json", "JsonUtilities" });PrivateDependencyModuleNames.AddRange(new string[] {  });//添加第三方库,ModuleDirectory就是Game/ProjectName/Source/ProjectNamestring HashilibPath = Path.Combine(ModuleDirectory,"Hashlib");Console.WriteLine($"-------------------【HashilibPath:{HashilibPath}】----------------------");PublicIncludePaths.AddRange(new string[]{Path.Combine(HashilibPath,"include/")//Path.Combine(ThirdPartyPath, "Hashlib", "include")});string SeaActorPath = Path.Combine(ModuleDirectory, "SeaActor");Console.WriteLine($"-------------------【SeaActorPath:{SeaActorPath}】----------------------");PublicIncludePaths.AddRange(new string[]{Path.Combine(SeaActorPath)//Path.Combine(ThirdPartyPath, "Hashlib", "include")});string SharedPath = Path.Combine(ModuleDirectory, "Shareds");Console.WriteLine($"------------------【SharedPath:】{SharedPath}--------------------------");PublicIncludePaths.Add(SeaActorPath);// Uncomment if you are using Slate UI// PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });// Uncomment if you are using online features// PrivateDependencyModuleNames.Add("OnlineSubsystem");// To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true}
}
5. 第四个,将路径添加到ue的cpp类中。就是直接把源文件引入这里是md5.h和hmac_sha256.h这两个文件。至于Base64是我后面发现能用现成的库的时候了,当时我天都塌了,那我弄这么久算什么,算我能吃苦吗?不过用都用了,就不改了,能跑就行,而且总会有需求ue没提供cpp吧?比如opencv,ffmpeg之类的。到时侯来这里看笔记就行了。这个导入主要还是导入到.cpp中,因为我们给蓝图节点预留的参数肯定是UE能识别的数据。
	#include "Misc/Base64.h"#include "md5.h"#include "Algo/StableSort.h"#include "HttpModule.h"#include "Interfaces/IHttpResponse.h"extern "C" {#include "hmac_sha256.h"}
  1. md5+base64:当时我弄的时候真希望友人能整整这个cpp的包管理。
//.h
static FString getRequestBodyMD5(const FString& BodyString);//.cpp
FString UAPI::getRequestBodyMD5(const FString& BodyString)
{UE_LOG(LogTemp, Warning, TEXT("BodyString:::%s"),*BodyString);std::string StdInput = TCHAR_TO_UTF8(*BodyString);if (StdInput.empty()) {return "";}MD5 md5Encoder(StdInput);std::string OnceEncode = md5Encoder.md5();TArray<uint8> MD5Bytes;MD5Bytes.Append((const uint8*)OnceEncode.c_str(), OnceEncode.length());FString TwiceEncode = FBase64::Encode(MD5Bytes);return TwiceEncode;
}
  1. HeadertoSign:我不知道为啥我的排序和提供方的排序不一样。按照ascil排序O应该在g后面,但是提供方的O在g前面。可能就是这个原因最终没能成功签名吧。主要提供方的后端也换人了,他也不知道为啥O的排序在g前面。
FString UAPI::getRequestHeadersToSign(const TMap<FString, FString>& Headers, const FString& SignatureHeadersRaw)
{TArray<FString> Keys;SignatureHeadersRaw.ParseIntoArray(Keys, TEXT(","), true);Keys.Sort([](const FString& A, const FString& B) {return A < B;});FString Result;for (const FString& Key : Keys){const FString* Value = Headers.Find(Key);  FString Line = Key + TEXT(":");            if (Value){Line += *Value;                        }Result += Line + TEXT("\n");               }return Result;
}
  1. urlToSign:这个后面又有调整,因为GET方法才有后面的?和参数,POST没有,所以得针对有无?进行判断,没有的话URI[0]作为返回值就行
FString UAPI::getRequestUrlToSign(const FString& URL)
{TArray<FString> URI;URL.ParseIntoArray(URI, TEXT("?"), true);if (URI.Num() < 2 || URI[1].IsEmpty()){return URL;}TArray<FString> KVPare;URI[1].ParseIntoArray(KVPare, TEXT("&"), true);TArray<TPair<FString, FString>> Params;for (const FString& KV : KVPare){FString Key, Value;if (KV.Split(TEXT("="), &Key, &Value)){Params.Emplace(Key, Value);}}if (Params.Num() == 0){return URI[0];}Algo::StableSortBy(Params, &TPair<FString, FString>::Key,[](const FString& A, const FString& B) { return A < B; });FString NewKVPairStr;for (const auto& Param:Params) {if (!NewKVPairStr.IsEmpty())NewKVPairStr += TEXT("&");NewKVPairStr += Param.Key + TEXT("=") + Param.Value;}//GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Blue, RetStr);return URI[0] + TEXT("?") + NewKVPairStr;
}
  1. 签名,hash256
FString UAPI::GenerateSignature(const FString& StringToSign, const FString& SecretKey)
{// 1. 把 FString → UTF-8 字节FTCHARToUTF8 SignBytes(StringToSign);FTCHARToUTF8 KeyBytes(SecretKey);// 2. 计算 HMAC-SHA256uint8 Digest[32];hmac_sha256((const uint8*)KeyBytes.Get(), KeyBytes.Length(),(const uint8*)SignBytes.Get(), SignBytes.Length(),Digest, sizeof(Digest));// 3. Base64 编码并返回FString RetStr = FBase64::Encode(Digest, sizeof(Digest));//GEngine.AddOnScreenDebugMessage(-1, 5.f, FColor::Blue, RetStr);return RetStr;
}

暴露签名用的方法

下面的这些方法基本就是想要的效果。其中有几个特别需要注意的点。

  1. UFUNCTION(BlueprintCallable,Category = "SeaAPI",DisplayName = "F002_BuildBodyString")UE用于暴露cpp函数给蓝图的宏,DisplayName是用标签替换函数名,Category是蓝图中的分类检索。
  2. 蓝图中的节点有两种,一种是static打头的,一种没有static(由实例化一个对象来调用);我这里是一个蓝图库类,本意就是只存放一批函数。一点都不想调用一个方法还得进行如下操作(拖actor到关卡蓝图,选中actor,进入关卡蓝图,获取索引),而,UPARAM(ref) FAPIData& APIDAta是一个结构体存放请求涉及的数据。
UFUNCTION(BlueprintCallable, Category = "SeaAPI", DisplayName="F000_DataSaver")
static FAPIData CreateDataSaver();UFUNCTION(BlueprintCallable,Category = "SeaAPI",DisplayName = "F002_BuildBodyString")
static FString BuildBodyString(UPARAM(ref) FAPIData& APIData,const FString& Query,const TMap<FString, FString>& Inputs,const FString& ResponseMode=TEXT("blocking"),const FString& User = TEXT(""),const FString& ConversationId = TEXT(""));UFUNCTION(BlueprintCallable, Category = "SeaAPI",DisplayName = "F001_SetParameter")
static void SetParameters(UPARAM(ref) FAPIData& APIData,const FString& InRequestUuid,const FString& InTenantId,const FString& InUserName,const FString& InRequestMethod=TEXT("POST"),const FString& InURL = TEXT("https://mr-stage.sensetime.com/api/dify/v1/parameters"),const FString& InAppKey = TEXT("3n8qrFG2ZprS5EzW"),const FString& InAppSecret = TEXT("U64GJatMDafySqRVTV"),const FString InSignatureHeader = TEXT("TenantId,UserName"));//借助外界的AppKey,AppSecret,
UFUNCTION(BlueprintCallable, Category = "SeaAPI", DisplayName = "F004_BuildSignature")
static FString BuildSignature(UPARAM(ref) FAPIData& APIData);
//static FString BuildSignature(FAPIData& APIData, const FString& RequestMethod, const FString& BodyString, const TMap<FString, FString>& Headers, const FString& SignatureHeadersRaw, const FString& URL);UFUNCTION(BlueprintCallable,Category = "SeaAPI",DisplayName = "F003_GetTimestamp")
static FString BuildTimestamp(UPARAM(ref) FAPIData& APIData);

Http异步请求

这块儿,我连看都看不懂,完全理解不了,现在的我也还理解不了。直接炒的答案。我看的后半段教程
点我查看视频,我照着实现了后面的例子,因为前面的不支持异步调用。然后对方的后端老哥人很好。还帮我停掉了签名让我来测请求能不能过关。请求很容易就发出去了,然后因为这一段完全不会,所以解析请求里的内容并转码成utf16也是交给claude。等于说接下里把签名和请求连个类衔接起来就可以跑了。

这就是之前存储数据到结构体里的好处,直接拿出来构造请求就可以,而且还可以用数组存放多个用户的请求。让我们的客户端在访问的时候自己指定一些id之类的。让关卡中的多个玩家分别和ai对话。这里主要靠客户端大哥帮我擦屁股吧。因为我还不够强。

http://www.sczhlp.com/news/12535/

相关文章:

  • 使用 MetaWeblog API 修改博客
  • Poste.io自建域名的邮箱本地化部署方案 - 明明就
  • vscode里退出github Copilot账号,切换github Copilot账号,completion quota用完了,显示100%,vscode不能自动补全
  • Grain用于读取和处理用于训练和评估 JAX 模型的数据
  • 华三-OSPF
  • 嘉立创地阔星STM32F103C8T6 arduino ch340串口烧录
  • 实战指南|电力管理系统搭建全流程解析
  • 公司项目之 qiankun 微前端项目 总结;
  • 《ESP32-S3使用指南—IDF版 V1.6》第三十三章 RGB显示屏实验
  • Python工具箱系列(六十五)
  • 华三-堆叠
  • 赋能 Gulp 构建流:使用腾讯云 EdgeOne 为 Pug 博客注入全球 CDN 与安全防护能力
  • redis主从复制详解
  • 使用XXL-SSO实现登录认证以及权限管控
  • XXL-SSO v2.0.0 发布|单点登录框架
  • XXL-TOOL v2.0.0 发布 | Java工具类库
  • Python工具箱系列(六十一)
  • Python工具箱系列(六十)
  • LeNet(Jax/Flax)实现
  • CMC蒲和平1.2
  • 华三-无线-集中转发
  • CVPR 2024计算机视觉前沿论文速览
  • 华三-无线-本地转发
  • mainwindows.cpp
  • 华三-BFD
  • 华三-路由策略
  • 华三-策略路由
  • 华三-浮动路由
  • is这个特性你有用过吗?主要用在哪些方面?
  • 7、制作人物对话