Add subreddit tone profiles for message style guidance
Introduces a tone-profile system that lets the processor adapt outgoing message style per-subreddit (and per-flair) instead of using one tone for everything. Profiles act as a "tone mic" layered after the base prompt and strategy override, so they shape voice without redefining the whole message. - src/config/tone-profiles.ts defines the catalog (default, dominant, submissive, playful, direct, ...) and a resolveTone() helper that falls back to the default profile for unknown keys. - config.yaml maps subreddits to tone keys; the schema in src/config/index.ts validates it. - src/services/processor.ts threads the resolved tone into the prompt build, picking based on subreddit and optional link flair. - src/reddit/api.ts adds link_flair_text to RedditPost so the processor can use it for tone selection. - src/ai/openrouter.ts accepts and forwards the tone-shaped prompt. - public/index.html surfaces the active tone in the dashboard. - Tests cover the catalog, config validation, and processor integration. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
1 parent
0c7df6e1d3
commit
46a213e3e0
10 files changed
+497
-51
No files matched your search
+21
-4
@@ -226,6 +226,8 @@ ${this.config.openrouter.imageAnalysisPrompt}`;
|
||||
successfulExamples: string[] = [],
|
||||
strategyPrompt?: string,
|
||||
attractivenessScore: number | null = null,
|
||||
postFlair?: string | null,
|
||||
toneGuidance?: string,
|
||||
): Promise<string> {
|
||||
try {
|
||||
this.logger.debug('Generating message...');
|
||||
@@ -234,13 +236,19 @@ ${this.config.openrouter.imageAnalysisPrompt}`;
|
||||
.replace('{analysis}', imageAnalysis)
|
||||
.replace('{title}', postTitle)
|
||||
.replace('{author}', authorName)
|
||||
.replace('{rating}', attractivenessScore != null ? String(attractivenessScore) : 'unknown');
|
||||
.replace('{rating}', attractivenessScore != null ? String(attractivenessScore) : 'unknown')
|
||||
.replace('{flair}', postFlair || '(no flair)');
|
||||
|
||||
// Append strategy-specific style guidance if provided
|
||||
if (strategyPrompt) {
|
||||
prompt += `\n\n${strategyPrompt}`;
|
||||
}
|
||||
|
||||
// Append tone guidance if provided
|
||||
if (toneGuidance) {
|
||||
prompt += `\n\n${toneGuidance}`;
|
||||
}
|
||||
|
||||
// Add successful examples if available
|
||||
if (successfulExamples.length > 0) {
|
||||
const examplesText = successfulExamples
|
||||
@@ -371,6 +379,8 @@ Just write the message, nothing else.`;
|
||||
detectedGender: DetectedGender,
|
||||
successfulExamples: string[] = [],
|
||||
strategyPrompt?: string,
|
||||
postFlair?: string | null,
|
||||
toneGuidance?: string,
|
||||
): Promise<string> {
|
||||
try {
|
||||
this.logger.debug('Generating chat opener...');
|
||||
@@ -379,12 +389,17 @@ Just write the message, nothing else.`;
|
||||
.replace('{title}', postTitle)
|
||||
.replace('{selftext}', selftext || '(no body)')
|
||||
.replace('{author}', authorName)
|
||||
.replace('{gender}', detectedGender);
|
||||
.replace('{gender}', detectedGender)
|
||||
.replace('{flair}', postFlair || '(no flair)');
|
||||
|
||||
if (strategyPrompt) {
|
||||
prompt += `\n\n${strategyPrompt}`;
|
||||
}
|
||||
|
||||
if (toneGuidance) {
|
||||
prompt += `\n\n${toneGuidance}`;
|
||||
}
|
||||
|
||||
if (successfulExamples.length > 0) {
|
||||
const examplesText = successfulExamples
|
||||
.map((ex, i) => `Example ${i + 1}:\n${ex}`)
|
||||
@@ -482,10 +497,12 @@ Just write the message, nothing else.`;
|
||||
postTitle: string,
|
||||
authorName: string,
|
||||
successfulExamples: string[] = [],
|
||||
strategyPrompt?: string
|
||||
strategyPrompt?: string,
|
||||
postFlair?: string | null,
|
||||
toneGuidance?: string,
|
||||
): Promise<{ analysis: ImageAnalysisResult; message: string }> {
|
||||
const analysis = await this.analyzeImage(imageBase64, mimeType);
|
||||
const message = await this.generateMessage(analysis.description, postTitle, authorName, successfulExamples, strategyPrompt, analysis.attractivenessScore);
|
||||
const message = await this.generateMessage(analysis.description, postTitle, authorName, successfulExamples, strategyPrompt, analysis.attractivenessScore, postFlair, toneGuidance);
|
||||
return { analysis, message };
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user