Files
medtech-hackathon/scripts/gen_fixtures.py
T
2026-06-26 12:53:04 +05:00

150 lines
8.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Генератор синтетических прайсов клиник (RU/KZ) в разных форматах для отладки pipeline."""
import csv, os, random, subprocess, sys
OUT = sys.argv[1] if len(sys.argv) > 1 else "fixtures/raw"
os.makedirs(OUT, exist_ok=True)
random.seed(42) # детерминированно
def ensure(pkg, mod=None):
try:
__import__(mod or pkg)
except ImportError:
subprocess.check_call([sys.executable, "-m", "pip", "install", "-q", pkg])
# Базовый каталог: (канон RU, канон KZ, [варианты названий], мин, макс, единица)
CATALOG = [
("Общий анализ крови", "Қанның жалпы анализі",
["Общий анализ крови", "ОАК", "Общий анализ крови (развернутый)", "Клинический анализ крови", "Қанның жалпы анализі"],
1200, 4500, "1 иссл."),
("УЗИ органов брюшной полости", "Құрсақ қуысы ағзаларының УДЗ",
["УЗИ органов брюшной полости", "УЗИ ОБП", "УЗИ брюшной полости", "Құрсақ қуысы УДЗ"],
6000, 13000, "1 иссл."),
("Приём врача-терапевта", "Терапевт дәрігердің қабылдауы",
["Прием терапевта", "Консультация терапевта первичная", "Приём врача-терапевта", "Терапевт қабылдауы"],
4000, 9000, "1 приём"),
("Электрокардиография (ЭКГ)", "Электрокардиография (ЭКГ)",
["ЭКГ", "Электрокардиография", "ЭКГ с расшифровкой", "ЭКГ + описание"],
2000, 5000, "1 иссл."),
("Глюкоза крови", "Қандағы глюкоза",
["Глюкоза", "Глюкоза крови", "Сахар крови", "Қандағы глюкоза"],
800, 2200, "1 иссл."),
("Консультация кардиолога", "Кардиолог кеңесі",
["Консультация кардиолога", "Прием кардиолога", "Кардиолог консультация первичная"],
5000, 12000, "1 приём"),
("МРТ головного мозга", "Бас миының МРТ",
["МРТ головного мозга", "Магнитно-резонансная томография головного мозга", "МРТ г/м", "Бас миы МРТ"],
18000, 35000, "1 иссл."),
("Биохимический анализ крови", "Қанның биохимиялық анализі",
["Биохимия крови", "Биохимический анализ крови (базовый)", "Б/х крови", "Қан биохимиясы"],
3500, 9000, "1 иссл."),
("Удаление зуба", "Тісті жұлу",
["Удаление зуба", "Удаление зуба простое", "Экстракция зуба", "Тіс жұлу"],
6000, 15000, "1 зуб"),
("Рентген грудной клетки", "Кеуде клеткасының рентгені",
["Рентген грудной клетки", "Рентгенография ОГК", "Флюорография", "Кеуде рентгені"],
2500, 6000, "1 иссл."),
]
CLINICS = ["Клиника «Аль-Шифа»", "Медцентр «Сункар»", "Diagnostic Lab Astana", "Клиника «Береке»", "Медцентр «Тенгри»"]
def price(lo, hi):
return round(random.randint(lo, hi), -2) # круглые сотни
def variants_for(clinic_idx, n):
"""Выбрать n услуг с разными вариантами написания и ценами."""
rows = []
chosen = random.sample(CATALOG, k=min(n, len(CATALOG)))
for ru, kz, names, lo, hi, unit in chosen:
name = random.choice(names)
rows.append((name, price(lo, hi), unit))
return rows
ensure("openpyxl")
from openpyxl import Workbook
# 1) Чистый Excel
wb = Workbook(); ws = wb.active; ws.title = "Прайс"
ws.append(["Наименование услуги", "Цена, тг"])
for name, p, _ in variants_for(0, 9):
ws.append([name, p])
wb.save(f"{OUT}/clinic_alpha_clean.xlsx")
# 2) Грязный Excel: секции-заголовки, "от", разные колонки, KZ
wb = Workbook(); ws = wb.active; ws.title = "PRICE 2026"
ws.append(["Прайс-лист медцентра «Сункар» (с 01.06.2026)"])
ws.append([])
ws.append(["№", "Услуга / Қызмет", "Стоимость (тенге)", "Ед."])
section = ["— Лаборатория / Зертхана —", "— Диагностика —", "— Приём специалистов —"]
i = 1
for s in section:
ws.append([s, None, None, None])
for name, p, unit in variants_for(1, 3):
val = f"от {p}" if random.random() < 0.3 else p
ws.append([i, name, val, unit]); i += 1
wb.save(f"{OUT}/clinic_beta_dirty.xlsx")
# 3) CSV с разделителем ; и смешанными языками
with open(f"{OUT}/clinic_gamma.csv", "w", encoding="utf-8", newline="") as f:
w = csv.writer(f, delimiter=";")
w.writerow(["service", "price_kzt", "unit"])
for name, p, unit in variants_for(2, 8):
w.writerow([name, p, unit])
# 4) Грязный текст (прайс абзацем)
with open(f"{OUT}/clinic_delta_messy.txt", "w", encoding="utf-8") as f:
f.write("МЕДЦЕНТР «ТЕНГРИ» — действующие цены\n\n")
for name, p, unit in variants_for(3, 7):
sep = random.choice([" — ", " ... ", ": ", " "])
cur = random.choice(["тг", "тенге", "₸", "KZT"])
f.write(f"{name}{sep}{p} {cur} ({unit})\n")
f.write("\n* Цены справочные, уточняйте в регистратуре. Бағалар анықтамалық.\n")
# 5) Картинка-«скан» прайса (имитация фото)
ensure("Pillow", "PIL")
from PIL import Image, ImageDraw, ImageFont
img = Image.new("RGB", (900, 700), (250, 248, 244))
d = ImageDraw.Draw(img)
def font(sz):
for p in ["/System/Library/Fonts/Supplemental/Arial.ttf", "/Library/Fonts/Arial.ttf",
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"]:
if os.path.exists(p):
return ImageFont.truetype(p, sz)
return ImageFont.load_default()
d.text((40, 30), "Клиника «Береке» — прайс-лист", fill=(20, 20, 20), font=font(34))
d.line((40, 85, 860, 85), fill=(180, 180, 180), width=2)
y = 110
for name, p, unit in variants_for(4, 9):
d.text((50, y), name, fill=(30, 30, 30), font=font(24))
d.text((720, y), f"{p} тг", fill=(30, 30, 30), font=font(24))
y += 58
img = img.rotate(-1.4, expand=False, fillcolor=(250, 248, 244)) # лёгкий наклон как у фото
img.save(f"{OUT}/clinic_epsilon_scan.png")
# 6) PDF (если есть reportlab)
try:
ensure("reportlab")
from reportlab.lib.pagesizes import A4
from reportlab.pdfgen import canvas
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
fp = next((p for p in ["/Library/Fonts/Arial.ttf", "/System/Library/Fonts/Supplemental/Arial.ttf",
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"] if os.path.exists(p)), None)
if fp:
pdfmetrics.registerFont(TTFont("U", fp))
c = canvas.Canvas(f"{OUT}/clinic_zeta_prices.pdf", pagesize=A4)
c.setFont("U", 18); c.drawString(60, 790, "Diagnostic Lab Astana — Price list / Прайс")
c.setFont("U", 12); y = 750
for name, p, unit in variants_for(2, 10):
c.drawString(60, y, name[:55]); c.drawRightString(540, y, f"{p} KZT"); y -= 28
c.save()
pdf = "ok"
else:
pdf = "no font"
except Exception as e:
pdf = f"skip ({e})"
print("PDF:", pdf)
print("Files:", sorted(os.listdir(OUT)))