File size: 6,965 Bytes
c7a6fe6 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | import os
import json
from openai import OpenAI
import tqdm
import re
from FH_es import fernandez_huerta
# Initialize client (ensure you have OPENAI_API_KEY in env vars)
client = OpenAI(api_key=json.load(open('/home/mshahidul/api.json', 'r'))['openai_api_key'])
PROMPTS_ES = {
"B1": """Eres un asistente que reescribe resúmenes de casos clínicos para niñas y niños de primaria (aprox. 6–11 años).
Escribe SIEMPRE en español claro.
Objetivo de legibilidad (aprox. Fernández–Huerta): 70–100.
Restricciones de forma (cumple todas):
- Longitud total: 45–90 palabras.
- Oraciones: 4–6 oraciones.
- Promedio de palabras por oración: 8–12.
- Palabras: prefiere palabras cortas (1–2 sílabas). Evita tecnicismos. Si un término médico es inevitable, explícalo con 3–8 palabras sencillas.
- Conectores simples: “y”, “pero”, “porque”. Evita oraciones subordinadas largas.
- No inventes información. Sé fiel al artículo y al resumen experto.
- Prohibido: viñetas, listas, emojis, abreviaturas técnicas, explicaciones de pronunciación, títulos/cabeceras.
Tono y contenido:
- Amable, tranquilizador, sin alarmar.
- Destaca 1–3 ideas principales. Explica hallazgos normales con calma; anormalidades con lenguaje sencillo y breve.
Responde solo con el resumen (sin prefacios, sin notas).""",
"B2": """Eres un asistente que reescribe resúmenes de casos clínicos para estudiantes de secundaria (aprox. 11–17 años).
Escribe SIEMPRE en español claro.
Objetivo de legibilidad (aprox. Fernández–Huerta): 55–65.
Restricciones de forma (cumple todas):
- Longitud total: 90–140 palabras.
- Oraciones: 5–8 oraciones.
- Promedio de palabras por oración: 12–18.
- Palabras: evita jerga innecesaria. Puedes usar términos médicos comunes con una breve explicación (3–10 palabras) la primera vez.
- Conectores permitidos: “porque”, “aunque”, “sin embargo”, “por eso”. Oraciones compuestas moderadas.
- No inventes información. Sé fiel al artículo y al resumen experto.
- Prohibido: viñetas, listas, emojis, explicaciones de pronunciación, títulos/cabeceras.
Tono y contenido:
- Claro y empático.
- Distingue hallazgos normales y anormales, e incluye posibles pasos siguientes cuando sea útil.
Responde solo con el resumen (sin prefacios, sin notas).""",
"B3": """Eres un asistente que reescribe resúmenes de casos clínicos para lectores con nivel universitario (17+), sin especialización médica.
Escribe SIEMPRE en español claro.
Objetivo de legibilidad (aprox. Fernández–Huerta): 40–55.
Restricciones de forma (cumple todas):
- Longitud total: 140–220 palabras.
- Oraciones: 6–10 oraciones.
- Promedio de palabras por oración: 18–25.
- Palabras: se permiten términos técnicos de uso común; define brevemente solo los poco conocidos. Se aceptan oraciones subordinadas si mantienen claridad.
- Conectores: “sin embargo”, “por lo tanto”, “además”, “no obstante”, “en consecuencia”.
- No inventes información. Sé fiel al artículo y al resumen experto.
- Prohibido: viñetas, listas, emojis, explicaciones de pronunciación, títulos/cabeceras.
Tono y contenido:
- Preciso y empático.
- Estructura más detallada: contexto breve, hallazgos clave, implicaciones y posibles próximos pasos.
Responde solo con el resumen (sin prefacios, sin notas)."""
}
FH_TARGETS = {
"B1": (70, 100),
"B2": (55, 65),
"B3": (40, 55),
}
def count_syllables(word):
# Simple Spanish syllable counter
word = word.lower()
word = re.sub(r'[^a-záéíóúüñ]', '', word)
return len(re.findall(r'[aeiouáéíóúü]+', word))
def generate_synthetic_summary(article, gold_summary, band, lang='es'):
prompt_user = f"""Artículo:
{article}
Resumen experto:
{gold_summary}
Tarea:
Genera un resumen en la banda {band} indicada por el sistema. Responde solo con el resumen."""
response = client.chat.completions.create(
model="gpt-4.1-mini", # <-- Check this model name!
messages=[
{"role": "system", "content": PROMPTS_ES[band]},
{"role": "user", "content": prompt_user}
],
temperature=0.4,
)
return response.choices[0].message.content.strip()
def revise_to_band(text, band):
adjustments = {
"B1": "Acorta oraciones a 8–12 palabras, usa palabras más comunes y evita tecnicismos.",
"B2": "Ajusta oraciones a 12–18 palabras y limita tecnicismos con breve explicación.",
"B3": "Usa 18–25 palabras por oración, permite frases subordinadas y vocabulario más técnico.",
}
msg = f"""Reescribe el texto para que cumpla la banda {band}:
- {adjustments[band]}
- Mantén fidelidad al contenido.
Devuelve solo el texto revisado, sin comentarios."""
r = client.chat.completions.create(
model="gpt-4.1-mini",
messages=[
{"role": "system", "content": PROMPTS_ES[band]},
{"role": "user", "content": text},
{"role": "user", "content": msg}
],
temperature=0.3,
)
return r.choices[0].message.content.strip()
def build_synthetic_dataset(input_path, output_path, max_samples=None):
"""Generate synthetic dataset from a JSON file with {fulltext, summary}"""
results = []
seen_articles = set()
if os.path.exists(output_path):
with open(output_path, 'r') as f:
results = json.load(f)
seen_articles = set(r['article'] for r in results)
with open(input_path, "r") as f:
data = json.load(f)
for item in tqdm.tqdm(data):
if max_samples and len(results) >= max_samples:
break
article, gold = item["fulltext"], item["summary"]
if article in seen_articles:
continue
temp = {}
for band in ["B1", "B2", "B3"]:
synthetic = generate_synthetic_summary(article, gold, band)
fh = fernandez_huerta(synthetic)
lo, hi = FH_TARGETS[band]
if fh is None or not (lo <= fh <= hi):
synthetic = revise_to_band(synthetic, band)
temp[band] = synthetic
results.append({
"article": article,
"gold_summary": gold,
"synthetic_summary": temp
})
seen_articles.add(article)
if len(results) % 5 == 0:
print(f"Processed {len(results)} samples, saving progress...")
with open(output_path, "w") as f:
json.dump(results, f, ensure_ascii=False, indent=4)
with open(output_path, "w") as f:
json.dump(results, f, ensure_ascii=False, indent=4)
# Example usage:
lang = "es"
path = f"/home/mshahidul/readctrl/data/testing_data_gs/multiclinsum_gs_train_{lang}.json"
build_synthetic_dataset(path, f"/home/mshahidul/readctrl/generating_data/{lang}_synthetic.json", max_samples=100) |