Rewrite Text in Different Communication Styles
The same information needs different phrasing for different audiences. A technical explanation for engineers needs to become a concise executive summary. A casual chat response needs to become a professional email. LM-Kit.NET's TextRewriter class transforms text into three communication styles (Concise, Professional, Friendly) while preserving the original meaning. This tutorial builds a text rewriting tool with streaming output and multi-style comparison.
Why Local Text Rewriting Matters
Two enterprise problems that on-device rewriting solves:
- Internal communications stay private. Rewriting drafts of sensitive emails, internal memos, and strategy documents means feeding confidential business content into a language model. Local rewriting ensures that content never leaves your infrastructure.
- Consistent brand voice at scale. Customer-facing teams write in different styles. A local rewriter standardizes tone across support replies, marketing copy, and documentation without per-request costs.
Prerequisites
| Requirement | Minimum |
|---|---|
| .NET SDK | 8.0+ |
| VRAM | 4+ GB |
| Disk | ~3 GB free for model download |
Step 1: Create the Project
dotnet new console -n RewriteQuickstart
cd RewriteQuickstart
dotnet add package LM-Kit.NET
Step 2: Rewrite Text in Three Styles
using System.Text;
using LMKit.Model;
using LMKit.TextEnhancement;
LMKit.Licensing.LicenseManager.SetLicenseKey("");
Console.InputEncoding = Encoding.UTF8;
Console.OutputEncoding = Encoding.UTF8;
// ──────────────────────────────────────
// 1. Load model
// ──────────────────────────────────────
Console.WriteLine("Loading model...");
using LM model = LM.LoadFromModelID("gemma3:4b",
downloadingProgress: (_, len, read) =>
{
if (len.HasValue) Console.Write($"\r Downloading: {(double)read / len.Value * 100:F1}% ");
return true;
},
loadingProgress: p => { Console.Write($"\r Loading: {p * 100:F0}% "); return true; });
Console.WriteLine("\n");
// ──────────────────────────────────────
// 2. Rewrite in all three styles
// ──────────────────────────────────────
var rewriter = new TextRewriter(model);
string original = """
Hey team, so basically the server went down last night around 2am because the
disk was completely full. Nobody noticed until morning when customers started
complaining. We really need to set up monitoring alerts so this doesn't happen
again. Also the backup script hasn't been running for like 2 weeks.
""";
Console.ForegroundColor = ConsoleColor.DarkGray;
Console.WriteLine($"Original:\n {original.Trim()}\n");
Console.ResetColor();
var styles = new[]
{
TextRewriter.CommunicationStyle.Concise,
TextRewriter.CommunicationStyle.Professional,
TextRewriter.CommunicationStyle.Friendly
};
foreach (var style in styles)
{
string rewritten = rewriter.Rewrite(original, style);
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine($"{style}:");
Console.ResetColor();
Console.WriteLine($" {rewritten}\n");
}
Step 3: Streaming Output
For longer texts, stream the rewritten output token by token:
using LMKit.TextEnhancement;
using LMKit.TextGeneration;
using LMKit.TextGeneration.Chat;
var rewriter = new TextRewriter(model);
rewriter.AfterTextCompletion += (sender, e) =>
{
if (e.SegmentType == TextSegmentType.UserVisible)
{
Console.Write(e.Text);
}
};
string input = """
The deployment process is really messy right now. First you gotta ssh into the
server, then manually pull the latest code, restart the services one by one, and
hope nothing breaks. If something goes wrong you have to roll back manually which
takes forever. We should probably automate this whole thing.
""";
Console.WriteLine("Professional version:\n");
rewriter.Rewrite(input, TextRewriter.CommunicationStyle.Professional);
Console.WriteLine("\n");
Step 4: Multilingual Rewriting
Rewrite text while targeting a specific output language:
using LMKit.Global;
string englishText = "Our quarterly results exceeded expectations with a 23% increase in revenue.";
// Rewrite in French (Professional)
string french = rewriter.Rewrite(
englishText,
TextRewriter.CommunicationStyle.Professional,
Language.French);
Console.WriteLine($"French (Professional):\n {french}\n");
// Rewrite in Spanish (Friendly)
string spanish = rewriter.Rewrite(
englishText,
TextRewriter.CommunicationStyle.Friendly,
Language.Spanish);
Console.WriteLine($"Spanish (Friendly):\n {spanish}\n");
// Rewrite in German (Concise)
string german = rewriter.Rewrite(
englishText,
TextRewriter.CommunicationStyle.Concise,
Language.German);
Console.WriteLine($"German (Concise):\n {german}\n");
Step 5: Interactive Rewriter
Build an interactive tool that lets users choose the style:
using System.Text;
using LMKit.Model;
using LMKit.TextEnhancement;
LMKit.Licensing.LicenseManager.SetLicenseKey("");
Console.InputEncoding = Encoding.UTF8;
Console.OutputEncoding = Encoding.UTF8;
// ──────────────────────────────────────
// 1. Load model
// ──────────────────────────────────────
Console.WriteLine("Loading model...");
using LM model = LM.LoadFromModelID("gemma3:4b",
downloadingProgress: (_, len, read) =>
{
if (len.HasValue) Console.Write($"\r Downloading: {(double)read / len.Value * 100:F1}% ");
return true;
},
loadingProgress: p => { Console.Write($"\r Loading: {p * 100:F0}% "); return true; });
Console.WriteLine("\n");
// ──────────────────────────────────────
// 2. Rewrite in all three styles
// ──────────────────────────────────────
var rewriter = new TextRewriter(model);
string original = """
Hey team, so basically the server went down last night around 2am because the
disk was completely full. Nobody noticed until morning when customers started
complaining. We really need to set up monitoring alerts so this doesn't happen
again. Also the backup script hasn't been running for like 2 weeks.
""";
Console.ForegroundColor = ConsoleColor.DarkGray;
Console.WriteLine($"Original:\n {original.Trim()}\n");
Console.ResetColor();
var styles = new[]
{
TextRewriter.CommunicationStyle.Concise,
TextRewriter.CommunicationStyle.Professional,
TextRewriter.CommunicationStyle.Friendly
};
Console.WriteLine("Text Rewriter (enter text, then choose a style)\n");
while (true)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.Write("Text: ");
Console.ResetColor();
string? input = Console.ReadLine();
if (string.IsNullOrWhiteSpace(input) || input.Equals("quit", StringComparison.OrdinalIgnoreCase))
break;
Console.WriteLine(" [1] Concise [2] Professional [3] Friendly [4] All three");
Console.Write(" Style: ");
string? choice = Console.ReadLine();
if (choice == "4")
{
foreach (var style in styles)
{
string result = rewriter.Rewrite(input, style);
Console.ForegroundColor = ConsoleColor.Cyan;
Console.Write($" {style,-14}");
Console.ResetColor();
Console.WriteLine(result);
}
}
else
{
var style = choice switch
{
"2" => TextRewriter.CommunicationStyle.Professional,
"3" => TextRewriter.CommunicationStyle.Friendly,
_ => TextRewriter.CommunicationStyle.Concise
};
string result = rewriter.Rewrite(input, style);
Console.ForegroundColor = ConsoleColor.Cyan;
Console.Write($" {style}: ");
Console.ResetColor();
Console.WriteLine(result);
}
Console.WriteLine();
}
Step 6: Batch Rewriting
Process a file of messages and export all three style variants:
using System.Text;
using LMKit.Model;
using LMKit.TextEnhancement;
LMKit.Licensing.LicenseManager.SetLicenseKey("");
Console.InputEncoding = Encoding.UTF8;
Console.OutputEncoding = Encoding.UTF8;
// ──────────────────────────────────────
// 1. Load model
// ──────────────────────────────────────
Console.WriteLine("Loading model...");
using LM model = LM.LoadFromModelID("gemma3:4b",
downloadingProgress: (_, len, read) =>
{
if (len.HasValue) Console.Write($"\r Downloading: {(double)read / len.Value * 100:F1}% ");
return true;
},
loadingProgress: p => { Console.Write($"\r Loading: {p * 100:F0}% "); return true; });
Console.WriteLine("\n");
// ──────────────────────────────────────
// 2. Rewrite in all three styles
// ──────────────────────────────────────
var rewriter = new TextRewriter(model);
string original = """
Hey team, so basically the server went down last night around 2am because the
disk was completely full. Nobody noticed until morning when customers started
complaining. We really need to set up monitoring alerts so this doesn't happen
again. Also the backup script hasn't been running for like 2 weeks.
""";
string[] lines = File.ReadAllLines("draft_messages.txt")
.Where(l => !string.IsNullOrWhiteSpace(l))
.ToArray();
var output = new List<string>();
output.Add("original,concise,professional,friendly");
Console.WriteLine($"Rewriting {lines.Length} messages...\n");
foreach (string line in lines)
{
string concise = rewriter.Rewrite(line, TextRewriter.CommunicationStyle.Concise);
string professional = rewriter.Rewrite(line, TextRewriter.CommunicationStyle.Professional);
string friendly = rewriter.Rewrite(line, TextRewriter.CommunicationStyle.Friendly);
output.Add($"\"{Escape(line)}\",\"{Escape(concise)}\",\"{Escape(professional)}\",\"{Escape(friendly)}\"");
Console.WriteLine($" Processed: {(line.Length > 50 ? line.Substring(0, 50) + "..." : line)}");
}
File.WriteAllLines("rewritten_messages.csv", output);
Console.WriteLine($"\nExported to rewritten_messages.csv");
static string Escape(string s) => s.Replace("\"", "\"\"");
Common Issues
| Problem | Cause | Fix |
|---|---|---|
| Output includes reasoning or preamble | Streaming handler not filtering segments | Only display TextSegmentType.UserVisible segments |
| Rewrite changes the meaning | Input is ambiguous or too informal | Pre-process with TextCorrection to fix grammar first |
| Output in wrong language | Language not specified | Pass the target Language parameter explicitly |
| Slow on long texts | Full text processed at once | Split into paragraphs; rewrite each separately |
| Style differences are subtle | Small model with limited nuance | Use a larger model (gemma3:12b) for more distinct style differences |
Next Steps
- Correct Grammar and Spelling: fix errors before rewriting.
- Translate and Localize Content: full translation across languages.
- Samples: Text Rewriter: text rewriting demo.