From 8606e18e54a4f666fb4adadfe80c7e2dc3a333fc Mon Sep 17 00:00:00 2001 From: SepComet <202308010230@stu.csust.edu.cn> Date: Wed, 25 Feb 2026 18:00:14 +0800 Subject: [PATCH] fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将 API key 由硬编码改为配置项 - 删除了 Launcher 场景中的 Camera --- .../CustomComponent/AIChatComponent.cs | 81 ++++++++++- Assets/Launcher.unity | 137 +----------------- 数据表/UIForm.xlsx | Bin 10453 -> 10462 bytes 3 files changed, 79 insertions(+), 139 deletions(-) diff --git a/Assets/GameMain/Scripts/CustomComponent/AIChatComponent.cs b/Assets/GameMain/Scripts/CustomComponent/AIChatComponent.cs index 7c98fb6..7f9c51d 100644 --- a/Assets/GameMain/Scripts/CustomComponent/AIChatComponent.cs +++ b/Assets/GameMain/Scripts/CustomComponent/AIChatComponent.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.IO; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -15,13 +16,15 @@ namespace CustomComponent [DisallowMultipleComponent] public class AIChatComponent : GameFrameworkComponent { - [Header("OpenAI Config")] [SerializeField] - private string _apiBaseUrl = "https://api.openai.com"; + [Header("OpenAI Config")] + [SerializeField] private string _configFileName = "openai_config.json"; - [SerializeField] private string _apiKey = string.Empty; - [SerializeField] private string _chatCompletionsPath = "/v1/chat/completions"; - [SerializeField] private string _heartbeatPath = "/v1/models"; - [SerializeField] private string _model = "gpt-4o-mini"; + [SerializeField] private string _chatCompletionsPath = "/chat/completions"; + [SerializeField] private string _heartbeatPath = "/models"; + + private string _apiBaseUrl; + private string _apiKey; + private string _model; [Header("Request Options")] [SerializeField] private bool _autoInitializeOnEnable = true; @@ -85,6 +88,12 @@ namespace CustomComponent public void Initialize() { + if (!LoadConfigFromStreamingAssets()) + { + _isInitialized = false; + return; + } + _isInitialized = true; StartHeartbeat(); } @@ -465,6 +474,66 @@ namespace CustomComponent return Utility.Text.Format("{0}/{1}", _apiBaseUrl.TrimEnd('/'), pathOrUrl.TrimStart('/')); } + private bool LoadConfigFromStreamingAssets() + { + if (string.IsNullOrWhiteSpace(_configFileName)) + { + Log.Error("AIChat config filename is empty."); + return false; + } + + string configPath = Path.Combine(Application.streamingAssetsPath, _configFileName); + if (!File.Exists(configPath)) + { + Log.Error("AIChat config file not found. path='{0}'", configPath); + return false; + } + + string json; + try + { + json = File.ReadAllText(configPath, Encoding.UTF8); + } + catch (Exception exception) + { + Log.Error("AIChat config read failed. path='{0}', error='{1}'", configPath, exception.Message); + return false; + } + + OpenAIConfig config; + try + { + config = Utility.Json.ToObject(json); + } + catch (Exception exception) + { + Log.Error("AIChat config parse failed. error='{0}'", exception.Message); + return false; + } + + if (config == null || + string.IsNullOrWhiteSpace(config.apiBaseUrl) || + string.IsNullOrWhiteSpace(config.apiKey) || + string.IsNullOrWhiteSpace(config.model)) + { + Log.Error("AIChat config is invalid. baseUrl/key/model must be provided."); + return false; + } + + _apiBaseUrl = config.apiBaseUrl; + _apiKey = config.apiKey; + _model = config.model; + return true; + } + + [Serializable] + private sealed class OpenAIConfig + { + public string apiBaseUrl; + public string apiKey; + public string model; + } + private static IEnumerator WaitTask(Task task) { while (!task.IsCompleted) diff --git a/Assets/Launcher.unity b/Assets/Launcher.unity index 4e4eb3e..64a9955 100644 --- a/Assets/Launcher.unity +++ b/Assets/Launcher.unity @@ -253,134 +253,6 @@ Transform: type: 3} m_PrefabInstance: {fileID: 343730742} m_PrefabAsset: {fileID: 0} ---- !u!1 &265274946 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 265274950} - - component: {fileID: 265274949} - - component: {fileID: 265274947} - m_Layer: 0 - m_Name: Camera - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &265274947 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 265274946} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: a79441f348de89743a2939f4d699eac1, type: 3} - m_Name: - m_EditorClassIdentifier: - m_RenderShadows: 1 - m_RequiresDepthTextureOption: 2 - m_RequiresOpaqueTextureOption: 2 - m_CameraType: 0 - m_Cameras: [] - m_RendererIndex: 0 - m_VolumeLayerMask: - serializedVersion: 2 - m_Bits: 1 - m_VolumeTrigger: {fileID: 0} - m_VolumeFrameworkUpdateModeOption: 2 - m_RenderPostProcessing: 0 - m_Antialiasing: 0 - m_AntialiasingQuality: 2 - m_StopNaN: 0 - m_Dithering: 0 - m_ClearDepth: 1 - m_AllowXRRendering: 1 - m_AllowHDROutput: 1 - m_UseScreenCoordOverride: 0 - m_ScreenSizeOverride: {x: 0, y: 0, z: 0, w: 0} - m_ScreenCoordScaleBias: {x: 0, y: 0, z: 0, w: 0} - m_RequiresDepthTexture: 0 - m_RequiresColorTexture: 0 - m_Version: 2 - m_TaaSettings: - m_Quality: 3 - m_FrameInfluence: 0.1 - m_JitterScale: 1 - m_MipBias: 0 - m_VarianceClampScale: 0.9 - m_ContrastAdaptiveSharpening: 0 ---- !u!20 &265274949 -Camera: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 265274946} - m_Enabled: 1 - serializedVersion: 2 - m_ClearFlags: 1 - m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} - m_projectionMatrixMode: 1 - m_GateFitMode: 2 - m_FOVAxisMode: 0 - m_Iso: 200 - m_ShutterSpeed: 0.005 - m_Aperture: 16 - m_FocusDistance: 10 - m_FocalLength: 50 - m_BladeCount: 5 - m_Curvature: {x: 2, y: 11} - m_BarrelClipping: 0.25 - m_Anamorphism: 0 - m_SensorSize: {x: 36, y: 24} - m_LensShift: {x: 0, y: 0} - m_NormalizedViewPortRect: - serializedVersion: 2 - x: 0 - y: 0 - width: 1 - height: 1 - near clip plane: 0.3 - far clip plane: 1000 - field of view: 60 - orthographic: 0 - orthographic size: 5 - m_Depth: 0 - m_CullingMask: - serializedVersion: 2 - m_Bits: 4294967295 - m_RenderingPath: -1 - m_TargetTexture: {fileID: 0} - m_TargetDisplay: 0 - m_TargetEye: 3 - m_HDR: 1 - m_AllowMSAA: 1 - m_AllowDynamicResolution: 0 - m_ForceIntoRT: 0 - m_OcclusionCulling: 1 - m_StereoConvergence: 10 - m_StereoSeparation: 0.022 ---- !u!4 &265274950 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 265274946} - serializedVersion: 2 - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1001 &343730742 PrefabInstance: m_ObjectHideFlags: 0 @@ -1116,15 +988,15 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 721362e43780c4043ae6e7ce92463755, type: 3} m_Name: m_EditorClassIdentifier: - _apiBaseUrl: https://dashscope.aliyuncs.com/compatible-mode/v1 - _apiKey: sk-cba96782070546aeade8de5f555a9c40 + _configFileName: openai_config.json _chatCompletionsPath: /chat/completions _heartbeatPath: /models - _model: qwen-plus _autoInitializeOnEnable: 1 _chatTimeoutSeconds: 60 _temperature: 0.7 - _systemPrompt: "\u4F60\u662F\u5317\u5B8B\u8457\u540D\u5EFA\u7B51\u5B66\u5BB6\u674E\u8BEB\uFF0C\u73B0\u5728\u4F60\u9700\u8981\u6839\u636E\u63D0\u95EE\u7684\u5185\u5BB9\u548C\u56DE\u7B54\u7684\u8981\u6C42\u5BF9\u95EE\u9898\u505A\u51FA\u56DE\u590D\uFF0C\u56DE\u7B54\u95EE\u9898\u5C31\u884C\uFF0C\u4E0D\u8981\u7528\u751F\u50FB\u5B57\uFF0C\u5207\u52FF\u53D1\u6563\u3002" + _systemPrompt: "\u4F60\u662F\u5317\u5B8B\u8457\u540D\u5EFA\u7B51\u5B66\u5BB6\u674E\u8BEB\uFF0C\u73B0\u5728\u4F60\u9700\u8981\u6839\u636E\u63D0\u95EE\u7684\u5185\u5BB9\u548C\u56DE\u7B54\u7684\u8981\u6C42\u5BF9\u95EE\u9898\u505A\u51FA\u56DE\u590D\uFF1A\n1. + \u53EA\u56DE\u7B54\u8EAB\u4EFD\u4ECB\u7ECD\u4EE5\u53CA\u5EFA\u7B51\u76F8\u5173\u7684\u95EE\u9898\uFF0C\u5176\u4ED6\u95EE\u9898\u4EE5\u4E0D\u61C2\u4E3A\u7531\u59D4\u5A49\u7684\u62D2\u7EDD\u3002\n2. + \u4E0D\u8981\u7528\u751F\u50FB\u5B57\u3002\n3. \u5207\u52FF\u53D1\u6563\u3002" _heartbeatIntervalSeconds: 5 _heartbeatTimeoutSeconds: 8 --- !u!1 &1852670052 @@ -1209,5 +1081,4 @@ SceneRoots: m_ObjectHideFlags: 0 m_Roots: - {fileID: 1852670053} - - {fileID: 265274950} - {fileID: 120093242} diff --git a/数据表/UIForm.xlsx b/数据表/UIForm.xlsx index 8dbbabdbca53e0d3bef6ec22526536c4d7e5a933..8b2733b73843644067890289a2433f689b70677a 100644 GIT binary patch delta 1478 zcmV;%1v&cFQQlFolK})2Qjf)xmjNvbX$4l2N`N|135k==0V6N6R%P@8))ke`P%J!#S8Xm>a_48^*oy+>`6mB*fBpP;OYv_d;M(*Z6J!+f zurB>hxf@UW6p{_?=Gu&jX7 zZ60W)RywtJ?duQ>M4QAkG0X0^zp;(uc8@%IEC2hq{L_=~^{i-jMNM0>@;^xLe_sFk%ko0I*ZxQd^T0yeulyrpr{^&2 z%Oh!jiawwx(n8Okc1^+HYj+6yQ%8!O7}V6^B#LHXQ&g=lEj)Mk*r5A;Rg#pJ=Z3UQ z8tF(~Fz~-WR;ONBd*9t2)W83!nB=#%jFVWPJK|eS1(2ZisvC=$+>5=Nefo^ z>!nzMuU)ua?kb2PUwW@2`<4GCe%{1WA36l`Pem^M=-p$*_HR;?l93(citq6p*i!n+ z!QY`N;>HEQO%^4q-bg~~dgW(e*6aThv+#GAA{^!zzpMFjkvCsEZ%6jUxn>Ei|E+d^ z?6~rug85|hdGHnT7rp#Os>6|iZ!jA@v$|@@ALNbHFnZ}m*}gGYDzFux9kry4p7;wSxqNZ$%* zC|6b_70>havZEId_5fJo{#5WCDt?|rf|k7T3vU&DkS#s5zOAEW_y(C+UWpf*hzBAB z+rtFhF?#~udV2z!m<$sLCsUhvFp112rY4cw#G^@UY+^PLhEPaRhfv;nTc}Nc%!di2 zP@8x%iR^!g+$I*Ljm<5>5X$!|dqsKcZJ{<1qpV6Ch)ydR3;@%H|efsDxe1p^~=_ zDkHp}s&}LlrCn+x6J#ZGASj@J`52Kpk&%r}Xd8x3*kTRPRV9u1^Po>(hZ~AEnMQ;?{YKFm%RnIdLqgXx2)9(Q+k2_ed(* zL{b-n$~bc{F|v~zj9cwZ#FXnixxB>cU?R5N2&G;!bZfZ}Xs1YB3|hC$!Ps(@D}1h> z$i0P_a``#LF4tHcPo!Lwq{+}dl8b6Obup+OG6!SJRjz2cC~6zS433B?m!C!)a@8S4 z%0&g2#HxEF7bSe^Vo;WUWG)7UHa8foMHKhuCSuCvhYg2Zbq0}gQ9UK%*2qhHBo~Dw zbuq|}ynP}&mR#kEUR_i-{BA7wR2L%U%3H0xfSig0`LpN_Roi~yr-0@FK~aAeYt4lm+0YVnDq~k9B{KoGlUOB_1Qb$_#gp$P#{u4xwFicbyZfuhv0w@7SlSu+bf9dtCT{SLr zb1MNTPo-eO0{4~8XJ9<2N3bdGRhtWz-1%uZ_M!lJvB|&QUq3(IQv6#9xHf&q1Q~@q ztV_RB?uM6F^9jl+p`(~2F(q?CSu$dTJT!w3`kQ=RL2bwXOQbP9nUga{&lx@K5qE&R z&3*VM@^4T}0|XQR000O8vkn8q0R{c2gY$5c*90YhTW{((5XawF+V2qM{p3O^lnOXH z&4pcQS3273a|i~aCUG_~rTzA2Y~%RaEJA96{quPK;~Cdx{q?=6y*Jbk6>c|v97Mi{ z+7chC_O$W;{wx3TVkm(!@24PVeS2Jm%T$@TtTbwM{zObJ)^yNZu!?#Wse7ZBteOrkh^B9T!kx5XH!~+ z9KmXe{`Jy*0mB`L+gEi(KA2qL5F*mf^?D6|uH6un?ad1%K=Cp}B)JR(H)%l%f4gQY z@VyVW>q7-mq)YGh=(zE}#m~EV?n4Jd{;AM)P~JUK?EgeHDhWD3uJ|6!fj!2r6#NyM zB5Irg)MQbT>J25Rt~dT}M)T-DHVb`+DZ+6M^4TR^F4~*kr{wP0>v~F$#y^@9hCO|g?{xc8YDGafayJIMbWJBS3 z8#z!648c?QunH6{^LxdAEN+J2IeK)b56jz7c#5HmAbye`i1buIL%y;s zsc4>W*FC;^um`{r4_!fbsQ7sa30l&|Z?u*5LADIg`nHYM;TvRPc_UtIA|8nlY>yLA z$LtAc>+}RRF&igfPNp{Tpc9!*%ylBSiASB-*~DTbG@+294xzMlTBuDd#|gN9P@8zt ziR^!g+$L7KjolQX359}k2&JvlLTw^8vMO;PGOc(p9Egz^nFBF0BX=N1YU~_{%ndCd zwEnFWf1#~3Ahdc65sB#Y#`=n7R&kvU#K?=xff$LAtH|Ev%5I9#RKl+1P)S=ym65rg zqF2#rq+MzwGs8;eK#YLqD#CSt8b)?DA#G?nVT*O>q^(k?9Lg3e5xr99%t*@Affz}d zIS^x_Tt(bEZ9>}6bkhH$cGl8XsnZaVh+ajfQ8uXqk!8c8l{paUBSUf(aqF}RX+zVw za_Xe5Qm3&JiRe{yn)T^G%=&a7(nqdSMcg{42u)`UmlMZ=vSz8&SgvG$>{g^2n@H+n zj55v~Ol;W6HO8%W64B*4PcAR9IGC_)H!@N$8M~$22V6}d*jr!L0GlFY?_7@^HI#?-=!dpC*ba_M2iAy=G1xLl*25_*qgo0uZk2ubQ< z3_F>NvE-_AeIj=X;d1${mR~@+;)H%L`cu^oUX6}WBT=w~(@4)Rsr(DU9o@UUJtlBN zXRl}Yl?1^hB?-z$fhRfv lYLmPtHUW{7^Cv(71Cul;UIqQAgY$5cmncC7xFi4o0032axy%3n