############################################################################### # 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 = "" for k, v in ratio_row.items(): pct = abs(v) / max_abs * 100 bars_html += ( f"" f"" f"" f"" f"" ) bars_html += "
{k}" f"
" f"
{v:.2f}
" # 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()