This commit is contained in:
2025-12-13 14:51:37 +08:00
parent 7a3153fd5c
commit 7931a3dae5
4 changed files with 82 additions and 48 deletions

View File

@@ -37,7 +37,7 @@ namespace WulaFallenEmpire.EventSystem.AI
StringBuilder jsonBuilder = new StringBuilder(); StringBuilder jsonBuilder = new StringBuilder();
jsonBuilder.Append("{"); jsonBuilder.Append("{");
jsonBuilder.Append($"\"model\": \"{_model}\","); jsonBuilder.Append($"\"model\": \"{_model}\",");
jsonBuilder.Append("\"stream\": false,"); jsonBuilder.Append("\"stream\": false,"); // We request non-stream, but handle stream if returned
jsonBuilder.Append("\"messages\": ["); jsonBuilder.Append("\"messages\": [");
// System instruction // System instruction
@@ -108,37 +108,72 @@ namespace WulaFallenEmpire.EventSystem.AI
{ {
try try
{ {
// Robust parsing for "content": "..." allowing for whitespace variations // Check for stream format (SSE)
int contentIndex = json.IndexOf("\"content\""); // SSE lines start with "data: "
if (contentIndex == -1) return null; if (json.TrimStart().StartsWith("data:"))
// Find the opening quote after "content"
int openQuoteIndex = -1;
for (int i = contentIndex + 9; i < json.Length; i++)
{ {
if (json[i] == '"') StringBuilder fullContent = new StringBuilder();
string[] lines = json.Split(new[] { "\n", "\r" }, StringSplitOptions.RemoveEmptyEntries);
foreach (string line in lines)
{ {
openQuoteIndex = i; string trimmedLine = line.Trim();
break; if (trimmedLine == "data: [DONE]") continue;
if (trimmedLine.StartsWith("data: "))
{
string dataJson = trimmedLine.Substring(6);
// Extract content from this chunk
string chunkContent = ExtractJsonValue(dataJson, "content");
if (!string.IsNullOrEmpty(chunkContent))
{
fullContent.Append(chunkContent);
} }
} }
if (openQuoteIndex == -1) return null; }
return fullContent.ToString();
}
else
{
// Standard non-stream format
return ExtractJsonValue(json, "content");
}
}
catch (Exception ex)
{
Log.Error($"[WulaAI] Error parsing response: {ex}");
}
return null;
}
int startIndex = openQuoteIndex + 1; private string ExtractJsonValue(string json, string key)
StringBuilder content = new StringBuilder(); {
// Simple parser to find "key": "value"
// This is not a full JSON parser and assumes standard formatting
string keyPattern = $"\"{key}\"";
int keyIndex = json.IndexOf(keyPattern);
if (keyIndex == -1) return null;
// Find the colon after the key
int colonIndex = json.IndexOf(':', keyIndex + keyPattern.Length);
if (colonIndex == -1) return null;
// Find the opening quote of the value
int valueStart = json.IndexOf('"', colonIndex);
if (valueStart == -1) return null;
// Extract string with escape handling
StringBuilder sb = new StringBuilder();
bool escaped = false; bool escaped = false;
for (int i = valueStart + 1; i < json.Length; i++)
for (int i = startIndex; i < json.Length; i++)
{ {
char c = json[i]; char c = json[i];
if (escaped) if (escaped)
{ {
if (c == 'n') content.Append('\n'); if (c == 'n') sb.Append('\n');
else if (c == 'r') content.Append('\r'); else if (c == 'r') sb.Append('\r');
else if (c == 't') content.Append('\t'); else if (c == 't') sb.Append('\t');
else if (c == '"') content.Append('"'); else if (c == '"') sb.Append('"');
else if (c == '\\') content.Append('\\'); else if (c == '\\') sb.Append('\\');
else content.Append(c); // Literal else sb.Append(c); // Literal
escaped = false; escaped = false;
} }
else else
@@ -150,19 +185,14 @@ namespace WulaFallenEmpire.EventSystem.AI
else if (c == '"') else if (c == '"')
{ {
// End of string // End of string
return content.ToString(); return sb.ToString();
} }
else else
{ {
content.Append(c); sb.Append(c);
} }
} }
} }
}
catch (Exception ex)
{
Log.Error($"[WulaAI] Error parsing response: {ex}");
}
return null; return null;
} }
} }

View File

@@ -103,7 +103,7 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
Faction faction = Find.FactionManager.FirstFactionOfDef(FactionDef.Named("Wula_PIA_Legion_Faction")); Faction faction = Find.FactionManager.FirstFactionOfDef(FactionDef.Named("Wula_PIA_Legion_Faction"));
if (faction != null) if (faction != null)
{ {
Messages.Message("Wula_ResourceDrop".Translate(faction.Name), new LookTargets(dropSpot, map), MessageTypeDefOf.PositiveEvent); Messages.Message("Wula_ResourceDrop".Translate(faction.Name.Named("FACTION_name")), new LookTargets(dropSpot, map), MessageTypeDefOf.PositiveEvent);
} }
resultLog.Length -= 2; // Remove trailing comma resultLog.Length -= 2; // Remove trailing comma

View File

@@ -506,7 +506,9 @@ When the player requests any form of resources, you MUST follow this multi-turn
bool isLastMessage = i == filteredHistory.Count - 1; bool isLastMessage = i == filteredHistory.Count - 1;
Text.Font = (isLastMessage && entry.role == "assistant") ? GameFont.Medium : GameFont.Small; Text.Font = (isLastMessage && entry.role == "assistant") ? GameFont.Medium : GameFont.Small;
viewHeight += Text.CalcHeight(text, rect.width - 16f) + 15f; // Add padding // Increase padding significantly for Medium font to prevent clipping
float padding = (isLastMessage && entry.role == "assistant") ? 30f : 15f;
viewHeight += Text.CalcHeight(text, rect.width - 16f) + padding;
} }
Rect viewRect = new Rect(0f, 0f, rect.width - 16f, viewHeight); Rect viewRect = new Rect(0f, 0f, rect.width - 16f, viewHeight);
Widgets.BeginScrollView(rect, ref _scrollPosition, viewRect); Widgets.BeginScrollView(rect, ref _scrollPosition, viewRect);
@@ -520,7 +522,9 @@ When the player requests any form of resources, you MUST follow this multi-turn
bool isLastMessage = i == filteredHistory.Count - 1; bool isLastMessage = i == filteredHistory.Count - 1;
Text.Font = (isLastMessage && entry.role == "assistant") ? GameFont.Medium : GameFont.Small; Text.Font = (isLastMessage && entry.role == "assistant") ? GameFont.Medium : GameFont.Small;
float height = Text.CalcHeight(text, viewRect.width) + 10f; // Increased padding
float padding = (isLastMessage && entry.role == "assistant") ? 30f : 15f;
float height = Text.CalcHeight(text, viewRect.width) + padding;
Rect labelRect = new Rect(0f, curY, viewRect.width, height); Rect labelRect = new Rect(0f, curY, viewRect.width, height);
if (entry.role == "user") if (entry.role == "user")
{ {