import os from groq import Groq from pathlib import Path BASE_DIR = Path(__file__).parent.parent FALLACY_DEFINITIONS = { "no fallacy": "The text contains no logical fallacy and the reasoning is sound", "ad hominem": "Attacking the person making the argument rather than the argument itself", "ad populum": "Claiming something is true because many people believe it", "appeal to emotion": "Manipulating emotions rather than using logical reasoning", "circular reasoning": "Using the conclusion as a premise in the argument", "equivocation": "Using an ambiguous term in multiple senses within the same argument", "fallacy of credibility": "Misusing or fabricating authority or credentials to support a claim", "fallacy of extension": "Misrepresenting someone's argument to make it easier to attack", "fallacy of logic": "A general error in the logical structure of the argument", "fallacy of relevance": "Using irrelevant information to support a conclusion", "false causality": "Assuming that because one thing follows another, it was caused by it", "false dilemma": "Presenting only two options when more alternatives exist", "faulty generalization": "Drawing a broad conclusion from insufficient or unrepresentative evidence", "intentional": "A deliberate and deceptive use of misleading reasoning" } DEFAULT_MODEL_ID = "llama-3.1-8b-instant" class FallacyExplainer: DEFAULT_FALLACY_CLASSES = list(FALLACY_DEFINITIONS.keys()) def __init__(self, fallacy_classes=None, fallacy_definitions=None): self._model_id = os.environ.get("EXPLAIN_MODEL_ID", DEFAULT_MODEL_ID) self._client = Groq(api_key=os.environ["GROQ_API_KEY"]) self.fallacy_classes = fallacy_classes or self.DEFAULT_FALLACY_CLASSES self.fallacy_definitions = fallacy_definitions or FALLACY_DEFINITIONS print(f"FallacyExplainer ready (model: {self._model_id} via Groq)") def _generate_with_prompt(self, prompt_text, max_new_tokens=128): result = self._client.chat.completions.create( model=self._model_id, messages=[{"role": "user", "content": prompt_text}], max_tokens=max_new_tokens, temperature=0.1, ) return result.choices[0].message.content.strip() def _load_prompt(self, path): with open(BASE_DIR / path, "r") as f: return f.read() def _fill_template(self, template, replacements): result = template for key, value in replacements.items(): result = result.replace("{{" + key + "}}", value) return result def explain(self, input_text, final_label, query_results): template = self._load_prompt("proposed_prompts/explain.txt") prompt = self._fill_template(template, { "INPUT_TEXT": input_text, "DETECTED_FALLACY": final_label, "REASONING_CONTEXT": query_results["explanation"] }) response = self._generate_with_prompt(prompt, max_new_tokens=120) explanation = "" highlighted_phrase = "" if "" in response and "" in response: explanation = response.split("")[1].split("")[0].strip() if "" in response and "" in response: highlighted_phrase = response.split("")[1].split("")[0].strip() return { "explanation": explanation, "highlighted_phrase": highlighted_phrase }