citee-methodology/tools/prompt_curation/config.py
Jacek Kubas 03a397343e Faza 1: brand catalog (świece sojowe PL) + prompt curation pipeline
DATA — Public reference datasets for methodology:
- data/README.md: schema + format definitions for brand catalogs
- data/swiece-sojowe-pl/brand_catalog.json: 35 tracked brands (33 manufacturers + 2 importers) + 5 excluded marketplaces/resellers
- data/swiece-sojowe-pl/brand_catalog.md: human-readable companion
- data/swiece-sojowe-pl/market_metadata.json: GMV estimate, personas, seasonality, expected dynamics

TOOLS — 6-stage prompt curation pipeline (Python 3.12+):
- tools/prompt_curation/README.md: process documentation + cost estimates
- tools/prompt_curation/config.py: tunable parameters per stage
- tools/prompt_curation/.env.example: required API keys template
- tools/prompt_curation/requirements.txt: dependencies
- tools/prompt_curation/1_persona_generator.py: Claude generates 7 buyer personas
- tools/prompt_curation/2_prompt_brainstormer.py: per persona × 30 prompts in voice
- tools/prompt_curation/3_reality_checker.py: Google Trends + Reddit cross-check
- tools/prompt_curation/4_validation_agents.py: 3 critic agents async (real_buyer/methodology/exploit_hunter)
- tools/prompt_curation/5_pilot_test_runner.py: sample × 3 LLM models pre-flight
- tools/prompt_curation/6_human_review_export.py: CSV export for founder approval
- tools/prompt_curation/7_finalize.py: post-approval → closed prompts/{cat}/v{N}.json
- tools/prompt_curation/pipeline.py: orchestrator (stages 1–6, then human review, then 7)

GITIGNORE — Fixed .env.* exclusion to allow .env.example.

This commit completes Faza 1. Stages outputs (data/{cat}/personas.json,
raw_prompts.json, validated_prompts.json, critic_review.json, pilot_test_results.json,
for_human_review.csv) are runtime artifacts — public when committed, derived from
public methodology + public brand catalog. Final approved prompt strings in
prompts/{cat}/v{N}.json remain CLOSED (gitignored, anti-Goodhart's Law).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 18:40:12 +02:00

86 lines
2.8 KiB
Python

"""Pipeline configuration — tunable per category and stage."""
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Literal
PromptType = Literal["buying", "comparison", "specific_need", "informational", "brand_direct"]
@dataclass
class PipelineConfig:
"""Default config — override via command-line args or per-category YAML."""
# Stage 1 — Persona Generator
num_personas: int = 7
persona_model: str = "claude-sonnet-4-6"
# Stage 2 — Prompt Brainstormer
prompts_per_persona: int = 30
brainstormer_model: str = "claude-sonnet-4-6"
type_distribution: dict[PromptType, float] = field(
default_factory=lambda: {
"buying": 0.30,
"comparison": 0.25,
"specific_need": 0.20,
"informational": 0.15,
"brand_direct": 0.10,
}
)
# Stage 3 — Reality Checker
google_trends_min_volume: int = 1 # PL queries per month, minimum signal
reddit_min_organic_mentions: int = 3
fallback_to_quora_if_no_signal: bool = True
# Stage 4 — Validation Agents
flagged_by_n_critics_to_remove: int = 2 # Remove if 2+ agents flag it
critic_models: dict[str, str] = field(
default_factory=lambda: {
"real_buyer_critique": "claude-sonnet-4-6",
"methodology_critic": "claude-sonnet-4-6",
"vendor_exploit_hunter": "claude-sonnet-4-6",
}
)
# Stage 5 — Pilot Test Runner
pilot_sample_size: int = 10
pilot_models: list[str] = field(
default_factory=lambda: [
"gpt-4o-search",
"perplexity-sonar-pro",
"gemini-pro",
]
)
repetitions_per_prompt: int = 1 # In pilot test only, production uses 2+
# Final pool size after all filtering
final_pool_size: int = 100
# Output paths
data_dir: str = "data" # Public stage outputs
prompts_dir: str = "../../prompts" # Closed final prompts (gitignored)
CONFIG = PipelineConfig()
# Type distribution as integer counts for final pool
def get_target_counts(config: PipelineConfig = CONFIG) -> dict[PromptType, int]:
"""Return integer counts per prompt type for final pool of `final_pool_size`."""
counts = {
ptype: int(round(config.final_pool_size * pct))
for ptype, pct in config.type_distribution.items()
}
# Adjust rounding to ensure sum == final_pool_size
total = sum(counts.values())
if total != config.final_pool_size:
# Adjust the largest category to absorb difference
largest_type = max(counts, key=lambda k: counts[k])
counts[largest_type] += config.final_pool_size - total
return counts
if __name__ == "__main__":
print(f"Final pool size: {CONFIG.final_pool_size}")
print(f"Target counts per type: {get_target_counts()}")