chrysopedia/backend/pipeline/quality/voice_dial.py
jlightner 15a7afdaff feat: Added VoiceDial class with 3-band prompt modification and ScoreRu…
- "backend/pipeline/quality/voice_dial.py"
- "backend/pipeline/quality/scorer.py"
- "backend/pipeline/quality/__main__.py"

GSD-Task: S02/T02
2026-04-01 08:57:07 +00:00

91 lines
3.8 KiB
Python
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.

"""Voice preservation dial — modifies Stage 5 synthesis prompt by intensity band.
Three bands control how much of the creator's original voice is preserved:
- Low (0.00.33): Clinical, encyclopedic tone — suppress direct quotes
- Mid (0.340.66): Base prompt unchanged (already ~0.6 voice preservation)
- High (0.671.0): Maximum voice — prioritize exact words, strong opinions
"""
from __future__ import annotations
# ── Band modifier text ────────────────────────────────────────────────────────
_LOW_BAND_MODIFIER = """
## Voice Suppression Override
IMPORTANT — override the voice/tone guidelines above. For this synthesis:
- Do NOT include any direct quotes from the creator. Rephrase all insights in neutral third-person encyclopedic style.
- Do NOT attribute opinions or preferences to the creator by name (avoid "he recommends", "she prefers").
- Remove all personality markers, humor, strong opinions, and conversational tone.
- Write as a reference manual: factual, impersonal, technically precise.
- Replace phrases like "he warns against" with neutral statements like "this approach is generally avoided because."
- Suppress colloquialisms and informal language entirely.
"""
_HIGH_BAND_MODIFIER = """
## Maximum Voice Preservation Override
IMPORTANT — amplify the voice/tone guidelines above. For this synthesis:
- Maximize the use of direct quotes from the transcript. Every memorable phrase, vivid metaphor, or strong opinion should be quoted verbatim with quotation marks.
- Attribute all insights, preferences, and techniques to the creator by name — use their name frequently.
- Preserve personality, humor, strong opinions, and conversational tone. If the creator is emphatic, the prose should feel emphatic.
- Prioritize the creator's exact words over paraphrase. When a transcript excerpt contains a usable phrase, quote it rather than summarizing it.
- Include warnings, caveats, and opinionated asides in the creator's own voice.
- The resulting page should feel like the creator is speaking directly to the reader through the text.
"""
# ── VoiceDial class ───────────────────────────────────────────────────────────
class VoiceDial:
"""Modifies a Stage 5 synthesis prompt based on a voice_level parameter.
Parameters
----------
base_prompt:
The original stage5_synthesis.txt system prompt content.
"""
# Band boundaries
LOW_UPPER = 0.33
HIGH_LOWER = 0.67
def __init__(self, base_prompt: str) -> None:
self.base_prompt = base_prompt
def modify(self, voice_level: float) -> str:
"""Return the system prompt modified for the given voice_level.
Parameters
----------
voice_level:
Float 0.01.0. Values outside this range are clamped.
Returns
-------
str
Modified system prompt with band-appropriate instructions appended.
"""
voice_level = max(0.0, min(1.0, voice_level))
if voice_level <= self.LOW_UPPER:
return self.base_prompt + _LOW_BAND_MODIFIER
elif voice_level >= self.HIGH_LOWER:
return self.base_prompt + _HIGH_BAND_MODIFIER
else:
# Mid band — base prompt is already moderate voice preservation
return self.base_prompt
@staticmethod
def band_name(voice_level: float) -> str:
"""Return the human-readable band name for a voice_level value."""
voice_level = max(0.0, min(1.0, voice_level))
if voice_level <= VoiceDial.LOW_UPPER:
return "low"
elif voice_level >= VoiceDial.HIGH_LOWER:
return "high"
return "mid"