Text-to-SQL / pilot /belge_uret.py
SevdanurGenc's picture
Upload 466 files
a72d1cf verified
Raw History Blame Contribute Delete
33.2 kB
"""Pilot çalışması için gerçek belge düzenlerini taklit eden KURGUSAL belgeler, sorular ve altın cevaplar üretir.
Amaç: gerçek belgeler bulunana kadar sistemi, geliştirme sırasında hiç görmediği düzenlerde sınamak.
Belgeler ana test kümesinden (data/docs) bilerek farklı tasarlanmıştır:
* çok sayfaya bölünen ve başlığı her sayfada tekrar eden tablo
* yalnızca yatay çizgili (dikey çizgisiz) KAP tarzı finansal tablolar, dipnot sütunu, girintili kalemler,
ara toplam satırları, parantezli negatifler, 4 ondalıklı pay başına kazanç
* birimi yalnızca sütun başlığında "(%)" olan yüzde sütunları, "-" ile gösterilen tanımsız değerler
* dipnot işaretli satır adları ("Şirket Personeli (*)") ve tablo altı açıklama satırları
* HTML'de <tfoot> içinde kaynak notu, çeyrek (Ç1–Ç4) başlıkları, "Ocak 2025" biçimli ay satırları
Altın cevaplar soruların metninden değil, belgeyi üreten ham verilerden programla hesaplanır.
Bütün kurum, il ve ilçe adları kurgusaldır; her sayfada "KURGUSAL ÖRNEK BELGE" uyarısı bulunur.
Kullanım: python pilot/belge_uret.py -> pilot/belgeler/*, pilot/sorular.json
"""
from __future__ import annotations
import json
import random
from pathlib import Path
from reportlab.lib import colors
from reportlab.lib.enums import TA_CENTER
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.units import cm
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.platypus import Paragraph, SimpleDocTemplate, Spacer, Table, TableStyle, PageBreak
ROOT = Path(__file__).resolve().parent.parent
OUT = ROOT / "pilot" / "belgeler"
FONTS = ROOT / "assets" / "fonts"
pdfmetrics.registerFont(TTFont("DejaVu", str(FONTS / "DejaVuSans.ttf")))
pdfmetrics.registerFont(TTFont("DejaVu-Bold", str(FONTS / "DejaVuSans-Bold.ttf")))
rng = random.Random(31)
UYARI = "KURGUSAL ÖRNEK BELGE — Tablo2SQL-TR pilot çalışması için üretilmiştir; gerçek kurum verisi değildir."
# ------------------------------------------------------------------ biçimlendirme
def tr(x, dec=2):
s = f"{abs(x):,.{dec}f}".replace(",", "§").replace(".", ",").replace("§", ".")
return ("-" if x < 0 else "") + s
def paren(x, dec=0):
return f"({tr(abs(x), dec)})" if x < 0 else tr(x, dec)
ST = {
"h1": ParagraphStyle("h1", fontName="DejaVu-Bold", fontSize=15, leading=19, spaceAfter=10, alignment=TA_CENTER),
"h2": ParagraphStyle("h2", fontName="DejaVu-Bold", fontSize=11.5, leading=15, spaceBefore=10, spaceAfter=6),
"p": ParagraphStyle("p", fontName="DejaVu", fontSize=9.5, leading=13.5, spaceAfter=6),
"cap": ParagraphStyle("cap", fontName="DejaVu-Bold", fontSize=9.5, leading=12, spaceBefore=8, spaceAfter=4),
"note": ParagraphStyle("note", fontName="DejaVu", fontSize=7.8, leading=10, spaceAfter=8),
"cell": ParagraphStyle("cell", fontName="DejaVu", fontSize=8, leading=9.6),
"cellb": ParagraphStyle("cellb", fontName="DejaVu-Bold", fontSize=8, leading=9.6),
}
def footer(canvas, doc):
canvas.saveState()
canvas.setFont("DejaVu", 7)
canvas.setFillColor(colors.HexColor("#9a3412"))
canvas.drawCentredString(A4[0] / 2, 1.1 * cm, UYARI)
canvas.setFillColor(colors.grey)
canvas.drawRightString(A4[0] - 2 * cm, 1.1 * cm, str(doc.page))
canvas.restoreState()
def P(t, s="p"):
return Paragraph(t, ST[s])
# ================================================================== D1: belediye faaliyet raporu
KOD = [("01", "Personel Giderleri"), ("02", "Sosyal Güvenlik Kurumlarına Devlet Primi Giderleri"),
("03", "Mal ve Hizmet Alım Giderleri"), ("04", "Faiz Giderleri"), ("05", "Cari Transferler"),
("06", "Sermaye Giderleri"), ("07", "Sermaye Transferleri"), ("08", "Borç Verme"),
("09", "Yedek Ödenekler")]
MAHALLE = ["Cumhuriyet", "Atatürk", "Yenidoğan", "Fatih", "Yavuz Selim", "Kurtuluş", "İstiklal", "Bahçelievler",
"Gazi Osman Paşa", "Hürriyet", "Barbaros", "Mimar Sinan", "Yunus Emre", "Mevlana", "Karşıyaka",
"Çamlıbel", "Esentepe", "Güzeltepe", "İnönü", "Kazım Karabekir", "Sakarya", "Turgut Özal", "Zafer",
"Ilıca", "Örnekköy", "Şirinevler", "Çiftlik", "Değirmenönü", "Gülbahçe", "Akarca", "Yeşilyurt",
"Pınarönü", "Selçuklu", "Ulubatlı", "Kocatepe", "Hacı Bayram", "Kemalpaşa", "Fevzi Çakmak", "Malazgirt",
"Dumlupınar", "Sütçü İmam", "Namık Kemal", "Ziya Gökalp", "Mehmet Akif", "Akşemsettin", "Emek", "Gençlik",
"Bağlarbaşı", "Yıldırım Beyazıt", "Osmangazi", "Orhangazi", "Alparslan", "Kayabaşı", "Çınarlı", "Söğütlü",
"Kavaklı", "Ihlamur", "Nergis", "Lale", "Menekşe", "Papatya", "Sümbül", "Işıklar"]
def d1_data():
b = {}
for kod, ad in KOD:
if kod == "09":
butce = 18_500_000.00
b[kod] = dict(ad=ad, butce=butce, ekl=0.0, dus=butce, top=0.0, gerc=0.0, oran=None)
continue
butce = round(rng.uniform(4e6, 160e6), -3) + rng.choice([0, 0.5, 0.25])
if kod == "08":
butce = round(rng.uniform(1e6, 3e6), -3)
ekl = round(butce * rng.uniform(0, 0.12), 2) if kod not in ("08",) else 0.0
dus = round(butce * rng.uniform(0, 0.06), 2)
top = round(butce + ekl - dus, 2)
oran_r = {"01": 0.97, "02": 0.95, "06": 0.58, "08": 0.41}.get(kod, rng.uniform(0.70, 0.93))
gerc = round(top * oran_r, 2)
b[kod] = dict(ad=ad, butce=butce, ekl=ekl, dus=dus, top=top, gerc=gerc, oran=round(100 * gerc / top, 2))
tot = {k: round(sum(v[k] for v in b.values()), 2) for k in ("butce", "ekl", "dus", "top", "gerc")}
tot["oran"] = round(100 * tot["gerc"] / tot["top"], 2)
pers = {"Memur": (142, 38), "Sözleşmeli Personel": (27, 9), "Kadrolu İşçi": (64, 21), "Geçici İşçi": (12, 0),
"Şirket Personeli (*)": (318, None)}
mah = {}
for m in MAHALLE:
n24 = rng.randint(1_800, 24_000)
ch = rng.uniform(-0.035, 0.06)
n25 = int(round(n24 * (1 + ch)))
hane = int(round(n25 / rng.uniform(2.6, 3.6)))
mah[m] = dict(n24=n24, n25=n25, hane=hane, deg=round(100 * (n25 - n24) / n24, 2))
return b, tot, pers, mah
def d1_pdf(b, tot, pers, mah, path):
doc = SimpleDocTemplate(str(path), pagesize=A4, leftMargin=1.8 * cm, rightMargin=1.8 * cm, topMargin=1.8 * cm,
bottomMargin=2 * cm, title="Yeşilvadi Belediyesi 2025 Yılı Faaliyet Raporu")
el = [P("T.C.<br/>YEŞİLVADİ BELEDİYESİ<br/>2025 YILI FAALİYET RAPORU", "h1"),
P("Bu rapor, 5018 sayılı Kamu Mali Yönetimi ve Kontrol Kanunu'nun 41. maddesi ile Kamu İdarelerince Hazırlanacak "
"Faaliyet Raporları Hakkında Yönetmelik uyarınca hazırlanmıştır. Raporda belediyenin 2025 mali yılına ait bütçe "
"uygulama sonuçları, insan kaynakları ve mahalle bazında nüfus bilgileri yer almaktadır."),
P("3. MALİ BİLGİLER", "h2"),
P("3.1. Bütçe Uygulama Sonuçları", "h2"),
P("2025 mali yılı bütçesi ile verilen ödenekler, yıl içinde yapılan aktarmalar sonucunda eklenen ve düşülen "
"tutarlar ile birlikte aşağıda ekonomik sınıflandırmanın birinci düzeyine göre sunulmuştur."),
P("Tablo 4: Bütçe Giderlerinin Ekonomik Sınıflandırmaya Göre Dağılımı (TL)", "cap")]
H = lambda t: Paragraph(t, ParagraphStyle("bh", fontName="DejaVu-Bold", fontSize=6.4, leading=7.8)) # noqa: E731
hdr1 = [H("Ekonomik Kod"), H("Gider Türü"), H("Ödenek"), "", "", "", H("Gerçekleşme"), H("Gerçekleşme Oranı (%)")]
hdr2 = ["", "", H("Bütçe Ödeneği"), H("Eklenen"), H("Düşülen"), H("Toplam Ödenek"), "", ""]
rows = [hdr1, hdr2]
for kod, _ in KOD:
v = b[kod]
rows.append([kod, P(v["ad"], "cell"), tr(v["butce"]), tr(v["ekl"]), tr(v["dus"]), tr(v["top"]), tr(v["gerc"]),
"-" if v["oran"] is None else tr(v["oran"])])
rows.append(["", P("TOPLAM", "cellb"), tr(tot["butce"]), tr(tot["ekl"]), tr(tot["dus"]), tr(tot["top"]),
tr(tot["gerc"]), tr(tot["oran"])])
t = Table(rows, colWidths=[1.9 * cm, 2.5 * cm, 2.15 * cm, 2.0 * cm, 2.0 * cm, 2.15 * cm, 2.3 * cm, 2.15 * cm],
repeatRows=2)
t.setStyle(TableStyle([
("FONT", (0, 0), (-1, -1), "DejaVu", 6.2), ("FONT", (0, 0), (-1, 1), "DejaVu-Bold", 6.2),
("GRID", (0, 0), (-1, -1), 0.5, colors.black), ("SPAN", (2, 0), (5, 0)), ("SPAN", (0, 0), (0, 1)),
("SPAN", (1, 0), (1, 1)), ("SPAN", (6, 0), (6, 1)), ("SPAN", (7, 0), (7, 1)),
("BACKGROUND", (0, 0), (-1, 1), colors.HexColor("#e8eef6")), ("ALIGN", (2, 2), (-1, -1), "RIGHT"),
("VALIGN", (0, 0), (-1, -1), "MIDDLE"), ("ALIGN", (0, 0), (-1, 1), "CENTER"),
("FONT", (0, -1), (-1, -1), "DejaVu-Bold", 6.0)]))
el += [t, P("Kaynak: Yeşilvadi Belediyesi Mali Hizmetler Müdürlüğü, 2025 yılı kesin hesap verileri.", "note")]
el += [P("4. İNSAN KAYNAKLARI", "h2"), P("Tablo 5: Norm Kadro ve Personel Durumu (Kişi)", "cap")]
rows = [["Personel Türü", "Dolu", "Boş", "Toplam"]]
td = tb = 0
for k, (dolu, bos) in pers.items():
rows.append([k, tr(dolu, 0), "-" if bos is None else tr(bos, 0), tr(dolu + (bos or 0), 0)])
td += dolu
tb += bos or 0
rows.append(["TOPLAM", tr(td, 0), tr(tb, 0), tr(td + tb, 0)])
t = Table(rows, colWidths=[6 * cm, 2.4 * cm, 2.4 * cm, 2.4 * cm])
t.setStyle(TableStyle([("FONT", (0, 0), (-1, -1), "DejaVu", 8.4), ("FONT", (0, 0), (-1, 0), "DejaVu-Bold", 8.4),
("FONT", (0, -1), (-1, -1), "DejaVu-Bold", 8.4),
("GRID", (0, 0), (-1, -1), 0.5, colors.black), ("ALIGN", (1, 0), (-1, -1), "RIGHT"),
("BACKGROUND", (0, 0), (-1, 0), colors.HexColor("#e8eef6"))]))
el += [t, P("(*) 4734 sayılı Kamu İhale Kanunu kapsamında hizmet alımı yoluyla çalıştırılan personeli ifade eder; "
"norm kadro kapsamında değildir.", "note")]
el += [P("5. MAHALLE BİLGİLERİ", "h2"),
P("Belediye sınırları içindeki mahallelerin Adrese Dayalı Nüfus Kayıt Sistemi (ADNKS) sonuçlarına göre nüfusları "
"ve hane sayıları aşağıda verilmiştir."),
P("Tablo 6: Mahallelere Göre Nüfus ve Hane Sayısı", "cap")]
rows = [["Mahalle", "Nüfus (2024)", "Nüfus (2025)", "Hane Sayısı (2025)", "Değişim (%)"]]
for m, v in mah.items():
rows.append([m, tr(v["n24"], 0), tr(v["n25"], 0), tr(v["hane"], 0), tr(v["deg"], 2)])
s24 = sum(v["n24"] for v in mah.values())
s25 = sum(v["n25"] for v in mah.values())
sh = sum(v["hane"] for v in mah.values())
rows.append(["Genel Toplam", tr(s24, 0), tr(s25, 0), tr(sh, 0), tr(round(100 * (s25 - s24) / s24, 2), 2)])
t = Table(rows, colWidths=[4.6 * cm, 2.8 * cm, 2.8 * cm, 3.6 * cm, 2.4 * cm], repeatRows=1)
t.setStyle(TableStyle([("FONT", (0, 0), (-1, -1), "DejaVu", 8.2), ("FONT", (0, 0), (-1, 0), "DejaVu-Bold", 8.2),
("FONT", (0, -1), (-1, -1), "DejaVu-Bold", 8.2),
("GRID", (0, 0), (-1, -1), 0.5, colors.black), ("ALIGN", (1, 0), (-1, -1), "RIGHT"),
("BACKGROUND", (0, 0), (-1, 0), colors.HexColor("#e8eef6"))]))
el += [t, P("Kaynak: TÜİK ADNKS verileri esas alınarak Belediye Planlama Müdürlüğünce derlenmiştir (kurgusal).", "note")]
doc.build(el, onFirstPage=footer, onLaterPages=footer)
# ================================================================== D2: KAP tarzı finansal tablolar
def d2_data():
r = lambda a, b_: float(round(rng.uniform(a, b_), -3)) # noqa: E731
cur, prev = {}, {}
for k, lo, hi in [("nakit", 40e6, 120e6), ("ticari_alacak", 150e6, 320e6), ("diger_alacak", 3e6, 12e6),
("stok", 180e6, 260e6), ("pesin", 4e6, 9e6), ("mdv", 600e6, 900e6), ("mod", 20e6, 45e6),
("ert_vergi", 5e6, 15e6), ("kv_borc", 120e6, 220e6), ("ticari_borc", 140e6, 250e6),
("uv_borc", 180e6, 300e6)]:
cur[k] = r(lo, hi)
prev[k] = float(round(cur[k] * rng.uniform(0.78, 1.12), -3))
prev["stok"] = float(round(cur["stok"] / 1.237, -3)) # stoklar ~%23,7 artış
inc = {}
for d, scale in ((cur, 1.0), (prev, 0.81)):
h = float(round(2_450e6 * scale * rng.uniform(0.97, 1.03), -3))
smm = -float(round(h * rng.uniform(0.71, 0.75), -3))
gyg = -float(round(h * 0.041, -3))
pzg = -float(round(h * 0.063, -3))
dg = float(round(h * 0.012, -3))
dgid = -float(round(h * 0.007, -3))
bk = h + smm
efk = bk + gyg + pzg + dg + dgid
fin = -float(round(h * 0.052, -3))
vok = efk + fin
vg = -float(round(vok * 0.25, -3))
dk = vok + vg
inc[id(d)] = dict(hasilat=h, smm=smm, bk=bk, gyg=gyg, pzg=pzg, dg=dg, dgid=dgid, efk=efk, fin=fin, vok=vok,
vg=vg, dk=dk, pbk=round(dk / 250e6, 4))
for d in (cur, prev):
i = inc[id(d)]
d.update(i)
d["sermaye"] = 250e6
d["top_donen"] = d["nakit"] + d["ticari_alacak"] + d["diger_alacak"] + d["stok"] + d["pesin"]
d["top_duran"] = d["mdv"] + d["mod"] + d["ert_vergi"]
d["top_varlik"] = d["top_donen"] + d["top_duran"]
d["top_kv"] = d["kv_borc"] + d["ticari_borc"]
d["top_uv"] = d["uv_borc"]
d["net_kar"] = d["dk"]
d["gecmis"] = d["top_varlik"] - d["top_kv"] - d["top_uv"] - d["sermaye"] - d["net_kar"]
d["top_oz"] = d["sermaye"] + d["gecmis"] + d["net_kar"]
d["top_kaynak"] = d["top_kv"] + d["top_uv"] + d["top_oz"]
return cur, prev
BILANCO = [("VARLIKLAR", None, None, 0), ("Dönen Varlıklar", None, None, 0),
("Nakit ve Nakit Benzerleri", "5", "nakit", 1), ("Ticari Alacaklar", "7", "ticari_alacak", 1),
("Diğer Alacaklar", "8", "diger_alacak", 1), ("Stoklar", "9", "stok", 1),
("Peşin Ödenmiş Giderler", "10", "pesin", 1), ("TOPLAM DÖNEN VARLIKLAR", None, "top_donen", 0),
("Duran Varlıklar", None, None, 0), ("Maddi Duran Varlıklar", "11", "mdv", 1),
("Maddi Olmayan Duran Varlıklar", "12", "mod", 1), ("Ertelenmiş Vergi Varlığı", "24", "ert_vergi", 1),
("TOPLAM DURAN VARLIKLAR", None, "top_duran", 0), ("TOPLAM VARLIKLAR", None, "top_varlik", 0),
("KAYNAKLAR", None, None, 0), ("Kısa Vadeli Yükümlülükler", None, None, 0),
("Kısa Vadeli Borçlanmalar", "6", "kv_borc", 1), ("Ticari Borçlar", "7", "ticari_borc", 1),
("TOPLAM KISA VADELİ YÜKÜMLÜLÜKLER", None, "top_kv", 0), ("Uzun Vadeli Yükümlülükler", None, None, 0),
("Uzun Vadeli Borçlanmalar", "6", "uv_borc", 1), ("TOPLAM UZUN VADELİ YÜKÜMLÜLÜKLER", None, "top_uv", 0),
("Özkaynaklar", None, None, 0), ("Ödenmiş Sermaye", "16", "sermaye", 1),
("Geçmiş Yıllar Karları", None, "gecmis", 1), ("Net Dönem Karı", None, "net_kar", 1),
("TOPLAM ÖZKAYNAKLAR", None, "top_oz", 0), ("TOPLAM KAYNAKLAR", None, "top_kaynak", 0)]
GELIR = [("Hasılat", "18", "hasilat"), ("Satışların Maliyeti (-)", "18", "smm"), ("BRÜT KAR", None, "bk"),
("Genel Yönetim Giderleri (-)", "19", "gyg"), ("Pazarlama Giderleri (-)", "19", "pzg"),
("Esas Faaliyetlerden Diğer Gelirler", "20", "dg"), ("Esas Faaliyetlerden Diğer Giderler (-)", "20", "dgid"),
("ESAS FAALİYET KARI", None, "efk"), ("Finansman Giderleri (-)", "21", "fin"),
("SÜRDÜRÜLEN FAALİYETLER VERGİ ÖNCESİ KARI", None, "vok"), ("Dönem Vergi Gideri (-)", "24", "vg"),
("DÖNEM KARI", None, "dk"), ("Pay Başına Kazanç (TL)", "25", "pbk")]
def _fin_table(spec, cur, prev, with_indent=True, pbk_key="pbk"):
H = lambda t: Paragraph(t, ParagraphStyle("fh", fontName="DejaVu-Bold", fontSize=7.2, leading=8.6, alignment=2)) # noqa: E731
hdr1 = ["", H("Dipnot"), H("Bağımsız Denetimden Geçmiş"), H("Bağımsız Denetimden Geçmiş")]
hdr2 = ["", H("Referansları"), H("Cari Dönem"), H("Önceki Dönem")]
hdr3 = ["", "", "31.12.2025", "31.12.2024"]
rows = [hdr1, hdr2, hdr3]
bold_rows = []
for item in spec:
lab, dip, key = item[0], item[1], item[2]
ind = item[3] if len(item) > 3 else (0 if lab.isupper() else 1)
if key is None:
rows.append([lab, "", "", ""])
elif key == pbk_key:
rows.append([(" " * ind) + lab, dip or "", tr(cur[key], 4), tr(prev[key], 4)])
else:
rows.append([(" " * ind) + lab, dip or "", paren(cur[key]), paren(prev[key])])
if lab.isupper() or key is None:
bold_rows.append(len(rows) - 1)
t = Table(rows, colWidths=[7.4 * cm, 2.0 * cm, 3.9 * cm, 3.9 * cm], repeatRows=3)
style = [("FONT", (0, 0), (-1, -1), "DejaVu", 7.8), ("FONT", (0, 0), (-1, 2), "DejaVu-Bold", 7.4),
("ALIGN", (1, 0), (-1, -1), "RIGHT"), ("ALIGN", (1, 0), (1, -1), "CENTER"),
("LINEBELOW", (0, 2), (-1, 2), 0.8, colors.black), ("LINEABOVE", (0, 0), (-1, 0), 0.8, colors.black),
("TOPPADDING", (0, 0), (-1, -1), 1.6), ("BOTTOMPADDING", (0, 0), (-1, -1), 1.6)]
for r in bold_rows:
style.append(("FONT", (0, r), (-1, r), "DejaVu-Bold", 7.8))
if rows[r][0].startswith("TOPLAM") or rows[r][0] in ("BRÜT KAR", "DÖNEM KARI", "ESAS FAALİYET KARI"):
style.append(("LINEABOVE", (2, r), (-1, r), 0.5, colors.black))
t.setStyle(TableStyle(style))
return t
def d2_pdf(cur, prev, path):
doc = SimpleDocTemplate(str(path), pagesize=A4, leftMargin=1.8 * cm, rightMargin=1.8 * cm, topMargin=1.8 * cm,
bottomMargin=2 * cm, title="Kuzeyçınar Gıda 31.12.2025 Konsolide Finansal Tablolar")
el = [P("KUZEYÇINAR GIDA SANAYİ VE TİCARET A.Ş.<br/>VE BAĞLI ORTAKLIKLARI", "h1"),
P("31 ARALIK 2025 TARİHİ İTİBARIYLA HAZIRLANAN KONSOLİDE FİNANSAL TABLOLAR VE BAĞIMSIZ DENETÇİ RAPORU", "h2"),
P("Konsolide finansal tablolar, Sermaye Piyasası Kurulu'nun II-14.1 sayılı Tebliği hükümleri uyarınca Türkiye "
"Finansal Raporlama Standartları'na (TFRS) uygun olarak hazırlanmıştır."),
P("31 Aralık 2025 Tarihli Konsolide Finansal Durum Tablosu (Bilanço)", "cap"),
P("(Tutarlar aksi belirtilmedikçe Türk Lirası (\"TL\") olarak ifade edilmiştir.)", "note"),
_fin_table(BILANCO, cur, prev), PageBreak(),
P("1 Ocak - 31 Aralık 2025 Hesap Dönemine Ait Konsolide Kar veya Zarar Tablosu", "cap"),
P("(Tutarlar aksi belirtilmedikçe Türk Lirası (\"TL\") olarak ifade edilmiştir.)", "note"),
_fin_table([(a, b_, c) for a, b_, c in GELIR], cur, prev),
Spacer(1, 8),
P("İlişikteki dipnotlar bu konsolide finansal tabloların tamamlayıcı parçasıdır.", "note")]
doc.build(el, onFirstPage=footer, onLaterPages=footer)
# ================================================================== D3: il istatistik bülteni (HTML)
ILCE = ["Merkez", "Yukarıova", "Kızılçam", "Taşlıdere", "Akpınar", "Sarıyurt", "Çaltepe", "Karaağıl"]
AYLAR = ["Ocak", "Şubat", "Mart", "Nisan", "Mayıs", "Haziran", "Temmuz", "Ağustos", "Eylül", "Ekim", "Kasım", "Aralık"]
def d3_data():
tur = {}
for i in ILCE:
base = rng.randint(4_000, 60_000) * (4 if i == "Merkez" else 1)
q = [int(base * f * rng.uniform(0.9, 1.1)) for f in (0.6, 1.1, 1.6, 0.7)]
prev = int(sum(q) * rng.uniform(0.85, 1.12))
tur[i] = dict(q=q, top=sum(q), prev=prev, deg=round(100 * (sum(q) - prev) / prev, 1))
konut = {}
for a in AYLAR:
ip = rng.randint(180, 520)
dg = rng.randint(700, 1500)
prev = int((ip + dg) * rng.uniform(0.82, 1.18))
konut[a] = dict(ip=ip, dg=dg, top=ip + dg, prev=prev, deg=round(100 * (ip + dg - prev) / prev, 1))
return tur, konut
def d3_html(tur, konut, path):
def fmt(x):
return tr(x, 0)
il_q = [sum(v["q"][k] for v in tur.values()) for k in range(4)]
il_top, il_prev = sum(il_q), sum(v["prev"] for v in tur.values())
rows1 = "".join(
f"<tr><td>{i}</td>" + "".join(f"<td>{fmt(x)}</td>" for x in v["q"]) +
f"<td>{fmt(v['top'])}</td><td>{fmt(v['prev'])}</td><td>{tr(v['deg'], 1)}</td></tr>\n" for i, v in tur.items())
rows1 += (f"<tr class='toplam'><td>İl Toplamı</td>" + "".join(f"<td>{fmt(x)}</td>" for x in il_q) +
f"<td>{fmt(il_top)}</td><td>{fmt(il_prev)}</td><td>{tr(round(100 * (il_top - il_prev) / il_prev, 1), 1)}</td></tr>")
rows2 = "".join(f"<tr><td>{a} 2025</td><td>{fmt(v['ip'])}</td><td>{fmt(v['dg'])}</td><td>{fmt(v['top'])}</td>"
f"<td>{fmt(v['prev'])}</td><td>{tr(v['deg'], 1)}</td></tr>\n" for a, v in konut.items())
html = f"""<!doctype html>
<html lang="tr"><head><meta charset="utf-8"><title>Ardıçlı İli 2025 Yılı İstatistik Bülteni</title>
<style>body{{font-family:DejaVu Sans,Arial,sans-serif;max-width:900px;margin:24px auto;color:#222}}
table{{border-collapse:collapse;margin:8px 0 4px}}td,th{{border:1px solid #888;padding:3px 8px;font-size:13px}}
td:not(:first-child){{text-align:right}}th{{background:#e8eef6}}.toplam td{{font-weight:bold}}
tfoot td{{border:none;font-size:11px;color:#555;text-align:left!important}}.uyari{{color:#9a3412;font-size:12px}}</style></head>
<body>
<p class="uyari">{UYARI}</p>
<h1>Ardıçlı İli 2025 Yılı İstatistik Bülteni</h1>
<p>Bu bülten, Ardıçlı İl Planlama ve Koordinasyon Müdürlüğü tarafından derlenen turizm ve konut istatistiklerini içermektedir.
Veriler geçicidir ve sonraki yayımlarda güncellenebilir.</p>
<h2>1. Turizm</h2>
<table>
<caption>Tablo 1: İlçelere Göre Konaklama Tesislerine Geliş Sayısı (Kişi)</caption>
<thead>
<tr><th rowspan="2">İlçe</th><th colspan="4">2025</th><th rowspan="2">2025 Toplam</th><th rowspan="2">2024 Toplam</th><th rowspan="2">Değişim (%)</th></tr>
<tr><th>Ç1</th><th>Ç2</th><th>Ç3</th><th>Ç4</th></tr>
</thead>
<tbody>
{rows1}
</tbody>
<tfoot><tr><td colspan="8">Kaynak: Ardıçlı İl Kültür ve Turizm Müdürlüğü, belediye ve bakanlık belgeli tesis kayıtları. Ç: çeyrek.</td></tr></tfoot>
</table>
<h2>2. Konut</h2>
<table>
<caption>Tablo 2: Aylara Göre Konut Satışları (Adet)</caption>
<thead><tr><th>Ay</th><th>İpotekli Satış</th><th>Diğer Satış</th><th>Toplam Satış</th><th>Önceki Yılın Aynı Ayı</th><th>Yıllık Değişim (%)</th></tr></thead>
<tbody>
{rows2}
</tbody>
<tfoot><tr><td colspan="6">Kaynak: Ardıçlı Tapu Müdürlüğü kayıtları. Aralık ayı verileri geçicidir.</td></tr></tfoot>
</table>
</body></html>"""
path.write_text(html, encoding="utf-8")
return il_q, il_top, il_prev
# ================================================================== sorular ve altın cevaplar
def questions(b, tot, pers, mah, cur, prev, tur, konut, il_top):
Q = []
def q(belge, soru, cevap, tip="sayi", ozellik="", zorluk="orta", birim=None, **kw):
Q.append(dict(id=f"P{len(Q) + 1:02d}", belge=belge, soru=soru, tip=tip, cevap=cevap, birim=birim,
ozellik=ozellik, zorluk=zorluk, **kw))
D1, D2, D3 = "yesilvadi_belediyesi_2025_faaliyet_raporu.pdf", "kuzeycinar_gida_2025_finansal_tablolar.pdf", \
"ardicli_ili_2025_istatistik_bulteni.html"
num = {k: v for k, v in b.items() if v["oran"] is not None}
# --- D1 bütçe
q(D1, "Yeşilvadi Belediyesinin 2025 yılında personel giderleri gerçekleşmesi ne kadardır?", b["01"]["gerc"],
ozellik="iki satırlı başlık; ekonomik kod sütunu", zorluk="kolay", birim="TL")
q(D1, "Mal ve hizmet alım giderleri için toplam ödenek kaç TL'dir?", b["03"]["top"],
ozellik="birleşik 'Ödenek' başlığı altındaki alt sütun", birim="TL")
q(D1, "Sermaye giderlerinin gerçekleşme oranı yüzde kaçtır?", b["06"]["oran"],
ozellik="yüzde birimi yalnızca başlıkta (%)", zorluk="kolay")
q(D1, "Gerçekleşme oranı en düşük olan gider türü hangisidir?", min(num.values(), key=lambda v: v["oran"])["ad"],
tip="metin", ozellik="en düşük; '-' değerli satır ve TOPLAM satırı dışlanmalı", zorluk="zor")
q(D1, "Belediyenin 2025 yılı toplam bütçe gerçekleşmesi kaç TL'dir?", tot["gerc"],
ozellik="belgenin TOPLAM satırı; çift sayım tuzağı", birim="TL")
q(D1, "Faiz giderlerine yıl içinde eklenen ödenek ne kadardır?", b["04"]["ekl"], ozellik="alt sütun 'Eklenen'",
birim="TL")
q(D1, "Gerçekleşmesi 50 milyon TL'yi aşan gider türleri hangileridir?",
sorted(v["ad"] for v in b.values() if v["gerc"] > 50e6), tip="liste",
ozellik="eşik + birim dönüşümü (milyon TL)", zorluk="zor")
q(D1, "Personel giderleri gerçekleşmesi kaç milyon TL'dir?", round(b["01"]["gerc"] / 1e6, 2),
ozellik="birim dönüşümü TL → milyon TL", zorluk="zor", birim="milyon TL")
q(D1, "Cari transferlerin toplam bütçe gerçekleşmesi içindeki payı yüzde kaçtır?",
round(100 * b["05"]["gerc"] / tot["gerc"], 2), ozellik="pay; toplam satırı dışlanmalı", zorluk="zor")
q(D1, "Yeşilvadi Belediyesinin 2024 yılı personel gideri ne kadardı?", None, tip="cevapsiz",
ozellik="tabloda olmayan yıl")
# --- D1 personel
q(D1, "Belediyede kaç memur kadrosu doludur?", pers["Memur"][0], ozellik="basit seçim", zorluk="kolay")
q(D1, "Belediyede toplam kaç boş kadro bulunmaktadır?", sum(v[1] or 0 for v in pers.values()),
ozellik="TOPLAM satırı; '-' değerli satır")
q(D1, "Sözleşmeli personel için toplam kadro sayısı kaçtır?", sum(x or 0 for x in pers["Sözleşmeli Personel"]),
ozellik="sütun adı 'Toplam' (toplam sözcüğü çok anlamlı)", zorluk="zor")
q(D1, "Belediyede hizmet alımıyla çalışan şirket personeli sayısı kaçtır?", pers["Şirket Personeli (*)"][0],
ozellik="dipnot işaretli satır adı '(*)'", zorluk="zor")
q(D1, "Belediyede kaç itfaiye eri kadrosu vardır?", None, tip="cevapsiz", ozellik="tabloda olmayan unvan")
# --- D1 mahalle (çok sayfalı)
m_list = list(mah.items())
q(D1, "Cumhuriyet Mahallesinin 2025 nüfusu kaçtır?", mah["Cumhuriyet"]["n25"], ozellik="çok sayfalı tablonun ilk sayfası",
zorluk="kolay")
q(D1, "Işıklar Mahallesinin 2025 nüfusu kaçtır?", mah["Işıklar"]["n25"],
ozellik="çok sayfalı tablonun son sayfası; I/ı", zorluk="zor")
q(D1, "Belediye sınırları içinde kaç mahalle vardır?", len(mah),
ozellik="sayım; tablo sayfalara bölünmüş; Genel Toplam satırı dışlanmalı", zorluk="zor")
q(D1, "2025 nüfusu en yüksek olan mahalle hangisidir?", max(m_list, key=lambda kv: kv[1]["n25"])[0], tip="metin",
ozellik="en yüksek; tüm sayfalar", zorluk="zor")
q(D1, "Nüfusu 2024'ten 2025'e azalan kaç mahalle vardır?", sum(1 for _, v in m_list if v["n25"] < v["n24"]),
ozellik="negatif değişim sayımı", zorluk="zor")
q(D1, "Mahallelerin 2025 yılı toplam nüfusu kaçtır?", sum(v["n25"] for v in mah.values()),
ozellik="Genel Toplam satırı", zorluk="orta")
q(D1, "Kurtuluş Mahallesinde 2025 yılında hane başına ortalama kaç kişi düşmektedir?",
round(mah["Kurtuluş"]["n25"] / mah["Kurtuluş"]["hane"], 2), ozellik="iki sütun oranı", zorluk="zor")
# --- D2 bilanço
q(D2, "Kuzeyçınar Gıda'nın 31.12.2025 itibarıyla nakit ve nakit benzerleri ne kadardır?", cur["nakit"],
ozellik="dikey çizgisiz tablo; tarihli dönem başlığı", zorluk="orta", birim="TL")
q(D2, "Stoklar önceki döneme göre yüzde kaç artmıştır?", round(100 * (cur["stok"] - prev["stok"]) / prev["stok"], 2),
ozellik="cari/önceki dönem yüzde değişim", zorluk="zor")
q(D2, "Şirketin 2025 yılı sonu toplam varlıkları kaç TL'dir?", cur["top_varlik"],
ozellik="ara toplam satırı (büyük harf)", birim="TL")
q(D2, "Kısa vadeli borçlanmalar 31.12.2024 tarihinde ne kadardı?", prev["kv_borc"],
ozellik="önceki dönem sütunu; aynı kalem adı iki kez değil", birim="TL")
q(D2, "Cari dönemde toplam özkaynaklar ne kadardır?", cur["top_oz"], ozellik="ara toplam", birim="TL")
q(D2, "Şirketin ödenmiş sermayesi kaç TL'dir?", cur["sermaye"], ozellik="dipnot sütunu bitişik", zorluk="kolay",
birim="TL")
# --- D2 gelir tablosu
q(D2, "Kuzeyçınar Gıda'nın 2025 yılı hasılatı ne kadardır?", cur["hasilat"], ozellik="ikinci sayfadaki tablo",
zorluk="kolay", birim="TL")
q(D2, "2025 yılında brüt kâr ne kadar gerçekleşmiştir?", cur["bk"], ozellik="'kâr' / 'KAR' yazımı", birim="TL")
q(D2, "2025 yılında satışların maliyeti ne kadardır?", abs(cur["smm"]),
ozellik="parantezli negatif; '(-)' etiketi", birim="TL", isaret_serbest=True)
q(D2, "Dönem kârı önceki yıla göre yüzde kaç değişmiştir?", round(100 * (cur["dk"] - prev["dk"]) / prev["dk"], 2),
ozellik="yüzde değişim", zorluk="zor")
q(D2, "2025 yılı pay başına kazanç kaç TL'dir?", cur["pbk"], ozellik="4 ondalıklı küçük sayı", zorluk="orta")
q(D2, "2025 yılı brüt kâr marjı yüzde kaçtır?", round(100 * cur["bk"] / cur["hasilat"], 2),
ozellik="alan formülü (brüt kâr / hasılat)", zorluk="zor")
q(D2, "Kuzeyçınar Gıda'nın 2025 yılında kaç çalışanı vardır?", None, tip="cevapsiz", ozellik="tabloda olmayan bilgi")
q(D2, "Şirketin 2026 yılı ilk çeyrek hasılatı ne kadardır?", None, tip="cevapsiz", ozellik="kapsam dışı dönem")
# --- D3 turizm ve konut
q(D3, "Merkez ilçesine 2025 yılının üçüncü çeyreğinde kaç kişi gelmiştir?", tur["Merkez"]["q"][2],
ozellik="colspan başlık altında Ç3 sütunu", zorluk="orta")
q(D3, "2025 yılında il genelinde konaklama tesislerine toplam kaç kişi gelmiştir?", il_top,
ozellik="İl Toplamı satırı", zorluk="orta")
q(D3, "Geliş sayısı 2024'e göre azalan ilçeler hangileridir?", sorted(i for i, v in tur.items() if v["deg"] < 0),
tip="liste", ozellik="negatif değişim filtresi; toplam satırı dışlanmalı", zorluk="zor")
q(D3, "Mart 2025'te toplam kaç konut satılmıştır?", konut["Mart"]["top"], ozellik="'Ay yyyy' satır etiketi",
zorluk="orta")
q(D3, "2025 yılında toplam kaç ipotekli konut satışı yapılmıştır?", sum(v["ip"] for v in konut.values()),
ozellik="toplam satırı olmayan tabloda SUM", zorluk="orta")
q(D3, "Konut satışlarının bir önceki yılın aynı ayına göre en çok düştüğü ay hangisidir?",
min(konut.items(), key=lambda kv: kv[1]["deg"])[0] + " 2025", tip="metin", ozellik="en düşük negatif değişim",
zorluk="zor")
q(D3, "Ocak 2026'da kaç konut satılmıştır?", None, tip="cevapsiz", ozellik="kapsam dışı ay")
q(D3, "Hangi ilçede en çok konut satılmıştır?", None, tip="cevapsiz", ozellik="tablo ilçe kırılımı içermiyor")
return Q
def main():
OUT.mkdir(parents=True, exist_ok=True)
b, tot, pers, mah = d1_data()
cur, prev = d2_data()
tur, konut = d3_data()
d1_pdf(b, tot, pers, mah, OUT / "yesilvadi_belediyesi_2025_faaliyet_raporu.pdf")
d2_pdf(cur, prev, OUT / "kuzeycinar_gida_2025_finansal_tablolar.pdf")
il_q, il_top, il_prev = d3_html(tur, konut, OUT / "ardicli_ili_2025_istatistik_bulteni.html")
Q = questions(b, tot, pers, mah, cur, prev, tur, konut, il_top)
meta = {"aciklama": "Kurgusal pilot belgeler için sorular ve ham veriden hesaplanan altın cevaplar.",
"tohum": 31, "sorular": Q}
(ROOT / "pilot" / "sorular.json").write_text(json.dumps(meta, ensure_ascii=False, indent=1), encoding="utf-8")
# ham değerler (değer geri çağırma ölçümü için)
ham = {"yesilvadi_belediyesi_2025_faaliyet_raporu.pdf":
[x for v in b.values() for x in (v["butce"], v["ekl"], v["dus"], v["top"], v["gerc"]) ] +
[x for v in b.values() if v["oran"] is not None for x in [v["oran"]]] +
[x for d, bo in pers.values() for x in [d] + ([bo] if bo is not None else [])] +
[x for v in mah.values() for x in (v["n24"], v["n25"], v["hane"], v["deg"])],
"kuzeycinar_gida_2025_finansal_tablolar.pdf":
[d[k] for d in (cur, prev) for _, _, k, *_ in BILANCO if k] + [d[k] for d in (cur, prev) for _, _, k in GELIR],
"ardicli_ili_2025_istatistik_bulteni.html":
[x for v in tur.values() for x in v["q"] + [v["top"], v["prev"], v["deg"]]] +
[x for v in konut.values() for x in (v["ip"], v["dg"], v["top"], v["prev"], v["deg"])]}
(ROOT / "pilot" / "ham_degerler.json").write_text(json.dumps(ham, ensure_ascii=False), encoding="utf-8")
print("Belgeler:", sorted(p.name for p in OUT.iterdir()))
print("Soru:", len(Q), "| cevapsız:", sum(1 for x in Q if x["tip"] == "cevapsiz"))
if __name__ == "__main__":
main()