This commit is contained in:
2025-12-12 20:15:24 +08:00
parent 8141c6cad2
commit a12fccc06e
9 changed files with 380 additions and 373 deletions

View File

@@ -10,7 +10,7 @@ namespace WulaFallenEmpire.EventSystem.AI
public class AIHistoryManager : WorldComponent
{
private string _saveId;
private Dictionary<string, List<(string role, string message)>> _cache = new Dictionary<string, List<(string role, string message)>>();
private Dictionary<string, List<ApiMessage>> _cache = new Dictionary<string, List<ApiMessage>>();
public AIHistoryManager(World world) : base(world)
{
@@ -35,7 +35,7 @@ namespace WulaFallenEmpire.EventSystem.AI
return Path.Combine(GetSaveDirectory(), $"{_saveId}_{eventDefName}.json");
}
public List<(string role, string message)> GetHistory(string eventDefName)
public List<ApiMessage> GetHistory(string eventDefName)
{
if (_cache.TryGetValue(eventDefName, out var cachedHistory))
{
@@ -61,10 +61,10 @@ namespace WulaFallenEmpire.EventSystem.AI
}
}
return new List<(string role, string message)>();
return new List<ApiMessage>();
}
public void SaveHistory(string eventDefName, List<(string role, string message)> history)
public void SaveHistory(string eventDefName, List<ApiMessage> history)
{
_cache[eventDefName] = history;
string path = GetFilePath(eventDefName);
@@ -93,7 +93,7 @@ namespace WulaFallenEmpire.EventSystem.AI
public static class SimpleJsonParser
{
public static string Serialize(List<(string role, string message)> history)
public static string Serialize(List<ApiMessage> history)
{
StringBuilder sb = new StringBuilder();
sb.Append("[");
@@ -102,7 +102,8 @@ namespace WulaFallenEmpire.EventSystem.AI
var item = history[i];
sb.Append("{");
sb.Append($"\"role\":\"{Escape(item.role)}\",");
sb.Append($"\"message\":\"{Escape(item.message)}\"");
sb.Append($"\"content\":\"{Escape(item.content)}\"");
// Note: tool_calls are not serialized for history to keep it simple.
sb.Append("}");
if (i < history.Count - 1) sb.Append(",");
}
@@ -110,13 +111,11 @@ namespace WulaFallenEmpire.EventSystem.AI
return sb.ToString();
}
public static List<(string role, string message)> Deserialize(string json)
public static List<ApiMessage> Deserialize(string json)
{
var result = new List<(string role, string message)>();
var result = new List<ApiMessage>();
if (string.IsNullOrEmpty(json)) return result;
// Very basic parser, assumes standard format produced by Serialize
// Remove outer brackets
json = json.Trim();
if (json.StartsWith("[") && json.EndsWith("]"))
{
@@ -124,10 +123,6 @@ namespace WulaFallenEmpire.EventSystem.AI
}
if (string.IsNullOrEmpty(json)) return result;
// Split by objects
// This is fragile if objects contain nested objects or escaped braces, but for this specific structure it's fine
// We are splitting by "},{" which is risky. Better to iterate.
int depth = 0;
int start = 0;
@@ -153,16 +148,10 @@ namespace WulaFallenEmpire.EventSystem.AI
return result;
}
private static (string role, string message) ParseObject(string json)
public static Dictionary<string, string> Parse(string json)
{
string role = null;
string message = null;
// Remove braces
var dict = new Dictionary<string, string>();
json = json.Trim('{', '}');
// Split by key-value pairs, respecting quotes
// Again, simple parsing
var parts = SplitByComma(json);
foreach (var part in parts)
{
@@ -171,17 +160,48 @@ namespace WulaFallenEmpire.EventSystem.AI
{
string key = Unescape(kv[0].Trim().Trim('"'));
string val = Unescape(kv[1].Trim().Trim('"'));
if (key == "role") role = val;
if (key == "message") message = val;
dict[key] = val;
}
}
return dict;
}
public static List<Dictionary<string, string>> ParseArray(string json)
{
var list = new List<Dictionary<string, string>>();
json = json.Trim('[', ']');
int depth = 0;
int start = 0;
for (int i = 0; i < json.Length; i++)
{
if (json[i] == '{')
{
if (depth == 0) start = i;
depth++;
}
else if (json[i] == '}')
{
depth--;
if (depth == 0)
{
list.Add(Parse(json.Substring(start, i - start + 1)));
}
}
}
return list;
}
return (role, message);
private static ApiMessage ParseObject(string json)
{
var msg = new ApiMessage();
var dict = Parse(json);
if (dict.TryGetValue("role", out string r)) msg.role = r;
if (dict.TryGetValue("content", out string c)) msg.content = c;
return msg;
}
private static string[] SplitByComma(string input)
{
// Split by comma but ignore commas inside quotes
var list = new List<string>();
bool inQuote = false;
int start = 0;
@@ -200,7 +220,6 @@ namespace WulaFallenEmpire.EventSystem.AI
private static string[] SplitByColon(string input)
{
// Split by first colon outside quotes
bool inQuote = false;
for (int i = 0; i < input.Length; i++)
{
@@ -219,7 +238,7 @@ namespace WulaFallenEmpire.EventSystem.AI
return s.Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("\n", "\\n").Replace("\r", "\\r");
}
private static string Unescape(string s)
public static string Unescape(string s) // Changed to public
{
if (s == null) return "";
return s.Replace("\\r", "\r").Replace("\\n", "\n").Replace("\\\"", "\"").Replace("\\\\", "\\");