buraktrk's picture
Update app.py
82f63fe verified
###############################################################################
# 0. IMPORTS & CONSTANTS
##############################################################################
import gradio as gr
import joblib
import numpy as np
import pandas as pd
from pathlib import Path
import re
SAMPLE_DIR = "Sample Inputs (Excel)"
EXAMPLE_XLSX = [
f"{SAMPLE_DIR}/ADESE_2021.xlsx",
f"{SAMPLE_DIR}/YYAPI_2017.xlsx",
f"{SAMPLE_DIR}/SRVGY_2022.xlsx",
f"{SAMPLE_DIR}/THYAO_2023.xlsx",
f"{SAMPLE_DIR}/TTRAK_2024.xlsx",
]
FIN_DATA = pd.read_csv("financial_data.csv")
MODEL_PATH = "slim_xgb.joblib"
SELECTED_FEATS = [
"Altman Z-Skoru", "Finansal Kaldıraç", "Nakit Oranı", "Aktif Devir Hızı",
"L Model Skoru", "Zmijewski Skoru", "Asit Test Oranı",
"Özsermaye / Maddi Duran Varlıklar", "Faaliyet Kar Marjı",
"Duran Varlıklar / Maddi Özkaynak", "Ticari Borçlar Devir Hızı",
"Stok Devir Hızı", "Brüt Kar Marjı (%)", "Cari Oran",
"Esas Faaliyet Karı / Kısa Vadeli Borç", "Esas Faaliyet Kar Marjı",
"Özsermaye / Aktif", "Alacak Devir Hızı", "Borç Kaynak Oranı",
"Net Kar Marjı", "Net Satışlar / Kısa Vade Borç",
"Kısa Vade Borç / Özsermaye", "Kısa Vade Borç / Toplam Borç",
"Kısa Vade Borç / Aktif", "Kısa Vade Borç / Dönen Varlık",
"FAVÖK / Kısa Vade Borç", "Duran Varlıklar / Aktif ",
"Dönen Varlıklar / Aktif (%)", "Dönen Varlıklar Devir Hızı",
"Aktif Karlılık (%)", "ROCE Oranı", "Finansman Gider / Net Satış",
]
DISPLAY_FEATS = [
"Altman Z-Skoru",
"L Model Skoru",
"Zmijewski Skoru",
]
###############################################################################
# 1. HELPER FUNCTIONS
###############################################################################
def safe_div(num: pd.Series, denom: pd.Series) -> pd.Series:
denom_replaced = denom.replace(0, np.nan)
return (num / denom_replaced).fillna(0)
def compute_ratios(df: pd.DataFrame) -> pd.DataFrame:
total_assets = df["Dönen Varlıklar"] + df["Duran Varlıklar"]
total_liab = df["Kısa Vadeli Yükümlülükler"] + df["Uzun Vadeli Yükümlülükler"]
df["Cari Oran"] = safe_div(df["Dönen Varlıklar"], df["Kısa Vadeli Yükümlülükler"])
df["Asit Test Oranı"] = safe_div(
df["Dönen Varlıklar"] - df["Stoklar"] - df["Diğer Dönen Varlıklar"],
df["Kısa Vadeli Yükümlülükler"])
df["Nakit Oranı"] = safe_div(df["Nakit ve Nakit Benzerleri"], df["Kısa Vadeli Yükümlülükler"])
df["Faaliyet Kar Marjı"] = safe_div(df["FAALİYET KARI (ZARARI)"]*100, df["Satış Gelirleri"])
df["Esas Faaliyet Kar Marjı"] = safe_div(df["Net Faaliyet Kar/Zararı"]*100, df["Satış Gelirleri"])
df["Brüt Kar Marjı (%)"] = safe_div(df["Ticari Faaliyetlerden Brüt Kar (Zarar)"]*100,
df["Satış Gelirleri"])
df["Net Kar Marjı"] = safe_div(df["Dönem Net Kar/Zararı"]*100, df["Satış Gelirleri"])
df["FAVÖK / Kısa Vade Borç"] = safe_div(df["FAALİYET KARI (ZARARI)"], df["Kısa Vadeli Yükümlülükler"])
df["Aktif Devir Hızı"] = safe_div(df["Satış Gelirleri"], total_assets)
df["Alacak Devir Hızı"] = safe_div(df["Satış Gelirleri"], df["Ticari Alacaklar"])
df["Dönen Varlıklar Devir Hızı"] = safe_div(df["Dönen Varlıklar"], df["Satış Gelirleri"])
df["Ticari Borçlar Devir Hızı"] = -safe_div(df["Satışların Maliyeti (-)"], df["Ticari Borçlar"])
df["Stok Devir Hızı"] = -safe_div(df["Satışların Maliyeti (-)"], df["Stoklar"])
df["Borç Kaynak Oranı"] = safe_div(total_liab, df["Özkaynaklar"])*100
df["Finansal Kaldıraç"] = safe_div(total_liab, total_assets)*100
df["Özsermaye / Aktif"] = safe_div(df["Özkaynaklar"], total_assets)
df["Özsermaye / Maddi Duran Varlıklar"] = safe_div(df["Özkaynaklar"], df["Maddi Duran Varlıklar"])
df["Duran Varlıklar / Maddi Özkaynak"] = safe_div(df["Duran Varlıklar"],
df["Özkaynaklar"] - df["Maddi Olmayan Duran Varlıklar"])
df["Duran Varlıklar / Aktif "] = safe_div(df["Duran Varlıklar"]*100, total_assets)
df["Dönen Varlıklar / Aktif (%)"] = safe_div(df["Dönen Varlıklar"]*100, total_assets)
df["Kısa Vade Borç / Aktif"] = safe_div(df["Kısa Vadeli Yükümlülükler"], total_assets)
df["Kısa Vade Borç / Dönen Varlık"] = safe_div(df["Kısa Vadeli Yükümlülükler"], df["Dönen Varlıklar"])
df["Kısa Vade Borç / Özsermaye"] = safe_div(df["Kısa Vadeli Yükümlülükler"], df["Özkaynaklar"])
df["Kısa Vade Borç / Toplam Borç"] = safe_div(df["Kısa Vadeli Yükümlülükler"], total_liab)
df["Net Satışlar / Kısa Vade Borç"] = safe_div(df["Satış Gelirleri"], df["Kısa Vadeli Yükümlülükler"])
df["Esas Faaliyet Karı / Kısa Vadeli Borç"] = safe_div(
df["Net Faaliyet Kar/Zararı"], df["Kısa Vadeli Yükümlülükler"])
df["Aktif Karlılık (%)"] = safe_div(df["Dönem Net Kar/Zararı"]*100, total_assets)
df["ROCE Oranı"] = safe_div(df["FAALİYET KARI (ZARARI)"]*100, total_assets)
df["Finansman Gider / Net Satış"] = safe_div(df["Finansman Giderleri"], df["Satış Gelirleri"])
X1 = safe_div(df["Dönen Varlıklar"] - df["Kısa Vadeli Yükümlülükler"], total_assets)
X2 = safe_div(df["Geçmiş Yıllar Kar/Zararları"] + df["Dönem Net Kar/Zararı"], total_assets)
X3 = safe_div(df["SÜRDÜRÜLEN FAALİYETLER VERGİ ÖNCESİ KARI (ZARARI)"], total_assets)
X4 = safe_div(df["Özkaynaklar"], total_liab)
X5 = safe_div(df["Satış Gelirleri"], total_assets)
df["Altman Z-Skoru"] = 1.2*X1 + 1.4*X2 + 3.3*X3 + 0.6*X4 + X5
Z1 = safe_div(df["Dönem Net Kar/Zararı"], total_assets)
Z2 = safe_div(total_liab, total_assets)
Z3 = safe_div(df["Dönen Varlıklar"], df["Kısa Vadeli Yükümlülükler"])
df["Zmijewski Skoru"] = -4.3 - 4.5*Z1 + 5.7*Z2 - 0.004*Z3
L6 = safe_div(safe_div(df["Nakit ve Nakit Benzerleri"], df["Kısa Vadeli Yükümlülükler"]), total_liab)
L7 = safe_div(total_liab, total_assets)
df["L Model Skoru"] = -0.113*X1 + 0.238*X2 - 0.052*X3 - 0.051*X4 + 0.011*X5 + 0.729*L6 - 0.639*L7
return df
def predict_opinion(excel_file: gr.File):
# 0) Dosya kontrolü
if excel_file is None:
raise gr.Error("Lütfen analiz edilecek Excel dosyasını yükleyin.")
p = gr.Progress(track_tqdm=False)
# 1) Excel oku
p(0.05, "Excel okunuyor…")
raw_vert = pd.read_excel(excel_file.name, header=None, sheet_name=0)
raw_df = (
raw_vert.set_index(0) # ilk sütun -> indeks
.T.rename_axis(None)
.reset_index(drop=True)
)
raw_df.columns = raw_df.columns.str.strip()
raw_df = raw_df.loc[:, ~raw_df.columns.duplicated()]
raw_df.rename(columns={"Desc": "Periyot"}, inplace=True)
raw_df["Periyot"] = raw_df["Periyot"].astype(str).str.replace(r"\s+", " ", regex=True).str.strip()
# 2) 32 oran
p(0.30, "32 oran hesaplanıyor…")
enriched = compute_ratios(raw_df.copy())
model_input = enriched[SELECTED_FEATS].copy().dropna()
if model_input.empty:
raise gr.Error("Hiç analiz edilebilir satır kalmadı – oran hesaplanamadı.")
# 3) Model tahmini
p(0.55, "Model yükleniyor…")
pipe, enc = joblib.load(MODEL_PATH)
p(0.75, "Tahmin yapılıyor…")
pred_label = enc.inverse_transform(pipe.predict(model_input))
# 4) Gerçek görüşü CSV’den eşleştir
actual = []
# 4-a) Dosya adından şirket kodu & yıl
code_from_file, year_from_file = None, None
parts = Path(excel_file.name).stem.split("_", 1)
if len(parts) == 2 and parts[1].isdigit():
code_from_file, year_from_file = parts[0].upper(), int(parts[1])
# 4-b) Her satır (periyot) için kod+ yıl + periyot eşle
for idx in model_input.index:
period_lbl = str(raw_df.loc[idx, "Periyot"]).strip()
row = FIN_DATA[
(FIN_DATA["Şirketin Kodu"].str.upper() == code_from_file)
& (FIN_DATA["Yıl"] == year_from_file)
& (FIN_DATA["Periyot"].astype(str).str.strip() == period_lbl)
]
# Yine de bulunamazsa – eski ~yakın değer yaklaşımına geri dön
if row.empty:
dv_val = raw_df.loc[idx, "Dönen Varlıklar"]
tl_val = (
raw_df.loc[idx, "Toplam Yükümlülükler"]
if "Toplam Yükümlülükler" in raw_df.columns
else raw_df.loc[idx, "Kısa Vadeli Yükümlülükler"] +
raw_df.loc[idx, "Uzun Vadeli Yükümlülükler"]
)
row = FIN_DATA[
np.isclose(FIN_DATA["Dönen Varlıklar"], dv_val, rtol=0, atol=1e-3) &
np.isclose(FIN_DATA["Toplam Yükümlülükler"], tl_val, rtol=0, atol=1e-3)
]
actual.append(row["Görüs Tipi"].iloc[0] if not row.empty else "—")
result_df = pd.DataFrame({
"Periyot": raw_df.loc[model_input.index, "Periyot"],
"Tahmin Görüş Tipi": pred_label,
"Gerçek Görüş Tipi": actual
})
# 5) 3 ana skorun mini bar-grafiği
p(0.90, "Bar grafikleri hazırlanıyor…")
ratio_row = model_input.iloc[0][DISPLAY_FEATS]
# ▸ En büyük mutlak değer referans alınır
max_abs = ratio_row.abs().max() or 1
bars_html = "<table style='width:100%;font-size:0.85rem'>"
for k, v in ratio_row.items():
pct = abs(v) / max_abs * 100
bars_html += (
f"<tr>"
f"<td style='padding:2px 6px;white-space:nowrap'>{k}</td>"
f"<td style='width:100%'>"
f"<div style='background:#e5e5e5;height:8px;border-radius:4px'>"
f"<div style='width:{pct:.1f}%;height:8px;"
f"background:#3b82f6;border-radius:4px'></div></div></td>"
f"<td style='padding-left:6px'>{v:.2f}</td>"
f"</tr>"
)
bars_html += "</table>"
# 6) UI çıktılarını döndür
return (
gr.update(value="### Ham Veri", visible=True),
gr.update(value=raw_df.head(), visible=True),
gr.update(value="### Finansal Oranlar", visible=True),
gr.update(value=bars_html, visible=True),
gr.update(value="### Tahmin Sonuçları", visible=True),
gr.update(value=result_df.head(), visible=True),
)
# --- 3. GRADIO UI
with gr.Blocks(theme=gr.themes.Default(primary_hue="blue")) as demo:
gr.Markdown("# Denetçi Görüşü Tahmin Uygulaması")
# 1️⃣ Üst satır: dosya + buton
with gr.Row():
file_input = gr.File(file_types=[".xlsx", ".xls", ".xlsm"],
label="Excel Yükleyin")
predict_btn = gr.Button("Tahmin Et", variant="primary")
# 2️⃣ Örnek dosyalar – daima sabit kalacak
gr.Examples(
examples=EXAMPLE_XLSX,
inputs=file_input,
label="Örnek Dosyayı Deneyin",
cache_examples=False,)
# 3️⃣ Çıktılar
ham_title = gr.Markdown("### Ham Veri", visible=False)
raw_table = gr.Dataframe(visible=False, wrap=True, show_label=False)
ratio_title = gr.Markdown("### Finansal Oranlar", visible=False)
ratio_html = gr.HTML(visible=False)
pred_title = gr.Markdown("### Tahmin Sonuçları", visible=False)
pred_table = gr.Dataframe(visible=False, wrap=True, show_label=False)
predict_btn.click(
predict_opinion,
inputs=file_input,
outputs=[ham_title, raw_table,
ratio_title, ratio_html,
pred_title, pred_table],
api_name="predict",
)
if __name__ == "__main__":
demo.launch()