- 将 API key 由硬编码改为配置项
- 删除了 Launcher 场景中的 Camera
This commit is contained in:
SepComet 2026-02-25 18:00:14 +08:00
parent f8c0f46c36
commit 8606e18e54
3 changed files with 79 additions and 139 deletions

View File

@ -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<OpenAIConfig>(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)

View File

@ -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}

Binary file not shown.