#!/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)))