How to Create AI Output Style Transfer
Train AI to write in your exact brand voice using style examples.
Jay Banlasan
The AI Systems Guy
Style transfer is the process of taking content and rewriting it in a specific voice. The use case I run into most often: a business has years of great content written by a specific person, then that person leaves, and every new piece of content sounds different. Style transfer solves that. You feed the AI examples of your best existing content and it learns to replicate the patterns, vocabulary, rhythm, and tone.
I have used this to replicate founder voices for ghostwritten LinkedIn posts, match a brand's newsletter tone across different writers, and maintain a consultant's teaching style across automated content. The output is not perfect on the first pass, but it is close enough that editing takes minutes instead of hours.
What You Need Before Starting
- Python 3.9+
- OpenAI or Anthropic API key
- At least 5-10 high-quality writing samples in the target voice (more is better)
- A clear understanding of what makes the voice distinctive
Step 1: Build a Style Analysis Function
Before you can transfer a style, you need to understand it. Use the model to analyze your writing samples and extract explicit rules.
import openai
client = openai.OpenAI(api_key="YOUR_API_KEY")
def analyze_writing_style(samples: list[str]) -> str:
combined_samples = "\n\n---\n\n".join(samples)
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{
"role": "system",
"content": """You are a writing style analyst. Analyze the provided writing samples and extract a precise style guide.
Cover: sentence length patterns, vocabulary level, use of questions, use of numbers/data, structural patterns, what topics are addressed directly vs avoided, tone markers, what this writer NEVER does, and 5-10 characteristic phrases or constructions."""
},
{
"role": "user",
"content": f"Analyze the writing style in these samples:\n\n{combined_samples}"
}
],
temperature=0.3
)
return response.choices[0].message.content
# Run once and save the analysis
WRITING_SAMPLES = [
"""Most agencies will tell you results take 90 days. That's true for some things.
For paid ads, you should see data in 7 days and a signal in 30. If you don't have
a signal in 30 days, the problem isn't time. It's the offer or the audience.""",
"""Stop optimizing your ads. I know that sounds backwards. But if you're changing
variables every 3 days, you're not learning anything. Pick one thing to test.
Run it long enough to get statistical significance. Then make one change. That's it.""",
"""The number I care about is cost per booked call, not cost per lead.
Leads are noise. Calls are signal. If you're celebrating a $4 lead but it takes
50 leads to book a call, your real cost is $200. Run the full funnel math."""
]
style_analysis = analyze_writing_style(WRITING_SAMPLES)
print(style_analysis)
Step 2: Build the Style System Prompt
Convert the analysis into a system prompt that drives style-consistent output.
def build_style_prompt(style_analysis: str, few_shot_examples: list[str]) -> str:
examples_text = "\n\n".join([f"Example {i+1}:\n{ex}" for i, ex in enumerate(few_shot_examples)])
return f"""You are a writing engine that produces content in a specific author's voice.
STYLE GUIDE (follow precisely):
{style_analysis}
WRITING EXAMPLES (study these carefully):
{examples_text}
RULES:
- Match the rhythm and sentence patterns exactly
- Use similar vocabulary level and directness
- Never use hedge words: "might", "could potentially", "it's possible"
- Never use filler openers: "Great", "Certainly", "Of course"
- Never use passive voice where active is possible
- Match the structural pattern of the examples above
- Write as if you ARE this person, not as if you're imitating them"""
STYLE_SYSTEM_PROMPT = build_style_prompt(style_analysis, WRITING_SAMPLES)
Step 3: The Style Transfer Function
Take input content and rewrite it in the target voice.
def style_transfer(
content: str,
style_prompt: str,
content_type: str = "general",
preserve_facts: bool = True
) -> str:
preservation_note = """
IMPORTANT: Preserve all specific numbers, names, dates, and factual claims exactly.
Only change the style and structure, not the substance.""" if preserve_facts else ""
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": style_prompt + preservation_note},
{
"role": "user",
"content": f"Rewrite the following {content_type} in this exact voice. Keep all the facts but match the style perfectly:\n\n{content}"
}
],
temperature=0.5
)
return response.choices[0].message.content
# Usage
generic_content = """
When running paid advertising campaigns, it is important to monitor your metrics
regularly. Cost per lead can vary depending on many factors including audience
targeting and creative quality. You should consider testing different approaches
to optimize your results over time.
"""
transferred = style_transfer(generic_content, STYLE_SYSTEM_PROMPT, "marketing advice")
print(transferred)
Step 4: Add a Style Consistency Scorer
Score how well the transferred output actually matches the target style.
def score_style_match(
transferred_text: str,
style_examples: list[str],
scorer_model: str = "gpt-4o"
) -> dict:
examples_text = "\n\n---\n\n".join(style_examples[:3])
response = client.chat.completions.create(
model=scorer_model,
messages=[
{
"role": "system",
"content": "You evaluate how well a text matches a target writing style. Score 1-10 on: tone, sentence rhythm, vocabulary level, directness, and overall match. Return JSON only."
},
{
"role": "user",
"content": f"""Target style examples:
{examples_text}
---
Text to evaluate:
{transferred_text}
Return: {{"tone": N, "rhythm": N, "vocabulary": N, "directness": N, "overall": N, "notes": "..."}}"""
}
],
temperature=0,
response_format={"type": "json_object"}
)
import json
return json.loads(response.choices[0].message.content)
score = score_style_match(transferred, WRITING_SAMPLES)
print(f"Style match score: {score['overall']}/10")
print(f"Notes: {score['notes']}")
Step 5: Build a Style Library for Multiple Voices
Manage multiple brand voices in a reusable library.
import json
from pathlib import Path
STYLES_DIR = Path("./style_library")
STYLES_DIR.mkdir(exist_ok=True)
def save_style(name: str, examples: list[str], additional_rules: str = ""):
analysis = analyze_writing_style(examples)
style_data = {
"name": name,
"analysis": analysis,
"examples": examples,
"additional_rules": additional_rules,
"system_prompt": build_style_prompt(analysis + "\n\n" + additional_rules, examples)
}
(STYLES_DIR / f"{name}.json").write_text(json.dumps(style_data, indent=2))
print(f"Style saved: {name}")
def load_style(name: str) -> dict:
path = STYLES_DIR / f"{name}.json"
if not path.exists():
raise FileNotFoundError(f"Style not found: {name}")
return json.loads(path.read_text())
def transfer_to_named_style(content: str, style_name: str) -> str:
style = load_style(style_name)
return style_transfer(content, style["system_prompt"])
# Save a style once
save_style("jay-banlasan", WRITING_SAMPLES, "Never uses em dashes. Never uses 'perhaps'.")
# Use it anywhere
result = transfer_to_named_style("Your ad results might improve with some testing.", "jay-banlasan")
print(result)
Step 6: Batch Process Content for a Migration
Rewrite an entire archive of content in a new voice.
from pathlib import Path
def batch_style_transfer(
input_folder: str,
output_folder: str,
style_name: str,
file_pattern: str = "*.txt"
) -> dict:
input_path = Path(input_folder)
output_path = Path(output_folder)
output_path.mkdir(parents=True, exist_ok=True)
style = load_style(style_name)
files = list(input_path.glob(file_pattern))
processed = 0
errors = []
for file in files:
try:
content = file.read_text(encoding="utf-8")
transferred = style_transfer(content, style["system_prompt"])
output_file = output_path / file.name
output_file.write_text(transferred, encoding="utf-8")
processed += 1
print(f"Processed: {file.name}")
except Exception as e:
errors.append({"file": file.name, "error": str(e)})
return {"processed": processed, "errors": len(errors), "error_details": errors}
What to Build Next
- Build a style drift detector that scores new content against your style library monthly and flags posts that have drifted from the target voice
- Add a fine-tuning pipeline using your best-scored transferred content to create a model that is cheaper and faster for high-volume style transfer jobs
- Create a style comparison tool that shows the original and transferred text side by side with specific change annotations
Related Reading
- How to Write System Prompts That Control AI Behavior - system prompt precision is the main lever for style fidelity
- How to Build AI Guardrails for Safe Outputs - ensure transferred content stays within brand-safe boundaries
- How to Use AI for Automated Data Extraction - extract voice patterns from large content archives to build your style library faster
Want this system built for your business?
Get a free assessment. We will map every system your business needs and show you the ROI.
Get Your Free Assessment