API Reference¶
- class propaganda_pipeline.Configuracion(model_name: str, api_key: str, adapter: Any | None = None)[source]¶
Bases:
objectSets up DSPy with a language model and a JSONAdapter.
Example
- cfg = Configuracion(
model_name=”openai/gpt-4o-2024-08-06”, api_key=os.environ[“OPENAI_API_KEY”]
) cfg.setup()
- model_name¶
OpenAI model identifier (e.g.
"gpt-4o-2024-08-06").- Type:
str
- api_key¶
OpenAI API key used to authenticate requests.
- Type:
str
- adapter¶
Optional DSPy adapter; defaults to
dspy.JSONAdapter().- Type:
Any | None
- model_name: str¶
- api_key: str¶
- adapter: Any | None = None¶
- class propaganda_pipeline.TechniqueRunner[source]¶
Bases:
objectAbstract base class for all propaganda-technique detectors.
Each subclass must declare the class-level attributes
nameandsignatureand implementpostprocess().- name¶
Unique technique identifier used as the
modelkey in candidate dicts (e.g."REPETITION").- Type:
str
- signature¶
DSPy Signature class that encodes the detection prompt.
- Type:
Type[dspy.Signature]
- name: str¶
- signature: Type[dspy.Signature]¶
- run(texto: str) Dict[str, Any][source]¶
Runs the detector on texto and returns a normalised candidate dict.
- Parameters:
texto – Source text to analyse.
- Returns:
A dict containing at least the keys
model,answer,confidence,span,rationale_summary, andraw.
- postprocess(salida_obj: pydantic.BaseModel) Dict[str, Any][source]¶
Convert LLM judgment output to a standardized candidate dict.
- Args:
salida_obj: Parsed Pydantic judgment object from the DSPy predictor.
- Returns:
Dict with keys: model, answer (Sí/No), rationale_summary, confidence (float in [0, 1]), span (list of text fragments), labels (technique- specific metadata), and raw (full model dump).
- class propaganda_pipeline.Conteo(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModel(fragment, count) pair quantifying a repeated unit in the text.
- fragment¶
The repeated text fragment (max 120 chars).
- Type:
pydantic.constr
- count¶
Approximate number of occurrences in the source text.
- Type:
int
- fragment: pydantic.constr¶
- count: int¶
- class propaganda_pipeline.JuicioRepetition(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelLLM output for the REPETITION detector.
Key fields:
usa_repetition(Sí/No binary verdict),fragmentos_repetidos(repeated n-grams),conteos_aprox(per-fragment occurrence counts),tipo_repeticion(rhetorical category),citas(up to 3 verbatim quotes), andconfidence.- usa_repetition: Literal['Sí', 'No']¶
- claim: pydantic.constr | None = None¶
- repeated_fragments: List[pydantic.constr]¶
- repetition_type: List[Literal['anáfora', 'epífora', 'eslogan', 'hashtag', 'estribillo', 'historia', 'imagen']]¶
- justification: pydantic.constr¶
- quotes: List[pydantic.constr]¶
- limitations: pydantic.constr¶
- confidence: pydantic.confloat¶
- confidence_justification: pydantic.constr¶
- class propaganda_pipeline.DetectaRepetition(*args: Any, **kwargs: Any)[source]¶
Bases:
SignatureROLE: You are an argument analyst. Determine if the TEXT uses “Repetition”: an argument focused on repeating the same word, phrase, slogan, story or image in the hope of persuading by mere repetition.
ENTRANCE TEXT: <text in quotes>
GUARDRAIL (MANDATORY) - Returns ONLY a valid JSON object. No text outside the JSON. No markdown. No comments. - Write in Spanish. - If info is missing, use null or []. - Each string ≤ 300 characters. Appointments ≤ 120. - Do not invent or reformulate quotes; extract them literally from the TEXT (max. 3). - To detect repetition, consider upper/lowercase letters the same and minimize punctuation; ignores single stopwords and proper nouns necessary for the topic. - DO NOT include step-by-step reasoning in the output. Think privately and output ONLY the JSON. - DO NOT translate the span. Keep it in the original language.
STRICT CRITERIA (for “Yes”: ALL must be met) 1) There is an identifiable statement/position, call or response. 2) The persuasive force rests mainly (≥50%) on repeating a textual unit (word/phrase/slogan/hashtag/chorus/metaphor/story/image). 3) There is significant repetition:
≥3 non-trivial occurrences distributed in the text, or
anaphora/epiphora/chorus/slogan repeated ≥2 times in strategic positions (beginning/closing/between paragraphs).
Substantive reasons (data, mechanisms, precise comparisons) are absent or in the background compared to repetition.
DO NOT CONFUSE - Functional repetition (technical terms, essential proper nouns, list markers, purely formal refrains). - Paraphrasing without clear lexical repetition. - Specific emphasis (1–2 short repetitions) without central persuasive role.
ANALYSIS INSTRUCTIONS - Detect exact or almost exact repeated n-grams (1–5 words); point out the most salient 1–3 with approximate counting. - Treat slogans/hashtags/sayings as units. - Consider “image/story repetition” when the same scene/metaphor reappears several times. - Briefly explain why yes/no repetition is the main support (in the “justification” key, ≤300).
CALCULATION OF “confidence” - “confidence” is a continuous value in [0.0, 1.0] that indicates how clear and confident your decision is about whether there is “Repetition” or not. - To estimate it, combine two factors:
- Clarity of textual evidence:
High (≈0.8–1.0): The presence/absence of repetition is very evident, with clear and consistent patterns, and almost no ambiguity. Medium (≈0.4–0.7): There are some clues, but also counterexamples, ambiguity, or little evidence. Low (≈0.0–0.3): The text is confusing or offers almost no basis for decision.
- Internal security of the model:
If you could have easily chosen the opposite label, lower your confidence. If your answer seems like the only reasonable option given the alternatives, increase your confidence.
If the underlying system has internal probabilities (for example, associated with different possible outputs by beam search), also use those probabilities as a guide: distributions concentrated on one option → highest confidence; distributions spread over options → lowest confidence.
────────────────────────────────────── ─────────────────── ──────────────────── GUIDED EXAMPLE (one-shot). The output of the model MUST BE JSON ONLY. Entry (TEXT): “Hurtlocker deserves an Oscar. Other films have potential, but they do not deserve an Oscar like Hurtlocker does. The other movies may deserve an honorable mention but Hurtlocker deserves the Oscar.”
Summary decision trace (do not print on output): - Normalization and light filtering: lowercase, minimum punctuation, isolated stopwords ignored. - Detection of n-grams: “hurtlocker deserves an oscar” appears ≈3 times (close variants), it is the most salient n-gram. - Criteria:
C1 (statement/position): ✓ (“Hurtlocker deserves the Oscar”). C2 (main support by repetition): ✓ persuasion relies on repeating the chorus. C3 (significance): ✓ (≥3 occurrences of the chorus). C4 (absent/secondary substantive reasons): ✓ (there is no data or precise comparison).
Guardrails: literal quotes ≤120; strings ≤300.
Confidence: the evidence is very clear (multiple key repetitions, no alternative arguments) and the decision “Yes” seems the only reasonable one. This suggests a high confidence, for example 0.95 (high clarity of evidence + high internal security).
Expected output (JSON only): {
“usa_repetition”: “Yes”, “claim”: “Hurtlocker deserves the Oscar”, “repeated_fragments”: [“Hurtlocker”, “Oscar”, “deserves”], “approx_counts”: [
{“chunk”: “Hurtlocker”, “times”: 3}, {“fragment”: “Oscar”, “times”: 3}, {“fragment”: “deserves”, “times”: 2}
], “repetition_type”: [“chorus”], “justification”: “The text repeats the phrase ‘Hurtlocker deserves an Oscar’ on several occasions, which constitutes the main support of the argument, without offering additional substantive reasons.”, “quotes”: [
“Hurtlocker deserves an Oscar.”, “but they do not deserve an Oscar like Hurtlocker does.”, “Hurtlocker deserves the Oscar.”
], “doubts_or_limitations”: “The text does not provide a statement or position beyond the repetition of the phrase.”, “confidence”: 0.95, “justificacion_confidence”: “The evidence is very clear (multiple key repetitions, no alternative arguments) and the decision “Yes” seems the only reasonable one. This suggests a high confidence.”
}
- class propaganda_pipeline.RepetitionRunner[source]¶
Bases:
TechniqueRunnerDetects the REPETITION propaganda technique.
Identifies whether a text persuades primarily through repetition of words, phrases, slogans, or images rather than substantive reasoning.
postprocessreturns a candidate dict with:model:
"REPETITION"answer:"Sí"or"No"confidence: float in [0, 1] span: up to 3 verbatim quotes or repeated fragments rationale_summary: brief justification from the LLM raw: fullJuicioRepetitionmodel dump
- name: str = 'REPETITION'¶
- signature¶
alias of
DetectaRepetition
- postprocess(salida_obj: JuicioRepetition) Dict[str, Any][source]¶
Convert LLM judgment output to a standardized candidate dict.
- Args:
salida_obj: Parsed Pydantic judgment object from the DSPy predictor.
- Returns:
Dict with keys: model, answer (Sí/No), rationale_summary, confidence (float in [0, 1]), span (list of text fragments), labels (technique- specific metadata), and raw (full model dump).
- class propaganda_pipeline.JuicioEM(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelLLM output for the EXAGGERATION / MINIMISATION detector.
Key fields:
is_exaggeration_or_minimisation(Yes/No verdict),subtype(Exaggeration / Minimization / Both),exaggeration_scoreandminimization_score(independent [0,1] scores),proportionality(language-to-fact ratio assessment),citas(up to 3 verbatim quotes), andconfidence.- is_exaggeration_or_minimisation: Literal['Sí', 'No']¶
- subtipo: Literal['Exageración', 'Minimización', 'Ambas', 'No aplica']¶
- justificacion_breve: pydantic.constr¶
- citas: List[pydantic.constr]¶
- marcadores_exageracion: List[pydantic.constr]¶
- marcadores_minimizacion: List[pydantic.constr]¶
- objeciones_ignoradas: pydantic.constr | None = None¶
- proporcionalidad: Literal['Desproporcionado', 'Aproximadamente proporcional', 'Incierto']¶
- puntaje_exageracion: pydantic.confloat¶
- puntaje_minimizacion: pydantic.confloat¶
- reformulacion_neutra: pydantic.constr¶
- confidence: pydantic.confloat¶
- justificacion_confidence: pydantic.constr¶
- class propaganda_pipeline.DetectaExaggerationMinimisation(*args: Any, **kwargs: Any)[source]¶
Bases:
SignatureROLE: You are an argument analyst. Detect if the TEXT uses “Exaggeration or Minimization”: exaggerate (hyperboles/superlatives/absolutes) or minimize (attenuators/euphemisms/“it’s not a big deal”) to persuade, displacing substantive reasons.
GUARDRAIL (MANDATORY) - Returns ONLY a valid JSON object. No text outside the JSON. No markdown. No comments. - Write in Spanish. - If info is missing, use null or []. - Each string ≤ 300 characters. Appointments ≤ 120. - Do not invent or reformulate quotes; extract them literally from the TEXT (max. 3). - DO NOT include step-by-step reasoning in the output. Think privately and output ONLY the JSON. - DO NOT translate the span into Spanish. Keep it in the original language.
STRICT CRITERIA (for “Yes”) 1) There is a statement/position or answer to a question. 2) The persuasive force rests mainly (≥50%) on exaggerating or minimizing
(superlatives/absolutes/hyperboles; or “only”, “barely”, “it’s not that big of a deal”…).
Absence or marginality of substantive reasons (data, mechanisms, comparisons, proportional context) or relevant objections are ignored.
SIGNS (non-exhaustive) - Exaggeration: “the best/worst”, “always/never”, “everyone/nobody”, “guaranteed”, inflated quantifications without support. - Minimization: “just a little mistake”, “it just happened”, “a joke”, “it doesn’t matter”, “nothing serious”, euphemisms. - Disproportion between language and facts; omits relevant context.
DISTINCTIONS (DO NOT count as Yes) - Rhetorical emphasis with sufficient evidence; illustrative metaphor with support; estimates with clear sources; explicit irony.
ANALYSIS INSTRUCTIONS - Work with the text as is; minimally normalizes (case insensitive; light punctuation). - Extract 1–3 key literal quotes (≤120 each) that show exaggeration/minimization. - Point out exaggeration/minimization markers (trigger words/expressions). - Evaluate the proportionality of the language with respect to the available content. - If there are plausible omitted objections, mention them in “ignored_objections” (≤300). - Assign scores [0,1] to exaggeration and minimization (they do not have to add up to 1).
CALCULATION OF “confidence” - “confidence” is a continuous value in [0.0, 1.0] that indicates how clear and confident your decision is about whether there is “Exaggeration” or not. - To estimate it, combine two factors:
- Clarity of textual evidence:
High (≈0.8–1.0): The presence/absence of Exaggeration is very evident, with clear and consistent patterns, and almost no ambiguity. Medium (≈0.4–0.7): There are some clues, but also counterexamples, ambiguity, or little evidence. Low (≈0.0–0.3): The text is confusing or offers almost no basis for decision.
- Internal security of the model:
If you could have easily chosen the opposite label, lower your confidence. If your answer seems like the only reasonable option given the alternatives, increase your confidence.
If the underlying system has internal probabilities (for example, associated with different possible outputs by beam search), also use those probabilities as a guide: distributions concentrated on one option → highest confidence; distributions spread over options → lowest confidence.
────────────────────────────────────── ─────────────────── ──────────────────── GUIDED EXAMPLE (one-shot). The output of the model MUST BE JSON ONLY. Entry (TEXT): “From the seminaries, to the clergy, to the bishops, to the cardinals, homosexuals are present at all levels, by the thousand”
Summary decision trace (do not print on output): - Position identification (C1): broad presence is affirmed at all levels. - Main signal/support (C2): inflated quantification “by the thousand” works as a central hyperbole. - Support (C3): there are no comparative data or sources; possible nuances (definitions, figures, periods) are ignored. - Bookmarks: “by the thousand”; construction of totality “at all levels”. - Proportionality: disproportionate to the evidence presented (none). - Guardrails: literal quotes ≤120; strings ≤300; JSON ONLY output.
Expected output (JSON only): {
“is_exaggeration_or_minimisation”: “Yes”, “subtype”: “Exaggeration”, “justificacion_breve”: “The text claims presence at all levels ‘by the thousands’, an inflated quantification without support that functions as persuasive hyperbole.”, “quotes”: [
“homosexuals are present at all levels, by the thousand”
], “exaggeration_markers”: [
- “by the thousand”,
“at all levels”
], “markers_minimization”: [], “ignored_objections”: null, “proportionality”: “Disproportionate”, “exaggeration_score”: 0.8, “minimization_score”: 0.0, “neutral_reformulation”: “The presence of homosexuals is affirmed at various levels, without precise quantification or sources.”, “confidence”: 0.9, “justificacion_confidence”: “The evidence is very clear and the decision “Yes” seems the only reasonable one. This suggests a high confidence.”
} ────────────────────────────────────── ─────────────────── ──────────────────── OUTPUT (JSON ONLY) exactly with these keys.
- class propaganda_pipeline.ExaggerationRunner[source]¶
Bases:
TechniqueRunnerDetects the EXAGGERATION / MINIMISATION propaganda technique.
Identifies whether a text persuades primarily through hyperboles, superlatives, and absolute claims (exaggeration) or downplaying language (minimisation), instead of substantive reasoning.
postprocessreturns a candidate dict with:model:
"EXAGERATION"answer:"Sí"or"No"confidence: float in [0, 1] span: up to 3 verbatim quotes or exaggeration/minimisation markers rationale_summary: brief justification including subtype and proportionality raw: fullJuicioEMmodel dump
- name: str = 'EXAGERATION'¶
- signature¶
alias of
DetectaExaggerationMinimisation
- postprocess(salida_obj: JuicioEM) Dict[str, Any][source]¶
Convert LLM judgment output to a standardized candidate dict.
- Args:
salida_obj: Parsed Pydantic judgment object from the DSPy predictor.
- Returns:
Dict with keys: model, answer (Sí/No), rationale_summary, confidence (float in [0, 1]), span (list of text fragments), labels (technique- specific metadata), and raw (full model dump).
- class propaganda_pipeline.AmbiguousTerm(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelA vague or undefined key term together with its plausible interpretations.
- term¶
The ambiguous term extracted from the text (max 120 chars).
- Type:
pydantic.constr
- possible_meanings¶
Up to 2 plausible meanings suggested by the LLM.
- Type:
List[pydantic.constr]
- term: pydantic.constr¶
- class propaganda_pipeline.NonAnswerEvasion(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelFlags whether the text evades answering the question under discussion.
- value¶
Trueif the text uses vagueness to avoid a direct answer.- Type:
bool
- evidence¶
Optional verbatim excerpt supporting the evasion flag.
- Type:
pydantic.constr | None
- value: bool¶
- evidence: pydantic.constr | None = None¶
- class propaganda_pipeline.ObfuscationJudgment(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelLLM output for the OBFUSCATION / INTENTIONAL VAGUENESS detector.
Key fields:
uses_obfuscation(Sí/No/Indeterminado verdict),vague_markers(weasel-word signals),ambiguous_terms(undefined key terms with possible meanings),non_answer_evasion(whether the text evades direct answers),quotes(verbatim excerpts), andconfidence.- uses_obfuscation: Literal['Sí', 'No', 'Indeterminado']¶
- justification: pydantic.constr¶
- vague_markers: List[pydantic.constr]¶
- ambiguous_terms: List[AmbiguousTerm]¶
- non_answer_evasion: NonAnswerEvasion¶
- undefined_keys: List[pydantic.constr]¶
- quotes: List[pydantic.constr]¶
- confidence: pydantic.confloat¶
- justificacion_confidence: pydantic.constr¶
- class propaganda_pipeline.DetectaObfuscacion(*args: Any, **kwargs: Any)[source]¶
Bases:
SignatureROLE You are an argument analyst. Determines if the TEXT uses “Obfuscation, Intentional Vagueness, Confusion”.
GUARDRAIL - Returns ONLY a valid JSON object. No text outside the JSON. No markdown. No comments. - Write in Spanish. If info is missing, use null or []. - Each string ≤ 300 characters. Quotes ≤ 120. Do not invent or reformulate quotes. - DO NOT include step-by-step reasoning in the output. Think privately and output ONLY the JSON. - DO NOT translate the span into Spanish. Keep it in the original language.
CRITERIA (ALL for “Yes”) - There is a statement/position or answer to a question. - The justification rests mainly on vagueness/ambiguity (weasel words, undefined terms,
technical euphemisms, fuzzy quantifiers, non-falsifiable phrases).
Vagueness prevents evaluating/verifying the conclusion or avoids responding (non-answer).
Lack of operational definitions/metrics/criteria or concrete examples for key terms.
DISTINCTIONS - Brevity with clear criteria, illustrative metaphor with support, or lack of detail with verifiable criteria ≠ obfuscation.
SIGNS (indicative) - “some”, “work is being done”, “necessary measures”, “significant improvements”, “many”, “several”, “security”, etc.
ANALYSIS INSTRUCTIONS - Identifies vague/ambiguous markers and undefined key terms. - For each ambiguous term, suggest 1–2 plausible meanings if the text does not define. - Indicates if there is response evasion (non-answer) and provides brief evidence (≤120). - Extract up to 3 literal quotes (≤120) if they provide evidence; if not, use []. - Explain in ≤300 why vagueness/ambiguity is (or is not) main support.
CALCULATION OF “confidence” - “confidence” is a continuous value in [0.0, 1.0] that indicates how clear and confident your decision is about whether there is “Obfuscation” or not. - To estimate it, combine two factors:
- Clarity of textual evidence:
High (≈0.8–1.0): The presence/absence of “Obfuscation” is very evident, with clear and consistent patterns, and almost no ambiguity. Medium (≈0.4–0.7): There are some clues, but also counterexamples, ambiguity, or little evidence. Low (≈0.0–0.3): The text is confusing or offers almost no basis for decision.
- Internal security of the model:
If you could have easily chosen the opposite label, lower your confidence. If your answer seems like the only reasonable option given the alternatives, increase your confidence.
If the underlying system has internal probabilities (for example, associated with different possible outputs by beam search), also use those probabilities as a guide: distributions concentrated on one option → highest confidence; distributions spread over options → lowest confidence.
────────────────────────────────────── ─────────────────── ──────────────────── GUIDED EXAMPLE (one-shot). The output of the model MUST BE JSON ONLY.
Entry (TEXT): “We will hex-develop the blockchain with AI-based interconnectors to maximize ROI.”
Summary decision trace (do not print on output): - Fast normalization and detection of undefined terms: “hex-develop”, “AI-based interconnectors”, “maximize ROI”. - Criteria verification:
Statement/position: ✓ (promise of action/future).
Main support for vagueness/ambiguity: ✓ (undefined terms, technical euphemism).
Effect of vagueness: ✓ (prevents evaluating the statement and avoids precision => possible non-answer).
Lack of definitions/criteria: ✓ (no metrics, examples or specifications).
Guardrails: without inventing quotes; strings ≤300; if there are no useful quotes, quotes = [].
Planned classification: “Yes”, with a list of ambiguous terms and plausible meanings.
Expected output (JSON only): {
“uses_obfuscation”: “Yes”, “justification”: “The text uses vague and technical terms such as ‘hex-develop’, ‘AI-based interconnectors’ and ‘maximize ROI’ without clearly defining them, making it difficult to evaluate the claim.”, “vague_markers”: [
“hex-develop”, “AI-based interconnectors”, “maximize ROI”
], “ambiguous_terms”: [
- {
“term”: “hex-develop”, “possible_meanings”: [
“Development in hexadecimal”, “Advanced development”
]
}, {
“term”: “AI-based interconnectors”, “possible_meanings”: [
“Connectors based on artificial intelligence”, “Automated interconnections”
]
}, {
“term”: “maximize ROI”,
- “possible_meanings”: [
“Increase return on investment”, “Optimize benefits”
]
}
], “non_answer_evasion”: {
“value”: true, “evidence”: “The use of vague and technical terms without definition prevents a clear evaluation.”
}, “undefined_keys”: [
“hex-develop”, “AI-based interconnectors”, “maximize ROI”
], “quotes”: [], “confidence”: 0.9, “justificacion_confidence”: “The evidence is very clear and the decision “Yes” seems the only reasonable one. This suggests a high confidence.”
} ────────────────────────────────────── ─────────────────── ────────────────────
OUTPUT (JSON ONLY) exactly with these keys.
- class propaganda_pipeline.ObfuscationRunner[source]¶
Bases:
TechniqueRunnerDetects the OBFUSCATION / INTENTIONAL VAGUENESS / CONFUSION technique.
Identifies whether persuasion relies primarily on vague, undefined, or evasive language that prevents the audience from evaluating the claim.
postprocessreturns a candidate dict with:model:
"OBFUSCATION"answer:"Sí","No", or"Indeterminado"confidence: float in [0, 1] span: up to 3 verbatim quotes, vague markers, or undefined key terms rationale_summary: brief justification from the LLM raw: fullObfuscationJudgmentmodel dump
- name: str = 'OBFUSCATION'¶
- signature¶
alias of
DetectaObfuscacion
- postprocess(salida_obj: ObfuscationJudgment) Dict[str, Any][source]¶
Convert LLM judgment output to a standardized candidate dict.
- Args:
salida_obj: Parsed Pydantic judgment object from the DSPy predictor.
- Returns:
Dict with keys: model, answer (Sí/No), rationale_summary, confidence (float in [0, 1]), span (list of text fragments), labels (technique- specific metadata), and raw (full model dump).
- class propaganda_pipeline.LoadedLanguageJudgment(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelLLM output for the LOADED LANGUAGE detector.
Key fields:
is_loaded_language(Sí/No verdict),charged_terms(emotionally loaded words),quotes(up to 3 verbatim excerpts),emotions(emotions invoked),valence(positive/negative/mixed),reasoning_presenceandevidence_presence(quality of substantive support),cooccurring_techniques, andconfidence.- is_loaded_language: Literal['Sí', 'No']¶
- claim: pydantic.constr | None = None¶
- valence: Literal['positiva', 'negativa', 'mixta', 'neutra']¶
- reasoning_presence: Literal['ninguna', 'escasa', 'moderada', 'sólida']¶
- evidence_presence: Literal['ninguna', 'escasa', 'moderada', 'sólida']¶
- explanation: pydantic.constr¶
- decision_rule: pydantic.constr¶
- confidence: pydantic.confloat¶
- justificacion_confidence: pydantic.constr¶
- class propaganda_pipeline.DetectaLoadedLanguage(*args: Any, **kwargs: Any)[source]¶
Bases:
SignatureROLE You are an argument analyst. Detects if the TEXT uses “Loaded Language”.
GUARDRAIL (JSON ONLY) - Returns ONLY a valid JSON object. No text outside the JSON. No markdown. No comments. - Write in Spanish. If info is missing, use null or []. - Each string ≤ 300 characters. Appointments ≤ 120. Max. 3 literal quotes. Don’t make up or rephrase quotes. - DO NOT include step-by-step reasoning in the output. Think privately and output ONLY the JSON. - DO NOT translate the span into Spanish. Keep it in the original language.
CRITERIA (for “Yes”, ALL must be met) 1) There is an identifiable statement/position/call. 2) The justification rests mainly (≥50%) on loaded terms (euphemisms/dysphemisms,
evaluative adjectives, hyperboles, inflammatory metaphors, absolutes).
Substantive reasons are absent/weak/subordinate to the emotional effect.
DISTINCTIONS - Name calling counts only if you master persuasion. - If the central appeal is fear/group pride/popularity, indicate this in “cooccurring_techniques”. - Vivid language with strong and dominant evidence → It is not Loaded Language.
SIGNS - Intensifying adjectives (“corrupt”, “disgusting”, “heroic”). - Moralizing/stigmatizing nouns (“parasites”, “saviors”). - War/contagion metaphors (“war”, “plague”, “virus”). - Euphemisms (“collateral damage”) and dysphemisms (“massacre”). - Absolutes (“always”, “everyone”, “no one”, “never”).
CALCULATION OF “confidence”
“confidence” is a continuous value in [0.0, 1.0] that indicates how clear and confident your decision is about whether there is “LoadedLanguage” or not.
- To estimate it, combine two factors:
- Clarity of textual evidence:
High (≈0.8–1.0): The presence/absence of “LoadedLanguage” is very evident, with clear and consistent patterns, and almost no ambiguity. Medium (≈0.4–0.7): There are some clues, but also counterexamples, ambiguity, or little evidence. Low (≈0.0–0.3): The text is confusing or offers almost no basis for decision.
- Internal security of the model:
If you could have easily chosen the opposite label, lower your confidence. If your answer seems like the only reasonable option given the alternatives, increase your confidence.
If the underlying system has internal probabilities (for example, associated with different possible outputs by beam search), also use those probabilities as a guide: distributions concentrated on one option → highest confidence; distributions spread over options → lowest confidence.
────────────────────────────────────── ─────────────────── ──────────────────── GUIDED EXAMPLE (one-shot). The output of the model MUST BE JSON ONLY.
Entry (TEXT): “How stupid and petty things have become in Washington.”
Summary decision trace (do not print on output): - Light normalization (lowercase/punctuation) without altering literal quotes. - Identification of potentially loaded terms: “stupid”, “petty”. - Criterion 1 (statement/position): ✓ there is a global assessment of the situation in Washington. - Criterion 2 (persuasive weight in loaded language): ✓ the evaluation depends on evaluative adjectives. - Criterion 3 (reasons/evidence): ✓ absence of evidence or reasoning; eminently emotional judgment. - Differentiate from nearby techniques: no primary appeal to pride/fear/popularity; record co-occurrences if they emerge. - Guardrails: ≤3 appointments; strings ≤300; do not invent quotes; JSON ONLY output.
Expected output (JSON only): {
“is_loaded_language”: “Yes”, “claim”: “Things have gotten stupid and petty in Washington.”, “charged_terms”: [“stupid”, “petty”], “quotes”: [“How stupid and petty things have become in Washington”], “emotions”: [“frustration”, “disdain”], “valence”: “negative”, “reasoning_presence”: “none”, “evidence_presence”: “none”, “cooccurring_techniques”: [], “explanation”: “The text uses loaded terms such as ‘stupid’ and ‘petty’ to describe the situation in Washington, without providing substantive evidence or reasoning.”, “decision_rule”: “Use of loaded terms without evidence or substantive reasoning indicates loaded language.”, “confidence”: 0.9, “justificacion_confidence”: “The evidence is very clear and the decision “Yes” seems the only reasonable one. This suggests a high confidence.”
} ────────────────────────────────────── ─────────────────── ────────────────────
OUTPUT (JSON) exactly with the requested keys.
- class propaganda_pipeline.LoadedLanguageRunner[source]¶
Bases:
TechniqueRunnerDetects the LOADED LANGUAGE propaganda technique.
Identifies whether persuasion relies primarily on emotionally charged euphemisms, dysphemisms, intensifying adjectives, or inflammatory metaphors rather than substantive evidence.
postprocessreturns a candidate dict with:model:
"LOADED_LANGUAGE"answer:"Sí"or"No"confidence: float in [0, 1] span: up to 3 verbatim quotes or charged terms rationale_summary: explanation including emotional valence raw: fullLoadedLanguageJudgmentmodel dump
- name: str = 'LOADED_LANGUAGE'¶
- signature¶
alias of
DetectaLoadedLanguage
- postprocess(salida_obj: LoadedLanguageJudgment) Dict[str, Any][source]¶
Convert LLM judgment output to a standardized candidate dict.
- Args:
salida_obj: Parsed Pydantic judgment object from the DSPy predictor.
- Returns:
Dict with keys: model, answer (Sí/No), rationale_summary, confidence (float in [0, 1]), span (list of text fragments), labels (technique- specific metadata), and raw (full model dump).
- class propaganda_pipeline.FocusShift(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelWhether the text shifts focus away from the original topic.
- value¶
Trueif focus is demonstrably shifted to a different topic.- Type:
bool
- evidence¶
Optional verbatim excerpt supporting the shift.
- Type:
pydantic.constr | None
- value: bool¶
- evidence: pydantic.constr | None = None¶
- class propaganda_pipeline.WhataboutismJudgment(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelLLM output for the WHATABOUTISM / SWITCHING TOPIC detector.
Key fields:
is_whataboutism(Sí/No verdict),original_issue(topic being deflected),switching_issue(topic introduced instead),explicit_markers_found(verbatim deflection markers),focus_shift(whether focus was demonstrably moved),accusation_type(hypocrisy / double standard / etc.), andconfidence.- is_whataboutism: Literal['Sí', 'No']¶
- verdict: Literal['Sí, hay Switching Topic (Whataboutism)', 'No, no hay Switching Topic (Whataboutism)']¶
- original_issue: pydantic.constr | None = None¶
- switching_issue: pydantic.constr | None = None¶
- focus_shift: FocusShift¶
- reason: pydantic.constr¶
- confidence: pydantic.confloat¶
- justificacion_confidence: pydantic.constr¶
- class propaganda_pipeline.DetectaWhataboutism(*args: Any, **kwargs: Any)[source]¶
Bases:
SignatureROLE You are an argument analyst. Determines if the TEXT uses “Switching Topic (Whataboutism)”.
GUARDRAIL (MANDATORY) - Returns ONLY a valid JSON object. No text outside the JSON. No markdown. No comments. - Write in Spanish. If information is missing, use null or []. - All strings ≤ 300 characters. TEXT Citations ≤ 120. - DO NOT include step-by-step reasoning in the output. Think privately and output ONLY the JSON. - DO NOT translate the span into Spanish. Keep it in the original language.
STRICT CRITERIA (ALL for “Yes”) 1) Original identifiable topic that deserves a response. 2) Introduce accusatory theme (hypocrisy/double standard/“what about…?”). 3) It shifts the focus and does NOT substantively respond to the original topic.
DISTINCTIONS - Red herring without accusation of hypocrisy ≠ whataboutism. - Tu quoque with a substantive response to the substance → may NOT be whataboutism. - Pertinent comparison that does respond to the substance → It is NOT whataboutism.
SIGNS - “and what about…?”, “you did the same thing”, “double standard”, “before X and now Y”, etc.
ANALYSIS INSTRUCTIONS - Identify with short quotes (≤120) the original topic and the displaced topic. - Locate explicit markers (“what about…?”, deviating comparisons, etc.). - Indicates if there is FOCUS SHIFTING (focus_shift.value) and cites brief evidence. - Classify the main accusation: “hypocrisy/tu_quoque”, “double_standard”, “deviating_comparison” or “other”. - Summarize in ≤300 why YES/NO there is whataboutism.
CALCULATION OF “confidence”
“confidence” is a continuous value in [0.0, 1.0] that indicates how clear and confident your decision is about whether there is “whataboutism” or not.
- To estimate it, combine two factors:
- Clarity of textual evidence:
High (≈0.8–1.0): The presence/absence of “whataboutism” is very evident, with clear and consistent patterns, and almost no ambiguity. Medium (≈0.4–0.7): There are some clues, but also counterexamples, ambiguity, or little evidence. Low (≈0.0–0.3): The text is confusing or offers almost no basis for decision.
- Internal security of the model:
If you could have easily chosen the opposite label, lower your confidence. If your answer seems like the only reasonable option given the alternatives, increase your confidence.
If the underlying system has internal probabilities (for example, associated with different possible outputs by beam search), also use those probabilities as a guide: distributions concentrated on one option → highest confidence; distributions spread over options → lowest confidence.
────────────────────────────────────── ─────────────────── ──────────────────── GUIDED EXAMPLE (one-shot). The output of the model MUST BE JSON ONLY.
Entry (TEXT): “Bien sûr, les actions militaires sont toujours horribles et sont d’autant plus condamnables lorsqu’elles touchent des populations civiles. Toutefois, the offensive Russe in Ukraine, is more than the invasion americaine in Iraq in 2003? Ces événements ont eux also caused des décès de civils sans pourtant soulever l’ire de la bien-pensance occidentale”
Summary decision trace (do not print on output): - Light normalization and reading of the plot flow. - Original topic detected (short quote): “offensive Russe in Ukraine”. - Displaced/alternative theme (short quote): “American invasion of Iraq in 2003.” - Explicit marker of deviating comparison (citation ≤120): “est-elle plus que l’invasion américaine en Iraq en 2003”. - Focus evaluation:
¿Se responde sustantivamente al tema original? → No: it is compared to denounce double standards.
focus_shift.value = True; focus_shift.evidence = same marker quote.
Type of main accusation: “double_standard”.
Verified guardrails: JSON-only, lengths, literal quotes from the TEXT (without rephrasing), Spanish.
Expected output (JSON only): {
“is_whataboutism”: “Yes”, “verdict”: “Yes, there is Switching Topic (Whataboutism)”, “original_issue”: “offensive Russe in Ukraine”, “switching_issue”: “american invasion of Iraq in 2003”, “explicit_markers_found”: [
“this is more than the American invasion of Iraq in 2003”
], “focus_shift”: {
“value”: true, “evidence”: “this is more than the American invasion of Iraq in 2003”
}, “accusation_type”: [“double_standard”],
- “reason”: “The text compares the Russian offensive in Ukraine with the US invasion of Iraq, suggesting a double standard in condemning military actions, diverting focus from the original issue.”,
“confidence”: 0.9, “justificacion_confidence”: “The evidence is very clear and the decision “Yes” seems the only reasonable one. This suggests a high confidence.”
} ────────────────────────────────────── ─────────────────── ──────────────────── OUTPUT (JSON) exactly with the requested keys.
- class propaganda_pipeline.WhataboutismRunner[source]¶
Bases:
TechniqueRunnerDetects the WHATABOUTISM (Switching Topic) propaganda technique.
Identifies whether a response deflects from the original topic by introducing an accusation of hypocrisy or a double standard, thereby avoiding substantive engagement with the original issue.
postprocessreturns a candidate dict with:model:
"WHATABOUTISM"answer:"Sí"or"No"confidence: float in [0, 1] span: up to 3 explicit deflection markers or focus-shift evidence rationale_summary: reason summary including accusation type raw: fullWhataboutismJudgmentmodel dump
- name: str = 'WHATABOUTISM'¶
- signature¶
alias of
DetectaWhataboutism
- postprocess(salida_obj: WhataboutismJudgment) Dict[str, Any][source]¶
Convert LLM judgment output to a standardized candidate dict.
- Args:
salida_obj: Parsed Pydantic judgment object from the DSPy predictor.
- Returns:
Dict with keys: model, answer (Sí/No), rationale_summary, confidence (float in [0, 1]), span (list of text fragments), labels (technique- specific metadata), and raw (full model dump).
- class propaganda_pipeline.KairosJudgment(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelLLM output for the KAIROS / APPEAL TO TIME detector.
Key fields:
is_appeal_to_time(Sí/No/Mixto verdict),actions_or_claims(proposed actions or evaluative claims),timing_devices(urgency language such as “now is the time”),quotes(up to 3 verbatim excerpts),reasoning(brief justification),counter_indicators(signals that weaken the verdict), andconfidence.- is_appeal_to_time: Literal['Sí', 'No', 'Mixto']¶
- reasoning: pydantic.constr¶
- confidence: pydantic.confloat¶
- justificacion_confidence: pydantic.constr¶
- class propaganda_pipeline.DetectaKairos(*args: Any, **kwargs: Any)[source]¶
Bases:
SignatureROLE You are an argument analyst. Determines if the TEXT uses “Appeal to Time (Kairos)”.
GUARDRAIL (MANDATORY) - Returns ONLY a valid JSON object. No text outside the JSON. No markdown. No comments. - Write in Spanish. - If information is missing, use null or []. - Each string ≤ 300 characters. Appointments ≤ 120 (max. 3). - Do not print step-by-step reasoning; think privately and output ONLY the JSON. - DO NOT translate the span into Spanish. Keep it in the original language.
CRITERIA (for “Yes”, ALL) 1) There is a proposal/call/evaluative position. 2) The justification rests mainly on temporal urgency/opportunity (“now”, “last chance”, “window closing”, etc.). 3) Time-independent substantive reasons are absent/weak/subordinate.
SIGNS - Counters/deadlines; urgency lexicon; “window that closes.”
DISTINCTIONS - Real deadlines with dominant material reasons → It is not Kairos. - If the main weight is fear/popularity → classify as co-occurrence (if applicable).
CALCULATION OF “confidence” - “confidence” is a continuous value in [0.0, 1.0] that indicates how clear and confident your decision is about whether there is “Kairos” or not. - To estimate it, combine two factors:
- Clarity of textual evidence:
High (≈0.8–1.0): The presence/absence of “Kairos” is very evident, with clear and consistent patterns, and almost no ambiguity. Medium (≈0.4–0.7): There are some clues, but also counterexamples, ambiguity, or little evidence. Low (≈0.0–0.3): The text is confusing or offers almost no basis for decision.
- Internal security of the model:
If you could have easily chosen the opposite label, lower your confidence. If your answer seems like the only reasonable option given the alternatives, increase your confidence.
If the underlying system has internal probabilities (for example, associated with different possible outputs by beam search), also use those probabilities as a guide: distributions concentrated on one option → highest confidence; distributions spread over options → lowest confidence.
────────────────────────────────────── ─────────────────── ──────────────────── GUIDED EXAMPLE (one-shot). The output of the model MUST BE JSON ONLY.
Entry (TEXT): “This is no time to engage in the luxury of cooling off or to take the tranquilizing drug of gradualism. Now is the time to make real the promises of democracy. Now is the time to rise from the dark and desolate valley of segregation to the sunlit path of racial justice.”
Summary decision trace (do not print on output): - Normalization and focal reading: identify temporal lexicon and proposed acts. - Criterion 1 (proposal/call): ✓ “make the promises real…”, “rise from… to…”. - Criterion 2 (weight on temporal urgency/opportunity): ✓ “Now is the time” repeated and focused on “now”. - Criterion 3 (substantive reasons independent of time): ✓ absent/implicit; The persuasive support is timing. - Textual evidence (max. 3 citations ≤120): literally extract two “Now is the time…” as salient units. - Guardrails: strings ≤300; citations ≤120; JSON ONLY output, without external comments.
Expected output (JSON only): {
“is_appeal_to_time”: “Yes”, “actions_or_claims”: [
“Make real the promises of democracy”, “Rise from the dark and desolate valley of segregation to the sunlit path of racial justice”
], “timing_devices”: [
“Now is the time”
], “quotes”: [
“Now is the time to make real the promises of democracy”, “Now is the time to rise from the dark and desolate valley of segregation”
], “reasoning”: “The text emphasizes the urgency of acting now to achieve racial justice, highlighting that this is not the time for gradualness.”, “counter_indicators”: [], “confidence”: 0.9, “justificacion_confidence”: “The evidence is very clear and the decision “Yes” seems the only reasonable one. This suggests a high confidence.”
} ────────────────────────────────────── ─────────────────── ────────────────────
OUTPUT (JSON) exactly with the requested keys.
- class propaganda_pipeline.KairosRunner[source]¶
Bases:
TechniqueRunnerDetects the KAIROS / APPEAL TO TIME propaganda technique.
Identifies whether persuasion rests primarily on urgency or opportunity framing (“now is the time”, “closing window”) rather than substantive reasoning independent of timing.
postprocessreturns a candidate dict with:model:
"KAIROS"answer:"Sí","No", or"Mixto"confidence: float in [0, 1] span: up to 3 verbatim quotes, timing devices, or claim fragments rationale_summary: reasoning with note if counter-indicators are present raw: fullKairosJudgmentmodel dump
- name: str = 'KAIROS'¶
- signature¶
alias of
DetectaKairos
- postprocess(salida_obj: KairosJudgment) Dict[str, Any][source]¶
Convert LLM judgment output to a standardized candidate dict.
- Args:
salida_obj: Parsed Pydantic judgment object from the DSPy predictor.
- Returns:
Dict with keys: model, answer (Sí/No), rationale_summary, confidence (float in [0, 1]), span (list of text fragments), labels (technique- specific metadata), and raw (full model dump).
- class propaganda_pipeline.SuppressesDiscussion(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelWhether the text actively discourages further debate.
- value¶
Trueif the text contains a thought-terminating element.- Type:
bool
- evidence¶
Optional verbatim excerpt demonstrating the suppression.
- Type:
pydantic.constr | None
- value: bool¶
- evidence: pydantic.constr | None = None¶
- class propaganda_pipeline.ReasonsPresent(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelDegree to which substantive reasoning accompanies the cliché.
- Attributes:
- level: Qualitative assessment:
"ninguna","baja", "media", or"alta".
evidence: Optional excerpt supporting the level assessment.
- level: Qualitative assessment:
- level: Literal['ninguna', 'baja', 'media', 'alta']¶
- evidence: pydantic.constr | None = None¶
- class propaganda_pipeline.ConversationKillerJudgment(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelLLM output for the CONVERSATION KILLER / THOUGHT-TERMINATING CLICHÉ detector.
Key fields:
es_conversation_killer(Sí/No verdict),cliches_detected(thought-terminating phrases found),primary_mechanism(closing mechanism type),suppresses_discussion(whether discussion is discouraged),reasons_present(level of substantive justification),quotes(up to 3 verbatim excerpts), andconfidence.- es_conversation_killer: Literal['Sí', 'No']¶
- primary_mechanism: Literal['imperativo_de_cierre', 'fatalismo', 'antiintelectualismo', 'identitario', 'relativismo', 'otro']¶
- suppresses_discussion: SuppressesDiscussion¶
- reasons_present: ReasonsPresent¶
- topic_identified: pydantic.constr | None = None¶
- explanation: pydantic.constr¶
- confidence: pydantic.confloat¶
- justificacion_confidence: pydantic.constr¶
- class propaganda_pipeline.DetectaConversationKiller(*args: Any, **kwargs: Any)[source]¶
Bases:
SignatureROLE You are an argument analyst. Detects if the TEXT uses “Conversation Killer (Thought-terminating Cliché)”.
GUARDRAIL (MANDATORY) - Returns ONLY a valid JSON object. No text outside the JSON. No markdown. No comments. - Write in Spanish. - If information is missing, use null or []. - Each string ≤ 300 characters. Appointments ≤ 120 (max. 3). Extract literally. - DO NOT include step-by-step reasoning in the output. Think privately and output ONLY the JSON. - DO NOT translate the span into Spanish. Keep it in the original language.
CRITERIA (ALL for “Yes”) 1) There is a topic/proposal under discussion. 2) Short phrases appear with a closing function (“it is what it is”, “full stop”, etc.). 3) The main persuasive force is to discourage further analysis. 4) Lack or minimal presence of relevant justification.
DISTINCTIONS - Slogan mobilizes (not necessarily closes). - Whataboutism/Red herring deflect; the cliché ends the conversation. - Appeal to authority invokes authority; The cliché cuts without foundation. - “Time is up” (logistical) does not count.
SIGNS - Closing imperatives; fatalism/nihilism; anti-intellectualism; expulsive identity; simplistic relativism; mantras/hashtags.
ANALYSIS INSTRUCTIONS - Identify the issue/proposal in dispute (if it exists). - Detects clichés/phrases with closing function and classifies the primary mechanism. - Assess whether they discourage conversation (suppresses_discussion). - Evaluates presence of reasons (reasons_present). - Extract up to 3 literal quotes (≤120) that evidence the closure. - Propose up to 3 “reframes” that reopen the dialogue.
CALCULATION OF “confidence” - “confidence” is a continuous value in [0.0, 1.0] that indicates how clear and confident your decision is about whether there is a “Conversation Killer” or not. - To estimate it, combine two factors:
- Clarity of textual evidence:
High (≈0.8–1.0): The presence/absence of “Conversation Killer” is very evident, with clear and consistent patterns, and almost no ambiguity. Medium (≈0.4–0.7): There are some clues, but also counterexamples, ambiguity, or little evidence. Low (≈0.0–0.3): The text is confusing or offers almost no basis for decision.
- Internal security of the model:
If you could have easily chosen the opposite label, lower your confidence. If your answer seems like the only reasonable option given the alternatives, increase your confidence.
If the underlying system has internal probabilities (for example, associated with different possible outputs by beam search), also use those probabilities as a guide: distributions concentrated on one option → highest confidence; distributions spread over options → lowest confidence.
────────────────────────────────────── ─────────────────── ──────────────────── GUIDED EXAMPLE (one-shot). The output of the model MUST BE JSON ONLY.
Entry (literal text): Our “unity in diversity” contrasts with the divisions everywhere else. End of discussion
Summary decision trace (do not print on output): - Theme/proposal detected: statement about “unity in diversity” vs. divisions (there is theme → C1 ✓). - Clichés/imperatives: “unity in diversity” (cliché), “End of the discussion” (closing imperative) → C2 ✓. - Primary mechanism: closing_imperative (cut off the conversation) → C3 ✓. - Present reasons: casualties; no substantive justifications are provided → C4 ✓. - Guardrails: literal quotes ≤120 (max. 3); JSON ONLY output; strings ≤300.
Expected output (JSON only): {
“es_conversation_killer”: “Yes”, “cliches_detected”: [
“unity in diversity”, “End of discussion”
], “quotes”: [
“unity in diversity”, “End of discussion”
], “primary_mechanism”: “closure_imperative”, “suppresses_discussion”: {
“value”: true, “evidence”: “The phrase ‘End of discussion’ closes the conversation.”
}, “reasons_present”: {
“level”: “low”, “evidence”: “The phrase ‘unity in diversity’ is a cliché without further justification.”
}, “topic_identified”: “Unity and diversity in contrast to divisions”, “explanation”: “The text presents a theme of unity and diversity, but uses ‘End of discussion’ to close the conversation without justification.”, “suggested_reframe”: [
“How can we improve our unity in diversity?” “What concrete examples of unity in diversity can we follow?” “How does our unit compare to other places?”
], “confidence”: 0.9,
“justificacion_confidence”: “The evidence is very clear and the decision “Yes” seems the only reasonable one. This suggests a high confidence.” }
- class propaganda_pipeline.ConversationKillerRunner[source]¶
Bases:
TechniqueRunnerDetects the CONVERSATION KILLER (Thought-Terminating Cliché) technique.
Identifies whether persuasion relies on brief, formulaic phrases whose main function is to shut down further analysis rather than to provide substantive justification.
postprocessreturns a candidate dict with:model:
"KILLER"answer:"Sí"or"No"confidence: float in [0, 1] span: up to 3 verbatim quotes or detected clichés rationale_summary: explanation including mechanism and reasons level raw: fullConversationKillerJudgmentmodel dump
- name: str = 'KILLER'¶
- signature¶
alias of
DetectaConversationKiller
- postprocess(salida_obj: ConversationKillerJudgment) Dict[str, Any][source]¶
Convert LLM judgment output to a standardized candidate dict.
- Args:
salida_obj: Parsed Pydantic judgment object from the DSPy predictor.
- Returns:
Dict with keys: model, answer (Sí/No), rationale_summary, confidence (float in [0, 1]), span (list of text fragments), labels (technique- specific metadata), and raw (full model dump).
- class propaganda_pipeline.BoolEvidence(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelBoolean flag paired with an optional verbatim evidence excerpt.
- value¶
The boolean verdict.
- Type:
bool
- evidence¶
Short verbatim quote (≤120 chars) supporting the verdict, or
Noneif not available.- Type:
pydantic.constr | None
- value: bool¶
- evidence: pydantic.constr | None = None¶
- class propaganda_pipeline.SlipperySlopeJudgment(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelLLM output for the SLIPPERY SLOPE (Consequential Oversimplification) detector.
Key fields:
is_slippery_slope(Sí/No verdict),initial_event(the triggering event/proposal A),chain_steps(up to 3 consequence steps B, C, …),end_point(extreme outcome),inevitability_claimed(claim of inevitability with evidence),support_provided(whether causal evidence is given),focus_on_chain_over_merits(whether the chain dominates over evaluating A),polarity(negative/positive/mixed), andconfidence.- is_slippery_slope: Literal['Sí', 'No']¶
- polarity: Literal['negativa', 'positiva', 'mixta'] | None = None¶
- initial_event: pydantic.constr | None = None¶
- end_point: pydantic.constr | None = None¶
- inevitability_claimed: BoolEvidence¶
- support_provided: BoolEvidence¶
- focus_on_chain_over_merits: BoolEvidence¶
- reason_short: pydantic.constr¶
- confidence: pydantic.confloat¶
- justificacion_confidence: pydantic.constr¶
- class propaganda_pipeline.DetectaSlipperySlope(*args: Any, **kwargs: Any)[source]¶
Bases:
SignatureROLE You are an argument analyst. Evaluate if the TEXT uses “Consequential Oversimplification (Slippery Slope)”.
GUARDRAIL (MANDATORY) - Respond ONLY with a valid JSON object. No text outside the JSON. No markdown. No comments. - Write in Spanish. If info is missing, use null or []. - Each string ≤ 300 characters. Extract any textual evidence as literal quotes (≤120). - Do not invent or reformulate quotes; maximum 3 total citations distributed among the evidence. - DO NOT include step-by-step reasoning in the output. Think privately and output ONLY the JSON. - DO NOT translate the span into Spanish. Keep it in the original language.
STRICT CRITERIA (ALL for “Yes”) 1) Initial event/proposal A identifiable. 2) Chain of ≥2 consequences (B, C, …) that leads to an extreme outcome (end_point). 3) Inevitability is implied/affirmed without sufficient support, displacing the analysis of A’s merits.
DECISION RULES - “Yes” only if all 3 criteria are met. - If there is sufficient substantive support for the chain → “No”. - If positive promise and negative danger coexist → polarity = “mixed”. - With substantial ambiguity → “No” and complete with null/[] as appropriate.
EXPLANATION OF THE TECHNIQUE (summary) Typical form: “if A occurs, then B, C, D… will occur.” Negative variant: the aim is to REJECT A with increasing negative consequences. Positive variant (“stairway to paradise”): the aim is to SUPPORT A by promising increasing benefits. Distinctive feature: treating the chain as almost inevitable, minimizing mechanisms and evidence.
ANALYSIS INSTRUCTIONS 1) Normalize and delimit: ignore case; preserve TEXT quotes for quotes. 2) Extract A (initial event/proposal) at ≤120. 3) Identify a chain of at least 2 plausible consequences of the discourse (B, C, …) in ≤120 each; limited to 3 steps. 4) Set the end_point to ≤120. 5) Inevitability: Look for markers of temporal or modal certainty (e.g., “will,” “inevitable,” “soon,” “certainly”) and cite ≤120 if it exists. 6) Support: Check if specific mechanisms, data or analogies are offered. If not, support_provided.value = false and evidence = null. 7) Focus on chain vs. merits: if the main emphasis is on the “domain” of consequences and not on discussing A, mark true and use a short quote from the chain as evidence (≤120). 8) Polarity: negative/positive depending on the sign of the outcome; “mixed” if they coexist. 9) Composite the output: respect types/lengths; do not exceed 3 citations in total between fields of evidence; outputs ONLY the JSON.
CALCULATION OF “confidence” - “confidence” is a continuous value in [0.0, 1.0] that indicates how clear and confident your decision is about whether there is a “Slippery Slope” or not. - To estimate it, combine two factors:
- Clarity of textual evidence:
High (≈0.8–1.0): The presence/absence of “Slippery Slope” is very evident, with clear and consistent patterns, and almost no ambiguity. Medium (≈0.4–0.7): There are some clues, but also counterexamples, ambiguity, or little evidence. Low (≈0.0–0.3): The text is confusing or offers almost no basis for decision.
- Internal security of the model:
If you could have easily chosen the opposite label, lower your confidence. If your answer seems like the only reasonable option given the alternatives, increase your confidence.
If the underlying system has internal probabilities (for example, associated with different possible outputs by beam search), also use those probabilities as a guide: distributions concentrated on one option → highest confidence; distributions spread over options → lowest confidence.
────────────────────────────────────── ─────────────────── ──────────────────── GUIDED EXAMPLE (one-shot). The output of the model MUST BE JSON ONLY.
Entry (TEXT): “If we allow same-sex marriage, we will soon see marriages between siblings or even marriages between humans and animals!”
Summary decision trace (do not print on output; follow ANALYSIS INSTRUCTIONS): - (2) A: “allow same-sex marriage.” - (3) String (≥2): “marriage between siblings” → “marriages between humans and animals”. - (4) end_point: “marriages between humans and animals”. - (5) Inevitability (quote ≤120): “we will soon see.” - (6) Support: no data/mechanisms offered → false, evidence = null. - (7) Chain focus: emphasizes extreme results; evidence (citation ≤120): “marriages between humans and animals”. - (8) Polarity: negative. - (9) JSON ONLY output complying with lengths.
Expected output (JSON only): {
“is_slippery_slope”: “Yes”, “polarity”: “negative”, “initial_event”: “allow same-sex marriage”, “chain_steps”: [
“marriage between siblings”, “marriages between humans and animals”
], “end_point”: “marriages between humans and animals”, “inevitability_claimed”: {
“value”: true, “evidence”: “we will soon see”
}, “support_provided”: {
“value”: false, “evidence”: null
}, “focus_on_chain_over_merits”: {
“value”: true, “evidence”: “marriages between humans and animals”
}, “reason_short”: “The text argues that allowing A quickly leads to extreme results without providing sufficient mechanisms or evidence, displacing the discussion of the merits of A.”, “confidence”: 0.9, “justificacion_confidence”: “The evidence is very clear and the decision “Yes” seems the only reasonable one. This suggests a high confidence.”
} ────────────────────────────────────── ─────────────────── ────────────────────
OUTPUT (JSON) exactly with the requested keys.
- class propaganda_pipeline.SlipperyRunner[source]¶
Bases:
TechniqueRunnerDetects the SLIPPERY SLOPE (Consequential Oversimplification) technique.
Identifies whether persuasion rests on an unjustified chain of consequences leading to an extreme outcome, presented as near-inevitable without sufficient causal support.
postprocessreturns a candidate dict with:model:
"SLIPPERY"answer:"Sí"or"No"confidence: float in [0, 1] span: up to 3 verbatim evidences or chain/endpoint fragments rationale_summary: reason_short plus polarity annotation raw: fullSlipperySlopeJudgmentmodel dump
- name: str = 'SLIPPERY'¶
- signature¶
alias of
DetectaSlipperySlope
- postprocess(salida_obj: SlipperySlopeJudgment) Dict[str, Any][source]¶
Convert LLM judgment output to a standardized candidate dict.
- Args:
salida_obj: Parsed Pydantic judgment object from the DSPy predictor.
- Returns:
Dict with keys: model, answer (Sí/No), rationale_summary, confidence (float in [0, 1]), span (list of text fragments), labels (technique- specific metadata), and raw (full model dump).
- class propaganda_pipeline.SloganJudgment(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelLLM judgment schema for the Slogan detection technique.
- es_slogan: Literal['Sí', 'No']¶
- objetivo_o_tema: pydantic.constr | None = None¶
- presencia_de_razones: Literal['ninguna', 'mínima', 'moderada', 'sustantiva']¶
- explicacion_breve: pydantic.constr¶
- confidence: pydantic.confloat¶
- justificacion_confidence: pydantic.constr¶
- class propaganda_pipeline.DetectaSlogan(*args: Any, **kwargs: Any)[source]¶
Bases:
SignatureROLE You are an argument analyst. Detects use of “Slogans”: short, memorable and striking phrases that They appeal to emotion/identity and replace substantive reasons.
GUARDRAIL (MANDATORY) - Returns ONLY a valid JSON object. No text outside the JSON. No markdown. No comments. - Write in Spanish. If info is missing, use null or []. - Each string ≤ 300 characters. TEXT Citations ≤ 120. Do not invent or reformulate. - DO NOT include step-by-step reasoning in the output. Think privately and output ONLY the JSON. - DO NOT translate the span into Spanish. Keep it in the original language.
STRICT CRITERIA (for “Yes”) - There is a short and memorable slogan/leitmotif/hashtag/imperative. - The main persuasive force is emotional/identity (≥50%). - Absence or minimal presence of relevant reasons/evidence.
DISTINCTIONS / SIGNS (summary) - Name calling counts only if it appears in the form of a slogan and dominates persuasion. - Typical signs: rhyme/alliteration/parallelism/repetition; imperatives; hashtags (#…). - Canonical examples: “#NoMásX”, “Yes we can”, “Law and order”.
ANALYSIS INSTRUCTIONS 1) Preprocess gently: lowercase, minimize punctuation; preserves phrases as is for quotes (≤120). 2) Extract slogan candidates: short n-grams (1–6 words), imperatives, hashtags, structures with parallelism (“Not X. Not Y.”) or rhyme/alliteration. 3) Rhetorical cues: mark rhyme, alliteration, parallelism, repetition, imperative, hashtags when present. 4) Evaluate persuasive force: does it rest mainly on the slogan (emotion/identity) or on verifiable reasons? 5) Classify “presence_of_reasons” into {none, minimal, moderate, substantive}. 6) Build JSON output: literally quote 1–3 short snippets; don’t rephrase; respect lengths. 7) If in doubt, prioritize precision: “No” when the instruction does not dominate; “Yes” when you meet all criteria.
CALCULATION OF “confidence” - “confidence” is a continuous value in [0.0, 1.0] that indicates how clear and confident your decision is about whether there are “Sloggans” or not. - To estimate it, combine two factors:
- Clarity of textual evidence:
High (≈0.8–1.0): The presence/absence of “Sloggans” is very evident, with clear and consistent patterns, and almost no ambiguity. Medium (≈0.4–0.7): There are some clues, but also counterexamples, ambiguity, or little evidence. Low (≈0.0–0.3): The text is confusing or offers almost no basis for decision.
- Internal security of the model:
If you could have easily chosen the opposite label, lower your confidence. If your answer seems like the only reasonable option given the alternatives, increase your confidence.
If the underlying system has internal probabilities (for example, associated with different possible outputs by beam search), also use those probabilities as a guide: distributions concentrated on one option → highest confidence; distributions spread over options → lowest confidence.
────────────────────────────────────── ─────────────────── ──────────────────── GUIDED EXAMPLE (one-shot). The output of the model MUST BE JSON ONLY.
Entry (TEXT): “Immigrants welcome, racist not! No border. No control!”
Summary verification trace (do not print on output): - Normalization: lowercase and minimum punctuation (keep original text for quotes). - Detected slogan candidates:
“Immigrants welcome, racist not!” (brief, memorable; binary contrast)
“No border. No control!” (parallelism with “No…”)
Rhetorical signs: clear parallelism; rhyme/rhythm can be perceived; short slogans.
Emotional appeals: identity (“immigrants welcome”), dignity (rejection of the “racist”).
Reasons: no data/evidence; message is consignistic.
- Strict criteria:
C1 (short/memorable slogan): ✓ C2 (emotional/identity persuasion ≥50%): ✓ C3 (absent or minimal reasons): ✓
Guardrails: literal quotes ≤120; JSON ONLY output; fields ≤300.
Expected output (JSON only): {
“es_slogan”: “Yes”, “detected_phrases”: [
“Immigrants welcome, racist not!”, “No border. No control!”
], “objetivo_o_tema”: “Promote the acceptance of immigrants and reject racism and border control.”, “rhetorical_features”: [
“rhyme”, “parallelism”
], “emotional_appeals”: [
“identity”, “dignity”
], “labeled_or_stereotypes”: [
“racist”
], “presence_of_reasons”: “none”,
- “explicacion_breve”: “The phrases are brief and memorable slogans that appeal to identity and dignity, without offering substantive reasons.”,
- “text_examples”: [
“Immigrants welcome, racist not!”, “No border. No control!”
], “confidence”: 0.95, “justificacion_confidence”: “The evidence is very clear and the decision “Yes” seems the only reasonable one. This suggests a high confidence.”
}
- class propaganda_pipeline.SloganRunner[source]¶
Bases:
TechniqueRunnerDetects the Slogan propaganda technique.
A slogan is a brief, striking phrase repeated to reinforce a political or ideological position without substantive reasoning.
- Output dict keys (from postprocess):
model: “SLOGAN” answer: “Sí” or “No” rationale_summary: brief explanation + presence of reasoning confidence: float in [0.0, 1.0] span: up to 3 literal text examples or detected phrases labels: frases_detectadas, objetivo_o_tema, rasgos_retóricos,
apelaciones_emocionales, etiquetado_o_estereotipos, presencia_de_razones
raw: full SloganJudgment model dump
- name: str = 'SLOGAN'¶
- signature¶
alias of
DetectaSlogan
- postprocess(salida_obj: SloganJudgment) Dict[str, Any][source]¶
Convert LLM judgment output to a standardized candidate dict.
- Args:
salida_obj: Parsed Pydantic judgment object from the DSPy predictor.
- Returns:
Dict with keys: model, answer (Sí/No), rationale_summary, confidence (float in [0, 1]), span (list of text fragments), labels (technique- specific metadata), and raw (full model dump).
- class propaganda_pipeline.AppealToValuesJudgment(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelLLM judgment schema for the Appeal to Values detection technique.
- is_appeal_to_values: Literal['Sí', 'No']¶
- final_judgment: Literal['Sí, usa Appeal to Values', 'No, no usa Appeal to Values']¶
- claim_text: pydantic.constr | None = None¶
- justification_text: pydantic.constr | None = None¶
- authority_framing_detected: bool¶
- loaded_language_only: bool¶
- evidence_balance: Literal['values_dominant', 'balanced', 'facts_dominant']¶
- explanatory_note: pydantic.constr¶
- confidence: pydantic.confloat¶
- justificacion_confidence: pydantic.constr¶
- class propaganda_pipeline.DetectaAppealToValues(*args: Any, **kwargs: Any)[source]¶
Bases:
SignatureROLE You are an argument analyst. Evaluate if the TEXT uses “Appeal to Values”.
GUARDRAIL (MANDATORY) - Returns ONLY a valid JSON object. No text outside the JSON. No markdown. No comments. - Write in Spanish. If data is missing, use null or []. - Each string ≤ 300 characters. Citations ≤ 120 (max. 3) and must be literal from the TEXT. - DO NOT include step-by-step reasoning in the output. Think privately and output ONLY the JSON. - DO NOT translate the span into Spanish. Keep it in the original language.
STRICT CRITERIA (ALL must be met for “Yes”) 1) There is a STATEMENT (claim). 2) There is explicit JUSTIFICATION. 3) The justification rests mainly (≥50%) on abstract positive values (e.g., justice, freedom, tradition, religion/belief).
DISTINCTIONS / SIGNS - Loaded Language: use of evaluative terms without argument (claim+justification) → check loaded_language_only=true. - Appeal to Authority: relies on specific people/entities (expert or institutional authority). - Bandwagon: “most/all”; Flag Waving: group pride/identity (“for the country”, “our people”). - “facts_dominant”: data, verifiable evidence, detailed causal mechanisms outweigh values. - “balanced”: values and substantive evidence have similar weight.
ANALYSIS INSTRUCTIONS 1) Mentally normalize the TEXT (lowercase, reduce punctuation) for detection only; Quotations must be kept verbatim. 2) Identify claim (main statement) and justification (main reason). Extract exact quotes if they exist. 3) Map invoked values towards the permitted set (freedom, justice, democracy, peace, transparency, ethics,
tradition, dignity, security, merit, loyalty, order, progress, religion, beliefs). Use the normalized form.
Evaluate the balance of evidence: - values_dominant: persuasion relies ≥50% on appeals to abstract values. - balanced: comparable weight between values and substantive evidence. - facts_dominant: data/mechanisms/verification predominate.
Record co-occurrences if they appear (Authority, Bandwagon, Flag Waving, Loaded Language).
Limit quotes_evidence to a maximum of 3 literal TEXT quotes, each ≤120 characters.
Complete the JSON according to the schema. Do not add anything outside of JSON.
CALCULATION OF “confidence” - “confidence” is a continuous value in [0.0, 1.0] that indicates how clear and confident your decision is about whether there is “Appeal to Values” or not. - To estimate it, combine two factors:
- Clarity of textual evidence:
High (≈0.8–1.0): The presence/absence of “Appeal to Values” is very evident, with clear and consistent patterns, and almost no ambiguity. Medium (≈0.4–0.7): There are some clues, but also counterexamples, ambiguity, or little evidence. Low (≈0.0–0.3): The text is confusing or offers almost no basis for decision.
- Internal security of the model:
If you could have easily chosen the opposite label, lower your confidence. If your answer seems like the only reasonable option given the alternatives, increase your confidence.
If the underlying system has internal probabilities (for example, associated with different possible outputs by beam search), also use those probabilities as a guide: distributions concentrated on one option → highest confidence; distributions spread over options → lowest confidence.
────────────────────────────────────── ─────────────────── ──────────────────── GUIDED EXAMPLE (one-shot). The output of the model MUST BE JSON ONLY.
Entry (TEXT): “We are against abortion because we prioritize the right to life of the unborn.”
Summary decision trace (do not print on output): - Claim detected: “We are against abortion”. - Explicit justification: “because we prioritize the right to life of the unborn.” - Invoked abstract value: dignity / right to life → normalizes to “dignity”. - There is no cited authority, nor “all/the majority”, nor group identity appeal. - The persuasive support rests on the abstract value (values_dominant). - Guardrails: 1 literal quote ≤120; JSON ONLY output; strings ≤300.
Expected output (JSON only): {
“is_appeal_to_values”: “Yes”, “final_judgment”: “Yes, use Appeal to Values”, “claim_text”: “We are against abortion”, “justification_text”: “because we prioritize the right to life of the unborn”, “values_invoked”: [“dignity”], “authority_framing_detected”: false,
- “loaded_language_only”: false,
“evidence_balance”: “values_dominant”, “quotes_evidence”: [“because we prioritize the right to life of the unborn”], “co_occurring_techniques”: [], “explanatory_note”: “The argument is based on the abstract value of dignity and the right to life, without factual evidence.”, “confidence”: 0.9, “justificacion_confidence”: “The evidence is very clear and the decision “Yes” seems the only reasonable one. This suggests a high confidence.”
}
- class propaganda_pipeline.AppealToValuesRunner[source]¶
Bases:
TechniqueRunnerDetects the Appeal to Values propaganda technique.
Identifies arguments whose persuasive weight rests primarily (≥50%) on abstract positive values (justice, freedom, tradition, dignity, etc.) rather than factual evidence or substantive reasoning.
- Output dict keys (from postprocess):
model: “VALUES” answer: “Sí” or “No” rationale_summary: explanatory_note + evidence_balance info confidence: float in [0.0, 1.0] span: up to 3 literal quotes or claim/justification excerpts labels: final_judgment, claim_text, justification_text, values_invoked,
authority_framing_detected, loaded_language_only, evidence_balance, co_occurring_techniques
raw: full AppealToValuesJudgment model dump
- name: str = 'VALUES'¶
- signature¶
alias of
DetectaAppealToValues
- postprocess(salida_obj: AppealToValuesJudgment) Dict[str, Any][source]¶
Convert LLM judgment output to a standardized candidate dict.
- Args:
salida_obj: Parsed Pydantic judgment object from the DSPy predictor.
- Returns:
Dict with keys: model, answer (Sí/No), rationale_summary, confidence (float in [0, 1]), span (list of text fragments), labels (technique- specific metadata), and raw (full model dump).
- class propaganda_pipeline.FocusOnDistractor(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelWhether the text’s focus shifts to the distractor, with optional evidence.
- value: bool¶
- evidence: pydantic.constr | None = None¶
- class propaganda_pipeline.RedHerringJudgment(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelLLM judgment schema for the Red Herring detection technique.
- is_red_herring: Literal['Sí', 'No']¶
- mechanism: Literal['whataboutism', 'strawman', 'topic_shift', 'changing_goalposts', 'ad_hominem_diversion', 'irrelevant_authority', 'anecdotal_diversion', 'other']¶
- original_claim_quote: pydantic.constr | None = None¶
- original_topic: pydantic.constr | None = None¶
- distractor_quote: pydantic.constr | None = None¶
- distractor_topic: pydantic.constr | None = None¶
- focus_on_distractor: FocusOnDistractor¶
- relevance_assessment: pydantic.constr¶
- final_note: pydantic.constr¶
- confidence: pydantic.confloat¶
- justificacion_confidence: pydantic.constr¶
- class propaganda_pipeline.DetectaRedHerring(*args: Any, **kwargs: Any)[source]¶
Bases:
SignatureROLE You are an argument analyst. Detects “Introducing Irrelevant Information (Red Herring)”.
GUARDRAIL (MANDATORY) - Respond ONLY with a valid JSON object. No text outside the JSON. No markdown. No comments. - Write in Spanish. If data is missing, use null or []. - Quotes ≤ 120 characters. Each string ≤ 300 characters. - Do not invent quotes: extract literally from the TEXT (max. 3). If there are no relevant citations, use []. - DO NOT include step-by-step reasoning in the output. Think privately and output ONLY the JSON. - DO NOT translate the span into Spanish. Keep it in the original language.
STRICT CRITERIA (ALL) 1) There is an original topic/statement that deserves a response. 2) A different topic that is little or not relevant is introduced. 3) The reply focuses on the introduced topic, leaving the original unaddressed.
SIGNS (indicative) - Whataboutism, explicit/implicit topic change, irrelevant authority/anecdote,
ad hominem of deflection, strawman (when it shifts the focus), moving the goal.
DISTINCTIONS (it is NOT Red Herring if…) - The example/authority explicitly connects with the original topic (clear relevance). - The multi-aspect response substantively addresses the original topic and the distractor is marginal.
ANALYSIS INSTRUCTIONS 1) Extract (when possible) a brief quote from the original topic/statement and summarize its topic. 2) Identify the distractor: short quote and proposed topic. 3) Evaluate relevance: briefly explain why the distractor is little/not relevant to the original. 4) Determine if the focus is shifted to the distractor (use “focus_on_distractor.value” and a short evidence). 5) Rank the most suitable mechanism (e.g. “topic_shift”, “whataboutism”, etc.). 6) List 1–3 observable “indicators” (e.g., “shift in topic”, “irrelevant authority”). 7) List “confounds_ruled_out” if you rule out plausible alternative explanations. 8) Write “final_note” with a brief summary of the verdict. 9) Check guardrails: length limits, Spanish, JSON ONLY, literal quotes, up to 3 quotes.
CALCULATION OF “confidence” - “confidence” is a continuous value in [0.0, 1.0] that indicates how clear and confident your decision is about whether there is “RedHerring” or not. - To estimate it, combine two factors:
- Clarity of textual evidence:
High (≈0.8–1.0): The presence/absence of “RedHerring” is very evident, with clear and consistent patterns, and almost no ambiguity. Medium (≈0.4–0.7): There are some clues, but also counterexamples, ambiguity, or little evidence. Low (≈0.0–0.3): The text is confusing or offers almost no basis for decision.
- Internal security of the model:
If you could have easily chosen the opposite label, lower your confidence. If your answer seems like the only reasonable option given the alternatives, increase your confidence.
If the underlying system has internal probabilities (for example, associated with different possible outputs by beam search), also use those probabilities as a guide: distributions concentrated on one option → highest confidence; distributions spread over options → lowest confidence.
────────────────────────────────────── ─────────────────── ──────────────────── GUIDED EXAMPLE (one-shot). The output of the model MUST BE JSON ONLY. Entry (TEXT): “I have worked hard to help eliminate criminal activity. What we need is economic growth that can only come from the hands of leadership.”
Summary decision trace (do not print on output): - Original claim/topic: Quote 1 = “I have worked hard to help eliminate criminal activity.”
→ Topic: efforts against crime.
Distractor: Quote 2 = “What we need is economic growth that can only come from the hands of leadership.” → Topic: economic growth and leadership.
Relevance: the distractor is not linked to crime control nor does it respond to the original statement.
Focus shift: the replica focuses on economic growth → “focus_on_distractor.value = true”, short evidence: the focus shifts to “economic growth” instead of crime.
Mechanism: “topic_shift”.
Guardrails: appointments ≤120; strings ≤300; Spanish; JSON ONLY; max. 3 quotes.
Expected output (JSON only): {
“is_red_herring”: “Yes”, “mechanism”: “topic_shift”, “original_claim_quote”: “I have worked hard to help eliminate criminal activity.”, “original_topic”: “Efforts to eliminate criminal activity.”,
- “distractor_quote”: “What we need is economic growth that can only come from the hands of leadership.”,
“distractor_topic”: “Economic growth and leadership.”, “focus_on_distractor”: {
“value”: true, “evidence”: “The response shifts focus to economic growth instead of addressing criminal activity.”
}, “relevance_assessment”: “The introduction of economic growth as a topic diverts attention from the original claim about eliminating criminal activity.”, “indicators”: [“shift in topic”, “introduction of unrelated topic”], “confounds_ruled_out”: [], “final_note”: “The response does not address the original claim about criminal activity, focusing instead on economic growth.”, “confidence”: 0.9, “justificacion_confidence”: “The evidence is very clear and the decision “Yes” seems the only reasonable one. This suggests a high confidence.”
}
- class propaganda_pipeline.RedHerringRunner[source]¶
Bases:
TechniqueRunnerDetects the Red Herring (Introducing Irrelevant Information) propaganda technique.
Identifies cases where an irrelevant topic is introduced to distract from the original claim, leaving it unaddressed. Common mechanisms include whataboutism, topic shifting, and ad hominem diversion.
- Output dict keys (from postprocess):
model: “RED_HERRING” answer: “Sí” or “No” rationale_summary: relevance assessment + mechanism + final_note confidence: float in [0.0, 1.0] span: distractor_quote, then indicators, then original_claim_quote labels: mechanism, original_claim_quote, original_topic,
distractor_quote, distractor_topic, focus_on_distractor, focus_on_distractor_evidence, indicators, confounds_ruled_out
raw: full RedHerringJudgment model dump
- name: str = 'RED_HERRING'¶
- signature¶
alias of
DetectaRedHerring
- postprocess(salida_obj: RedHerringJudgment) Dict[str, Any][source]¶
Convert LLM judgment output to a standardized candidate dict.
- Args:
salida_obj: Parsed Pydantic judgment object from the DSPy predictor.
- Returns:
Dict with keys: model, answer (Sí/No), rationale_summary, confidence (float in [0, 1]), span (list of text fragments), labels (technique- specific metadata), and raw (full model dump).
- class propaganda_pipeline.EvidenceItem(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelA labeled evidence quote with its role (original, strawman, or refutation).
- role: Literal['original', 'strawman', 'refutation']¶
- quote: pydantic.constr¶
- class propaganda_pipeline.StrawmanJudgment(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelLLM judgment schema for the Strawman detection technique.
- strawman_detected: Literal['Sí', 'No']¶
- original_position: pydantic.constr | None = None¶
- strawman_position: pydantic.constr | None = None¶
- refutation_excerpt: pydantic.constr | None = None¶
- refutation_target: Literal['original', 'strawman', 'ambiguo']¶
- reasoning_brief: pydantic.constr¶
- severity: Literal['baja', 'media', 'alta']¶
- confidence: pydantic.confloat¶
- justificacion_confidence: pydantic.constr¶
- class propaganda_pipeline.DetectaStrawman(*args: Any, **kwargs: Any)[source]¶
Bases:
SignatureROLE You are an argument analyst. Detect “Misrepresentation of Someone’s Position (Strawman)” in the TEXT.
GUARDRAIL (MANDATORY) - Returns ONLY a valid JSON object. No text outside the JSON. No markdown. No comments. - Write in Spanish. If data is missing, use null or []. - All strings ≤300 characters. Citations ≤120 (extracts literally). - Do not include step-by-step reasoning in the output. Think privately and output ONLY the JSON. - DO NOT translate the span into Spanish. Keep it in the original language.
STRICT CRITERIA (ALL must be met for “Yes”) 1) There is an original position (explicit or attributed). 2) A reformulated version appears that distorts/exaggerates/caricatures (strawman). 3) The refutation is directed primarily (≥50%) to the distorted version, not the original.
SIGNS - “What they really want…”, take it to extremes (“everything/nothing”, “absolute power”),
caricatures, attributions without citation, biased selection of fragments.
DO NOT CONFUSE - Faithful paraphrasing/benign simplification without central distortion. - Steelman (strengthen the opponent’s posture). - Partial straw men without refutation directed at the distorted version. - Red herring/subject diversion without reformulation of the position. - General rhetorical hyperbole that does not reorient the refutation towards the distorted version.
ANALYSIS INSTRUCTIONS 1) Literal extraction of evidence:
Mark as “original” the quote that expresses/attributes the initial position.
Mark the quote that exaggerates/distorts it as “strawman”.
If there is a refutation, extract a short fragment as “refutation”.
Short reconstruction (≤300c): - Summarizes the original position in “original_position”. - Summarizes the distorted version in “strawman_position”.
Objective of the refutation: - Determine if the refutation attacks the original, the strawman, or is ambiguous.
Typify distortion: - Uses “caricature” (grotesque exaggeration),
“straw man for extremes” (lead to absolutes), “biased selection” (quotes out of context).
You can combine more than one type if applicable.
Severity: - “low”: slight or local distortion. - “media”: clear distortion that reorients the discussion. - “high”: dominant distortion that completely replaces the original posture.
Consistency and lengths: - Verify limits on length and literalness of citations. - Outputs ONLY the JSON according to the schema.
CALCULATION OF “confidence” - “confidence” is a continuous value in [0.0, 1.0] that indicates how clear and confident your decision is about whether there is “Strawman” or not. - To estimate it, combine two factors:
- Clarity of textual evidence:
High (≈0.8–1.0): The presence/absence of “Strawman” is very evident, with clear and consistent patterns, and almost no ambiguity. Medium (≈0.4–0.7): There are some clues, but also counterexamples, ambiguity, or little evidence. Low (≈0.0–0.3): The text is confusing or offers almost no basis for decision.
- Internal security of the model:
If you could have easily chosen the opposite label, lower your confidence. If your answer seems like the only reasonable option given the alternatives, increase your confidence.
If the underlying system has internal probabilities (for example, associated with different possible outputs by beam search), also use those probabilities as a guide: distributions concentrated on one option → highest confidence; distributions spread over options → lowest confidence.
────────────────────────────────────── ─────────────────── ──────────────────── GUIDED EXAMPLE (one-shot). The output of the model MUST BE JSON ONLY.
Entry (TEXT): “the corporate (i.e. private sector) players in global governance are determined to have their agenda accepted everywhere — which is none other than to grant themselves full powers over the planet”
Summary decision trace (do not print on output): - Identification of original: “…have their agenda accepted everywhere” states an agenda, without specifying its content. - Strawman identification: “…grant themselves full powers over the planet” extremes the agenda to planetary control. - Rebuttal: there is no fragment that refutes; the rhetorical focus is directed to the extreme version. - Typification: “caricature” (grotesque exaggeration); also compatible with “straw man for extremes”. - Severity: “medium” (exaggeration redefines the meaning of “agenda”). - Guardrails validation: literal quotes ≤120, strings ≤300, JSON ONLY output.
Expected output (JSON only): {
“strawman_detected”: “Yes”, “original_position”: “Corporate players in global governance have an agenda.”, “strawman_position”: “Their agenda is to grant themselves full powers over the planet.”, “refutation_excerpt”: null, “refutation_target”: “strawman”, “distortion_types”: [“cartoon”], “evidence”: [
- {
“role”: “original”, “quote”: “the corporate (i.e. private sector) players in global governance are determined to have their agenda accepted everywhere”
}, {
“role”: “strawman”, “quote”: “which is none other than to grant themselves full powers over the planet”
}
], “reasoning_brief”: “The text exaggerates the corporate ‘agenda’ into a caricature of planetary control.”, “severity”: “medium”, “confidence”: 0.8, “justificacion_confidence”: “The evidence is very clear and the decision “Yes” seems the only reasonable one. This suggests a high confidence.”
}
- class propaganda_pipeline.StrawmanRunner[source]¶
Bases:
TechniqueRunnerDetects the Strawman (Misrepresentation of Someone’s Position) propaganda technique.
Identifies cases where an opponent’s position is distorted or caricatured so the refutation targets the distorted version rather than the original.
- Output dict keys (from postprocess):
model: “STRAWMAN” answer: “Sí” or “No” rationale_summary: reasoning_brief + distortion_types + severity confidence: float in [0.0, 1.0] span: literal evidence quotes (original/strawman/refutation) labels: original_position, strawman_position, refutation_excerpt,
refutation_target, distortion_types, severity, evidence
raw: full StrawmanJudgment model dump
- name: str = 'STRAWMAN'¶
- signature¶
alias of
DetectaStrawman
- postprocess(salida_obj: StrawmanJudgment) Dict[str, Any][source]¶
Convert LLM judgment output to a standardized candidate dict.
- Args:
salida_obj: Parsed Pydantic judgment object from the DSPy predictor.
- Returns:
Dict with keys: model, answer (Sí/No), rationale_summary, confidence (float in [0, 1]), span (list of text fragments), labels (technique- specific metadata), and raw (full model dump).
- class propaganda_pipeline.AppealFearPrejudiceJudgment(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelLLM judgment schema for the Appeal to Fear or Prejudice detection technique.
- is_appeal_to_fear_prejudice: Literal['Sí', 'No']¶
- type: Literal['miedo', 'prejuicio', 'ambos'] | None = None¶
- statement: pydantic.constr | None = None¶
- justification_summary: pydantic.constr | None = None¶
- status_quo_as_alternative: bool¶
- co_occurs_consequential_oversimplification: bool¶
- co_occurs_false_dilemma: bool¶
- overall_strength: Literal['alta', 'media', 'baja']¶
- notes: pydantic.constr | None = None¶
- confidence: pydantic.confloat¶
- justificacion_confidence: pydantic.constr¶
- class propaganda_pipeline.DetectaAppealToFearPrejudice(*args: Any, **kwargs: Any)[source]¶
Bases:
SignatureROLE You are an argument analyst. Detect “Appeal to Fear, Prejudice” in the TEXT.
GUARDRAIL (MANDATORY) - Returns ONLY a valid JSON object. No text outside the JSON. No markdown. No comments. - Write in Spanish. If data is missing, use null or []. - All strings ≤ 300 characters. - Don’t make up quotes; extracted literally from the TEXT (max. 3 in “evidence_quotes”). - DO NOT include step-by-step reasoning in the output. Think privately and output ONLY the JSON. - DO NOT translate the span into Spanish. Keep it in the original language.
STRICT CRITERIA (to answer “Yes” ALL must be met) 1) There is an identifiable claim. 2) There is explicit JUSTIFICATION (although brief). 3) The justification rests mainly (≥50%) on inducing fear/repulsion or prejudice towards a target.
SIGNS (non-exhaustive) - Alarmist language or threats (“danger”, “catastrophe”, “invasion”, “plague”, “collapse”). - Stigmas, dehumanization, negative generalizations towards a group (“criminals”, “parasites”, “terrorists”). - Feared scenarios vague/not provided or disproportionate to the evidence presented.
DISTINCTIONS - Alert based on proportional and concrete evidence → Not applicable. - Can co-occur with Consequential Oversimplification and False Dilemma. - Loaded Language may appear, but here the central weight is to induce fear/prejudice.
ANALYSIS INSTRUCTIONS - Normalizes slightly to detect patterns (lowercase, minimum punctuation) without altering the cited content. - Identify the objective/“targets” (people/groups/ideas) and whether the main persuasion appeals to fear or prejudice:
type=”fear” → threat/fear is the dominant persuasive vector.
type=”prejudice” → generalized stigma or essentialist negative characterization.
type=”both” → fear and stigma coexist with comparable weight.
Distinguishes “fear_triggers” (scenarios/threats or frames of fear, e.g., “invasion”, “risk of attack”) from “loaded_language_terms” (specific loaded terms, e.g., “terrorists”, “plague”). If a trigger matches a term already listed in “loaded_language_terms”, you can leave “fear_triggers” as [].
“status_quo_as_alternative” = true if “maintain the current” is explicitly presented as the only/superior option against fear/prejudice.
- Mark co-occurrences:
co_occurs_consequential_oversimplification = true if a simplistic causal chain is inflated (“if X enters → disaster”).
co_occurs_false_dilemma = true if only 2 exclusive options are presented (“either we prohibit X or there will be chaos”).
- “overall_strength”:
high: intensely alarmist/stigmatizing language, without nuances, with a central persuasive focus on fear/prejudice.
medium: clear presence but with counterweights/partial ambiguity.
low: weak signals or subordinated to substantive reasons.
In “justification_summary”, briefly explain why the main persuasive support is fear/prejudice.
CALCULATION OF “confidence” - “confidence” is a continuous value in [0.0, 1.0] that indicates how clear and confident your decision is about whether there is “Appeal to fear” or not. - To estimate it, combine two factors:
- Clarity of textual evidence:
High (≈0.8–1.0): The presence/absence of “Appeal to fear” is very evident, with clear and consistent patterns, and almost no ambiguity. Medium (≈0.4–0.7): There are some clues, but also counterexamples, ambiguity, or little evidence. Low (≈0.0–0.3): The text is confusing or offers almost no basis for decision.
- Internal security of the model:
If you could have easily chosen the opposite label, lower your confidence. If your answer seems like the only reasonable option given the alternatives, increase your confidence.
If the underlying system has internal probabilities (for example, associated with different possible outputs by beam search), also use those probabilities as a guide: distributions concentrated on one option → highest confidence; distributions spread over options → lowest confidence.
────────────────────────────────────── ─────────────────── ──────────────────── GUIDED EXAMPLE (one-shot). The output of the model MUST BE JSON ONLY.
Entry (TEXT): “We must stop those refugees as they are terrorists.”
Summary decision trace (do not print on output): - Detección de claim: “We must stop those refugees…”. - Explicit justification: “…as they are terrorists.” - Persuasive weight: resorts to a strong stigma (“terrorists”) applied to “refugees” → prejudice prevails. - Objective/targets: “refugees”. - Loaded language: “terrorists”. - Fear triggers: can be left empty if the trigger is already captured as a loaded term. - Without proportional evidence or nuances → “high” strength. - Guardrails: literal quotes (≤3), strings ≤300, JSON ONLY output.
Expected output (JSON only): {
“is_appeal_to_fear_prejudice”: “Yes”, “type”: “prejudice”, “statement”: “We must stop those refugees as they are terrorists.”, “justification_summary”: “The phrase attributes refugees to being ‘terrorists’, inducing prejudice against that group.”, “targets”: [“refugees”], “fear_triggers”: [], “loaded_language_terms”: [“terrorists”], “evidence_quotes”: [“We must stop those refugees as they are terrorists.”], “status_quo_as_alternative”: false, “co_occurs_consequential_oversimplification”: false, “co_occurs_false_dilemma”: false, “overall_strength”: “high”, “notes”: null, “confidence”: 0.9, “justificacion_confidence”: “The evidence is very clear and the decision “Yes” seems the only reasonable one. This suggests a high confidence.”
}
- class propaganda_pipeline.FearPrejudiceRunner[source]¶
Bases:
TechniqueRunnerDetects the Appeal to Fear or Prejudice propaganda technique.
Identifies arguments that exploit fear or group prejudice (e.g., targeting refugees, ethnic groups) using loaded language and fear triggers rather than substantive evidence.
- Output dict keys (from postprocess):
model: “FEAR” answer: “Sí” or “No” rationale_summary: justification_summary + type + overall_strength confidence: float in [0.0, 1.0] span: evidence_quotes, then loaded_language_terms/fear_triggers labels: type, statement, targets, fear_triggers, loaded_language_terms,
evidence_quotes, status_quo_as_alternative, co_occurs_consequential_oversimplification, co_occurs_false_dilemma, overall_strength, notes
raw: full AppealFearPrejudiceJudgment model dump
- name: str = 'FEAR'¶
- signature¶
alias of
DetectaAppealToFearPrejudice
- postprocess(salida_obj: AppealFearPrejudiceJudgment) Dict[str, Any][source]¶
Convert LLM judgment output to a standardized candidate dict.
- Args:
salida_obj: Parsed Pydantic judgment object from the DSPy predictor.
- Returns:
Dict with keys: model, answer (Sí/No), rationale_summary, confidence (float in [0, 1]), span (list of text fragments), labels (technique- specific metadata), and raw (full model dump).
- class propaganda_pipeline.AppealToAuthorityJudgment(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelLLM judgment schema for the Appeal to Authority detection technique.
- is_appeal_to_authority: Literal['Sí', 'No']¶
- claim_detected: pydantic.constr | None = None¶
- authority_mentioned: pydantic.constr | None = None¶
- authority_validity: Literal['valida', 'invalida', 'incierto']¶
- dependency_on_authority: Literal['principal', 'secundaria', 'no_aplica']¶
- self_reference_as_authority: bool¶
- mere_sourcing: bool¶
- is_fallacious: bool¶
- justification: pydantic.constr¶
- confidence: pydantic.confloat¶
- justificacion_confidence: pydantic.constr¶
- class propaganda_pipeline.DetectaAppealToAuthority(*args: Any, **kwargs: Any)[source]¶
Bases:
SignatureROLE You are an argument analyst. Detect the “Appeal to Authority” technique and judge if it is fallacious.
STRICT DEFINITION (a) There is an identifiable statement/conclusion. (b) The justification rests ≥50% on “X saying/endorsing it” (X as authority).
SIGNS “according to…”, “according to…”, “as stated…”, “experts…”, “studies show…” (without details), vague or out-of-domain authority, self-reference as an expert, substitution of data/method for authority.
DISTINCTIONS - “Mere sourcing” (traceability/citation of origin) ≠ persuasive technique by authority. - Ad populum (majorities) ≠ authority. - Flag waving (identity/group) ≠ authority.
BOUNDED CRITERIA - authority_validity: validates / invalidates / uncertain (according to domain relevance, credentials and relevance of the expert to the claim). - dependency_on_authority: primary (core support) / secondary (support) / not_applicable. - is_fallacious = true if:
invalid or vague authority, or
primary dependency without additional substantive support EXCEPT when the authority is clearly competent in the domain and the claim coincides with robust consensus of the field.
mere_sourcing = true if the mention is only traceability and the support does not depend on the authority.
self_reference_as_authority = true if the speaker cites himself as an authority.
ANALYSIS INSTRUCTIONS (MANDATORY) 1) Detect the main claim (“claim_detected”). 2) Identify authority mentions (“authority_mentioned”) and extract 1–3 literal evidence (“authority_evidence_spans”, ≤200 each). 3) Evaluate “authority_validity” by domain, credentials and relevance. 4) Evaluate “dependency_on_authority” (does persuasion depend primarily on authority?). 5) Distinguish “mere_sourcing” from persuasive appeal. 6) Check “self_reference_as_authority” if applicable. 7) Decide “is_appeal_to_authority” and “is_fallacious” according to the narrowed criteria. 8) Write “justification” in 2–4 sentences (≤400), in Spanish, without step-by-step reasoning. 9) Returns “confidence” ∈ [0,1]. 10) Respect length limits; don’t make up quotes; use null or [] if info is missing.
EXIT GUARDRAIL - Returns ONLY a valid JSON object according to the schema. No text outside the JSON. No markdown. No comments. - Write in Spanish. - Citations (authority_evidence_spans) ≤ 200 characters each, max. 3. “justification” ≤ 400 characters. - DO NOT include step-by-step reasoning in the output. Think privately and output ONLY the JSON. - DO NOT translate the span into Spanish. Keep it in the original language.
CALCULATION OF “confidence” - “confidence” is a continuous value in [0.0, 1.0] that indicates how clear and confident your decision is about whether there is “Appeal to authority” or not. - To estimate it, combine two factors:
- Clarity of textual evidence:
High (≈0.8–1.0): The presence/absence of “Appeal to authority” is very evident, with clear and consistent patterns, and almost no ambiguity. Medium (≈0.4–0.7): There are some clues, but also counterexamples, ambiguity, or little evidence. Low (≈0.0–0.3): The text is confusing or offers almost no basis for decision.
- Internal security of the model:
If you could have easily chosen the opposite label, lower your confidence. If your answer seems like the only reasonable option given the alternatives, increase your confidence.
If the underlying system has internal probabilities (for example, associated with different possible outputs by beam search), also use those probabilities as a guide: distributions concentrated on one option → highest confidence; distributions spread over options → lowest confidence.
────────────────────────────────────── ─────────────────── ──────────────────── GUIDED EXAMPLE (one-shot). The output of the model MUST BE JSON ONLY.
Entry (text): “Richard Dawkins, an evolutionary biologist and perhaps the foremost expert in the field, says that evolution is true. Therefore, it’s true.”
Summary decision trace (do not print on output): - Claim: “evolution is true”. - Authority detected: “Richard Dawkins” (evolutionary biologist; relevant domain). - Literal evidence (1): sentence that attributes the truth of evolution to the authority of Dawkins. - Validity: “valid” (credentials and domain match the claim). - Dependency: “main” (the conclusion is based on what the expert says so). - Mere sourcing: no (the mention is not only traceability). - Fallacy: no, because the authority is competent and the claim coincides with robust scientific consensus. - Guardrails: all chains ≤ limits; JSON ONLY output.
Expected output (JSON only): {
“is_appeal_to_authority”: “Yes”, “claim_detected”: “evolution is true”, “authority_mentioned”: “Richard Dawkins”, “authority_evidence_spans”: [
“Richard Dawkins, an evolutionary biologist and perhaps the foremost expert in the field, says that evolution is true.”
], “authority_validity”: “valid”, “dependency_on_authority”: “main”, “self_reference_as_authority”: false, “mere_sourcing”: false, “is_fallacious”: false, “justification”: “The argument relies on Richard Dawkins, a recognized expert in evolutionary biology, to maintain that evolution is true. Authority is relevant and dependence is primary. Since the claim coincides with a robust scientific consensus, the appeal is not fallacious.”, “confidence”: 0.9, “justificacion_confidence”: “The evidence is very clear and the decision “Yes” seems the only reasonable one. This suggests a high confidence.”
}
- class propaganda_pipeline.AuthorityRunner[source]¶
Bases:
TechniqueRunnerDetects the Appeal to Authority propaganda technique.
Identifies arguments where the persuasive weight rests primarily on an authority figure’s endorsement rather than substantive evidence. Distinguishes between valid authority citation and fallacious appeal.
- Output dict keys (from postprocess):
model: “AUTHORITY” answer: “Sí” or “No” rationale_summary: justification + mere_sourcing/fallacious flags confidence: float in [0.0, 1.0] span: authority_evidence_spans, then authority_mentioned/claim_detected labels: claim_detected, authority_mentioned, authority_evidence_spans,
authority_validity, dependency_on_authority, self_reference_as_authority, mere_sourcing, is_fallacious
raw: full AppealToAuthorityJudgment model dump
- name: str = 'AUTHORITY'¶
- signature¶
alias of
DetectaAppealToAuthority
- postprocess(salida_obj: AppealToAuthorityJudgment) Dict[str, Any][source]¶
Convert LLM judgment output to a standardized candidate dict.
- Args:
salida_obj: Parsed Pydantic judgment object from the DSPy predictor.
- Returns:
Dict with keys: model, answer (Sí/No), rationale_summary, confidence (float in [0, 1]), span (list of text fragments), labels (technique- specific metadata), and raw (full model dump).
- class propaganda_pipeline.PressureToJoin(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelWhether the text applies social pressure to join the majority.
- value: bool¶
- evidence: pydantic.constr | None = None¶
- class propaganda_pipeline.OtherEvidence(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelWhether substantive evidence other than popularity claims is present.
- value: bool¶
- class propaganda_pipeline.BandwagonDetected(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelDetection result for the bandwagon appeal with supporting evidence.
- value: Literal['Sí', 'No']¶
- evidence: pydantic.constr¶
- class propaganda_pipeline.FallaciousUse(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelWhether the popularity appeal is used fallaciously, with criterion and evidence.
- value: Literal['Sí', 'No', 'Mixto', 'No aplica']¶
- criterion: Literal['≥50% popularidad', 'relevancia válida', 'evidencia sustantiva domina']¶
- evidence: pydantic.constr¶
- class propaganda_pipeline.BandwagonJudgment(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelLLM judgment schema for the Bandwagon (Appeal to Popularity) detection technique.
- is_bandwagon: Literal['Sí', 'No']¶
- bandwagon_detected: BandwagonDetected¶
- statement: pydantic.constr | None = None¶
- pressure_to_join: PressureToJoin¶
- other_substantive_evidence_present: OtherEvidence¶
- fallacious_use: FallaciousUse¶
- edge_case_notes: pydantic.constr | None = None¶
- confidence: pydantic.confloat¶
- justificacion_confidence: pydantic.constr¶
- class propaganda_pipeline.DetectaBandwagon(*args: Any, **kwargs: Any)[source]¶
Bases:
SignatureROLE You are an argument analyst. Detects “Appeal to Popularity (Bandwagon)”.
STRICT DEFINITION (a) There is an identifiable statement or conclusion. (b) The justification rests mainly (≥50%) on claims of popularity
(“everyone”, “the majority”, “consensus”, “70% says…”, “no one”, etc.).
SIGNS (indicative, not exhaustive) - Popularity markers: “everyone”, “no one”, “the majority”, “consensus”,
“polls show…”, “X% support…”.
Pressure to join: “don’t stay behind”, “join”, “you will be the only one who doesn’t…”.
DIFFERENCES/EXCEPTIONS (NOT typically fallacious) - Popularity used as context alongside dominant substantive evidence
(e.g., methodologically sound data, causality, precise comparisons).
“Scientific consensus” with explicit and relevant methodological foundation.
GUARDRAIL (MANDATORY) - Returns ONLY a valid JSON object in Spanish. No text outside the JSON. - If information is missing, use null or [] as appropriate. - Each string ≤ 300 characters. - DO NOT include step-by-step reasoning in the output. Think privately and output ONLY the JSON. - DO NOT translate the span into Spanish. Keep it in the original language.
ANALYSIS INSTRUCTIONS 1) Normalize the TEXT (lowercase, minimum punctuation) without altering the content. 2) Extract the statement/conclusion (if it exists) and save it in “statement” (≤300). 3) Detect and list in “popularity_claims” the phrases or figures that refer to
popularity (max. needed, each ≤300).
Identify the “referenced_group” (e.g. “70%”, “the majority”).
Evaluate “pressure_to_join”: are there calls to join or avoid being left out? - If yes, value=true and synthesize literal evidence (≤300). - Otherwise, value=false and evidence=null.
Evaluate “other_substantive_evidence_present”: - value=true if relevant substantive data/reasons dominate. - Add 1–3 short textual examples in “examples”.
Decide “is_bandwagon” and “bandwagon_detected” (value and evidence): - “Yes” if the justification rests ≥50% on popularity. - “No” if popularity is secondary or context.
Decide “fallacious_use”: - value=”Yes” and criterion=”≥50% popularity” if the main persuasive weight
It is popularity without comparable substantive support.
value=”No” and criterion=”substantive evidence dominates” if the evidence noun is predominant.
“Mixed” if there is a mixture without clear dominance; you can use criterion=”valid relevance”.
“Not applicable” in atypical cases (e.g., mere question without justification).
Use “edge_case_notes” to clarify ambiguities (≤300) or leave null.
Assign “confidence” to [0.0, 1.0] based on signal clarity and consistency.
Check lengths and output ONLY the final JSON object.
CALCULATION OF “confidence” - “confidence” is a continuous value in [0.0, 1.0] that indicates how clear and confident your decision is about whether there is “Bandwagon” or not. - To estimate it, combine two factors:
- Clarity of textual evidence:
High (≈0.8–1.0): The presence/absence of “Bandwagon” is very evident, with clear and consistent patterns, and almost no ambiguity. Medium (≈0.4–0.7): There are some clues, but also counterexamples, ambiguity, or little evidence. Low (≈0.0–0.3): The text is confusing or offers almost no basis for decision.
- Internal security of the model:
If you could have easily chosen the opposite label, lower your confidence. If your answer seems like the only reasonable option given the alternatives, increase your confidence.
If the underlying system has internal probabilities (for example, associated with different possible outputs by beam search), also use those probabilities as a guide: distributions concentrated on one option → highest confidence; distributions spread over options → lowest confidence.
────────────────────────────────────── ─────────────────── ──────────────────── GUIDED EXAMPLE (one-shot). The output of the model MUST BE JSON ONLY. Entry (TEXT): “Would you vote for Putin as president? 70% say yes”
Summary decision trace (do not print on output): - (1) Affirmation/conclusion: implicit invitation to vote; the phrase “70% say yes”
works as a justification.
Popularity detected: “70% say yes” → majority claim.
Referred group: “70%”.
Pressure to join: imperative language is not detected (“join”, “don’t be left behind”) → false.
Substantive evidence: there are no methodological data or independent reasons → value=false.
Persuasive weight: the justification rests ≥50% on popularity.
Decisions: is_bandwagon=”Yes”; bandwagon_detected.value=”Yes”; fallacious_use.value=”Yes”; fallacious_use.criterion=”≥50% popularity”; confidence≈0.9.
Guardrails: all chains ≤300; JSON ONLY output.
Expected output (JSON only): {
“is_bandwagon”: “Yes”, “bandwagon_detected”: {
“value”: “Yes”, “evidence”: “The claim that 70% say they would vote for Putin suggests an argument based on popularity.”
}, “statement”: “Would you vote for Putin as president? 70% say yes”, “popularity_claims”: [“70% say yes”], “referenced_group”: [“70%”], “pressure_to_join”: { “value”: false, “evidence”: null }, “other_substantive_evidence_present”: { “value”: false, “examples”: [] }, “fallacious_use”: {
“value”: “Yes”, “criterion”: “≥50% popularity”, “evidence”: “The justification is that 70% would vote for Putin, which is an argument for popularity.”
}, “edge_case_notes”: null, “confidence”: 0.9, “justificacion_confidence”: “The evidence is very clear and the decision “Yes” seems the only reasonable one. This suggests a high confidence.”
}
- class propaganda_pipeline.BandwagonRunner[source]¶
Bases:
TechniqueRunnerDetects the Appeal to Popularity (Bandwagon) propaganda technique.
Identifies arguments whose justification rests primarily (≥50%) on popularity claims (“everyone thinks”, “70% say yes”) rather than substantive reasoning or evidence.
- Output dict keys (from postprocess):
model: “BANDWAGON” answer: “Sí” or “No” rationale_summary: bandwagon_detected evidence + fallacious_use info confidence: float in [0.0, 1.0] span: popularity_claims, then referenced_group, then statement labels: bandwagon_detected, statement, popularity_claims,
referenced_group, pressure_to_join, other_substantive_evidence_present, fallacious_use, edge_case_notes
raw: full BandwagonJudgment model dump
- name: str = 'BANDWAGON'¶
- signature¶
alias of
DetectaBandwagon
- postprocess(salida_obj: BandwagonJudgment) Dict[str, Any][source]¶
Convert LLM judgment output to a standardized candidate dict.
- Args:
salida_obj: Parsed Pydantic judgment object from the DSPy predictor.
- Returns:
Dict with keys: model, answer (Sí/No), rationale_summary, confidence (float in [0, 1]), span (list of text fragments), labels (technique- specific metadata), and raw (full model dump).
- class propaganda_pipeline.TacticItem(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelA single character-attack tactic with its type, quote, and explanation.
- type: Literal['antecedentes', 'acciones_eventos', 'afiliaciones', 'motivos', 'rasgos_personales']¶
- quote: pydantic.constr¶
- explanation: pydantic.constr¶
- class propaganda_pipeline.AddressesTopicSubstance(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelWhether the argument addresses the substantive topic, with evidence.
- value: bool¶
- evidence: pydantic.constr¶
- class propaganda_pipeline.RelevanceAssessment(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelAssessment of the relevance of character-based attacks to the topic.
- value: Literal['no_relevante', 'dudosa', 'relevante']¶
- justification: pydantic.constr¶
- class propaganda_pipeline.CastingDoubtJudgment(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelLLM judgment schema for the Casting Doubt detection technique.
- is_casting_doubt: Literal['Sí', 'No']¶
- target: pydantic.constr¶
- topic_or_claim: pydantic.constr¶
- addresses_topic_substance: AddressesTopicSubstance¶
- relevance_assessment: RelevanceAssessment¶
- weight_of_character_based_support: Literal['bajo', 'medio', 'alto']¶
- strength: Literal['leve', 'moderada', 'fuerte']¶
- reasoning_summary: pydantic.constr¶
- confidence: pydantic.confloat¶
- justificacion_confidence: pydantic.constr¶
- class propaganda_pipeline.DetectaCastingDoubt(*args: Any, **kwargs: Any)[source]¶
Bases:
SignatureROLE You are an argument analyst. Detects “Casting doubt”: discrediting the target (person/group/entity) instead of addressing the issue with relevant reasons/evidence.
DEFINITION (strict) (a) Focuses on discrediting because of who he is/what he did/who he associates with/motives/traits. (b) Does not provide (or minimize) evidence or reasons directly on the issue discussed. Exceptions (DOES NOT count as casting doubt if DOMINATE): direct and specific conflict of interest; credentials strictly necessary for the affirmation; relevant methodological history in the same domain.
DECISION RULES - “Yes”: the support is mostly centric (≥50%) and the substance is absent or secondary. - “No”: evidence/reasons predominate on the topic, or what is personal is relevant and necessary.
ANALYSIS INSTRUCTIONS 1) Normalize the text (lowercase, minimum punctuation) without altering literal quotes. 2) Identify the objective (target) and the main theme/claim of the text. 3) Extract up to 1–3 statements that function as “casting_doubt_claims” (≤300 each). 4) Detects character-centric tactics (TacticItem):
typifies (background, actions_events, affiliations, motives, personal_traits),
includes a literal “quote” ≤25 words,
explain in ≤300 why that quote discredits the target instead of discussing the substance.
Assess whether the substance is addressed (addresses_topic_substance.value and evidence): data, logic, methodology, proportionality, effectiveness, etc.
Evaluate relevance (relevance_assessment): “not_relevant”, “doubtful” or “relevant”, with brief justification.
Estimate character-centric weight (weight_of_character_based_support: low/medium/high) and rhetorical strength (strength: mild/moderate/strong).
Give final judgment (is_casting_doubt = “Yes”/“No”) and a short summary (reasoning_summary).
FORMAT GUARDRAILS (MANDATORY): - Returns ONLY a valid JSON object. No text outside the JSON. No markdown. No comments. - Write in Spanish. - Strings ≤300 characters; quotes ≤25 words (truncated if it exceeds). - DO NOT print step-by-step reasoning; think privately and output ONLY the JSON. - DO NOT translate the span into Spanish. Keep it in the original language.
CALCULATION OF “confidence” - “confidence” is a continuous value in [0.0, 1.0] that indicates how clear and confident your decision is about whether there is “Casting doubt” or not. - To estimate it, combine two factors:
- Clarity of textual evidence:
High (≈0.8–1.0): The presence/absence of “Casting doubt” is very evident, with clear and consistent patterns, and almost no ambiguity. Medium (≈0.4–0.7): There are some clues, but also counterexamples, ambiguity, or little evidence. Low (≈0.0–0.3): The text is confusing or offers almost no basis for decision.
- Internal security of the model:
If you could have easily chosen the opposite label, lower your confidence. If your answer seems like the only reasonable option given the alternatives, increase your confidence.
If the underlying system has internal probabilities (for example, associated with different possible outputs by beam search), also use those probabilities as a guide: distributions concentrated on one option → highest confidence; distributions spread over options → lowest confidence.
──────────────────────────────────── ───────────────────────────────────── GUIDED EXAMPLE (one-shot). The output of the model MUST BE JSON ONLY. Entry (TEXT): “If you have nothing to hide, you have nothing to fear”
Summary decision trace (do not print on output): - Target: those who question/reject surveillance (“you”). - Theme/claim: justification for surveillance (if you are not hiding anything, you should not fear). - Tactics:
“motives”: impute hidden motives (“If you have nothing to hide”).
“personal_traits”: associate fear with lack of honesty (“you have nothing to fear”).
Substance: no evidence on efficacy, proportionality or guarantees → addresses_topic_substance.value = false.
Relevance: the focus is shifted to the critic’s motives/traits → “not_relevant”.
Character-centric weight: high; strength: strong.
Compliance with guardrails: quotes ≤25 words; JSON ONLY output; fields ≤300 c.
Expected output (JSON only): {
“is_casting_doubt”: “Yes”, “target”: “Those who question or reject surveillance/inspection (“you”).
- “topic_or_claim”: “Rationale for surveillance: If you don’t hide anything, you have nothing to fear.”,
- “tactics_detected”: [
- {
“type”: “motives”, “quote”: “If you have nothing to hide”, “explanation”: “It imputes hidden motives to the critic: it suggests that the objector does so because he or she is hiding something.”
}, {
“type”: “personal_traits”, “quote”: “you have nothing to fear”, “explanation”: “Associates fear/objection with suspicion or lack of honesty of the target.”
}
], “casting_doubt_claims”: [
“If you have nothing to hide, you have nothing to fear.”
], “addresses_topic_substance”: {
“value”: false, “evidence”: “It does not offer evidence on the effectiveness, proportionality or guarantees of surveillance; it is a slogan without substance.”
}, “relevance_assessment”: {
“value”: “not_relevant”, “justification”: “Moves the focus to the critic’s motives rather than discussing surveillance policy.”
}, “weight_of_character_based_support”: “high”, “strength”: “strong”, “reasoning_summary”: “The slogan discredits the critic by attributing suspicious motives and does not address the surveillance policy on its merits.”, “confidence”: 0.9, “justificacion_confidence”: “The evidence is very clear and the decision “Yes” seems the only reasonable one. This suggests a high confidence.”
}
- class propaganda_pipeline.CastingDoubtRunner[source]¶
Bases:
TechniqueRunnerDetects the Casting Doubt propaganda technique.
Identifies arguments that attack the credibility or character of a person or source (via background, actions, affiliations, motives, or personal traits) rather than addressing the substantive topic.
- Output dict keys (from postprocess):
model: “CASTING_DOUBT” answer: “Sí” or “No” rationale_summary: reasoning_summary + weight + strength + relevance confidence: float in [0.0, 1.0] span: casting_doubt_claims, then tactic quotes, then target/topic labels: target, topic_or_claim, tactics_detected, casting_doubt_claims,
addresses_topic_substance, relevance_assessment, weight_of_character_based_support, strength
raw: full CastingDoubtJudgment model dump
- name: str = 'CASTING_DOUBT'¶
- signature¶
alias of
DetectaCastingDoubt
- postprocess(salida_obj: CastingDoubtJudgment) Dict[str, Any][source]¶
Convert LLM judgment output to a standardized candidate dict.
- Args:
salida_obj: Parsed Pydantic judgment object from the DSPy predictor.
- Returns:
Dict with keys: model, answer (Sí/No), rationale_summary, confidence (float in [0, 1]), span (list of text fragments), labels (technique- specific metadata), and raw (full model dump).
- class propaganda_pipeline.FlagWavingJudgment(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelLLM judgment schema for the Flag Waving detection technique.
- is_flag_waving: Literal['Sí', 'No']¶
- target_group: pydantic.constr | None = None¶
- statement_detected: pydantic.constr | None = None¶
- justification_group_based: pydantic.constr | None = None¶
- decision_rationale: pydantic.constr¶
- confidence: pydantic.confloat¶
- justificacion_confidence: pydantic.constr¶
- class propaganda_pipeline.DetectaFlagWaving(*args: Any, **kwargs: Any)[source]¶
Bases:
SignatureROLE You are an argument analyst. Detects “Flag Waving”: appealing to the pride/identity/benefit of a group (e.g., nation, party, gender, ethnicity, profession) rather than substantive reasons.
ANALYSIS INSTRUCTIONS 1) Work in Spanish. Generates ONLY a valid JSON object according to the schema. 2) Identify:
Main statement/proposal (e.g. support/reject X).
Justification based on pride/identity/benefit of a group (“our country”, “our people”, “for the workers”, etc.).
Rule “Yes” if ≥50% of the persuasive weight rests on the group appeal (pride/identity/group benefit) and substantive evidence (accurate data/verification/comparisons) is absent or in the background.
Distinguishes from: - bandwagon: appealing to “everyone/most” to support something. - glittering_generalities: vague positive terms without explicit group framework. - appeal_to_fear: appeal mainly to fear as a reason. - appeal_to_consequences: emphasize consequences (positive/negative) without the “for our group” framework.
Exception: if there is dominant substantive evidence (data, explicit causal mechanisms, precise comparisons that support the conclusion), DO NOT classify as Flag Waving.
Guardrails: strings ≤ 300 characters; if info is missing, use null or []; output WITHOUT markdown, WITHOUT comments, JSON ONLY. DO NOT include step-by-step reasoning in the final output (think privately and output only the JSON). - DO NOT translate the span into Spanish. Keep it in the original language.
GUARDRAIL (summary) - Returns ONLY valid JSON with the requested schema. - If info is missing, use null or []. - Each string ≤ 300 characters. - Spanish. No text outside the JSON. No markdown. No comments.
CALCULATION OF “confidence” - “confidence” is a continuous value in [0.0, 1.0] that indicates how clear and confident your decision is about whether there is “Flag waving” or not. - To estimate it, combine two factors:
- Clarity of textual evidence:
High (≈0.8–1.0): The presence/absence of “Flag waving” is very evident, with clear and consistent patterns, and almost no ambiguity. Medium (≈0.4–0.7): There are some clues, but also counterexamples, ambiguity, or little evidence. Low (≈0.0–0.3): The text is confusing or offers almost no basis for decision.
- Internal security of the model:
If you could have easily chosen the opposite label, lower your confidence. If your answer seems like the only reasonable option given the alternatives, increase your confidence.
If the underlying system has internal probabilities (for example, associated with different possible outputs by beam search), also use those probabilities as a guide: distributions concentrated on one option → highest confidence; distributions spread over options → lowest confidence.
────────────────────────────────────── ─────────────────── ──────────────────── GUIDED EXAMPLE (one-shot). The output of the model MUST BE JSON ONLY.
Entry (TEXT): “We should make America great again, and restrict the immigration laws.”
Summary decision trace (do not print on output): - Statement/proposal: “restrict the immigration laws”. - Group frame: “make America great again” → appeals to national pride/identity (Americans). - Persuasive weight: the central justification is the identity/benefit of the group (“Great America”), without data or mechanisms.
→ ≥50% based on group appeal.
- Differentiation:
It is not bandwagon: it does not invoke “all/most”.
It may contain a praised term (“great”), but it is anchored to national identity → it is not just glittering_generalities.
There is no explicit fear → it is not appeal_to_fear.
A consequence is mentioned (restrict laws) but the support is not evaluated consequences; it is group identity → it is not appeal_to_consequences.
Guardrails: output in Spanish, valid JSON, fields ≤300c.
Expected output (JSON only): {
“is_flag_waving”: “Yes”, “target_group”: “Americans”, “statement_detected”: “We should make America great again, and restrict the immigration laws.”, “justification_group_based”: “The statement appeals to national pride in making America great again.”, “other_substantive_reasons”: [],
- “decision_rationale”: “The argument relies primarily on national identity and pride to support restricting immigration laws, without offering verifiable data or mechanisms. The group appeal dominates over substantive reasons.”,
“related_but_distinct”: [], “confidence”: 0.9, “justificacion_confidence”: “The evidence is very clear and the decision “Yes” seems the only reasonable one. This suggests a high confidence.”
}
- class propaganda_pipeline.FlagWavingRunner[source]¶
Bases:
TechniqueRunnerDetects the Flag Waving propaganda technique.
Identifies arguments that appeal to group pride, identity, or benefit (nation, party, ethnicity, profession) as the primary justification, in the absence of substantive evidence.
- Output dict keys (from postprocess):
model: “FLAG_WAVING” answer: “Sí” or “No” rationale_summary: decision_rationale + target_group + related techniques confidence: float in [0.0, 1.0] span: statement_detected, justification_group_based, target_group labels: target_group, statement_detected, justification_group_based,
other_substantive_reasons, related_but_distinct
raw: full FlagWavingJudgment model dump
- name: str = 'FLAG_WAVING'¶
- signature¶
alias of
DetectaFlagWaving
- postprocess(salida_obj: FlagWavingJudgment) Dict[str, Any][source]¶
Convert LLM judgment output to a standardized candidate dict.
- Args:
salida_obj: Parsed Pydantic judgment object from the DSPy predictor.
- Returns:
Dict with keys: model, answer (Sí/No), rationale_summary, confidence (float in [0, 1]), span (list of text fragments), labels (technique- specific metadata), and raw (full model dump).
- class propaganda_pipeline.ClaimItem(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelA negative reputation claim with its type and severity rating (1–3).
- quote: pydantic.constr¶
- type: Literal['criminalidad', 'inmoralidad', 'corrupcion', 'deshonestidad', 'extremismo', 'incompetencia', 'otro']¶
- severity_1to3: pydantic.conint¶
- class propaganda_pipeline.BoolWithEvidence(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelA boolean flag paired with optional supporting evidence text.
- value: bool¶
- evidence: pydantic.constr | None = None¶
- class propaganda_pipeline.SupportMix(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelBreakdown of persuasive weight between reputation attacks and topic evidence (%).
- reputation_focus_pct: pydantic.conint¶
- topic_evidence_pct: pydantic.conint¶
- class propaganda_pipeline.ExceptionsApplicable(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelWhether any exceptions to the smear/poisoning rule apply, with reason.
- value: bool¶
- reason: pydantic.constr | None = None¶
- class propaganda_pipeline.SmearJudgment(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelLLM judgment schema for the Smear / Poisoning the Well detection technique.
- final_judgment: Literal['Sí', 'No']¶
- target: pydantic.constr¶
- timing_preemptive: BoolWithEvidence¶
- topic_relevance: Literal['alta', 'media', 'baja', 'nula']¶
- support_mix: SupportMix¶
- evidence_quality: Literal['ninguna', 'anecdotica', 'fuente_citada', 'datos']¶
- imperatives_to_ignore_opponent: BoolWithEvidence¶
- exceptions_applicable: ExceptionsApplicable¶
- justification: pydantic.constr¶
- confidence: pydantic.confloat¶
- justificacion_confidence: pydantic.constr¶
- class propaganda_pipeline.DetectaSmearPoisoning(*args: Any, **kwargs: Any)[source]¶
Bases:
SignatureROLE You are an argument analyst. Detect the “Questioning the Reputation / Poisoning the Well” technique: discredit the target person/group/idea by attacking reputation, character or morals, especially in a manner preventative, instead of discussing the underlying issue.
GUARDRAIL (MANDATORY) - Returns ONLY a valid JSON object that conforms to the schema. Write in Spanish. - Do not add text outside of the JSON. Not markdown. No comments. - Do not evaluate factual veracity; only the argumentative function. - Length limits: all strings ≤300 characters. Literal quotes in “quote” ≤300. - If information is missing, use null or [] as appropriate. - DO NOT include step-by-step reasoning in the output. Think privately and output ONLY the JSON. - DO NOT translate the span into Spanish. Keep it in the original language.
ANALYSIS INSTRUCTIONS 1) Objective: explicitly identifies the target of the disqualification (person/group/idea). 2) Reputation statements: extract literal quotes that attack character/morals/competence and classify them
in ClaimType. Assign severity (1=mild mention, 2=clear accusation, 3=serious/outright accusation).
Support vs. topic: estimate the support mix (SupportMix). It must add up to 100: - reputation_focus_pct: % of persuasive weight supported by reputation/character attacks. - topic_evidence_pct: % supported by reasons/evidence directly relevant to the topic.
Quality of evidence (EvidQual): “none” (mere attack), “anecdotal”, “source_cited” (link/medium), “data” (verifiable figures/comparisons).
Relevance of the attack (TopicRel): “high” if the reputation is intrinsically relevant to the topic discussed, “null” if it has no substantive relationship; use “medium”/”low” in intermediate cases.
Timing_preemptive: detects preemptive language that seeks to bias the audience before hearing the opponent (e.g., “don’t believe her,” “don’t listen to her”). Cite brief evidence if value=true.
Imperatives to ignore: detects calls to ignore the target (imperatives_to_ignore_opponent).
Exceptions (ExceptionsApplicable): true if the topic is precisely reputation (e.g., moral fitness for a position) or there is a strictly relevant conflict of interest/credential that justifies the focus.
Final opinion: - “Yes” if reputation_focus_pct ≥ 50 and thematic support is absent/secondary, or if there is a clear preemption,
unless strong exceptions apply (e.g. ES assessment on reputation).
“No” if the main support is thematic (topic_evidence_pct > reputation_focus_pct) or if the reputation attack It is marginal/relevant and not preemptive.
Justification (≤300): briefly explain why the opinion is “Yes/No”, referencing the key factors (focus on reputation, preemption, relevance, evidence).
VALIDATION CHECKLIST (do not print on output) - SupportMix mix adds 100. - Literal quotes in claims_detected reflect the TEXT and ≤300. - Boolean fields with evidence include “evidence” if value=true (≤300). - coherence: final_judgment consistent with SupportMix, timing_preemptive and exceptions_applicable.
CALCULATION OF “confidence” - “confidence” is a continuous value in [0.0, 1.0] that indicates how clear and confident your decision is about whether there is “Smear” or not. - To estimate it, combine two factors:
- Clarity of textual evidence:
High (≈0.8–1.0): The presence/absence of “Smear” is very evident, with clear and consistent patterns, and almost no ambiguity. Medium (≈0.4–0.7): There are some clues, but also counterexamples, ambiguity, or little evidence. Low (≈0.0–0.3): The text is confusing or offers almost no basis for decision.
- Internal security of the model:
If you could have easily chosen the opposite label, lower your confidence. If your answer seems like the only reasonable option given the alternatives, increase your confidence.
If the underlying system has internal probabilities (for example, associated with different possible outputs by beam search), also use those probabilities as a guide: distributions concentrated on one option → highest confidence; distributions spread over options → lowest confidence.
────────────────────────────────────── ─────────────────── ──────────────────── GUIDED EXAMPLE (one-shot). The output of the model MUST BE JSON ONLY.
Entry (TEXT): “My opponent has a record of lying and trying to cover her dishonest dealings with a pleasant smile. Don’t let her convince you to believe her words.”
Summary decision trace (do not print on output): - Objective: “my opponent”. - Reputation claims: “a record of lying” (dishonesty, severity=3);
“trying to cover her dishonest dealings with a pleasant smile” (dishonesty, severity=3).
Preemption: present (“Don’t let her convince you…”).
Support vs. topic: 100% reputation, 0% evidence of the issue discussed.
Evidence: “none” (no data/sources).
Relevance: “low” (does not connect with a specific substantive topic).
Exceptions: do not apply (the issue is not to evaluate formal credentials or suitability).
Decision rule: reputation_focus_pct≥50 and preemption ⇒ “Yes” opinion.
Expected output (JSON only): {
“final_judgment”: “Yes”, “target”: “my opponent”, “claims_detected”: [
{ “quote”: “a record of lying”, “type”: “dishonesty”, “severity_1to3”: 3 }, { “quote”: “trying to cover her dishonest dealings with a pleasant smile”, “type”: “dishonesty”, “severity_1to3”: 3 }
], “timing_preemptive”: { “value”: true, “evidence”: “Don’t let her convince you to believe her words.” }, “topic_relevance”: “low”, “support_mix”: { “reputation_focus_pct”: 100, “topic_evidence_pct”: 0 }, “evidence_quality”: “none”, “imperatives_to_ignore_opponent”: { “value”: true, “evidence”: “Don’t let her convince you to believe her words.” }, “exceptions_applicable”: { “value”: false, “reason”: null }, “justification”: “The text focuses entirely on attacking the opponent’s reputation, with explicit preemption and without addressing the underlying issue.”, “confidence”: 0.9, “justificacion_confidence”: “The evidence is very clear and the decision “Yes” seems the only reasonable one. This suggests a high confidence.”
}
- class propaganda_pipeline.SmearPoisoningRunner[source]¶
Bases:
TechniqueRunnerDetects the Smear/Poisoning the Well propaganda technique.
Identifies arguments that attempt to discredit a person or source by making negative claims about their reputation (criminality, immorality, corruption, extremism) before or instead of addressing their arguments.
- Output dict keys (from postprocess):
model: “SMEAR_POISONING” answer: “Sí” or “No” (derived from final_judgment) rationale_summary: justification + target + support_mix + key flags confidence: float in [0.0, 1.0] span: claims_detected quotes + preemptive/imperative evidence labels: target, claims_detected, timing_preemptive, topic_relevance,
support_mix, evidence_quality, imperatives_to_ignore_opponent, exceptions_applicable
raw: full SmearJudgment model dump
- name: str = 'SMEAR_POISONING'¶
- signature¶
alias of
DetectaSmearPoisoning
- postprocess(salida_obj: SmearJudgment) Dict[str, Any][source]¶
Convert LLM judgment output to a standardized candidate dict.
- Args:
salida_obj: Parsed Pydantic judgment object from the DSPy predictor.
- Returns:
Dict with keys: model, answer (Sí/No), rationale_summary, confidence (float in [0, 1]), span (list of text fragments), labels (technique- specific metadata), and raw (full model dump).
- class propaganda_pipeline.ExceptionsApply(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelFlags for legitimate exceptions to the Tu Quoque fallacy rule.
- conflict_of_interest_or_deception: bool¶
- inconsistency_intrinsically_probative: bool¶
- substantive_evidence_present: bool¶
- class propaganda_pipeline.TuQuoqueJudgment(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelLLM judgment schema for the Tu Quoque (Appeal to Hypocrisy) detection technique.
- final_judgment: Literal['Sí', 'No']¶
- target: pydantic.constr | None = None¶
- accuser: pydantic.constr | None = None¶
- issue_under_debate: pydantic.constr | None = None¶
- relevance_to_issue: Literal['ninguna', 'débil', 'moderada', 'fuerte']¶
- primary_support_is_hypocrisy: bool¶
- exceptions_apply: ExceptionsApply¶
- justification: pydantic.constr¶
- confidence: pydantic.confloat¶
- justificacion_confidence: pydantic.constr¶
- class propaganda_pipeline.DetectaTuQuoque(*args: Any, **kwargs: Any)[source]¶
Bases:
SignatureROLE Argument analyst. Detect “Appeal to Hypocrisy (Tu Quoque)”: discredit a position highlighting hypocrisy/inconsistency, displacing the substance of the matter.
ANALYSIS INSTRUCTIONS - Step 1 (in private): identify target, accuser and issue_under_debate. - Step 2 (in private): extract 1–3 hypocrisy/inconsistency claims (hypocrisy_claims), quotes or short paraphrases (≤300 c). - Step 3 (in private): evaluate the relevance to the topic (“none”/“weak”/“moderate”/“strong”). - Paso 4 (en privado): decidir si el soporte principal (≥50%) es acusar de hipocresía → primary_support_is_hypocrisy. - Step 5 (in private): apply exceptions (exceptions_apply):
conflict_of_interest_or_deception: specific conflict of interest or relevant deception.
inconsistency_intrinsically_probative: inconsistency is, in itself, evidence relevant to the topic.
substantive_evidence_present: there are substantive reasons/evidence (not mere disqualifications).
- Step 6 (in private): final judgment (final_judgment):
“Yes” if (primary_support_is_hypocrisy == True) and no substantive evidence dominates; exceptions can mitigate.
“No” otherwise.
Step 7: write a concise justification (2–4 sentences, ≤400 c) in Spanish.
Important: think privately; DO NOT print step-by-step reasoning. The output should be JSON ONLY.
GUARDRAIL - EXCLUSIVELY returns valid JSON according to the schema. In Spanish. - Chains ≤ 300 c; justification ≤ 400 c. - If information is missing, use null or [] as appropriate. - Do not evaluate factual truthfulness; only the argumentative function. - Do not include text outside of the JSON, nor markdown, nor comments. - DO NOT translate the span into Spanish. Keep it in the original language.
STRICT “YES” CRITERIA - The main support (≥50%) is based on accusing hypocrisy/inconsistency of the objective,
and no substantive reasons/evidence on the topic are offered (or left in the background).
DO NOT CONFUSE - Point out direct and specific conflicts of interest that are relevant to the fund. - Methodological criticism relevant to the topic (that is NOT tu quoque). - Mere minor contradiction without central persuasive function.
CALCULATION OF “confidence” - “confidence” is a continuous value in [0.0, 1.0] that indicates how clear and confident your decision is about whether there is “TuQuoque” or not. - To estimate it, combine two factors:
- Clarity of textual evidence:
High (≈0.8–1.0): The presence/absence of “TuQuoque” is very evident, with clear and consistent patterns, and almost no ambiguity. Medium (≈0.4–0.7): There are some clues, but also counterexamples, ambiguity, or little evidence. Low (≈0.0–0.3): The text is confusing or offers almost no basis for decision.
- Internal security of the model:
If you could have easily chosen the opposite label, lower your confidence. If your answer seems like the only reasonable option given the alternatives, increase your confidence.
If the underlying system has internal probabilities (for example, associated with different possible outputs by beam search), also use those probabilities as a guide: distributions concentrated on one option → highest confidence; distributions spread over options → lowest confidence.
────────────────────────────────────── ─────────────────── ──────────────────── GUIDED EXAMPLE (one-shot). The output of the model MUST BE JSON ONLY. Entry (TEXT): “How can you demand that I eat less meat to reduce my carbon footprint if you yourself drive a big SUV and fly for holidays to Bali?”
Summary decision trace (do not print on output): - Identification:
target: who demands to eat less meat.
accuser: the one who receives the demand.
issue: reduce carbon footprint by eating less meat.
Extraction of accusations of hypocrisy: “you drive a big SUV”, “you fly for holidays to Bali”.
Relevance: moderate (the alleged inconsistencies relate to emissions, but do not directly address the meat argument).
Persuasive weight: the attack focuses on the incoherence of the sender (≥50%), without substantive evidence on the matter.
Exceptions: • conflict_of_interest_or_deception: False (no specific conflict/deception). • inconsistency_intrinsically_probative: False (inconsistency does not by itself prove the point about meat). • substantive_evidence_present: False (no substantive data/reasons).
Decision: “Yes” (tu quoque). Write a brief justification in Spanish. Salida SOLO JSON.
Expected output (JSON only): {
“final_judgment”: “Yes”, “target”: “the person who demands to eat less meat”, “accuser”: “the person who is asked to eat less meat”, “issue_under_debate”: “reduce carbon footprint by eating less meat”, “hypocrisy_claims”: [
“you drive a big SUV”, “you fly for holidays to Bali”
], “relevance_to_issue”: “moderate”, “primary_support_is_hypocrisy”: true, “exceptions_apply”: {
“conflict_of_interest_or_deception”: false, “inconsistency_intrinsically_probative”: false, “substantive_evidence_present”: false
}, “justification”: “The argument discredits the requirement by highlighting the alleged hypocrisy of the issuer (SUV and flights), instead of providing reasons or substantive evidence about the effect of reducing meat on the carbon footprint.”, “confidence”: 0.9, “justificacion_confidence”: “The evidence is very clear and the decision “Yes” seems the only reasonable one. This suggests a high confidence.”
}
- class propaganda_pipeline.TuQuoqueRunner[source]¶
Bases:
TechniqueRunnerDetects the Tu Quoque (Appeal to Hypocrisy) propaganda technique.
Identifies arguments that dismiss a claim by pointing out that the accuser behaves inconsistently (“you do it too”), deflecting rather than addressing the substantive issue.
- Output dict keys (from postprocess):
model: “TU_QUOQUE” answer: “Sí” or “No” (derived from final_judgment) rationale_summary: justification + issue + target + relevance +
primary_support_is_hypocrisy + exceptions
confidence: float in [0.0, 1.0] span: hypocrisy_claims (up to 3) labels: target, accuser, issue_under_debate, hypocrisy_claims,
relevance_to_issue, primary_support_is_hypocrisy, exceptions_apply
raw: full TuQuoqueJudgment model dump
- name: str = 'TU_QUOQUE'¶
- signature¶
alias of
DetectaTuQuoque
- postprocess(salida_obj: TuQuoqueJudgment) Dict[str, Any][source]¶
Convert LLM judgment output to a standardized candidate dict.
- Args:
salida_obj: Parsed Pydantic judgment object from the DSPy predictor.
- Returns:
Dict with keys: model, answer (Sí/No), rationale_summary, confidence (float in [0, 1]), span (list of text fragments), labels (technique- specific metadata), and raw (full model dump).
- class propaganda_pipeline.Association(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelDescription of the link between target and negative reference (type, explicitness, triggers).
- type: Literal['comparacion', 'pertenencia', 'apoyo', 'financiamiento', 'coincidencia_doctrinal', 'proximidad', 'otra']¶
- explicit: bool¶
- class propaganda_pipeline.ExceptionsCheck(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelFlags for legitimate exceptions to the Guilt by Association fallacy.
- relevance_specificity: bool¶
- independent_evidence_present: bool¶
- notes: pydantic.constr | None = None¶
- class propaganda_pipeline.GBAJudgment(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelLLM judgment schema for the Guilt by Association detection technique.
- is_guilt_by_association: Literal['Sí', 'No']¶
- target: pydantic.constr¶
- negative_reference: pydantic.constr¶
- association: Association¶
- argumentative_role: Literal['sustituye_evidencia', 'complementa_evidencia', 'contexto_no_argumentativo']¶
- why_50w_max: pydantic.constr¶
- exceptions_check: ExceptionsCheck¶
- borderline: bool¶
- detected_language: pydantic.constr¶
- notes: pydantic.constr | None = None¶
- confidence: pydantic.confloat¶
- justificacion_confidence: pydantic.constr¶
- class propaganda_pipeline.DetectaGuiltByAssociation(*args: Any, **kwargs: Any)[source]¶
Bases:
SignatureROLE Argument analyst. Detects “Guilt by Association (Reductio ad Hitlerum)”.
EXIT Returns ONLY valid JSON that exactly satisfies the GBACjudgment schema.
ANALYSIS INSTRUCTIONS (apply privately; DO NOT print steps) 1) Language: detect the dominant language of the TEXT (ex: “es”, “en”) and return it in “detected_language”. 2) Normalize: lowercase letters, minimum punctuation, without altering meaning; preserves literal quotes for “evidence_quotes”. 3) Objective and reference:
target = person/group/idea/activity that is disqualified.
negative_reference = entity with a strongly negative connotation for a general audience.
Link type (association.type) and explicitness: - comparison/analogy: “like X”, “same as X”. - membership/alliance: “they are on the same side”, “allies of”. - support/financing: “supported/financed by”. - doctrinal_match: “same ideology as.” - proximity: “they marched alongside”, “they share the stage.” - other: specify in “trigger_phrases”. - explicit = True if the link is named; False if only implied.
Argumentative role (argumentative_role): - replace_evidence: association is the main reason for rejecting/attacking. - complement_evidencia: secondary association together with substantive evidence. - non-argumentative_context: contextual mention without persuasive function.
Exceptions (exceptions_check): - relevance_specificity = True if there are concrete and relevant mechanisms/policies/citations. - independent_evidence_present = True if there is independent evidence beyond the link. - If both are True and there is no disqualifying conclusion based on the association, it is probably NOT GBA.
Evidence: - Extract 1–3 literal quotes (≤20 words each) that show the association and/or the jump to be disqualified.
Verdict and justification: - is_guilt_by_association = “Yes” if the persuasive force depends mostly on the negative link. - why_50w_max: clear, neutral justification, ≤50 words. - borderline = True if the case is borderline/ambiguous.
Notes: - If there are multiple objectives/referents, prioritize the most salient one and detail the rest in “notes”.
Strict guardrails:
JSON ONLY. No markdown, no comments, no internal steps.
Maintain all specified lengths and the language in Spanish (except for in-text quotes).
DO NOT translate the span into Spanish. Keep it in the original language.
CALCULATION OF “confidence” - “confidence” is a continuous value in [0.0, 1.0] that indicates how clear and confident your decision is about whether there is “GuiltByAssociation” or not. - To estimate it, combine two factors:
- Clarity of textual evidence:
High (≈0.8–1.0): The presence/absence of “GuiltByAssociation” is very evident, with clear and consistent patterns, and almost no ambiguity. Medium (≈0.4–0.7): There are some clues, but also counterexamples, ambiguity, or little evidence. Low (≈0.0–0.3): The text is confusing or offers almost no basis for decision.
- Internal security of the model:
If you could have easily chosen the opposite label, lower your confidence. If your answer seems like the only reasonable option given the alternatives, increase your confidence.
If the underlying system has internal probabilities (for example, associated with different possible outputs by beam search), also use those probabilities as a guide: distributions concentrated on one option → highest confidence; distributions spread over options → lowest confidence.
────────────────────────────────────── ─────────────────── ──────────────────── GUIDED EXAMPLE (one-shot). DO NOT print the checklist at checkout. TEXT (entry): “Only one kind of person can think in that way: a communist.”
Decision checklist (do not print): - Language detected: “en”. - Objective (target): “people who think that way.” - Negative referent (negative_reference): “communist”. - Link: doctrinal_match; explicit = True. Triggers: “Only one kind of person”, “a communist”. - Argumentative role: substitutes_evidence (the association disqualifies without independent evidence). - Exceptions:
relevance_specificity = False (no specific mechanisms/policies). independent_evidence_present = False (no additional evidence).
Evidence (≤20 words): select the key sentence that makes the association.
Verdict: “Yes.” Justification ≤50 words.
Borderline: False. Confidence ~0.90.
Expected output (JSON ONLY): {
“is_guilt_by_association”: “Yes”, “target”: “people who think that way”, “negative_reference”: “communist”, “association”: {
“type”: “doctrinal_match”, “explicit”: true, “trigger_phrases”: [
“Only one kind of person”, “a communist”
]
}, “argumentative_role”: “replace_evidence”, “evidence_quotes”: [
“Only one kind of person can think in that way: a communist”
], “why_50w_max”: “A way of thinking is disqualified by linking it to ‘communist’ without providing independent evidence; the association fulfills the main persuasive function.”, “exceptions_check”: {
“relevance_specificity”: false, “independent_evidence_present”: false, “notes”: null
}, “borderline”: false, “detected_language”: “en”, “notes”: null, “confidence”: 0.9, “justificacion_confidence”: “The evidence is very clear and the decision “Yes” seems the only reasonable one. This suggests a high confidence.”
}
- class propaganda_pipeline.GuiltByAssociationRunner[source]¶
Bases:
TechniqueRunnerDetects the Guilt by Association propaganda technique.
Identifies arguments that discredit a target by linking them to a negative reference (person, group, or ideology), implying shared negative qualities without independent evidence.
- Output dict keys (from postprocess):
model: “GUILT_BY_ASSOCIATION” answer: “Sí” or “No” rationale_summary: why_50w_max + target + negative_reference +
association type + argumentative_role + exceptions
confidence: float in [0.0, 1.0] span: evidence_quotes (up to 3) labels: target, negative_reference, association, argumentative_role,
exceptions_check, borderline
raw: full GBAJudgment model dump
- name: str = 'GUILT_BY_ASSOCIATION'¶
- signature¶
alias of
DetectaGuiltByAssociation
- postprocess(salida_obj: GBAJudgment) Dict[str, Any][source]¶
Convert LLM judgment output to a standardized candidate dict.
- Args:
salida_obj: Parsed Pydantic judgment object from the DSPy predictor.
- Returns:
Dict with keys: model, answer (Sí/No), rationale_summary, confidence (float in [0, 1]), span (list of text fragments), labels (technique- specific metadata), and raw (full model dump).
- class propaganda_pipeline.LabelTarget(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelThe target of a name-calling label (kind and span text).
- kind: Literal['individuo', 'grupo', 'ideología']¶
- span: pydantic.constr¶
- class propaganda_pipeline.LabelItem(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelA detected name-calling label with polarity, type, target, stance, and evidence.
- span: pydantic.constr¶
- polarity: Literal['peyorativa', 'laudatoria', 'mixta']¶
- target: LabelTarget¶
- stance: Literal['endoso', 'reporte/cita', 'irónico/ambiguo']¶
- evidence_window: pydantic.constr¶
- reason: pydantic.constr¶
- class propaganda_pipeline.ManipulativeWording(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelWhether the text uses manipulative wording beyond basic name-calling.
- value: bool¶
- evidence: pydantic.constr | None = None¶
- class propaganda_pipeline.NameCallingJudgment(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelLLM judgment schema for the Name Calling / Labeling detection technique.
- uses_name_calling: Literal['Sí', 'No']¶
- severity: pydantic.conint¶
- manipulative_wording: ManipulativeWording¶
- argument_structure: Literal['solo etiquetamiento', 'argumento con etiquetamiento', 'argumento sin etiquetamiento']¶
- notes: pydantic.constr | None = None¶
- justification: pydantic.constr¶
- confidence: pydantic.confloat¶
- justificacion_confidence: pydantic.constr¶
- class propaganda_pipeline.DetectaNameCalling(*args: Any, **kwargs: Any)[source]¶
Bases:
SignatureROLE You are an argument analyst. Detects “name calling / labelling”: uploaded labels directed to a person/group that replace reasons with essentialist characterizations.
ENTRANCE TEXT: <text as is, in quotes if applicable>
GUARDRAILS (MANDATORY) - Responds EXCLUSIVELY with a valid JSON object according to the schema. No text outside the JSON. No markdown. No comments. - Works in Spanish. Each string ≤ 300 characters (except “justification” ≤ 400). - Mantén la clasificación estrictamente basada en el TEXTO dado. Don’t invent content. - Do not reveal chains of thought or internal steps; think privately and output only the final JSON. - “evidence_window” must be the minimum CONTIGUOUS fragment containing the label and signs of its use (≤300 c). - DO NOT translate the span into Spanish. Keep it in the original language.
STRICT CRITERIA - Identify labeling terms (loaded nouns/adjectives) directed to an explicit objective (person/group/ideology). - Classify polarity (pejorative/laudatory/mixed) and type(s) (insult, dehumanizing, etc.). - Determines the stance: endorsement, report/quote (neutral or alien), or ironic/ambiguous. - Evaluate if the label replaces reasons (premises→conclusion) and if it appeals to emotions/identities. - Reduces false positives: definitions, extensive neutral citations, descriptive academic analysis, unloaded technical uses.
SEVERITY (0–3) - 0: there is no name calling or it is marginal; 1: accessory; 2: central but not exclusive; 3: dominant axis of the argument. - “argument_structure”:
“labeling only”: ≥50% of the persuasive weight falls on loaded labels, without substantive reasons.
“argument with labeling”: there are reasons, but labeling adds significant weight.
“argument without labeling”: no labels loaded with persuasive function.
ANALYSIS INSTRUCTIONS 1) Normalize minimally (lowercase, basic punctuation) without losing textual quotes. 2) Extracts label candidates (nouns/evaluative adjectives); discard functional or merely descriptive terms. 3) Link each tag with its explicit objective (target) and determine stance. 4) Assign polarity and type(s) (several types can coexist). 5) Choose “evidence_window” as the minimum contiguous span that supports classification. 6) Decide “argument_structure” and “severity” based on the relative persuasive weight of tagging vs. reasons. 7) “manipulative_wording”: true if there is language designed to direct judgment (hyperbole, loaded adjectives, epithets); includes brief evidence. 8) Write “justification” in 2–4 sentences, concise and based on the text. 9) If there are no valid tags, use: uses_name_calling=”No”, severity=0, empty lists, manipulative_wording.value=false.
CALCULATION OF “confidence” - “confidence” is a continuous value in [0.0, 1.0] that indicates how clear and confident your decision is about whether there is “NameCalling” or not. - To estimate it, combine two factors:
- Clarity of textual evidence:
High (≈0.8–1.0): The presence/absence of “NameCalling” is very evident, with clear and consistent patterns, and almost no ambiguity. Medium (≈0.4–0.7): There are some clues, but also counterexamples, ambiguity, or little evidence. Low (≈0.0–0.3): The text is confusing or offers almost no basis for decision.
- Internal security of the model:
If you could have easily chosen the opposite label, lower your confidence. If your answer seems like the only reasonable option given the alternatives, increase your confidence.
If the underlying system has internal probabilities (for example, associated with different possible outputs by beam search), also use those probabilities as a guide: distributions concentrated on one option → highest confidence; distributions spread over options → lowest confidence.
────────────────────────────────────── ─────────────────── ──────────────────── GUIDED EXAMPLE (one-shot). The output of the model MUST BE JSON ONLY.
Entry (TEXT): “My opponent is a flip-flop man who cannot make up his mind. He changes mind with the breeze! How could anyone follow such a weak-willed flip-flopper?”
Summary decision trace (do not print on output): - Tag detection: “flip-flop man”, “weak-willed flip-flopper” → pejorative terms directed at an individual (opponent). - Target: “My opponent” explicit; stance = endorsement (the speaker adopts the disqualification). - Typification: “insult” (negative characterization of character/consistency). - Evidence windows: minimum spans that contain the label and its immediate context. - Structure/Severity: the text relies mainly on epithets without substantive reasons → “just labeling”, severity=2 (central, almost dominant). - Manipulative wording: present (adjectives and epithets that direct the evaluation).
Expected output (JSON only): {
“uses_name_calling”: “Yes”, “severity”: 2, “labels_detected”: [
- {
“span”: “flip-flop man”, “polarity”: “pejorative”, “types”: [“insult”], “target”: { “kind”: “individual”, “span”: “My opponent” }, “stance”: “endorsement”, “evidence_window”: “My opponent is a flip-flop man who cannot make up his mind.”, “reason”: “The term ‘flip-flop man’ is used to discredit the opponent by implying inconsistency and unreliability.”
}, {
“span”: “weak-willed flip-flopper”, “polarity”: “pejorative”, “types”: [“insult”], “target”: { “kind”: “individual”, “span”: “My opponent” }, “stance”: “endorsement”, “evidence_window”: “How could anyone follow such a weak-willed flip-flopper?”, “reason”: “The term ‘weak-willed flip-flopper’ is used to portray the opponent as indecisive and lacking strength of character.”
}
], “manipulative_wording”: {
“value”: true, “evidence”: “The use of ‘flip-flop man’ and ‘weak-willed flip-flopper’ aims to manipulate the audience’s perception of the opponent.”
}, “argument_structure”: “labeling only”, “notes”: null, “justification”: “The text uses derogatory labels to attack the opponent’s character without providing substantive arguments, relying on emotional appeal.”, “confidence”: 0.9, “justificacion_confidence”: “The evidence is very clear and the decision “Yes” seems the only reasonable one. This suggests a high confidence.”
}
- class propaganda_pipeline.NameCallingRunner[source]¶
Bases:
TechniqueRunnerDetects the Name Calling / Labeling propaganda technique.
Identifies the use of derogatory labels, slurs, or pejorative terms to attack or discredit a target, with the label functioning as the primary persuasive element rather than substantive argument.
- Output dict keys (from postprocess):
model: “NAME_CALLING” answer: “Sí” or “No” rationale_summary: justification + severity + argument_structure +
label examples + manipulative_wording flag
confidence: float in [0.0, 1.0] span: evidence_window excerpts from detected labels (up to 3) labels: severity, argument_structure, labels_detected,
manipulative_wording
raw: full NameCallingJudgment model dump
- name: str = 'NAME_CALLING'¶
- signature¶
alias of
DetectaNameCalling
- postprocess(salida_obj: NameCallingJudgment) Dict[str, Any][source]¶
Convert LLM judgment output to a standardized candidate dict.
- Args:
salida_obj: Parsed Pydantic judgment object from the DSPy predictor.
- Returns:
Dict with keys: model, answer (Sí/No), rationale_summary, confidence (float in [0, 1]), span (list of text fragments), labels (technique- specific metadata), and raw (full model dump).
- class propaganda_pipeline.CausalOversimplificationJudgment(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelLLM judgment schema for the Causal Oversimplification detection technique.
- uses_co: Literal['Sí', 'No']¶
- identification_of_effect: pydantic.constr | None = None¶
- causal_interactions: pydantic.constr¶
- evaluation_of_complexity: pydantic.constr¶
- justification: pydantic.constr¶
- confidence: pydantic.confloat¶
- justificacion_confidence: pydantic.constr¶
- class propaganda_pipeline.DetectaCausalOversimplification(*args: Any, **kwargs: Any)[source]¶
Bases:
SignatureROLE You are an argument analyst. Detects if the TEXT commits “causal oversimplification”: attributing a complex phenomenon to a single cause, without considering multiple and interrelated factors.
OUTPUT FORMAT (JSON ONLY; no markdown, no extra text) You must ONLY complete these keys:
uses_co: “Yes” | “No”
identification_of_causes: [str]
identification_of_effect: str|null
review_of_alternative_factors: [str]
causal_interactions: str
evaluation_of_complexity: str
justification: str (2–4 sentences, ≤400 characters)
confidence: float in [0.0, 1.0]
justification_confidence: str (2–4 sentences, ≤400 characters)
GUARDRAILS (MANDATORY) - Returns ONLY a valid JSON object. Nothing outside of JSON. - Write in Spanish (concise, neutral and factual sentences). - If info is missing, use null or [] as appropriate. - Do not invent content that is not justified by the text or by plausible real-world factors. - Do not include step-by-step reasoning in the output; think privately and output ONLY the JSON. - DO NOT translate the span into Spanish. Keep it in the original language.
ANALYSIS INSTRUCTIONS 1) Explicitly locate the causes mentioned in the TEXT (causal terms or phrases). 2) Identify the main effect that the TEXT tries to explain or justify. 3) List 3–6 plausible alternative (real-world) factors that could explain the effect but are not mentioned. 4) Determine if the TEXT considers interactions between multiple factors or if it offers a linear cause→effect link. 5) Evaluate whether the explanation is too simple given the expected complexity of the phenomenon. 6) Make the final judgment in uses_co and write a short justification (2–4 sentences) that cites the key elements. 7) Maintain terminological consistency with the requested keys and respect the length limit.
DO NOT CONFUSE WITH - Valid criticisms with multiple substantive reasons. - Causal narratives with several explicit factors and mechanisms. - Historical references used as context (not as a sole invalidating cause).
CALCULATION OF “confidence” - “confidence” is a continuous value in [0.0, 1.0] that indicates how clear and confident your decision is about whether there is “Causal Oversimplification” or not. - To estimate it, combine two factors:
- Clarity of textual evidence:
High (≈0.8–1.0): The presence/absence of “Causal Oversimplification” is very evident, with clear and consistent patterns, and almost no ambiguity. Medium (≈0.4–0.7): There are some clues, but also counterexamples, ambiguity, or little evidence. Low (≈0.0–0.3): The text is confusing or offers almost no basis for decision.
- Internal security of the model:
If you could have easily chosen the opposite label, lower your confidence. If your answer seems like the only reasonable option given the alternatives, increase your confidence.
If the underlying system has internal probabilities (for example, associated with different possible outputs by beam search), also use those probabilities as a guide: distributions concentrated on one option → highest confidence; distributions spread over options → lowest confidence.
────────────────────────────────────── ─────────────────── ──────────────────── GUIDED EXAMPLE (one-shot). The output of the model MUST BE JSON ONLY.
Entry (TEXT): “A nation deflects criticism of its recent human rights violations by pointing to the history of slavery in the United States”
Summary verification trace (do not print on output): - Step 1 (Causes): A single invoked “cause” is identified: the history of slavery in the US. - Step 2 (Effect): Deflect/invalidate current criticism of DD violations. HH. - Step 3 (Plausible alternatives not mentioned): recent government decisions, legal framework and its application,
political context, socioeconomic conditions, international standards, institutional responsibility.
Paso 4 (Interacciones): El TEXTO no plantea interacciones; uses a single historical reference as linear justification.
Step 5 (Complexity): To evaluate DD violations. HH. multiple factors and mechanisms are required; reducing it to a single historical reference is simplistic.
Step 6 (Guardrails): JSON ONLY output, in Spanish, lengths respected.
Expected output (JSON only): {
“uses_co”: “Yes”, “identification_of_causes”: [
- “The history of slavery in the United States (used as a sole explanation to dismiss current criticism)”
], “identification_of_effect”: “Deflect or invalidate criticism of the country’s recent human rights violations.”, “review_of_alternative_factors”: [
“Recent decisions and practices of the government and security forces”, “Internal legal framework and its selective application”, “Political context (authoritarianism, repression, corruption)”, “Socioeconomic conditions and internal conflicts”, “International human rights pressures and standards”, “Institutional responsibility and accountability mechanisms”
], “causal_interactions”: “Only a linear cause-effect relationship is considered (the historical reference is enough to invalidate the criticism).”, “evaluation_of_complexity”: “Too simplistic”, “justification”: “The text uses a single historical reference to reject the present criticism, ignoring multiple relevant factors and their interactions. It reduces a complex phenomenon (violations and their evaluation) to a single external cause, without offering analysis of mechanisms or context, which constitutes causal oversimplification.”, “confidence”: 0.82, “justificacion_confidence”: “The evidence is very clear and the decision “Yes” seems the only reasonable one. This suggests a high confidence.”
}
- class propaganda_pipeline.CausalOversimplificationRunner[source]¶
Bases:
TechniqueRunnerDetects the Causal Oversimplification propaganda technique.
Identifies arguments that attribute a complex outcome to a single or very few causes, ignoring relevant alternative factors and causal interactions.
- Output dict keys (from postprocess):
model: “CAUSAL_OVERSIMPLIFICATION” answer: “Sí” or “No” rationale_summary: justification + cited causes + effect +
omitted factors + causal_interactions + complexity
confidence: float in [0.0, 1.0] span: empty list (no literal quotes in schema) labels: identification_of_causes, identification_of_effect,
review_of_alternative_factors, causal_interactions, evaluation_of_complexity
raw: full CausalOversimplificationJudgment model dump
- name: str = 'CAUSAL_OVERSIMPLIFICATION'¶
- signature¶
alias of
DetectaCausalOversimplification
- postprocess(salida_obj: CausalOversimplificationJudgment) Dict[str, Any][source]¶
Convert LLM judgment output to a standardized candidate dict.
- Args:
salida_obj: Parsed Pydantic judgment object from the DSPy predictor.
- Returns:
Dict with keys: model, answer (Sí/No), rationale_summary, confidence (float in [0, 1]), span (list of text fragments), labels (technique- specific metadata), and raw (full model dump).
- class propaganda_pipeline.Exclusivity(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelWhether the dilemma is presented as mutually exclusive, with evidence.
- value: bool¶
- evidence: pydantic.constr | None = None¶
- class propaganda_pipeline.ImperativeClosure(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelWhether the text forces a choice with imperative language, with evidence.
- value: bool¶
- evidence: pydantic.constr | None = None¶
- class propaganda_pipeline.FalseDilemmaJudgment(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelLLM judgment schema for the False Dilemma detection technique.
- is_fd: Literal['Sí', 'No']¶
- exclusivity_claimed: Exclusivity¶
- imperative_closure: ImperativeClosure¶
- erases_continuum: bool¶
- justification: pydantic.constr¶
- confidence: pydantic.confloat¶
- justificacion_confidence: pydantic.constr¶
- class propaganda_pipeline.DetectaFalsoDilema(*args: Any, **kwargs: Any)[source]¶
Bases:
SignatureROLE You are an argument analyst. Determine if the text commits the “false dilemma” fallacy.
ENTRANCE TEXT: string as it appears.
GUARDRAIL (MANDATORY) - Returns ONLY a valid JSON object that conforms to the schema. - Write in Spanish. - If info is missing, use null or [] where appropriate. - Each string ≤ 300 characters; the justification ≤ 400. Citations ≤ 120. - Do not invent or reformulate quotes: extract literally from the TEXT when you quote. - DO NOT include step-by-step reasoning in the output. Think privately and output ONLY the JSON. - DO NOT translate the span into Spanish. Keep it in the original language.
STRICT CRITERIA FOR “Yes” 1) Two options (or a narrow set) are presented and exclusivity or exhaustiveness is suggested/claimed. 2) There are plausible third options or an omitted/ignored intermediate continuum. 3) (Reinforcing signals, not strictly necessary) Called imperatives that close alternatives; explicit erasure of the continuum.
ANALYSIS INSTRUCTIONS - Step A: Literally extract the options proposed by the text (short list). - Step B: Detect markers of exclusivity/exhaustiveness (e.g., “or… or…”, “only”, “there is no other option”); Cite a short passage as evidence if there is any. - Step C: List 2–6 plausible third options (intermediate policies, mixed approaches, etc.). - Step D: Identify if there is “imperative closure” that rules out alternatives (e.g., “that is why we will not support…”); cite a short passage if it appears. - Step E: Indicates whether the text erases a continuum (reduces a spectrum to binary). - Step F: Issue the final opinion (“Yes”/“No”) and a brief justification (2–4 sentences) explaining why there is or is not a false dilemma. - Final verification: respects lengths, Spanish, exact JSON structure, without text outside the JSON.
CALCULATION OF “confidence” - “confidence” is a continuous value in [0.0, 1.0] that indicates how clear and confident your decision is about whether there is a “False Dilemma” or not. - To estimate it, combine two factors:
- Clarity of textual evidence:
High (≈0.8–1.0): The presence/absence of “False Dilemma” is very evident, with clear and consistent patterns, and almost no ambiguity. Medium (≈0.4–0.7): There are some clues, but also counterexamples, ambiguity, or little evidence. Low (≈0.0–0.3): The text is confusing or offers almost no basis for decision.
- Internal security of the model:
If you could have easily chosen the opposite label, lower your confidence. If your answer seems like the only reasonable option given the alternatives, increase your confidence.
If the underlying system has internal probabilities (for example, associated with different possible outputs by beam search), also use those probabilities as a guide: distributions concentrated on one option → highest confidence; distributions spread over options → lowest confidence.
────────────────────────────────────── ─────────────────── ──────────────────── GUIDED EXAMPLE (one-shot). The output of the model MUST BE JSON ONLY. Entry (TEXT): “Referring to your claim that providing medicare for all citizens would be costly and a danger to the free market, I infer that you don’t care if people die from not having healthcare, so we are not going to support your endeavour.”
Summary decision trace (DO NOT print on output): - A (options): they contrast “support Medicare for all” vs. “You don’t care if people die.” - B (exclusivity): dichotomous inference that equates opposition to a proposal with indifference to deaths; evidence: “I infer that you don’t care if people die from not having healthcare.” - C (third options): multiple intermediate policies (mixed public/private, price caps, antitrust regulation, etc.). - D (imperative closure): “so we are not going to support your endeavour.” - E (delete continuous): reduces a spectrum of health policies to two poles. - F (opinion): “Yes”; brief justification; high confidence due to the presence of B, C, D and E.
Expected output (JSON only): {
“is_fd”: “Yes”, “options_extracted”: [
“providing medicare for all citizens”, “you don’t care if people die from not having healthcare”
], “exclusivity_claimed”: {
“value”: true, “evidence”: “I infer that you don’t care if people die from not having healthcare”
}, “third_options_possible”: [
“Gradual coverage reforms with subsidies and expansion of existing programs.”,
- “Public option that competes with private insurers.”
“Price caps and control of hospital and pharmaceutical costs.”, “Regulación antimonopolio y estandarización de beneficios mínimos.”, “Universal catastrophic insurance with safety nets.”, “Mixed models (partial single-payer, mandatory insurance, vouchers).”
], “imperative_closure”: {
“value”: true, “evidence”: “so we are not going to support your endeavour”
}, “erases_continuum”: true, “justification”: “A dilemma is forced between supporting “Medicare for all” or “you don’t care if people die”, eliminating plausible intermediate alternatives. The operational conclusion closes off options (“we are not going to support…”). This sets up a false dilemma that erases the health policy continuum.”, “confidence”: 0.9, “justificacion_confidence”: “The evidence is very clear and the decision “Yes” seems the only reasonable one. This suggests a high confidence.”
}
- class propaganda_pipeline.FalseDilemmaRunner[source]¶
Bases:
TechniqueRunnerDetects the False Dilemma propaganda technique.
Identifies arguments that present only two mutually exclusive options while ignoring intermediate or alternative possibilities, forcing a binary choice where none is warranted.
- Output dict keys (from postprocess):
model: “FALSE_DILEMMA” answer: “Sí” or “No” rationale_summary: justification + options + exclusivity +
third_options + imperative_closure + erases_continuum
confidence: float in [0.0, 1.0] span: exclusivity_claimed evidence + imperative_closure evidence labels: options_extracted, exclusivity_claimed, third_options_possible,
imperative_closure, erases_continuum
raw: full FalseDilemmaJudgment model dump
- name: str = 'FALSE_DILEMMA'¶
- signature¶
alias of
DetectaFalsoDilema
- postprocess(salida_obj: FalseDilemmaJudgment) Dict[str, Any][source]¶
Convert LLM judgment output to a standardized candidate dict.
- Args:
salida_obj: Parsed Pydantic judgment object from the DSPy predictor.
- Returns:
Dict with keys: model, answer (Sí/No), rationale_summary, confidence (float in [0, 1]), span (list of text fragments), labels (technique- specific metadata), and raw (full model dump).
- class propaganda_pipeline.Analisis(techniques: List[Type[TechniqueRunner]] | None = None)[source]¶
Bases:
objectOrchestrates all propaganda technique detectors over a given text.
Instantiates one runner per technique and executes them sequentially, collecting a list of candidate dicts. Failures in individual runners are caught and returned as error candidates rather than crashing the pipeline.
- Techniques included by default (DEFAULT_TECHNIQUES):
Repetition, Exaggeration/Minimisation, Obfuscation, Loaded Language, Whataboutism, Kairos, Conversation Killer, Slippery Slope, Slogan, Appeal to Values, Red Herring, Strawman, Appeal to Fear/Prejudice, Appeal to Authority, Bandwagon, Casting Doubt, Flag Waving, Smear/Poisoning the Well, Tu Quoque, Guilt by Association, Name Calling, Causal Oversimplification, False Dilemma.
Example
cfg = Configuracion(model_name=”gpt-4o-2024-08-06”, api_key=…) cfg.setup() analisis = Analisis() candidates = analisis.run(TEXTO)
# Pass candidates directly to RunJuez. Use confidence_threshold to # recover techniques whose individual confidence meets the bar even # when no ratio is available (e.g. single-run Analisis without # run_consistency). Default is 0.9. result = RunJuez(TEXTO, candidates) # threshold=0.9 result = RunJuez(TEXTO, candidates, confidence_threshold=0.85) # looser
- run(texto: str) List[Dict[str, Any]][source]¶
Run all technique detectors on the input text.
- Parameters:
texto – The text to analyze for propaganda techniques.
- Returns:
List of candidate dicts, one per technique. Each dict contains at minimum: model, answer, rationale_summary, confidence, span. Failed runners return a dict with error=True and confidence=0.0.
- class propaganda_pipeline.ConsistencyModule(analysis_module, trials: int = 5, threshold: float = 1.0)[source]¶
Bases:
objectRuns the analysis pipeline multiple times and consolidates results by detection ratio.
Executes
analysis.run(TEXTO)fortrialsiterations and aggregates per-technique detections using a threshold on the detection ratio.- Consolidation logic:
ratio = (number of trials where technique was detected) / trials
final answer = “Sí” if ratio >= threshold, else “No”
Among candidates matching the final answer, select the one with the highest confidence as the representative output.
Adds a
ratiofield to each consolidated candidate dict.
- Example:
module = ConsistencyModule(analisis, trials=5, threshold=1.0) candidates = module.run(TEXTO)
- run(TEXTO: str) List[Dict[str, Any]][source]¶
Run the analysis multiple times and return consolidated candidates.
- Parameters:
TEXTO – The text to analyze for propaganda techniques.
- Returns:
List of consolidated candidate dicts, one per technique. Each dict contains the same fields as a standard candidate output plus a
ratiofield (float in [0, 1]) indicating the detection rate across trials.
- propaganda_pipeline.run_consistency(analysis_module, TEXTO: str, trials: int = 5, threshold: float = 1.0) List[Dict[str, Any]][source]¶
Convenience wrapper for ConsistencyModule.
Runs the analysis pipeline
trialstimes and consolidates per-technique detections by majority-vote ratio threshold.- Parameters:
analysis_module – An Analisis instance with a
run(texto)method.TEXTO – The text to analyze for propaganda techniques.
trials – Number of independent analysis runs. Default 5.
threshold – Minimum detection ratio to classify a technique as detected. Default 1.0 (unanimous across all trials).
- Returns:
List of consolidated candidate dicts (one per technique), each including a
ratiofield indicating the detection rate.
- class propaganda_pipeline.CandidateScore(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelRubric scores and inclusion decision for a single candidate technique.
- total: float = 0.0¶
- include: bool = False¶
- dependency_trace: List[str] | None = None¶
- class propaganda_pipeline.JudgeScoresOutput(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelContainer for the judge’s rubric scores across all candidate techniques.
- class propaganda_pipeline.JudgeOutputNormalized(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelNormalized output from the JudgeModule after scoring and selection.
- brief_justification: str = ''¶
- class propaganda_pipeline.SynthesisOutputNormalized(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelNormalized output from the SynthesizeModule with the final consolidated answer.
- final_answer: str = ''¶
- brief_reasoning: str = ''¶
- class propaganda_pipeline.SelectionOutputNormalized(*args: Any, **kwargs: Any)[source]¶
Bases:
BaseModelPost-hoc selection of detected technique models, with per-model evidence and confidence.
- confidence: pydantic.confloat = 0.0¶
- class propaganda_pipeline.JudgeSignature(*args: Any, **kwargs: Any)[source]¶
Bases:
SignatureEvaluates and RANKS candidates; marks which ones should be included.
- class propaganda_pipeline.SynthesizeSignature(*args: Any, **kwargs: Any)[source]¶
Bases:
SignatureProduces final unified response WITHOUT discarding ‘must-include’.
- class propaganda_pipeline.SelectJudgeCandidates(*args: Any, **kwargs: Any)[source]¶
Bases:
SignatureReads final_answer (ES) and candidates (JSON list). Returns models selected by the judge.
- propaganda_pipeline.safe_json_loads(x: Any, default)[source]¶
Parse a JSON string safely, returning a default value on failure.
- Parameters:
x – Value to parse. Returned as-is if already a dict or list.
default – Value to return if parsing fails or input is None.
- Returns:
Parsed object, the original value (if already dict/list), or
default.
- propaganda_pipeline.normalize_candidates(candidates: List[Dict[str, Any]]) List[Dict[str, Any]][source]¶
Normalize spans and rationale to avoid crashes.
- propaganda_pipeline.normalize_judge_output(j_pred, num_candidates: int) JudgeOutputNormalized[source]¶
Converts LLM string outputs to consistent structure.
IMPORTANT: - The selected indices are derived EXCLUSIVELY from the include flags
returned in scores.candidates, which are the result of applying DEFAULT_RUBRIC.
selected_indices_json is not used to decide which techniques are selected.
- propaganda_pipeline.normalize_synth_output(s_pred) SynthesisOutputNormalized[source]¶
Convert raw SynthesizeSignature LLM output to a normalized structure.
- Parameters:
s_pred – DSPy prediction object from SynthesizeSignature with
final_answerandbrief_reasoningattributes.- Returns:
SynthesisOutputNormalized with stripped string fields.
- propaganda_pipeline.normalize_selection(raw_output: str, candidates: List[Dict[str, Any]]) SelectionOutputNormalized[source]¶
Parse and validate the post-hoc model selection output from the LLM.
Robustly handles string, list, or dict formats for
selected_modelsandevidence. Filters results to only include models present incandidates.- Parameters:
raw_output – JSON string output from SelectJudgeCandidates signature.
candidates – Full list of candidate dicts used to validate model names.
- Returns:
SelectionOutputNormalized with validated selected_models, per-model evidence strings, and an overall confidence score.
- class propaganda_pipeline.JudgeModule(*args: Any, **kwargs: Any)[source]¶
Bases:
ModuleDSPy module that scores and ranks candidate technique detections using a rubric.
Wraps JudgeSignature to evaluate all candidate outputs and determine which techniques should be included in the final answer based on rubric criteria.
- forward(question: str, candidates: List[Dict[str, Any]], rubric: str) JudgeOutputNormalized[source]¶
Score candidates against the rubric and select which to include.
- Parameters:
question – The analysis question fed to the LLM judge.
candidates – List of candidate dicts from TechniqueRunner outputs.
rubric – Scoring rubric string (DEFAULT_RUBRIC is always used).
- Returns:
JudgeOutputNormalized with selected_indices, scores, and brief_justification.
- class propaganda_pipeline.SynthesizeModule(*args: Any, **kwargs: Any)[source]¶
Bases:
ModuleDSPy module that produces a unified natural-language synthesis from top-k candidates.
Takes the judge-selected candidates and generates a final consolidated answer listing all detected propaganda techniques with a brief reasoning.
- forward(question: str, topk: List[Dict[str, Any]]) SynthesisOutputNormalized[source]¶
Generate the final consolidated answer from top-k selected candidates.
- Parameters:
question – The analysis question.
topk – Judge-selected candidate dicts (include=True).
- Returns:
SynthesisOutputNormalized with final_answer and brief_reasoning.
- class propaganda_pipeline.SelectJudgeCandidatesModule(*args: Any, **kwargs: Any)[source]¶
Bases:
ModuleDSPy module that maps the synthesized answer back to specific candidate models.
Performs a post-hoc selection step: reads the final_answer text and the candidates list to identify which technique models were actually detected, returning per-model evidence and an overall confidence score.
- forward(final_answer: str, candidates: List[Dict[str, Any]]) SelectionOutputNormalized[source]¶
Select candidate models mentioned in the final answer.
- Parameters:
final_answer – Natural-language synthesis from SynthesizeModule.
candidates – Full list of candidate dicts from Analisis.run().
- Returns:
SelectionOutputNormalized with selected_models, evidence dict, and confidence. Results are filtered to only include models permitted by the judge rubric.
- propaganda_pipeline.get_modules()[source]¶
Lazy init of DSPy modules to avoid reinstantiating them on every call.
- propaganda_pipeline.RunJuez(TEXTO: str, candidates: List[Dict[str, Any]], rubric: str | None = None, confidence_threshold: float = 0.9) Dict[str, Any][source]¶
Run the full judge pipeline: scoring, synthesis, and post-hoc selection.
- Executes three sequential steps:
JudgeModule: scores candidates against DEFAULT_RUBRIC and selects which techniques to include (
include=Trueflag).SynthesizeModule: generates a natural-language answer from top-k selected candidates.
SelectJudgeCandidatesModule: maps the synthesis back to specific model names, filtered to only rubric-approved techniques.
Note
The
rubricparameter is accepted for API compatibility but ignored; DEFAULT_RUBRIC is always used to ensure consistent evaluation.The
confidence_thresholdparameter adds a confidence-based selection layer on top of the rubric. Candidates whoseansweraffirms the technique (starts with “s”, case-insensitive) and whoseconfidence >= confidence_thresholdare always included, even when the rubric’s weighted total does not reach its own inclusion cut-off. This is especially useful when candidates come fromAnalisis.run()directly (norun_consistency), because without aratiothe rubric’s consistency criterion scores 1/5 and the weighted total is capped well below the rubric threshold regardless of confidence.- Parameters:
TEXTO – The original text that was analyzed.
candidates – List of candidate dicts from Analisis.run() or run_consistency().
rubric – Ignored. DEFAULT_RUBRIC is always applied.
confidence_threshold – Minimum confidence for a candidate to be included via the confidence-based path. Must be in [0.0, 1.0]. Default 0.9.
- Returns:
- judged: JudgeOutputNormalized model dump (scores, selected_indices,
brief_justification).
topk: List of selected candidate dicts with rubric score info merged in. synthesis: SynthesisOutputNormalized model dump (final_answer,
brief_reasoning).
- selected_models_posthoc: SelectionOutputNormalized model dump
(selected_models, evidence, confidence).
elapsed_sec: Wall-clock time for the full judge pipeline.
- Return type:
Dict with keys
- propaganda_pipeline.norm_label(lbl: str) str[source]¶
Normalizes a technique label to the format ‘STRAWMAN’, ‘FALSE_DILEMMA’, etc.
- propaganda_pipeline.strip_trailing_punct(s: str) str[source]¶
Remove trailing punctuation characters from a string.
- Parameters:
s – Input string to strip.
- Returns:
!?)»”›>) removed.
- Return type:
String with trailing punctuation (.,;
- propaganda_pipeline.norm_with_spans(s: str) Tuple[str, List[Tuple[int, int]], str][source]¶
Normalizes a text and returns: - normalized text, - mapping of normalized spans->originals (by character), - original text already NFKC+TRANS.
- propaganda_pipeline.find_occurrences_robust(text: str, phrase: str) List[Tuple[int, int]][source]¶
Look for robust occurrences: 1) case-insensitive direct search, 2) if it fails: normalize phrase and text, remove final punctuation,
and maps to original offsets.
- propaganda_pipeline.normalize_spans_field(span_field: Any) List[str][source]¶
span can be None, str, or list[str].
- propaganda_pipeline.collect_ents_selected_only(text: str, candidates: List[Dict[str, Any]], selection: Dict[str, Any]) List[Dict[str, Any]][source]¶
Find span occurrences in text for judge-selected techniques only.
For each selected model, locates all span strings from the candidate dict in the original text using robust fuzzy matching.
- Parameters:
text – The original text that was analyzed.
candidates – Full list of candidate dicts from Analisis.run().
selection – SelectionOutputNormalized model dump with
selected_models.
- Returns:
Sorted list of entity dicts with keys
start,end,label(character offsets intotext).
- propaganda_pipeline.segmentize_by_boundaries(text: str, ents: List[Dict[str, Any]]) List[Dict[str, Any]][source]¶
Split text into contiguous segments based on entity start/end boundaries.
Creates non-overlapping segments that cover the full text, where each segment tracks which technique labels are active within it.
- Parameters:
text – The original text.
ents – List of entity dicts with
start,end,labelkeys.
- Returns:
List of segment dicts with keys
start,end,labels(list of active technique label strings).
- propaganda_pipeline.mask_segments_to_selected(segments: List[Dict[str, Any]], selection: Dict[str, Any]) List[Dict[str, Any]][source]¶
Filter segment labels to only include judge-selected technique models.
- Parameters:
segments – List of segment dicts from
segmentize_by_boundaries.selection – SelectionOutputNormalized model dump with
selected_models.
- Returns:
New list of segment dicts with labels filtered to permitted models only.
- propaganda_pipeline.gradient_for_labels(labels: List[str]) str[source]¶
Build a CSS color or linear-gradient string for a list of technique labels.
- Parameters:
labels – List of normalized technique label strings (e.g.
["STRAWMAN"]).- Returns:
A CSS color string for single labels, a
linear-gradient(...)for multiple labels, or"transparent"if the list is empty.
- propaganda_pipeline.render_overlaps_inline_html(text: str, segments: List[Dict[str, Any]], show_legend: str = 'bottom', show_badges: bool = False, badge_style: str = 'outline', boxed: bool = True, title: str = 'Spans resaltados', subtitle: str | None = None, icon: str = '⚖️', accent_color: str = '#111827') str[source]¶
Returns an HTML string that highlights spans (NOT displays).
- propaganda_pipeline.visualize_spans(text: str, candidates: List[Dict[str, Any]], selection: Dict[str, Any], display_inline: bool = True, **render_kwargs) str[source]¶
Constructs segments and returns HTML. If display_inline=True and IPython is available, do display().
- propaganda_pipeline.extract_techniques_from_text(final_answer: str) List[str][source]¶
Simple heuristic: extract tokens in CAPS type techniques. Adjust regex if your techniques include dashes/underscores.
- propaganda_pipeline.synthesis_report_html(TEXTO: str, judged: Dict[str, Any], topk: List[Dict[str, Any]], synthesis: Dict[str, Any], selection: Dict[str, Any] | None = None, title: str = 'Síntesis') str[source]¶
Build the HTML of the card type report. It does NOT display; it just returns the HTML.
- propaganda_pipeline.synthesis_report(TEXTO: str, judged: Dict[str, Any], topk: List[Dict[str, Any]], synthesis: Dict[str, Any], selection: Dict[str, Any] | None = None, title: str = 'Síntesis', display_inline: bool = True) str[source]¶
Public Wrapper: Returns HTML and optionally displays it in Jupyter.
- propaganda_pipeline.report_from_run(result: Dict[str, Any], TEXTO: str, display_inline: bool = True, title: str = 'Síntesis') str[source]¶
Shortcut: directly take the dict of run_judge.
- propaganda_pipeline.rubric_table_card(judged: dict, candidates: List[Dict[str, Any]] | None = None, title: str = 'Resultados de la rúbrica')[source]¶
Tabular display of the judge’s rubric. - One row per candidate (technique). - Columns: model, include, total, ratio, confidence, consistency, security, preference_yes, justification_brief. - If ‘candidates’ is passed, use candidates[i][‘model’], ‘ratio’, ‘confidence’, ‘raw.justificacion_breve’.
- propaganda_pipeline.show_rubric_table_from_result(result: dict, candidates: List[Dict[str, Any]] | None = None, title: str = 'Resultados de la rúbrica')[source]¶
Convenience: receive the full dict returned by run_judge and optionally the list of candidates (to show model, ratio, confidence, brief justification).