| 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
|
|
|
|
|
| if val.isdigit():
|
| return True
|
|
|
|
|
| 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()]
|
|
|
|
|
| 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
|
|
|
|
|
| for raw_line in lines:
|
| line = raw_line.strip()
|
| if not line:
|
| continue
|
| if not _es_generico_ou_numero(line):
|
| return line
|
|
|
|
|
| return default
|
|
|