This commit is contained in:
2025-12-28 00:42:12 +08:00
parent 13abfef2c5
commit 4ef61320ce
3 changed files with 62 additions and 7 deletions

View File

@@ -489,6 +489,10 @@ You are 'The Legion', a super AI of the Wula Empire. Your personality is authori
if (hasImage && WulaFallenEmpireMod.settings?.enableVlmFeatures == true)
{
phaseInstruction += "\n- NATIVE MULTIMODAL: A current screenshot of the game is attached to this request. You can see the game state directly. Use it to determine coordinates for visual tools or to understand the context.";
if (phase == RequestPhase.ActionTools)
{
phaseInstruction += "\n- VISUAL PHASE RULE: This phase is for ACTIONS only. If you want to describe the screen to the user, wait for the next phase (Reply Phase). Output XML actions only here.";
}
}
string actionWhitelist = phase == RequestPhase.ActionTools
@@ -1150,7 +1154,8 @@ You are 'The Legion', a super AI of the Wula Empire. Your personality is authori
AddAssistantMessage("<i>[P.I.A] 正在汇总战报并建立通讯记录...</i>");
}
string reply = await client.GetChatCompletionAsync(replyInstruction, BuildReplyHistory());
// VISUAL CONTEXT FOR REPLY: Pass the image so the AI can describe what it sees.
string reply = await client.GetChatCompletionAsync(replyInstruction, BuildReplyHistory(), base64Image: base64Image);
if (string.IsNullOrEmpty(reply))
{
AddAssistantMessage("Wula_AI_Error_ConnectionLost".Translate());

View File

@@ -60,23 +60,44 @@ namespace WulaFallenEmpire.EventSystem.AI
if (maxTokens.HasValue) jsonBuilder.Append($"\"max_tokens\": {Math.Max(1, maxTokens.Value)},");
if (temperature.HasValue) jsonBuilder.Append($"\"temperature\": {temperature.Value.ToString("0.###", System.Globalization.CultureInfo.InvariantCulture)},");
var validMessages = messages.Where(m =>
{
string r = (m.role ?? "user").ToLowerInvariant();
return r != "toolcall";
}).ToList();
jsonBuilder.Append("\"messages\": [");
if (!string.IsNullOrEmpty(instruction))
{
jsonBuilder.Append($"{{\"role\": \"system\", \"content\": \"{EscapeJson(instruction)}\"}},");
jsonBuilder.Append($"{{\"role\": \"system\", \"content\": \"{EscapeJson(instruction)}\"}}");
if (validMessages.Count > 0) jsonBuilder.Append(",");
}
for (int i = 0; i < messages.Count; i++)
// Find the index of the last user message to attach the image to
int lastUserIndex = -1;
if (!string.IsNullOrEmpty(base64Image))
{
var msg = messages[i];
for (int i = validMessages.Count - 1; i >= 0; i--)
{
string r = (validMessages[i].role ?? "user").ToLowerInvariant();
if (r != "ai" && r != "assistant" && r != "tool" && r != "system")
{
lastUserIndex = i;
break;
}
}
}
for (int i = 0; i < validMessages.Count; i++)
{
var msg = validMessages[i];
string role = (msg.role ?? "user").ToLowerInvariant();
if (role == "ai" || role == "assistant") role = "assistant";
else if (role == "tool") role = "system";
else if (role == "toolcall") continue;
jsonBuilder.Append($"{{\"role\": \"{role}\", ");
if (i == messages.Count - 1 && role == "user" && !string.IsNullOrEmpty(base64Image))
if (i == lastUserIndex && !string.IsNullOrEmpty(base64Image))
{
jsonBuilder.Append("\"content\": [");
jsonBuilder.Append($"{{\"type\": \"text\", \"text\": \"{EscapeJson(msg.message)}\"}},");
@@ -89,7 +110,7 @@ namespace WulaFallenEmpire.EventSystem.AI
}
jsonBuilder.Append("}");
if (i < messages.Count - 1) jsonBuilder.Append(",");
if (i < validMessages.Count - 1) jsonBuilder.Append(",");
}
jsonBuilder.Append("]}");
@@ -215,6 +236,35 @@ namespace WulaFallenEmpire.EventSystem.AI
{
if (string.IsNullOrWhiteSpace(json)) return null;
// Handle SSE Stream (data: ...)
// Some endpoints return SSE streams even if stream=false is requested.
// We strip 'data:' prefix and aggregate the content deltas.
if (json.TrimStart().StartsWith("data:"))
{
StringBuilder sb = new StringBuilder();
string[] lines = json.Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
foreach (string line in lines)
{
string trimmed = line.Trim();
if (trimmed.StartsWith("data:") && !trimmed.Contains("[DONE]"))
{
string chunkJson = trimmed.Substring(5).Trim();
// Extract content from this chunk
string chunkContent = ExtractContentFromSingleJson(chunkJson);
if (!string.IsNullOrEmpty(chunkContent))
{
sb.Append(chunkContent);
}
}
}
return sb.ToString();
}
return ExtractContentFromSingleJson(json);
}
private string ExtractContentFromSingleJson(string json)
{
try
{
// 1. Gemini format