chore: seed repo — README, .gitignore, synthetic price fixtures (6 форматов)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-26 12:53:04 +05:00
commit fa2fbc59b0
10 changed files with 253 additions and 0 deletions
+149
View File
@@ -0,0 +1,149 @@
#!/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)))