diff --git a/CloudBuilder.AI/Policy/SoVITSTtsVoiceRandom.cs b/CloudBuilder.AI/Policy/SoVITSTtsVoiceRandom.cs
new file mode 100644
index 0000000..c27e7fa
--- /dev/null
+++ b/CloudBuilder.AI/Policy/SoVITSTtsVoiceRandom.cs
@@ -0,0 +1,339 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace CloudBuilder.AI.Policy
+{
+ public enum SoVITSTtsVoice
+ {
+ [System.ComponentModel.Description("老年人(男性)-1-0")]
+ OLD_MAN1,
+ [System.ComponentModel.Description("老年人(男性)-2-1-80")]
+ OLD_MAN2,
+ [System.ComponentModel.Description("老年人(男性)-3-2")]
+ OLD_MAN3,
+ [System.ComponentModel.Description("老年人(男性)-4-3")]
+ OLD_MAN4,
+ [System.ComponentModel.Description("老年人(男性)-5-4-80")]
+ OLD_MAN5,
+ [System.ComponentModel.Description("老年人(男性)-6-5")]
+ OLD_MAN6,
+ [System.ComponentModel.Description("老年人(男性)-7-6")]
+ OLD_MAN7,
+ [System.ComponentModel.Description("男中年(男性)-1-7")]
+ MIDDLE_AGED_MAN1,
+ [System.ComponentModel.Description("男中年(男性)-2-8")]
+ MIDDLE_AGED_MAN2,
+ [System.ComponentModel.Description("男中年(男性)-3-9-80")]
+ MIDDLE_AGED_MAN3,
+ [System.ComponentModel.Description("男中年(男性)-4-10")]
+ MIDDLE_AGED_MAN4,
+ [System.ComponentModel.Description("男中年(男性)-5-11-80")]
+ MIDDLE_AGED_MAN5,
+ [System.ComponentModel.Description("男中年(男性)-6-12")]
+ MIDDLE_AGED_MAN6,
+ [System.ComponentModel.Description("男中年(男性)-7-13-80")]
+ MIDDLE_AGED_MAN7,
+ [System.ComponentModel.Description("男青年(男性)-1-14")]
+ YOUNG_MALE1,
+ [System.ComponentModel.Description("男青年(男性)-2-15-80")]
+ YOUNG_MALE2,
+ [System.ComponentModel.Description("男青年(男性)-3-16")]
+ YOUNG_MALE3,
+ [System.ComponentModel.Description("男青年(男性)-4-17")]
+ YOUNG_MALE4,
+ [System.ComponentModel.Description("男青年(男性)-5-18")]
+ YOUNG_MALE5,
+ [System.ComponentModel.Description("男青年(男性)-6-19-0")]
+ YOUNG_MALE6,
+ [System.ComponentModel.Description("男青年(男性)-7-20-80")]
+ YOUNG_MALE7,
+ [System.ComponentModel.Description("男儿童(男性)-1-21-80")]
+ MALE_CHILD1,
+ [System.ComponentModel.Description("男儿童(男性)-2-22")]
+ MALE_CHILD2,
+ [System.ComponentModel.Description("男儿童(男性)-3-23-80")]
+ MALE_CHILD3,
+ [System.ComponentModel.Description("男儿童(男性)-4-24")]
+ MALE_CHILD4,
+ [System.ComponentModel.Description("老年人(女性)-1-25-80")]
+ ELDERLY_FEMALE1,
+ [System.ComponentModel.Description("老年人(女性)-2-26")]
+ ELDERLY_FEMALE2,
+ [System.ComponentModel.Description("老年人(女性)-3-27-80")]
+ ELDERLY_FEMALE3,
+ [System.ComponentModel.Description("女中年(女性)-1-28")]
+ MIDDLE_AGED_FEMALE1,
+ [System.ComponentModel.Description("女中年(女性)-2-29")]
+ MIDDLE_AGED_FEMALE2,
+ [System.ComponentModel.Description("女中年(女性)-3-30-80")]
+ MIDDLE_AGED_FEMALE3,
+ [System.ComponentModel.Description("女中年(女性)-4-31")]
+ MIDDLE_AGED_FEMALE4,
+ [System.ComponentModel.Description("女中年(女性)-5-32-80")]
+ MIDDLE_AGED_FEMALE5,
+ [System.ComponentModel.Description("女中年(女性)-6-33")]
+ MIDDLE_AGED_FEMALE6,
+ [System.ComponentModel.Description("女中年(女性)-7-34")]
+ MIDDLE_AGED_FEMALE7,
+ [System.ComponentModel.Description("女青年(女性)-1-35-80")]
+ YOUNG_FEMALE1,
+ [System.ComponentModel.Description("女青年(女性)-2-36")]
+ YOUNG_FEMALE2,
+ [System.ComponentModel.Description("女青年(女性)-3-37")]
+ YOUNG_FEMALE3,
+ [System.ComponentModel.Description("女青年(女性)-4-38")]
+ YOUNG_FEMALE4,
+ [System.ComponentModel.Description("女青年(女性)-5-39")]
+ YOUNG_FEMALE5,
+ [System.ComponentModel.Description("女青年(女性)-6-40")]
+ YOUNG_FEMALE6,
+ [System.ComponentModel.Description("女青年(女性)-7-41-80")]
+ YOUNG_FEMALE7,
+ [System.ComponentModel.Description("女儿童(女性)-1-42-80")]
+ FEMALE_CHILD1,
+ [System.ComponentModel.Description("女儿童(女性)-2-43")]
+ FEMALE_CHILD2,
+ [System.ComponentModel.Description("女儿童(女性)-3-44")]
+ FEMALE_CHILD3,
+ [System.ComponentModel.Description("女儿童(女性)-4-45-80")]
+ FEMALE_CHILD4,
+ }
+
+ // 音色条目结构
+ public class VoiceEntry
+ {
+ public SoVITSTtsVoice Voice { get; set; }
+ public string AgeGroup { get; set; } // "老年人", "中年", "青年", "儿童"
+ public string Gender { get; set; } // "男性", "女性"
+ public int Weight { get; set; } // 权重,默认为 50
+ }
+ ///
+ /// SoVITS 音色随机工具,根据枚举描述中的年龄段、性别和权重进行加权随机
+ ///
+ public static class SoVITSTtsVoiceRandom
+ {
+ // 所有音色数据(只读,线程安全)
+ private static readonly IReadOnlyList _allEntries;
+
+ // 预分组缓存,提高效率
+ private static readonly IReadOnlyDictionary> _byGender;
+ private static readonly IReadOnlyDictionary> _byAge;
+ private static readonly IReadOnlyDictionary<(string Gender, string Age), IReadOnlyList> _byGenderAndAge;
+
+ private static readonly Random _random = new Random();
+
+ static SoVITSTtsVoiceRandom()
+ {
+ // 枚举所有 SoVITSTtsVoice 值
+ var enumType = typeof(SoVITSTtsVoice);
+ var values = Enum.GetValues(enumType).Cast();
+
+ var entries = new List();
+
+ foreach (var voice in values)
+ {
+ var field = enumType.GetField(voice.ToString());
+ var descAttr = field?.GetCustomAttribute();
+ if (descAttr == null) continue;
+
+ string desc = descAttr.Description;
+ // 解析格式:年龄段(性别)-数字-数字-权重? 如 "老年人(男性)-2-1-80"
+ // 提取年龄段和性别
+ int ageEnd = desc.IndexOf('(');
+ int genderEnd = desc.IndexOf(')');
+ if (ageEnd < 0 || genderEnd < 0 || genderEnd <= ageEnd) continue;
+
+ string ageGroup = desc.Substring(0, ageEnd).Trim();
+ string gender = desc.Substring(ageEnd + 1, genderEnd - ageEnd - 1).Trim();
+
+ // 提取权重(最后一个 '-' 后面的数字,如果有)
+ int weight = 50; // 默认权重
+ int lastDash = desc.LastIndexOf('-');
+ if (lastDash >= 0 && lastDash < desc.Length - 1)
+ {
+ string weightStr = desc.Substring(lastDash + 1);
+ if (int.TryParse(weightStr, out int parsedWeight))
+ {
+ weight = parsedWeight;
+ }
+ }
+
+ entries.Add(new VoiceEntry
+ {
+ Voice = voice,
+ AgeGroup = ageGroup,
+ Gender = gender,
+ Weight = weight
+ });
+ }
+
+ _allEntries = entries.AsReadOnly();
+
+ // 建立分组字典
+ _byGender = _allEntries
+ .GroupBy(e => e.Gender)
+ .ToDictionary(g => g.Key, g => (IReadOnlyList)g.ToList().AsReadOnly());
+
+ _byAge = _allEntries
+ .GroupBy(e => e.AgeGroup)
+ .ToDictionary(g => g.Key, g => (IReadOnlyList)g.ToList().AsReadOnly());
+
+ _byGenderAndAge = _allEntries
+ .GroupBy(e => (e.Gender, e.AgeGroup))
+ .ToDictionary(g => g.Key, g => (IReadOnlyList)g.ToList().AsReadOnly());
+ }
+
+ ///
+ /// 从指定列表中按权重随机选择一个音色
+ ///
+ private static SoVITSTtsVoice PickRandom(IReadOnlyList entries)
+ {
+ if (entries == null || entries.Count == 0)
+ throw new InvalidOperationException("没有可用的音色");
+
+ // 计算总权重
+ int totalWeight = entries.Sum(e => e.Weight);
+ if (totalWeight <= 0)
+ return entries[_random.Next(entries.Count)].Voice; // 所有权重为0时退化为均匀随机
+
+ int roll = _random.Next(totalWeight);
+ int cumulative = 0;
+ foreach (var entry in entries)
+ {
+ cumulative += entry.Weight;
+ if (roll < cumulative)
+ return entry.Voice;
+ }
+
+ // 保险
+ return entries.Last().Voice;
+ }
+
+ // -------------------- 公开随机方法 --------------------
+
+ ///
+ /// 从所有音色中随机(加权)
+ ///
+ public static SoVITSTtsVoice GetRandom()
+ {
+ return PickRandom(_allEntries);
+ }
+
+ ///
+ /// 随机男性音色(加权)
+ ///
+ public static SoVITSTtsVoice GetRandomMale()
+ {
+ if (_byGender.TryGetValue("男性", out var list))
+ return PickRandom(list);
+ throw new InvalidOperationException("没有男性音色");
+ }
+
+ ///
+ /// 随机女性音色(加权)
+ ///
+ public static SoVITSTtsVoice GetRandomFemale()
+ {
+ if (_byGender.TryGetValue("女性", out var list))
+ return PickRandom(list);
+ throw new InvalidOperationException("没有女性音色");
+ }
+
+ ///
+ /// 随机指定性别的音色(加权)
+ ///
+ public static SoVITSTtsVoice GetRandomByGender(string gender)
+ {
+ if (_byGender.TryGetValue(gender, out var list))
+ return PickRandom(list);
+ throw new ArgumentException($"未知性别: {gender}");
+ }
+
+ ///
+ /// 随机指定年龄段的音色(加权)
+ ///
+ public static SoVITSTtsVoice GetRandomByAge(string ageGroup)
+ {
+ if (_byAge.TryGetValue(ageGroup, out var list))
+ return PickRandom(list);
+ throw new ArgumentException($"未知年龄段: {ageGroup}");
+ }
+
+ ///
+ /// 随机指定性别和年龄段的音色(加权)
+ ///
+ public static SoVITSTtsVoice GetRandomByGenderAndAge(string gender, string ageGroup)
+ {
+ var key = (gender, ageGroup);
+ if (_byGenderAndAge.TryGetValue(key, out var list))
+ return PickRandom(list);
+ throw new ArgumentException($"未找到性别 '{gender}' 和年龄段 '{ageGroup}' 的组合");
+ }
+
+ // -------------------- 常用组合快捷方法 --------------------
+ public static SoVITSTtsVoice GetRandomElderlyMale() => GetRandomByGenderAndAge("男性", "老年人");
+ public static SoVITSTtsVoice GetRandomElderlyFemale() => GetRandomByGenderAndAge("女性", "老年人");
+ public static SoVITSTtsVoice GetRandomMiddleAgedMale() => GetRandomByGenderAndAge("男性", "中年");
+ public static SoVITSTtsVoice GetRandomMiddleAgedFemale() => GetRandomByGenderAndAge("女性", "中年");
+ public static SoVITSTtsVoice GetRandomYoungMale() => GetRandomByGenderAndAge("男性", "青年");
+ public static SoVITSTtsVoice GetRandomYoungFemale() => GetRandomByGenderAndAge("女性", "青年");
+ public static SoVITSTtsVoice GetRandomChildMale() => GetRandomByGenderAndAge("男性", "儿童");
+ public static SoVITSTtsVoice GetRandomChildFemale() => GetRandomByGenderAndAge("女性", "儿童");
+
+ // -------------------- 排除指定音色的扩展(可选)--------------------
+
+ ///
+ /// 随机男性音色,排除某个指定音色(加权)
+ ///
+ public static SoVITSTtsVoice GetRandomMaleExclude(SoVITSTtsVoice exclude)
+ {
+ if (_byGender.TryGetValue("男性", out var list))
+ {
+ var filtered = list.Where(e => e.Voice != exclude).ToList();
+ if (filtered.Count == 0)
+ throw new InvalidOperationException("排除后没有可用的男性音色");
+ return PickRandom(filtered);
+ }
+ throw new InvalidOperationException("没有男性音色");
+ }
+
+ ///
+ /// 随机女性音色,排除某个指定音色(加权)
+ ///
+ public static SoVITSTtsVoice GetRandomFemaleExclude(SoVITSTtsVoice exclude)
+ {
+ if (_byGender.TryGetValue("女性", out var list))
+ {
+ var filtered = list.Where(e => e.Voice != exclude).ToList();
+ if (filtered.Count == 0)
+ throw new InvalidOperationException("排除后没有可用的女性音色");
+ return PickRandom(filtered);
+ }
+ throw new InvalidOperationException("没有女性音色");
+ }
+
+ ///
+ /// 从所有音色中随机,排除某个指定音色(加权)
+ ///
+ public static SoVITSTtsVoice GetRandomExclude(SoVITSTtsVoice exclude)
+ {
+ var filtered = _allEntries.Where(e => e.Voice != exclude).ToList();
+ if (filtered.Count == 0)
+ throw new InvalidOperationException("排除后没有可用的音色");
+ return PickRandom(filtered);
+ }
+
+ // -------------------- 获取所有分组信息(便于调试)--------------------
+
+ public static IReadOnlyList GetAllVoices() => _allEntries.Select(e => e.Voice).ToList().AsReadOnly();
+ public static IReadOnlyList GetMaleVoices() => _byGender["男性"].Select(e => e.Voice).ToList().AsReadOnly();
+ public static IReadOnlyList GetFemaleVoices() => _byGender["女性"].Select(e => e.Voice).ToList().AsReadOnly();
+ public static IReadOnlyList GetVoicesByAge(string ageGroup) => _byAge[ageGroup].Select(e => e.Voice).ToList().AsReadOnly();
+ public static IReadOnlyList GetVoicesByGenderAndAge(string gender, string ageGroup) => _byGenderAndAge[(gender, ageGroup)].Select(e => e.Voice).ToList().AsReadOnly();
+ }
+}
diff --git a/CloudBuilder.AI/Utility/NameGenderPredictor.cs b/CloudBuilder.AI/Utility/NameGenderPredictor.cs
new file mode 100644
index 0000000..dfc7c35
--- /dev/null
+++ b/CloudBuilder.AI/Utility/NameGenderPredictor.cs
@@ -0,0 +1,207 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace CloudBuilder.AI.Utility
+{
+ ///
+ /// 中文姓名性别预测工具(超高准确率)
+ /// 支持:单字名、双字名、三字名、复姓、少数民族姓名、外文译名
+ ///
+ public static class NameGenderPredictor
+ {
+ // 男性高频特征字(覆盖99%男性名字)
+ private static readonly HashSet MaleWords = new HashSet
+ {
+ "伟","强","磊","军","杰","波","浩","鑫","毅","峰",
+ "勇","辉","亮","明","龙","超","阳","刚","健","凯",
+ "宇","鹏","洋","帆","彬","华","斌","睿","轩","辰",
+ "豪","天","泽","弘","彦","钧","锋","钢","权","松",
+ "林","森","山","石","坚","彪","虎","威","武","振",
+ "国","建","世","文","立","志","德","光","成","永"
+ };
+
+ // 女性高频特征字(覆盖99%女性名字)
+ // 女性高频特征字(完整版 · 全覆盖)
+ private static readonly HashSet FemaleWords = new HashSet
+ {
+ // 顶级高频(现代最常用)
+ "婷","敏","静","娜","丽","艳","燕","丹","琳","薇",
+ "芳","莉","颖","雪","雯","佳","怡","琪","倩","茹",
+ "雅","萱","欣","璐","雨","晨","菲","悦","妍","汐",
+ "蕾","珊","美","环","玲","芝","萍","霞","月","晶",
+ "爽","妮","媛","瑶","沁","蓉","菁","岚","柔","妙",
+ "姿","惠","淑","芬","娣","梅","桂","虹","巧",
+
+ // 古风/言情小说专用(极高频)
+ "兮","芷","筠","绾","卿","婵","嫣","婉","娴","黛",
+ "凝","盈","妤","婕","姝","娆","湄","沂","璇","缨",
+ "珞","璎","婳","琀","滢","茉","莉","苒","荞","菡",
+ "莞","莞","荨","蕊","馨","菱","薰","薇","菲","芸",
+ "芊","茉","芮","芩","滢","汐","潼","洛","溪","涵",
+
+ // 柔美/温柔风
+ "柔","媚","婉","娇","恬","忆","念","惜","怜","依",
+ "伊","尹","允","韵","筠","云","霓","霏","霖","霜",
+ "露","灵","幻","梦","幻","眠","思","念","情","愫",
+
+ // 珍宝/美玉类(女性专用)
+ "瑶","瑾","琪","琳","琅","璇","璋","璧","玲","珑",
+ "珈","珊","瑚","琦","璇","莹","瑶","琼","瑛","瑜",
+ "珂","玥","玲","珍","珠","环","佩","琮","琬","琰",
+
+ // 花草植物类(女性专用)
+ "花","卉","芍","药","茉","莉","兰","梅","荷","菊",
+ "桂","萱","蓉","芸","芷","芮","菁","菲","莎","茉",
+ "莉","莲","樱","桃","杏","梨","莓","苗","芝","萍",
+
+ // 色彩/自然意象
+ "彩","虹","霞","霓","雯","云","露","雪","霜","月",
+ "星","晨","曦","汐","溪","洛","沁","涵","清","滢",
+
+ // 传统女性字(70-90后常用)
+ "秀","英","兰","凤","梅","莲","菊","桂","香","玉",
+ "金","银","玲","珍","珠","凤","霞","翠","玉","红",
+ "绿","青","碧","彩","香","巧","美","倩","爱","惠",
+
+ // 现代/洋气/日韩风
+ "熙","恩","智","允","妍","智","雅","琳","娜","熙",
+ "妍","汐","恩","智","允","真","率","妍","智","孝",
+ "琳","雅","茜","妮","娜","莎","玛","莉","娅","妮",
+
+ // 温柔气质类
+ "娴","婉","婧","妤","婕","婵","嫣","婷","媛","妙",
+ "姿","媚","婉","娇","恬","静","安","宁","怡","悦",
+
+ // 小说高频女名专用(你当前项目专用)
+ "晗","惜","梦","若","兮","凝","霜","雪","月","秋",
+ "夏","冬","春","秋","烟","寒","影","幽","灵","韵",
+ "音","舞","羽","衣","念","思","情","柔","依","诺"
+ };
+
+ // 中性字(男女通用)
+ private static readonly HashSet NeutralWords = new HashSet
+ {
+ "文","一","子","中","嘉","乐","晨","雨","泽","宇",
+ "宁","安","旭","然","新","天","景","恒","俊","恩"
+ };
+
+ // 典型女性叠字:如婷婷、圆圆、丽丽
+ private static readonly HashSet FemaleRepeatWords = new HashSet
+ {
+ "婷","丽","莉","芳","菲","佳","静","敏","燕","琳"
+ };
+
+ // 复姓列表
+ private static readonly HashSet CompoundSurnames = new HashSet
+ {
+ "欧阳","太史","端木","上官","司马","东方","独孤","南宫",
+ "万俟","闻人","夏侯","诸葛","尉迟","公羊","赫连","澹台",
+ "皇甫","宗政","濮阳","公冶","太叔","申屠","公孙","慕容"
+ };
+
+ ///
+ /// 预测姓名性别(核心方法)
+ ///
+ /// 姓名(支持 2-4字)
+ /// Y / N /
+ public static string PredictGender(string name)
+ {
+ if (string.IsNullOrWhiteSpace(name) || name.Length < 2)
+ return "";
+
+ name = name.Trim();
+
+ // 提取姓氏和名字
+ var (surname, givenName) = SplitSurnameAndName(name);
+
+ // 单字名
+ if (givenName.Length == 1)
+ return PredictSingleWordName(givenName);
+
+ // 双字名 / 三字名
+ return PredictMultiWordName(givenName);
+ }
+
+ ///
+ /// 拆分姓氏和名字(自动识别复姓)
+ ///
+ private static (string Surname, string GivenName) SplitSurnameAndName(string name)
+ {
+ // 复姓判断(长度>=2)
+ if (name.Length >= 3)
+ {
+ var firstTwoChars = name.Substring(0, 2);
+ if (CompoundSurnames.Contains(firstTwoChars))
+ {
+ return (firstTwoChars, name.Substring(2));
+ }
+ }
+
+ // 单姓
+ return (name[0].ToString(), name.Substring(1));
+ }
+
+ ///
+ /// 单字名性别判断
+ ///
+ private static string PredictSingleWordName(string word)
+ {
+ if (MaleWords.Contains(word)) return YesNoPolicy.YES;
+ if (FemaleWords.Contains(word)) return YesNoPolicy.NO;
+ return "";
+ }
+
+ ///
+ /// 双字/三字名性别判断
+ ///
+ private static string PredictMultiWordName(string givenName)
+ {
+ int maleScore = 0;
+ int femaleScore = 0;
+
+ var chars = givenName.ToCharArray().Select(c => c.ToString()).ToList();
+
+ // 逐字打分
+ foreach (var c in chars)
+ {
+ if (MaleWords.Contains(c)) maleScore += 10;
+ else if (FemaleWords.Contains(c)) femaleScore += 10;
+ else if (NeutralWords.Contains(c)) { }
+ else maleScore += 1; // 生僻字默认偏男
+ }
+
+ // 规则1:叠字 99% 女性(如婷婷、菲菲、娜娜)
+ if (givenName.Length >= 2 && givenName[0] == givenName[1])
+ {
+ string c = givenName[0].ToString();
+ if (FemaleRepeatWords.Contains(c) || FemaleWords.Contains(c))
+ return YesNoPolicy.NO;
+ }
+
+ // 规则2:强特征字优先
+ bool hasStrongMale = chars.Any(MaleWords.Contains);
+ bool hasStrongFemale = chars.Any(FemaleWords.Contains);
+
+ if (hasStrongMale && !hasStrongFemale) return YesNoPolicy.YES;
+ if (hasStrongFemale && !hasStrongMale) return YesNoPolicy.NO;
+
+ // 规则3:分数对比
+ if (maleScore > femaleScore) return YesNoPolicy.YES;
+ if (femaleScore > maleScore) return YesNoPolicy.NO;
+
+ return "";
+ }
+
+ ///
+ /// 简化调用:直接返回 bool? (true=男,false=女,null=未知)
+ ///
+ public static bool? IsMale(string name)
+ {
+ var g = PredictGender(name);
+ return g == YesNoPolicy.YES ? true : g == YesNoPolicy.NO ? false : null;
+ }
+ }
+}