readCtrl_lambda / code /old /synthetic_data_generationV2.py
mshahidul
Initial commit of readCtrl code without large models
030876e
Raw
History Blame Contribute Delete
6.97 kB
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)