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

149 lines
8.2 KiB
C#
Raw Permalink 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.Topshelf.Python;
using Microsoft.VisualBasic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Metadata;
using System.Runtime.Intrinsics.Arm;
using System.Text;
using System.Threading.Tasks;
namespace CloudBuilder.Topshelf.Task.Novel.Process
{
public class SpeakerFeatureLearner
{
private readonly List<SpeakerRule> _rules;
public SpeakerFeatureLearner()
{
_rules = new List<SpeakerRule>();
InitializeDefaultRules();
}
private void InitializeDefaultRules()
{
//AddRule("银月", "少妇");
}
public void AutoLearnFromText(string text)
{
}
public void AutoLearnFromText(string depRoot, List<NamedEntity> ners, List<List<MeaningRepresentationParsingEntity>> srls, List<HanlpConstituencyNode> cons)
{
if (ners == null || !ners.Where(x => x.Type.Trim().ToUpper().Contains("PERSON")).Any()) return;
HanlpConstituencyNode[] nodes;
HanlpConstituencyNode nodef;
string feature = null;
foreach (NamedEntity namedEntity in ners.Where(x => x.Type.Trim().ToUpper().Contains("PERSON")).ToArray())
{
nodes = HanlpResultHelper.GetNodeByLabel(cons, namedEntity.Text);
if (nodes == null || nodes.Length == 0) continue;
//如果存在找到父节点上的NP
foreach (HanlpConstituencyNode node in nodes)
{
nodef = HanlpResultHelper.GetNodeTopLabelById(cons, node.FatherId, "NP");
if (nodef == null) continue;
feature = HanlpResultHelper.GetNodeBottomLabelById(cons, nodef.ItemId, "NP");
if (string.IsNullOrEmpty(feature)) continue;
if (namedEntity.Text == feature) continue;
AddRule(namedEntity.Text, feature);
}
}
//自学创建特征
//NR->NP->NP->IP
//NN->NP(称呼、职业)
//完整汉语句法树库核心标签对照表(含 TOP/ NP / IP / CLP
//按 “核心层级 / 短语类型” 分类整理,覆盖 90 % 以上高频标注:
//1.顶层 / 句子级标签
//标签 英文全称 中文名称 定义 示例
//TOP Top - level Phrase 顶层短语 句法树的根节点,包含整个句子的最高层级结构 所有句子的根节点均标注为 TOP
//IP Inflectional Phrase / Simple Clause 简单从句 句子级核心短语(含主谓结构),是 TOP 的直接子节点 “我吃饭” 整体标注为 IP
//CP Complement Clause 补语从句 带补语标记(的 / 吗 / 呢)的从句 / 复句成分 “我买的书” 中 “我买的” 标注为 CP
//2.名词类短语
//标签 英文全称 中文名称 定义 示例
//NP Noun Phrase 名词短语 以名词为核心的短语(可含定语 / 量词) “苹果”“我的手机”“三本书”
//DNP XP+DEG Phrase “的” 字短语 由 “XP + 的” 构成的名词性短语 “红色的”“我喜欢的”
//NNP Proper Noun Phrase 专有名词短语 人名 / 地名 / 机构名等专有名词构成的短语 “北京大学”“张三”“北京市”
//3.动词类短语
//标签 英文全称 中文名称 定义 示例
//VP Verb Phrase 动词短语 以动词为核心的短语(可含宾语 / 状语) “吃饭”“快速跑步”“看电影”
//VV Verb Phrase(Verb Core) 动词核心短语 纯动词构成的短语(无附加成分) “跑”“思考”“购买”
//VCP Verb Complement Phrase 动补短语 动词 +补语构成的短语 “吃完”“跑快”“看明白”
//4.数量 / 量词类短语
//标签 英文全称 中文名称 定义 示例
//CLP Classifier Phrase 量词短语 以量词为核心的短语(数词 + 量词 / 指示词 + 量词) “三个”“这本”“那些”
//QP Quantifier Phrase 量化短语 以数量为核心的短语(涵盖数词 / 量词 / 数量整体) “三”“若干”“三本”“许多”
//DP Determiner Phrase 指示词短语 以指示词(这 / 那 / 此)为核心的短语 “这个”“那些”“此问题”
//5.介词 / 方位类短语
//标签 英文全称 中文名称 定义 示例
//PP Prepositional Phrase 介词短语 以介词为核心的短语 “在学校”“关于这件事”“把书”
//LCP Locative Complement Phrase 方位补语短语 含方位词的短语 “桌子上”“房间里”“马路边”
//LOC Locative Phrase 方位短语 纯方位名词构成的短语LCP 的简化版) “上面”“左边”“内部”
//6.形容词 / 副词类短语
//标签 英文全称 中文名称 定义 示例
//AP Adjective Phrase 形容词短语 以形容词为核心的短语 “漂亮”“非常开心”“红色的”
//ADVP Adverb Phrase 副词短语 以副词为核心的短语 “快速地”“很”“非常”
//7.其他功能类短语
//标签 英文全称 中文名称 定义 示例
//INTJ Interjection Phrase 感叹语短语 感叹词 / 语气词构成的短语 “啊”“哦”“哎呀”
//CONJP Conjunction Phrase 连词短语 连词构成的短语 “和”“但是”“因为”
//PRN Parenthetical Phrase 插入语短语 插入句子的附加成分 “换句话说”“总的来说”
//总结
//CLP 核心是量词短语,以量词为核心(如 “三本”“这本”),是数量表达的核心标注标签;
//TOP / IP 是句子层级标签(根节点 / 核心从句NP / VP 是核心短语标签(名词 / 动词为核心);
//不同工具CTB / HanLP / 北大树库)对标签的细分略有差异(如 CLP 是否归为 QP但核心含义一致优先以宾州中文树库CTB规范为准。
}
public void AddRule(string speaker, params string[] keywords)
{
if (string.IsNullOrWhiteSpace(speaker))
throw new ArgumentException("说话者名称不能为空", nameof(speaker));
if (keywords == null || keywords.Length == 0)
throw new ArgumentException("至少需要提供一个关键词", nameof(keywords));
_rules.Add(new SpeakerRule(speaker, keywords));
}
public string MatchSpeaker(string dialogue)
{
if (string.IsNullOrWhiteSpace(dialogue))
return null;
foreach (var rule in _rules)
{
if (rule.Match(dialogue))
{
return rule.Speaker;
}
}
return dialogue;
}
}
public class SpeakerRule
{
public string Speaker { get; }
public string[] Keywords { get; }
public SpeakerRule(string speaker, string[] keywords)
{
Speaker = speaker;
Keywords = keywords;
}
public bool Match(string dialogue)
{
return Keywords.Any(keyword =>
dialogue.IndexOf(keyword, StringComparison.OrdinalIgnoreCase) >= 0);
}
}
}