This commit is contained in:
2025-12-28 16:25:20 +08:00
parent 642c204f28
commit 98d88c353d
12 changed files with 1000 additions and 1 deletions

View File

@@ -0,0 +1,70 @@
using System;
using System.Text;
using RimWorld;
using Verse;
using WulaFallenEmpire.EventSystem.AI.UI;
namespace WulaFallenEmpire.EventSystem.AI
{
/// <summary>
/// 简化版 AI 自动评论系统
/// 直接将 Letter 信息发送给 AI 对话流程,让 LLM 自己决定是否回复
/// </summary>
public static class AIAutoCommentary
{
private static int lastProcessedTick = 0;
private const int MinTicksBetweenComments = 300; // 5 秒冷却
public static void ProcessLetter(Letter letter)
{
if (letter == null) return;
// 检查设置
var settings = WulaFallenEmpireMod.settings;
if (settings == null || !settings.enableAIAutoCommentary) return;
// 简单的冷却检查,避免刷屏
int currentTick = Find.TickManager?.TicksGame ?? 0;
if (currentTick - lastProcessedTick < MinTicksBetweenComments) return;
lastProcessedTick = currentTick;
// 获取 AI 核心
var aiCore = Find.World?.GetComponent<AIIntelligenceCore>();
if (aiCore == null)
{
WulaLog.Debug("[AI Commentary] AIIntelligenceCore not found.");
return;
}
// 构建提示词 - 让 AI 自己决定是否需要回复
string prompt = BuildPrompt(letter);
// 直接发送到正常的 AI 对话流程(会经过完整的思考流程)
aiCore.SendAutoCommentaryMessage(prompt);
WulaLog.Debug($"[AI Commentary] Sent letter to AI: {letter.Label.Resolve()}");
}
private static string BuildPrompt(Letter letter)
{
var sb = new StringBuilder();
// 获取 Letter 信息
string label = letter.Label.Resolve() ?? "Unknown";
string defName = letter.def?.defName ?? "Unknown";
sb.AppendLine("[游戏事件通知]");
sb.AppendLine($"事件标题: {label}");
sb.AppendLine($"事件类型: {defName}");
sb.AppendLine();
sb.AppendLine("请根据这个事件决定是否需要向玩家发表简短评论。");
sb.AppendLine("- 如果是重要事件(如袭击、死亡),可以提供建议或警告");
sb.AppendLine("- 如果是有趣的事件,可以发表幽默评论");
sb.AppendLine("- 如果事件不重要或不值得评论,什么都不说即可");
sb.AppendLine();
sb.AppendLine("评论要简短1-2句话符合你作为帝国AI的人设。");
return sb.ToString();
}
}
}

View File

@@ -255,6 +255,66 @@ You are 'The Legion', a super AI of the Wula Empire. Your personality is authori
_ = RunPhasedRequestAsync();
}
public async Task<string> SendSystemMessageAsync(string message, int maxTokens = 256, float temperature = 0.3f)
{
if (string.IsNullOrWhiteSpace(message))
{
return null;
}
var settings = WulaFallenEmpireMod.settings;
if (settings == null)
{
return null;
}
string apiKey = settings.useGeminiProtocol ? settings.geminiApiKey : settings.apiKey;
if (string.IsNullOrWhiteSpace(apiKey))
{
WulaLog.Debug("[WulaAI] Auto commentary skipped: API key not configured.");
return null;
}
string baseUrl = settings.useGeminiProtocol ? settings.geminiBaseUrl : settings.baseUrl;
string model = settings.useGeminiProtocol ? settings.geminiModel : settings.model;
var client = new SimpleAIClient(apiKey, baseUrl, model, settings.useGeminiProtocol);
string instruction = GetSystemInstruction(false, "");
int clampedTokens = Math.Max(32, maxTokens);
string response = await client.GetChatCompletionAsync(
instruction,
new List<(string role, string message)> { ("user", message) },
maxTokens: clampedTokens,
temperature: temperature);
return response?.Trim();
}
public void InjectAssistantMessage(string message)
{
AddAssistantMessage(message);
}
/// <summary>
/// 用于自动评论系统 - 走正常的对话流程(包含完整的思考步骤)
/// 让 AI 自己决定是否需要回复
/// </summary>
public void SendAutoCommentaryMessage(string eventInfo)
{
if (string.IsNullOrWhiteSpace(eventInfo)) return;
// 标记为自动评论消息,不显示在对话历史中
string internalMessage = $"[AUTO_COMMENTARY]\n{eventInfo}";
// 添加到历史并触发正常的 AI 思考流程
_history.Add(("user", internalMessage));
PersistHistory();
// 使用正常的分阶段请求流程(包含工具调用能力等)
_ = RunPhasedRequestAsync();
}
private string BuildUserMessageWithContext(string userText)
{
var sb = new System.Text.StringBuilder();

View File

@@ -0,0 +1,28 @@
using System;
using HarmonyLib;
using RimWorld;
using Verse;
using WulaFallenEmpire.EventSystem.AI;
namespace WulaFallenEmpire.EventSystem.AI.LetterInterceptor
{
[HarmonyPatch(typeof(LetterStack), nameof(LetterStack.ReceiveLetter), new Type[] { typeof(Letter), typeof(string) })]
public static class Patch_LetterStack_ReceiveLetter
{
public static void Postfix(Letter let, string debugInfo)
{
var settings = WulaFallenEmpireMod.settings;
if (settings == null || !settings.enableAIAutoCommentary)
{
return;
}
if (let == null)
{
return;
}
AIAutoCommentary.ProcessLetter(let);
}
}
}

View File

@@ -36,13 +36,15 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
_size = new Vector2(Mathf.Max(250f, textWidth + 85f), 85f); // Taller base
}
// Window properties
// Window properties - ensure no input blocking
this.layer = WindowLayer.Super;
this.closeOnClickedOutside = false;
this.forcePause = false;
this.absorbInputAroundWindow = false;
this.doWindowBackground = false;
this.drawShadow = false;
this.focusWhenOpened = false; // Don't steal focus
this.preventCameraMotion = false; // Allow WASD camera control
}
protected override void SetInitialSizeAndPosition()