CloudBuilder.Topshelf/Task/Novel/Process/SpeakerAnalysisHelper.cs
owenchen 597b88d075 ow
2026-05-28 15:49:25 +08:00

102 lines
4.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using CloudBuilder.AI.Entity;
using CloudBuilder.Topshelf.Python;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace CloudBuilder.Topshelf.Task.Novel.Process
{
public class SpeakerAnalysisHelper
{
public string GetPerson(string depRoot, List<NamedEntity> ners, List<List<MeaningRepresentationParsingEntity>> srls, List<HanlpConstituencyNode> cons)
{
string arg0 = string.Empty;
if (!string.IsNullOrEmpty(depRoot) && srls != null && srls.Count() > 0)
{
foreach (var srl in srls)
{
if (srl.Where(x => x.Text == depRoot).Any())
{
foreach (var mrp in srl)
{
if (mrp.Type.ToUpper() != "ARG0") continue;
if (ners != null && ners.Where(x => mrp.Text.Contains(x.Text)).Any() &&
ners.Where(x => mrp.Text.Contains(x.Text)).FirstOrDefault().Text.Length > 1)
return ners.Where(x => mrp.Text.Contains(x.Text)).FirstOrDefault().Text;
return mrp.Text.Length > 6 ? mrp.Text.Substring(mrp.Text.Length - 6, 6) : mrp.Text;
}
}
foreach (var mrp in srl)
{
if (mrp.Type.ToUpper() != "ARG0") continue;
arg0 = mrp.Text.Length > 6 ? mrp.Text.Substring(mrp.Text.Length - 6, 6) : mrp.Text;
}
}
}
if (ners != null && ners.Count() > 0)
return ners.FirstOrDefault().Text;
return arg0;
}
public AiParagraphEntity[] AiParagraphs { get; set; }
public AiSentenceEntity[] AiSentences { get; set; }
public AiChapterPersonEntity[] AiChapterPersons { get; set; }
}
}
/*
“文本解析→人物提取→上下文匹配→结果输出”
graph TD
A[对话行] --> B{规则1文本特征匹配};
B -->|匹配成功| C[直接赋值说话者];
B -->|匹配失败| D{规则2紧邻旁白匹配};
D -->|匹配成功| C;
D -->|匹配失败| E{规则3段落内最近人物};
E -->|匹配成功| C;
E -->|匹配失败| F[赋值默认值+标记异常];
规则 1文本特征精准匹配最高优先级
基于对话内容中的 “专属特征” 直接匹配说话者,避免上下文干扰:
示例规则:
对话内容特征 匹配的说话者
包含 “第二元婴” 韩立
包含 “银月所化” 银月
包含 “本座 / 本尊” 反派角色
落地:维护一个 “特征 - 人物” 映射字典,匹配时优先使用:
规则 2紧邻旁白匹配次高优先级只找对话行 “紧邻的前 1-2 行旁白”,而非整个段落的旁白,避免跨越多个人物导致匹配错误:
规则:仅检查对话行的前 1 行、前 2 行旁白(最多前 3 行),超过则停止;
落地:修改向前查找的逻辑,限制查找范围
规则 3排除无效人物避免干扰从旁白中提取人物时过滤掉 “非核心人物”(如 “店小二”“路人”),只保留主要人物:
落地:维护 “核心人物白名单”,提取人物时只保留白名单内的名称
3. 增加异常处理和人工校验(兜底保障)
即使逻辑再完善,也会有边缘场景匹配错误,需通过 “异常标记 + 人工复核” 兜底:
步骤 1标记可疑匹配结果对以下情况标记为 “可疑”,存入日志或单独字段:
匹配到的人物在旁白中出现次数≥2比如同一段落有韩立和银月无法确定
对话行前后 3 行都没有找到人物,最终赋值为 “未知人物”;
对话内容无任何特征且段落内人物数量≥3
落地为实体增加扩展字段如IsSuspected或生成异常日志
步骤 2人工复核可疑数据
规则:所有标记为 “可疑” 的匹配结果,必须经过人工复核后再更新到数据库;
落地:生成 “可疑数据清单”包含Guid、Content、PersonName供运营 / 编辑人员校验,修正错误后重新填充。
收集错误案例:记录每次匹配错误的场景(如 “银月的对话匹配给韩立”),分析错误原因;
迭代特征字典:将错误案例转化为新的特征规则(如新增 “乌云”→银月,“元婴”→韩立);
A/B 测试:对优化后的规则做小范围测试,对比匹配准确率,确认有效后全量上线。
*/