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

View File

@@ -88,6 +88,17 @@ namespace WulaFallenEmpire
listingStandard.GapLine();
listingStandard.CheckboxLabeled("Wula_EnableDebugLogs".Translate(), ref settings.enableDebugLogs, "Wula_EnableDebugLogsDesc".Translate());
listingStandard.GapLine();
listingStandard.CheckboxLabeled("Wula_AISettings_AutoCommentary".Translate(), ref settings.enableAIAutoCommentary, "Wula_AISettings_AutoCommentaryDesc".Translate());
if (settings.enableAIAutoCommentary)
{
listingStandard.Label("Wula_AISettings_CommentaryChance".Translate() + $" ({settings.aiCommentaryChance:P0})");
listingStandard.Label("Wula_AISettings_CommentaryChanceDesc".Translate());
settings.aiCommentaryChance = listingStandard.Slider(settings.aiCommentaryChance, 0f, 1f);
settings.aiCommentaryChance = Mathf.Clamp01(settings.aiCommentaryChance);
listingStandard.CheckboxLabeled("Wula_AISettings_NegativeOnly".Translate(), ref settings.commentOnNegativeOnly, "Wula_AISettings_NegativeOnlyDesc".Translate());
}
// 视觉设置部分
listingStandard.GapLine();
listingStandard.Label("<color=cyan>视觉与多模态设置</color>");

View File

@@ -19,6 +19,9 @@ namespace WulaFallenEmpire
// 视觉功能配置
public bool enableVlmFeatures = false;
public bool enableAIAutoCommentary = false;
public float aiCommentaryChance = 0.7f;
public bool commentOnNegativeOnly = false;
public override void ExposeData()
{
@@ -36,6 +39,9 @@ namespace WulaFallenEmpire
// 简化后的视觉配置
Scribe_Values.Look(ref enableVlmFeatures, "enableVlmFeatures", false);
Scribe_Values.Look(ref enableAIAutoCommentary, "enableAIAutoCommentary", false);
Scribe_Values.Look(ref aiCommentaryChance, "aiCommentaryChance", 0.7f);
Scribe_Values.Look(ref commentOnNegativeOnly, "commentOnNegativeOnly", false);
base.ExposeData();
}