Skip to content

Commit a6c7b95

Browse files
authored
Merge pull request #2 from Agash/feat/customization-options
Feat/customization options
2 parents e3d9913 + 2a19838 commit a6c7b95

22 files changed

+1225
-342
lines changed

README.md

Lines changed: 69 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
[![NuGet Version](https://img.shields.io/nuget/v/Agash.TTSTextNormalization.svg?style=flat-square)](https://www.nuget.org/packages/Agash.TTSTextNormalization/)
44
[![Build Status](https://img.shields.io/github/actions/workflow/status/Agash/TTSTextNormalization/dotnet-publish.yml?branch=master&style=flat-square)](https://github.com/Agash/TTSTextNormalization/actions)
55

6-
A .NET 9 / C# 13 class library designed to normalize text containing emojis, currency symbols, numbers, abbreviations, and other non-standard elements, making it suitable for consistent and natural-sounding Text-to-Speech (TTS) synthesis across different engines (e.g., System.Speech, KokoroSharp). Specifically tailored for scenarios involving user-generated content like Twitch/YouTube chat and donations.
6+
A .NET 9 / C# 13 class library designed to normalize text containing emojis, currency symbols, numbers, URLs, abbreviations, and other non-standard elements, making it suitable for consistent and natural-sounding Text-to-Speech (TTS) synthesis across different engines (e.g., System.Speech, KokoroSharp). Specifically tailored for scenarios involving user-generated content like Twitch/YouTube chat and donations.
77

88
## Problem Solved
99

@@ -13,31 +13,41 @@ TTS engines often struggle with or produce inconsistent results when encounterin
1313
* Currency symbols and codes from various locales (e.g., $, £, €, USD, JPY, BRL)
1414
* Different number formats (cardinals, ordinals, decimals, version numbers)
1515
* Common chat/gaming abbreviations and slang (e.g., lol, brb, gg, afk)
16+
* URLs (e.g., https://example.com, www.test.org)
1617
* Excessive punctuation or letter repetitions (e.g., !!!, ???, sooooo)
17-
* URLs or non-standard characters
18+
* Non-standard characters
1819

1920
This library preprocesses input text using a configurable pipeline of rules to replace or adjust these elements *before* sending the text to the TTS engine, leading to a more predictable, consistent, and pleasant listening experience.
2021

2122
## Features
2223

23-
* **Emoji Normalization:** Replaces Unicode emojis (including flags, ZWJ sequences) with descriptive text (e.g., ✨ -> `sparkles`, 👍 -> `thumbs up`, 🇬🇧 -> `flag United Kingdom`) using an up-to-date emoji dataset processed by a source generator.
24-
* **Currency Normalization:** Detects currency symbols and ISO codes known to the .NET runtime. Replaces amounts with spoken text using locale-aware mappings (e.g., `$10.50` -> `ten dollars fifty cents`, `€100` -> `one hundred euros`, `500 JPY` -> `five hundred yen`). Uses Humanizer for number-to-word conversion. Requires manual mapping for TTS spoken names per ISO code.
25-
* **Number Normalization:** Handles standalone cardinals ("123" -> `one hundred and twenty-three`), ordinals ("1st" -> `first`), decimals ("1.5" -> `one point five`), and basic version-like numbers ("1.2.3" -> `one point two point three`) using Humanizer and custom Regex.
26-
* **Abbreviation/Acronym Expansion:** Expands a comprehensive list of common chat, gaming, and streaming abbreviations (e.g., `lol` -> `laughing out loud`, `gg` -> `good game`, `afk` -> `away from keyboard`). Case-insensitive and whole-word matching.
27-
* **Basic Text Sanitization:** Normalizes line breaks, removes common problematic control/formatting characters, and replaces non-standard "fancy" punctuation (smart quotes, dashes, ellipsis) with ASCII equivalents.
24+
* **Emoji Normalization:** Replaces Unicode emojis (including flags, ZWJ sequences) with descriptive text (e.g., ✨ -> `sparkles`).
25+
* *Configurable:* Add optional prefix/suffix (e.g., "emoji sparkles", "sparkles emoji") via `EmojiRuleOptions`.
26+
* **Currency Normalization:** Detects currency symbols and ISO codes. Replaces amounts with spoken text using locale-aware mappings (e.g., `$10.50` -> `ten US dollars fifty cents`). Uses Humanizer.
27+
* **Number Normalization:** Handles standalone cardinals ("123" -> `one hundred and twenty-three`), ordinals ("1st" -> `first`), decimals ("1.5" -> `one point five`), and version-like numbers ("1.2.3" -> `one point two point three`). Uses Humanizer.
28+
* **URL Normalization:** Replaces detected URLs (http, https, www) with a placeholder (default: " link ").
29+
* *Configurable:* Specify custom placeholder text via `UrlRuleOptions`.
30+
* **Abbreviation/Acronym Expansion:** Expands a comprehensive list of common chat, gaming, and streaming abbreviations (e.g., `lol` -> `laughing out loud`). Case-insensitive and whole-word matching.
31+
* *Configurable:* Add custom abbreviations or completely replace the default list via `AbbreviationRuleOptions`.
32+
* **Basic Text Sanitization:** Normalizes line breaks, removes common problematic control/formatting characters, and replaces non-standard "fancy" punctuation with ASCII equivalents.
2833
* **Chat Text Cleanup:**
2934
* Reduces sequences of excessive punctuation (`!!!` -> `!`, `...` -> `.`, `???` -> `?`).
3035
* Reduces excessive letter repetitions (`soooo` -> `soo`).
31-
* **Whitespace Normalization:** Trims leading/trailing whitespace, collapses multiple internal whitespace characters to a single space, and normalizes spacing around common punctuation (removes space before, ensures space after).
32-
* **Extensibility:** Designed around a pipeline of `ITextNormalizationRule` instances, easily configurable via Dependency Injection. Custom rules can be created by implementing the interface.
33-
* **Performance:** Optimized using modern .NET features like source generators (Regex, Emoji data), `FrozenDictionary` for lookups, and efficient string handling where possible.
36+
* **Whitespace Normalization:** Trims leading/trailing whitespace, collapses multiple internal whitespace characters to a single space, and normalizes spacing around common punctuation.
37+
* **Extensibility & Configuration:**
38+
* Designed around a pipeline of `ITextNormalizationRule` instances.
39+
* Easily configurable via Dependency Injection using `AddTextNormalization`.
40+
* Rule execution order can be overridden during registration.
41+
* Specific rules offer configuration via the standard .NET Options pattern (`IOptions<T>`).
42+
* Custom rules can be created by implementing the `ITextNormalizationRule` interface.
43+
* **Performance:** Optimized using modern .NET features like source generators (Regex, Emoji data), `FrozenDictionary` for lookups, `IOptions`, and efficient string handling where possible.
3444

3545
## Technology
3646

37-
* **C# 13 / .NET 9 (Preview)**: Leverages the latest language and runtime features.
47+
* **C# 13 / .NET 9**: Leverages the latest language and runtime features.
3848
* **Source Generators:** Used for generating optimized Regex patterns and embedding up-to-date Emoji data at compile time.
3949
* **Humanizer:** Used for robust number-to-words and ordinal conversion.
40-
* **Core .NET Libraries:** `System.Text.RegularExpressions`, `System.Globalization`, `System.Collections.Frozen`, `System.Text.Json` (in generator).
50+
* **Core .NET Libraries:** `System.Text.RegularExpressions`, `System.Globalization`, `System.Collections.Frozen`, `System.Text.Json` (in generator), `Microsoft.Extensions.Options`.
4151
* **Dependency Injection:** Designed for easy integration using `Microsoft.Extensions.DependencyInjection`.
4252

4353
## Getting Started
@@ -57,27 +67,57 @@ Or install `Agash.TTSTextNormalization` via the NuGet Package Manager in Visual
5767
using Microsoft.Extensions.DependencyInjection;
5868
using TTSTextNormalization.Abstractions; // For ITextNormalizer
5969
using TTSTextNormalization.DependencyInjection; // For extension methods
70+
using TTSTextNormalization.Rules; // For rule options classes
71+
using System.Collections.Frozen; // For FrozenDictionary
6072
6173
// ... other using statements
6274
6375
var services = new ServiceCollection();
6476

65-
// Configure the normalization pipeline with desired rules
77+
// --- Configure Rule Options (Optional) ---
78+
services.Configure<AbbreviationRuleOptions>(options =>
79+
{
80+
// Example: Add custom abbreviations and override 'gg'
81+
var customMap = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
82+
{
83+
{ "cya", "see you" },
84+
{ "gg", "very good game" } // Overrides default
85+
};
86+
options.CustomAbbreviations = customMap.ToFrozenDictionary(StringComparer.OrdinalIgnoreCase);
87+
options.ReplaceDefaultAbbreviations = false; // Merge with defaults (default behavior)
88+
});
89+
90+
services.Configure<UrlRuleOptions>(options =>
91+
{
92+
options.PlaceholderText = " website link "; // Use a custom placeholder
93+
});
94+
95+
services.Configure<EmojiRuleOptions>(options =>
96+
{
97+
options.Suffix = "emoji"; // Append " emoji" to names, e.g., "thumbs up emoji"
98+
});
99+
100+
101+
// --- Configure the Normalization Pipeline ---
66102
services.AddTextNormalization(builder =>
67103
{
68-
// Add rules - order is managed internally by the 'Order' property of each rule (currently not yet configurable, opinionated)
69-
builder.AddBasicSanitizationRule(); // Runs first (Order 10)
70-
builder.AddEmojiRule(); // Order 100
71-
builder.AddCurrencyRule(); // Order 200
72-
builder.AddAbbreviationNormalizationRule(); // Order 300
73-
builder.AddNumberNormalizationRule(); // Order 400
74-
builder.AddExcessivePunctuationRule(); // Order 500
75-
builder.AddLetterRepetitionRule(); // Order 510
76-
// Add custom rules here if needed: builder.AddRule<MyCustomRule>();
77-
builder.AddWhitespaceNormalizationRule(); // Runs last (Order 9000)
104+
// Add rules. Order is determined by default 'Order' property unless overridden.
105+
builder.AddBasicSanitizationRule(); // Order 10
106+
builder.AddEmojiRule(); // Order 100 (Uses configured options)
107+
builder.AddCurrencyRule(); // Order 200
108+
builder.AddAbbreviationNormalizationRule(); // Order 300 (Uses configured options)
109+
builder.AddNumberNormalizationRule(); // Order 400
110+
builder.AddExcessivePunctuationRule(); // Order 500
111+
builder.AddLetterRepetitionRule(); // Order 510
112+
builder.AddUrlNormalizationRule(); // Order 600 (Uses configured options)
113+
// Example: Add Whitespace rule but make it run earlier
114+
builder.AddWhitespaceNormalizationRule(orderOverride: 50); // Runs before Emoji now!
115+
// Add custom rules here: builder.AddRule<MyCustomRule>(orderOverride: 700);
78116
});
79117

80118
// Register other services...
119+
// Add Logging if desired (pipeline logs information)
120+
// services.AddLogging(logBuilder => logBuilder.AddConsole());
81121
82122
// Build the provider
83123
var serviceProvider = services.BuildServiceProvider();
@@ -90,19 +130,19 @@ Or install `Agash.TTSTextNormalization` via the NuGet Package Manager in Visual
90130
var normalizer = serviceProvider.GetRequiredService<ITextNormalizer>();
91131

92132
// Example inputs
93-
string input1 = " OMG!!! That stream was 🔥🔥🔥!! Costs $10... BRB. 1st place!! ";
94-
string input2 = "He said “hello” ‹you› sooo many times... 1.2.3 check";
133+
string input1 = " OMG!!! That stream was 🔥🔥🔥!! CYA! Costs $10... Check www.example.com! ";
134+
string input2 = "He said “hello” ✨ gg.";
95135

96136
// Normalize
97137
string normalized1 = normalizer.Normalize(input1);
98138
string normalized2 = normalizer.Normalize(input2);
99139

100-
// Output (approximate, based on current rules)
140+
// Output (approximate, based on configured rules and options)
101141
Console.WriteLine(normalized1);
102-
// Output: oh my god! That stream was fire fire fire! Costs ten dollars. be right back. first place!
142+
// Output: oh my god! That stream was fire emoji fire emoji fire emoji! see you! Costs ten US dollars. Check website link!
103143
104144
Console.WriteLine(normalized2);
105-
// Output: He said "hello" 'you' soo many times. one point two point three check
145+
// Output: He said "hello" sparkles emoji very good game.
106146
107147
// Pass the normalized text to your TTS engine
108148
// MyTTSEngine.Speak(normalized1);
@@ -111,7 +151,7 @@ Or install `Agash.TTSTextNormalization` via the NuGet Package Manager in Visual
111151

112152
## Building
113153

114-
Ensure you have the .NET 9 SDK (Preview) installed.
154+
Ensure you have the .NET 9 SDK installed.
115155

116156
1. Clone the repository:
117157
```bash

0 commit comments

Comments
 (0)