+
{item.href ? (
{item.label}
) : (
-
+
{item.label}
)}
diff --git a/apps/admin/src/components/ui/tabs.tsx b/apps/admin/src/components/ui/tabs.tsx
index 7a5693f..7a691f0 100644
--- a/apps/admin/src/components/ui/tabs.tsx
+++ b/apps/admin/src/components/ui/tabs.tsx
@@ -11,7 +11,7 @@ const TabsList = React.forwardRef<
{
const openai = getOpenAI();
@@ -19,7 +19,6 @@ export async function analyzeQuestionText(
id: q.id,
text: q.text,
partner_text: q.partner_text,
- intensity: q.intensity,
}));
const toneInstruction = isExplicit
@@ -83,17 +82,6 @@ Cards should be "Proposals" for specific actions, NOT interview questions.
8. Skip questions that are ALREADY well-phrased
-
-Check if current intensity matches the activity:
-1 (Gentle): Emotional bonding, non-sexual (cooking, cuddling, foot massage)
-2 (Warm): Romantic, affectionate touch (slow dance, sensual massage, kissing)
-3 (Playful): Light sexual exploration (oral, mutual masturbation, light roleplay)
-4 (Steamy): Explicit sex, moderate adventure (intercourse, light bondage, anal play)
-5 (Intense): Advanced/BDSM/extreme (impact play, power dynamics, taboo kinks)
-
-If intensity seems wrong, include suggested_intensity and intensity_reason.
-
-
${JSON.stringify(simplifiedQuestions)}
@@ -105,14 +93,12 @@ ${JSON.stringify(simplifiedQuestions)}
"id": string, // Question ID
"suggested_text": string, // Improved text (short, direct)
"suggested_partner_text": string|null, // Improved partner_text or null if symmetric
- "reason": string, // Brief explanation of text improvement
- "suggested_intensity": number|null, // 1-5 if intensity seems wrong, null if correct
- "intensity_reason": string|null // Why intensity should change (if applicable)
+ "reason": string // Brief explanation of text improvement
}
]
}
-Only include questions that need text improvement OR intensity adjustment.
+Only include questions that need text improvement.
`;
const systemMessage = isExplicit
diff --git a/apps/admin/src/lib/ai/config.ts b/apps/admin/src/lib/ai/config.ts
index 24d4c43..48f2df7 100644
--- a/apps/admin/src/lib/ai/config.ts
+++ b/apps/admin/src/lib/ai/config.ts
@@ -1,6 +1,6 @@
// =============================================================================
// AI Configuration Constants
-// Council config, tone levels, intensity levels, and prompt guides
+// Council config, tone levels, and prompt guides
// =============================================================================
import { getCachedAiConfig, preloadAiConfig, type AiConfig } from '@/hooks/useAiConfig';
@@ -33,7 +33,6 @@ export function getCouncilConfig(): CouncilConfig {
reviewerModel: remoteConfig.council_reviewer_model || 'google/gemini-pro-1.5',
reviewerTemperature: remoteConfig.council_reviewer_temperature ?? 0.3,
selectionMode: remoteConfig.council_selection_mode || 'whole_set',
- cherryPickEnsureIntensityDistribution: remoteConfig.cherry_pick_ensure_intensity_distribution ?? true,
};
}
@@ -44,7 +43,6 @@ export function getCouncilConfig(): CouncilConfig {
reviewerModel: import.meta.env.VITE_COUNCIL_REVIEWER_MODEL || 'google/gemini-pro-1.5',
reviewerTemperature: 0.3,
selectionMode: 'whole_set',
- cherryPickEnsureIntensityDistribution: true,
};
}
@@ -69,67 +67,6 @@ export const TONE_LEVELS = [
{ level: 5, label: 'Intense', description: 'Advanced/BDSM/Extreme exploration' },
] as const;
-// =============================================================================
-// INTENSITY LEVELS
-// For UI display - consistent with AI grading
-// =============================================================================
-
-export const INTENSITY_LEVELS = [
- { level: 1, label: 'Gentle', description: 'Pure emotional connection & non-sexual bonding', color: 'bg-green-500' },
- { level: 2, label: 'Warm', description: 'Romantic atmosphere & affectionate touch', color: 'bg-lime-500' },
- { level: 3, label: 'Playful', description: 'Light sexual exploration & sensual discovery', color: 'bg-yellow-500' },
- { level: 4, label: 'Steamy', description: 'Explicit sexual activities & moderate adventure', color: 'bg-orange-500' },
- { level: 5, label: 'Intense', description: 'Advanced/BDSM/Extreme exploration', color: 'bg-red-500' },
-] as const;
-
-// =============================================================================
-// INTENSITY GRADING GUIDE
-// Full version for detailed AI prompts
-// =============================================================================
-
-export const INTENSITY_GUIDE = `
-INTENSITY GRADING GUIDE - Use this to assign intensity levels consistently:
-
-Level 1 - GENTLE (Pure emotional connection & non-sexual bonding):
-- Focus: Emotional safety, friendship-based activities, quality time
-- Examples: Cook together, take a walk holding hands, give non-sexual foot massages, watch a movie cuddling
-- Emotional bonding without sexual undertones
-
-Level 2 - WARM (Romantic atmosphere & affectionate touch):
-- Focus: Creating romantic moments, sensual but non-sexual touch, building anticipation
-- Examples: Slow dance in the living room, candlelit bath together (non-sexual), extended kissing sessions, sensual massage with oils
-- Romantic intimacy building up to arousal
-
-Level 3 - PLAYFUL (Light sexual exploration & sensual discovery):
-- Focus: Sexual touch without penetration, playful experimentation, building arousal
-- Examples: Mutual masturbation, oral sex, light roleplay (doctor/patient), using basic toys together
-- Fun and exploratory sexual contact
-
-Level 4 - STEAMY (Explicit sexual activities & moderate adventure):
-- Focus: Full sexual intercourse with adventurous elements, moderate BDSM/kink
-- Examples: Sex in different locations/positions, light bondage, anal play with toys, recording consensual intimate moments
-- Passionate and adventurous sexual connection
-
-Level 5 - INTENSE (Advanced/BDSM/Extreme exploration):
-- Focus: Edge play, power dynamics, intense physical experiences
-- Examples: Heavy impact play, advanced bondage, consensual non-consent scenes, multi-partner activities
-- Very intense, taboo kinks, and extreme exploration
-`;
-
-// =============================================================================
-// INTENSITY GUIDE (SHORT)
-// Condensed version for prompts to save tokens
-// =============================================================================
-
-export const INTENSITY_GUIDE_SHORT = `
-INTENSITY LEVELS:
-1 (Gentle): Pure emotional connection, non-sexual bonding (cooking, cuddling, foot massages)
-2 (Warm): Romantic atmosphere, affectionate touch (slow dance, sensual massage, kissing)
-3 (Playful): Light sexual exploration, sensual discovery (oral, mutual masturbation, light roleplay)
-4 (Steamy): Explicit sexual activities, moderate adventure (sex positions, light bondage, anal play)
-5 (Intense): Advanced/BDSM/Extreme exploration (impact play, power dynamics, taboo kinks)
-`;
-
// =============================================================================
// REVIEW GUIDELINES
// Used by council reviewer for quality assessment
@@ -155,32 +92,25 @@ REVIEW CRITERIA - Score each 1-10:
- Partner text (if present) clearly describes receiver's experience
- No confusing or ambiguous phrasing
-4. INTENSITY ACCURACY:
- Level 1 (Gentle): Pure emotional connection, non-sexual bonding
- Level 2 (Warm): Romantic atmosphere, affectionate touch
- Level 3 (Playful): Light sexual exploration, sensual discovery (oral, toys)
- Level 4 (Steamy): Explicit sexual activities, moderate adventure (intercourse, light bondage)
- Level 5 (Intense): Advanced/BDSM/Extreme exploration (impact play, power dynamics)
-
-5. ANATOMICAL CONSISTENCY:
+4. ANATOMICAL CONSISTENCY:
- No mixed male/female anatomy in alternatives
- BAD: "Finger or give your partner a handjob"
- GOOD: Pick one activity
-6. PARTNER TEXT QUALITY (if applicable):
+5. PARTNER TEXT QUALITY (if applicable):
- Engaging and enticing, not clinical
- BAD: "Receive oral from your partner"
- GOOD: "Let your partner pleasure you with their mouth"
- When initiator causes a response, frame as allowing: "Let your partner make you moan"
-7. COUPLE TARGETING (flag if incorrect):
+6. COUPLE TARGETING (flag if incorrect):
- Default: ALL couples (null) unless explicit anatomical requirement
- Restrict to ['male+male', 'female+male'] ONLY if activity requires penis
- Restrict to ['female+male', 'female+female'] ONLY if activity requires vagina
- Sex toys are GENDER-NEUTRAL (vibrators, dildos, plugs work for anyone)
- Flag if targeting seems too restrictive or missing needed restrictions
-8. INITIATOR TARGETING (for asymmetric questions only):
+7. INITIATOR TARGETING (for asymmetric questions only):
- Default: null (anyone can initiate) unless explicit anatomical requirement
- Set initiator based on WHO DOES the action in "text" field
- "Swallow your partner's cum" -> initiator: female (in M+F, receiver of cum)
diff --git a/apps/admin/src/lib/ai/generators/cherry-pick.ts b/apps/admin/src/lib/ai/generators/cherry-pick.ts
index 89fdde5..468e5f2 100644
--- a/apps/admin/src/lib/ai/generators/cherry-pick.ts
+++ b/apps/admin/src/lib/ai/generators/cherry-pick.ts
@@ -14,7 +14,6 @@ import type {
PooledQuestion,
CherryPickEvaluation,
CherryPickResult,
- CouncilConfig,
} from '../types';
/**
@@ -34,7 +33,6 @@ export async function evaluateQuestionPool(
index: i,
text: q.text,
partner_text: q.partner_text || null,
- intensity: q.intensity,
generatorIndex: q.sourceGeneratorIndex,
}));
@@ -69,11 +67,10 @@ ${REVIEW_GUIDELINES}
Your scores will be weighted as follows for final selection:
-- Guideline Compliance: 25%
-- Creativity: 20%
-- Clarity: 20%
+- Guideline Compliance: 30%
+- Creativity: 25%
+- Clarity: 25%
- Uniqueness: 20%
-- Intensity Accuracy: 15%
Calibrate your scores knowing these weights. A low compliance score has the most impact.
@@ -86,8 +83,7 @@ Two questions are duplicates if they:
For duplicates, mark the WORSE version as duplicate and keep the version with:
1. Better phrasing/creativity
-2. More appropriate intensity grading
-3. Better partner_text (if applicable)
+2. Better partner_text (if applicable)
@@ -110,7 +106,6 @@ ${JSON.stringify(questionsForEval, null, 2)}
"guidelineCompliance": 1-10,
"creativity": 1-10,
"clarity": 1-10,
- "intensityAccuracy": 1-10,
"uniqueness": 1-10
},
"isDuplicate": boolean,
@@ -151,16 +146,12 @@ Evaluate ALL ${pooledQuestions.length} questions.
}
/**
- * Select top N questions from evaluations, optionally balancing intensity levels
+ * Select top N questions from evaluations
*/
export function selectTopQuestions(
pooledQuestions: PooledQuestion[],
evaluations: CherryPickEvaluation[],
- requestedCount: number,
- options: {
- ensureIntensityDistribution: boolean;
- requestedIntensity?: number;
- }
+ requestedCount: number
): CherryPickResult {
// Step 1: Filter out duplicates (keep only the original, not the duplicate)
const duplicateIndices = new Set();
@@ -178,74 +169,25 @@ export function selectTopQuestions(
question: pooledQuestions[e.questionIndex],
// Weighted overall score
weightedScore: (
- (e.scores.guidelineCompliance * 0.25) +
- (e.scores.creativity * 0.20) +
- (e.scores.clarity * 0.20) +
- (e.scores.intensityAccuracy * 0.15) +
+ (e.scores.guidelineCompliance * 0.30) +
+ (e.scores.creativity * 0.25) +
+ (e.scores.clarity * 0.25) +
(e.scores.uniqueness * 0.20)
) * 10,
}))
.sort((a, b) => b.weightedScore - a.weightedScore);
- let selected: typeof scoredQuestions = [];
-
- // Step 3: Select questions
- if (options.requestedIntensity) {
- // If specific intensity requested, just take top N of that intensity
- const matchingIntensity = scoredQuestions.filter(
- sq => sq.question.intensity === options.requestedIntensity
- );
- selected = matchingIntensity.slice(0, requestedCount);
- } else if (options.ensureIntensityDistribution) {
- // Balance across intensity levels
- const perIntensity = Math.ceil(requestedCount / 5);
- const byIntensity: Record = { 1: [], 2: [], 3: [], 4: [], 5: [] };
-
- for (const sq of scoredQuestions) {
- const intensity = sq.question.intensity;
- if (intensity >= 1 && intensity <= 5) {
- byIntensity[intensity].push(sq);
- }
- }
-
- // Take top N from each intensity level
- for (let intensity = 1; intensity <= 5; intensity++) {
- const toTake = byIntensity[intensity].slice(0, perIntensity);
- selected.push(...toTake);
- }
-
- // If we still need more, fill from remaining top-scored questions
- if (selected.length < requestedCount) {
- const selectedIndices = new Set(selected.map(s => s.evaluation.questionIndex));
- const remaining = scoredQuestions.filter(
- sq => !selectedIndices.has(sq.evaluation.questionIndex)
- );
- selected.push(...remaining.slice(0, requestedCount - selected.length));
- }
-
- // Sort final selection by score
- selected.sort((a, b) => b.weightedScore - a.weightedScore);
- selected = selected.slice(0, requestedCount);
- } else {
- // Simple top N by score
- selected = scoredQuestions.slice(0, requestedCount);
- }
+ // Step 3: Select top N by score
+ const selected = scoredQuestions.slice(0, requestedCount);
// Step 4: Build result
const selectedQuestions = selected.map(s => s.question);
- // Calculate intensity distribution
- const intensityDistribution: Record = {};
- for (const q of selectedQuestions) {
- intensityDistribution[q.intensity] = (intensityDistribution[q.intensity] || 0) + 1;
- }
-
return {
selectedQuestions,
evaluations,
poolSize: pooledQuestions.length,
duplicatesRemoved: duplicateIndices.size,
- intensityDistribution,
};
}
@@ -255,8 +197,7 @@ export function selectTopQuestions(
export async function performCherryPickSelection(
candidates: GenerationCandidate[],
packContext: { name: string; description?: string | null; isExplicit: boolean; tone: ToneLevel },
- requestedCount: number,
- config: CouncilConfig
+ requestedCount: number
): Promise<{
questions: GeneratedQuestion[];
reviews: QuestionReview[];
@@ -280,10 +221,7 @@ export async function performCherryPickSelection(
const evaluations = await evaluateQuestionPool(pooledQuestions, packContext, requestedCount);
// Step 3: Select top questions
- const cherryPickResult = selectTopQuestions(pooledQuestions, evaluations, requestedCount, {
- ensureIntensityDistribution: config.cherryPickEnsureIntensityDistribution,
- requestedIntensity: undefined,
- });
+ const cherryPickResult = selectTopQuestions(pooledQuestions, evaluations, requestedCount);
// Step 4: Convert to standard review format for UI compatibility
const reviews: QuestionReview[] = cherryPickResult.selectedQuestions.map((q, i) => {
@@ -302,7 +240,6 @@ export async function performCherryPickSelection(
guidelineCompliance: 7,
creativity: 7,
clarity: 7,
- intensityAccuracy: 7,
anatomicalConsistency: 10,
partnerTextQuality: 10,
coupleTargeting: 10,
@@ -324,7 +261,6 @@ export async function performCherryPickSelection(
guidelineCompliance: evaluation.scores.guidelineCompliance,
creativity: evaluation.scores.creativity,
clarity: evaluation.scores.clarity,
- intensityAccuracy: evaluation.scores.intensityAccuracy,
// Cherry-pick doesn't evaluate these, default to passing
anatomicalConsistency: 10,
partnerTextQuality: 10,
@@ -346,8 +282,7 @@ export async function performCherryPickSelection(
totalScore += review.scores.guidelineCompliance || 0;
totalScore += review.scores.creativity || 0;
totalScore += review.scores.clarity || 0;
- totalScore += review.scores.intensityAccuracy || 0;
- scoreCount += 4;
+ scoreCount += 3;
}
}
const overallQuality = scoreCount > 0 ? Math.round((totalScore / scoreCount) * 10) / 10 : 0;
diff --git a/apps/admin/src/lib/ai/generators/council.ts b/apps/admin/src/lib/ai/generators/council.ts
index 39f9e54..78a595c 100644
--- a/apps/admin/src/lib/ai/generators/council.ts
+++ b/apps/admin/src/lib/ai/generators/council.ts
@@ -24,7 +24,6 @@ import type {
export async function generateQuestionsWithCouncil(
packName: string,
count: number = 10,
- intensity?: number,
tone: ToneLevel = 3,
packDescription?: string,
existingQuestions?: string[],
@@ -90,7 +89,6 @@ export async function generateQuestionsWithCouncil(
const questions = await generateQuestions(
packName,
count,
- intensity,
tone,
packDescription,
existingQuestions,
@@ -138,7 +136,6 @@ export async function generateQuestionsWithCouncil(
gen.model,
packName,
count,
- intensity,
tone,
packDescription,
existingQuestions,
@@ -191,8 +188,7 @@ export async function generateQuestionsWithCouncil(
const cherryPickResult = await performCherryPickSelection(
successfulCandidates,
packContext,
- count,
- config
+ count
);
const reviewTime = Date.now() - startReview;
diff --git a/apps/admin/src/lib/ai/generators/questions.ts b/apps/admin/src/lib/ai/generators/questions.ts
index 59e6ab5..d741659 100644
--- a/apps/admin/src/lib/ai/generators/questions.ts
+++ b/apps/admin/src/lib/ai/generators/questions.ts
@@ -1,10 +1,10 @@
// =============================================================================
// Question Generation Functions
-// Generate questions for packs with various tone/intensity settings
+// Generate questions for packs with various tone settings
// =============================================================================
import { getOpenAI, getModel, getTemperature } from '../client';
-import { INTENSITY_GUIDE_SHORT, TONE_INSTRUCTIONS, SYSTEM_MESSAGES, CORE_LANGUAGE_RULES } from '../config';
+import { TONE_INSTRUCTIONS, SYSTEM_MESSAGES, CORE_LANGUAGE_RULES } from '../config';
import type { GeneratedQuestion, ToneLevel } from '../types';
/**
@@ -13,7 +13,6 @@ import type { GeneratedQuestion, ToneLevel } from '../types';
function buildQuestionPrompt(
packName: string,
count: number,
- intensity: number | undefined,
tone: ToneLevel,
packDescription?: string,
existingQuestions?: string[],
@@ -38,12 +37,6 @@ function buildQuestionPrompt(
? `\n\n\n${sanitizedInspiration}\n\n\nIncorporate the user guidance above into your generation where appropriate. Use it to inform the theme and style of questions.`
: '';
- const intensityInstruction = tone === 1
- ? 'All questions should be intensity level 1 (non-sexual bonding).'
- : intensity
- ? `All questions should be at intensity level ${intensity}.`
- : 'Vary the intensity levels appropriate for the tone.';
-
const toneInstruction = TONE_INSTRUCTIONS[tone];
// Examples based on tone level
@@ -90,12 +83,7 @@ Generate ${count} unique questions for a couples' intimacy question pack called
${descriptionContext}${inspirationInstruction}${existingQuestionsContext}
-
-${INTENSITY_GUIDE_SHORT}
-
-
-${intensityInstruction}
${toneInstruction}${explicitWarning}${crudeLangInstruction}
@@ -147,7 +135,6 @@ Return a JSON object with this exact structure:
{
"text": string, // REQUIRED: 5-12 words, doer's perspective using "your partner"
"partner_text": string|null, // REQUIRED for asymmetric, null for symmetric
- "intensity": 1-5, // REQUIRED: must match the intensity level guidelines
"requires_props": string[]|null, // Optional: items needed (e.g., ["blindfold", "massage oil"])
"inverse_pair_id": string|null, // REQUIRED for asymmetric pairs, null for symmetric
"location_type": "home"|"public"|"outdoors"|"travel"|"anywhere", // Optional
@@ -164,7 +151,6 @@ Return a JSON object with this exact structure:
export async function generateQuestions(
packName: string,
count: number = 10,
- intensity?: number,
tone: ToneLevel = 3,
packDescription?: string,
existingQuestions?: string[],
@@ -176,7 +162,6 @@ export async function generateQuestions(
const prompt = buildQuestionPrompt(
packName,
count,
- intensity,
tone,
packDescription,
existingQuestions,
@@ -212,7 +197,6 @@ export async function generateQuestionsWithModel(
model: string,
packName: string,
count: number,
- intensity: number | undefined,
tone: ToneLevel,
packDescription: string | undefined,
existingQuestions: string[] | undefined,
@@ -225,7 +209,6 @@ export async function generateQuestionsWithModel(
const prompt = buildQuestionPrompt(
packName,
count,
- intensity,
tone,
packDescription,
existingQuestions,
diff --git a/apps/admin/src/lib/ai/index.ts b/apps/admin/src/lib/ai/index.ts
index 73f2e20..824bb95 100644
--- a/apps/admin/src/lib/ai/index.ts
+++ b/apps/admin/src/lib/ai/index.ts
@@ -41,9 +41,6 @@ export {
getCouncilConfig,
initializeAiConfig,
TONE_LEVELS,
- INTENSITY_LEVELS,
- INTENSITY_GUIDE,
- INTENSITY_GUIDE_SHORT,
REVIEW_GUIDELINES,
TONE_INSTRUCTIONS,
SYSTEM_MESSAGES,
diff --git a/apps/admin/src/lib/ai/review.ts b/apps/admin/src/lib/ai/review.ts
index 5fb7998..10e33fa 100644
--- a/apps/admin/src/lib/ai/review.ts
+++ b/apps/admin/src/lib/ai/review.ts
@@ -36,7 +36,6 @@ export async function reviewGeneratedQuestions(
index: i,
text: q.text,
partner_text: q.partner_text || null,
- intensity: q.intensity,
location_type: q.location_type,
effort_level: q.effort_level,
// Include targeting for review (may not always be present)
@@ -64,7 +63,7 @@ ${REVIEW_GUIDELINES}
- PASS: All scores >= 7, no major issues
- FLAG: Any score 5-7, or minor issues worth noting (admin should review but can use)
-- REJECT: Any score < 5, or major violations (mixed anatomy, wrong intensity, severe guideline violation)
+- REJECT: Any score < 5, or major violations (mixed anatomy, severe guideline violation)
@@ -83,13 +82,11 @@ ${JSON.stringify(questionsForReview, null, 2)}
"guidelineCompliance": 1-10, // Criterion 1
"creativity": 1-10, // Criterion 2
"clarity": 1-10, // Criterion 3
- "intensityAccuracy": 1-10, // Criterion 4
- "anatomicalConsistency": 1-10, // Criterion 5
- "partnerTextQuality": 1-10, // Criterion 6 (10 if no partner_text needed)
- "coupleTargeting": 1-10, // Criterion 7
- "initiatorTargeting": 1-10 // Criterion 8 (10 if symmetric)
+ "anatomicalConsistency": 1-10, // Criterion 4
+ "partnerTextQuality": 1-10, // Criterion 5 (10 if no partner_text needed)
+ "coupleTargeting": 1-10, // Criterion 6
+ "initiatorTargeting": 1-10 // Criterion 7 (10 if symmetric)
},
- "intensitySuggestion": number|null, // Suggested intensity (1-5) if current seems wrong, null if correct
"targetingSuggestions": { // Only include if targeting needs changes
"suggestedCoupleTargets": string[]|null, // ["male+male", "female+male", "female+female"] or subset
"suggestedInitiator": string[]|null, // ["male", "female"] or null for any
@@ -99,7 +96,7 @@ ${JSON.stringify(questionsForReview, null, 2)}
]
}
-Review ALL questions against ALL 8 criteria. Be thorough but fair - only flag/reject for genuine issues.
+Review ALL questions against ALL 7 criteria. Be thorough but fair - only flag/reject for genuine issues.
`;
const response = await openai.chat.completions.create({
@@ -132,18 +129,17 @@ Review ALL questions against ALL 8 criteria. Be thorough but fair - only flag/re
const flagged = reviews.filter(r => r.verdict === 'flag').length;
const rejected = reviews.filter(r => r.verdict === 'reject').length;
- // Calculate overall quality as weighted average of all 8 scores
- // Weights: guidelineCompliance 20%, creativity 15%, clarity 15%, intensityAccuracy 15%,
- // anatomicalConsistency 15%, partnerTextQuality 10%, coupleTargeting 5%, initiatorTargeting 5%
+ // Calculate overall quality as weighted average of all 7 scores
+ // Weights: guidelineCompliance 25%, creativity 18%, clarity 18%,
+ // anatomicalConsistency 17%, partnerTextQuality 12%, coupleTargeting 5%, initiatorTargeting 5%
let totalWeightedScore = 0;
let totalWeight = 0;
const weights = {
- guidelineCompliance: 0.20,
- creativity: 0.15,
- clarity: 0.15,
- intensityAccuracy: 0.15,
- anatomicalConsistency: 0.15,
- partnerTextQuality: 0.10,
+ guidelineCompliance: 0.25,
+ creativity: 0.18,
+ clarity: 0.18,
+ anatomicalConsistency: 0.17,
+ partnerTextQuality: 0.12,
coupleTargeting: 0.05,
initiatorTargeting: 0.05,
};
@@ -200,7 +196,6 @@ export async function selectBestGeneration(
index: qi,
text: q.text,
partner_text: q.partner_text || null,
- intensity: q.intensity,
allowed_couple_genders: (q as { allowed_couple_genders?: string[] | null }).allowed_couple_genders || null,
target_user_genders: (q as { target_user_genders?: string[] | null }).target_user_genders || null,
})),
@@ -235,9 +230,8 @@ Ranked by importance (approximate weights):
1. Overall quality and creativity of questions (30%)
2. Variety and uniqueness within the set (20%)
3. Adherence to pack theme and tone (20%)
-4. Proper intensity grading (15%)
-5. Correct use of "your partner" language (10%)
-6. Quality of partner_text for asymmetric questions (5%)
+4. Correct use of "your partner" language (15%)
+5. Quality of partner_text for asymmetric questions (10%)
@@ -254,13 +248,11 @@ Ranked by importance (approximate weights):
"guidelineCompliance": 1-10,
"creativity": 1-10,
"clarity": 1-10,
- "intensityAccuracy": 1-10,
"anatomicalConsistency": 1-10,
"partnerTextQuality": 1-10,
"coupleTargeting": 1-10,
"initiatorTargeting": 1-10
},
- "intensitySuggestion": number|null,
"targetingSuggestions": {
"suggestedCoupleTargets": string[]|null,
"suggestedInitiator": string[]|null,
@@ -270,7 +262,7 @@ Ranked by importance (approximate weights):
]
}
-Select the best set and review ALL questions in that set against ALL 8 criteria.
+Select the best set and review ALL questions in that set against ALL 7 criteria.
`;
const response = await openai.chat.completions.create({
@@ -300,7 +292,7 @@ Select the best set and review ALL questions in that set against ALL 8 criteria.
const reviews: QuestionReview[] = parsed.reviews || [];
const reasoning = parsed.reasoning || 'No reasoning provided';
- // Calculate summary with weighted average of all 8 scores
+ // Calculate summary with weighted average of all 7 scores
const passed = reviews.filter(r => r.verdict === 'pass').length;
const flagged = reviews.filter(r => r.verdict === 'flag').length;
const rejected = reviews.filter(r => r.verdict === 'reject').length;
@@ -308,12 +300,11 @@ Select the best set and review ALL questions in that set against ALL 8 criteria.
let totalWeightedScore = 0;
let totalWeight = 0;
const weights = {
- guidelineCompliance: 0.20,
- creativity: 0.15,
- clarity: 0.15,
- intensityAccuracy: 0.15,
- anatomicalConsistency: 0.15,
- partnerTextQuality: 0.10,
+ guidelineCompliance: 0.25,
+ creativity: 0.18,
+ clarity: 0.18,
+ anatomicalConsistency: 0.17,
+ partnerTextQuality: 0.12,
coupleTargeting: 0.05,
initiatorTargeting: 0.05,
};
diff --git a/apps/admin/src/lib/ai/types.ts b/apps/admin/src/lib/ai/types.ts
index 8e9f599..fd87855 100644
--- a/apps/admin/src/lib/ai/types.ts
+++ b/apps/admin/src/lib/ai/types.ts
@@ -23,7 +23,6 @@ export interface CouncilConfig {
reviewerModel: string;
reviewerTemperature?: number;
selectionMode: CouncilSelectionMode;
- cherryPickEnsureIntensityDistribution: boolean;
}
// =============================================================================
@@ -71,7 +70,6 @@ export interface QuestionReviewScores {
guidelineCompliance: number;
creativity: number;
clarity: number;
- intensityAccuracy: number;
anatomicalConsistency: number;
partnerTextQuality: number;
coupleTargeting: number;
@@ -85,7 +83,6 @@ export interface QuestionReview {
suggestions?: string;
scores: QuestionReviewScores;
// Additional detailed feedback
- intensitySuggestion?: number | null; // Suggested intensity if current seems wrong
targetingSuggestions?: {
suggestedCoupleTargets?: string[] | null;
suggestedInitiator?: string[] | null;
@@ -173,7 +170,6 @@ export interface CherryPickEvaluation {
guidelineCompliance: number;
creativity: number;
clarity: number;
- intensityAccuracy: number;
uniqueness: number;
};
isDuplicate: boolean;
@@ -187,7 +183,6 @@ export interface CherryPickResult {
evaluations: CherryPickEvaluation[];
poolSize: number;
duplicatesRemoved: number;
- intensityDistribution: Record;
}
// =============================================================================
@@ -206,9 +201,6 @@ export interface TextAnalysis {
suggested_text: string;
suggested_partner_text: string | null;
reason: string;
- // Intensity suggestion (only if AI thinks current is wrong)
- suggested_intensity?: number | null;
- intensity_reason?: string | null;
}
export interface DeletionAnalysis {
diff --git a/apps/admin/src/pages/AiSettingsPage.tsx b/apps/admin/src/pages/AiSettingsPage.tsx
index dd2e25f..e8ac68d 100644
--- a/apps/admin/src/pages/AiSettingsPage.tsx
+++ b/apps/admin/src/pages/AiSettingsPage.tsx
@@ -79,7 +79,6 @@ export function AiSettingsPage() {
council_reviewer_model: config.council_reviewer_model || '',
council_reviewer_temperature: config.council_reviewer_temperature,
council_selection_mode: config.council_selection_mode || 'whole_set',
- cherry_pick_ensure_intensity_distribution: config.cherry_pick_ensure_intensity_distribution ?? true,
classifier_enabled: config.classifier_enabled ?? true,
classifier_model: config.classifier_model || 'openai/gpt-4o',
classifier_temperature: config.classifier_temperature,
@@ -183,7 +182,6 @@ export function AiSettingsPage() {
council_reviewer_model: config.council_reviewer_model || '',
council_reviewer_temperature: config.council_reviewer_temperature,
council_selection_mode: config.council_selection_mode || 'whole_set',
- cherry_pick_ensure_intensity_distribution: config.cherry_pick_ensure_intensity_distribution ?? true,
classifier_enabled: config.classifier_enabled ?? true,
classifier_model: config.classifier_model || 'openai/gpt-4o',
classifier_temperature: config.classifier_temperature,
@@ -851,24 +849,6 @@ export function AiSettingsPage() {
- {/* Cherry-pick intensity option */}
- {formData.council_selection_mode === 'cherry_pick' && (
-
Uses {generators.length + 1} API calls ({generators.length} generator{generators.length > 1 ? 's' : ''} + reviewer)
diff --git a/apps/admin/src/pages/AppSettingsPage.tsx b/apps/admin/src/pages/AppSettingsPage.tsx
index 948f095..fc9db3c 100644
--- a/apps/admin/src/pages/AppSettingsPage.tsx
+++ b/apps/admin/src/pages/AppSettingsPage.tsx
@@ -4,7 +4,6 @@ import { useAuth, PERMISSION_KEYS } from '@/contexts/AuthContext';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
-import { Switch } from '@/components/ui/switch';
import { Skeleton } from '@/components/ui/skeleton';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
@@ -30,7 +29,6 @@ export function AppSettingsPage() {
setFormData({
answer_gap_threshold: config.answer_gap_threshold ?? 10,
daily_response_limit: config.daily_response_limit ?? 0,
- couple_intensity_gate_enabled: config.couple_intensity_gate_enabled ?? false,
});
setHasChanges(false);
}
@@ -63,7 +61,6 @@ export function AppSettingsPage() {
setFormData({
answer_gap_threshold: config.answer_gap_threshold ?? 10,
daily_response_limit: config.daily_response_limit ?? 0,
- couple_intensity_gate_enabled: config.couple_intensity_gate_enabled ?? false,
});
setHasChanges(false);
}
@@ -160,19 +157,6 @@ export function AppSettingsPage() {