| | |
| | |
| | |
| |
|
| | 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", |
| | ] |
| |
|
| | |
| | |
| | |
| |
|
| | 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): |
| |
|
| | |
| | if excel_file is None: |
| | raise gr.Error("Lütfen analiz edilecek Excel dosyasını yükleyin.") |
| |
|
| | p = gr.Progress(track_tqdm=False) |
| |
|
| | |
| | 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) |
| | .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() |
| |
|
| | |
| | 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ı.") |
| |
|
| | |
| | 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)) |
| |
|
| | |
| | actual = [] |
| |
|
| | |
| | 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]) |
| |
|
| | |
| | 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) |
| | ] |
| |
|
| | |
| | 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 |
| | }) |
| |
|
| | |
| | p(0.90, "Bar grafikleri hazırlanıyor…") |
| | ratio_row = model_input.iloc[0][DISPLAY_FEATS] |
| |
|
| | |
| | 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>" |
| |
|
| |
|
| |
|
| | |
| | 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), |
| | ) |
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | |
| | with gr.Blocks(theme=gr.themes.Default(primary_hue="blue")) as demo: |
| | gr.Markdown("# Denetçi Görüşü Tahmin Uygulaması") |
| |
|
| | |
| | with gr.Row(): |
| | file_input = gr.File(file_types=[".xlsx", ".xls", ".xlsm"], |
| | label="Excel Yükleyin") |
| | predict_btn = gr.Button("Tahmin Et", variant="primary") |
| |
|
| | |
| | gr.Examples( |
| | examples=EXAMPLE_XLSX, |
| | inputs=file_input, |
| | label="Örnek Dosyayı Deneyin", |
| | cache_examples=False,) |
| |
|
| | |
| | |
| | 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() |