readctrl / code /old /synthetic_data_generationV2.py
shahidul034's picture
Add files using upload-large-folder tool
c7a6fe6 verified
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)