import os import json def load_config(config_path="configs/config.json"): with open(config_path, "r", encoding="utf-8") as f: config = json.load(f) return config def load_prompts(path="configs/prompts.json"): """Carrega o arquivo completo de prompts. Retorna um dicionário com todas as seções definidas (em especial "system_prompts" e "meta"), para que tanto o LLM quanto as respostas fixas usem a mesma fonte de configuração. """ with open(path, "r", encoding="utf-8") as f: return json.load(f) def load_md(file_path): with open(file_path, "r", encoding="utf-8") as f: text = f.read() return text def extract_frontmatter(text: str) -> dict: """Extrae un frontmatter YAML básico delimitado por '---' al inicio. Soporta claves simples y listas en formato: authors:\n - "A"\n - "B" """ if not text: return {} lines = text.splitlines() if not lines or lines[0].strip() != "---": return {} frontmatter_lines = [] for line in lines[1:]: if line.strip() == "---": break frontmatter_lines.append(line) data: dict = {} current_key = None for raw in frontmatter_lines: line = raw.rstrip() if not line.strip(): continue if line.lstrip().startswith("- ") and current_key: value = line.lstrip()[2:].strip().strip('"').strip("'") data.setdefault(current_key, []) if isinstance(data[current_key], list): data[current_key].append(value) continue if ":" in line: key, value = line.split(":", 1) key = key.strip() value = value.strip().strip('"').strip("'") if value == "": current_key = key data[key] = [] else: current_key = key data[key] = value return data def extract_title_from_md(text: str, default: str) -> str: if not text: return default def _es_generico_ou_numero(line: str) -> bool: """Detecta líneas poco informativas: solo número/año o rótulos genéricos.""" val = line.strip() if not val: return True # Solo dígitos ("2007", "69", etc.) if val.isdigit(): return True # Año de 4 dígitos aislado if len(val) == 4 and val.isdigit(): return True lower = val.lower() genericos = { "article", "artigo", "artículo", "issue", "number", "número", } if lower in genericos: return True return False lines = [l.rstrip("\n") for l in text.splitlines()] # 1) Buscar primer heading "#" que no sea genérico/numérico for raw_line in lines: line = raw_line.strip() if not line: continue if line.startswith("#"): candidate = line.lstrip("#").strip() if candidate and not _es_generico_ou_numero(candidate): return candidate # 2) Si no hay heading válido, buscar primera línea de texto informativa for raw_line in lines: line = raw_line.strip() if not line: continue if not _es_generico_ou_numero(line): return line # 3) Fallback return default