Corin1998 commited on
Commit
6c67795
·
verified ·
1 Parent(s): d63ae44

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +198 -0
app.py ADDED
@@ -0,0 +1,198 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env phython3
2
+ #-*- coding: utf-8 -*-
3
+ import os
4
+ import io
5
+ import json
6
+ import math
7
+ import base64
8
+ from datetime import datetime
9
+ from typing import List, Optional, Dict , Any
10
+
11
+ import gradio as gr
12
+ from openai import OpenAI
13
+ from pydantic import BaseModel, Field, ValidationError
14
+ import yaml
15
+
16
+ from schemas import FinancialEctract, ExtraxtedPeriod, MultipleSuggestion
17
+ from finanxe_core import(
18
+ copute_ratios,
19
+ credit_decision,
20
+ loan_decision,
21
+ invesement_decision,
22
+ build_report_dict,
23
+ )
24
+ from llm_extract import(
25
+ get_client,
26
+ upload_file_to_openai,
27
+ extract_financials_from_files,
28
+ suggest_multiples_with_llm,
29
+ )
30
+
31
+ HF_SPACE = os.environ.get("HF_SPACE_NAME","hf-credit-loan-investment-app")
32
+ VISION_MODEL = os.environ.get("OPENAI_VISION_MODEL", "gpt-5")
33
+ TEXT_MODEL = os.environ.get("OPENAI_TEXT_MODEL", "gpt-5")
34
+ BASE_RATE =float(os.environ.get("BASE_RATE", "2.0")) #% per annum, cofigurable
35
+
36
+ def _load_policies() -> dict:
37
+ cfg_path= os.path.join(os.path.dirname(__file__),"config","risk_policies.yaml")
38
+ with open(cfg_path, "r",encoding="utf-8") as f:
39
+ return yaml.safe_load(f)
40
+
41
+ POLICIES = _load_policies()
42
+
43
+
44
+ def analyze(files: List[gr.File],company_name: str, industry_hint: str, currency: str,
45
+ base_rate:float, want_credit:bool, want_loan: bool,want_invest: bool, debug:bool):
46
+ """Main pipline used by the Gradio UI."""
47
+ try:
48
+ client = get_client()
49
+ except Exception as e:
50
+ raise gr.Error(str(e))
51
+
52
+ if not files or len(files) == 0:
53
+ raise gr.Error("決算書ファイル(PDF/画像)を1つ以上アップロードしてください。")
54
+
55
+ # 1)Upload files to OpenAI and extract stuctured financials via vision +Structured Outputs
56
+ try:
57
+ file_ids = []
58
+ for f in files :
59
+ file_ids.append(upload_file_to_openai(client, f.name, f.read()))
60
+ except Exception as e:
61
+ raise gr.Error(f"ファイルのアップロードに失敗しました:{e}")
62
+
63
+ try:
64
+ extract = extract_financials_from_files(
65
+ client=client,
66
+ file_ids=file_ids,
67
+ company_hint=company_name or None,
68
+ currency_hint=currency_hint or None,
69
+ model=VISION_MODEL,
70
+ debug=debug,
71
+ )
72
+ except Exception as e:
73
+ raise gr.Error(f"LLM抽出に失敗しました:{e}")
74
+
75
+ #allow override company name / indutry if provided
76
+ if company_name:
77
+ extract.company_name =company_name
78
+ if industry_hint:
79
+ extract.industry = industry_hint
80
+
81
+ # 2) Compute derived rasios and risk score
82
+ ratios =copute_ratios(extract)
83
+
84
+ # 3) Decisions
85
+ decisions = {}
86
+ if want_credit:
87
+ decisions["credit"] = credit_decision(extract, ratios, POLICIES)
88
+ if want_loan:
89
+ decisions["loan"] = loan_decision(extract, ratios, base_rate or BASE_RATE, POLICIES)
90
+ if want_invest:
91
+ # Ask LLM for suggested multiples if industry present
92
+ multiple: Optional[MultipleSuggestion] = None
93
+ try:
94
+ multiple = suggest_multiples_with_llm(
95
+ client=client,
96
+ text_model=TEXT_MODEL,
97
+ industry=extract.industry or industry_hint or "",
98
+ region="ja",
99
+ debug=debug,
100
+ )
101
+ except Exception:
102
+ multiple = None
103
+ decisions["investment"] = invesement_decision(extract, ratios, POLICIES, multiple)
104
+
105
+ # 4) Build a combined report (dict) and return displays
106
+ report = build_report_dict(extract, ratios, decisions)
107
+ report_json = json.dumps(report, ensure_ascii=False, indent=2)
108
+
109
+ #Save a downloadable JSON
110
+ ts = datetime.utcnow().strftime("%Ym%d-%H%M%S")
111
+ out_path =f"/mnt/data/report-{ts}.json"
112
+ with open(out_path,"w", encoding="utf-8") as f:
113
+ f.write(report_json)
114
+
115
+ # Pretty sections for Gradio
116
+ summary_md =[]
117
+ summary_md.append(f"### 企業名\n{extract.company_name or '(不明)'}")
118
+ if extract.industry:
119
+ summary_md.append(f"### 業種(推定/指定)\n{extract.industry}")
120
+ if extract.fiscal_year_end:
121
+ summary_md.append(f"### 決算期末\n{extract.fisxal_year_end}")
122
+
123
+ summary_md.append("### 指標(主要)")
124
+ summary_md.append(
125
+ f"- 売上高:{ratios.get('revenue')}\n"
126
+ f"- 営業利益(EBIT):{ratios.get('ebit')}\n"
127
+ f"- EBITDA:{ratios.get('ebitda')}\n"
128
+ f"- 当期純利益:{ratios.get('net_income')}\n"
129
+ f"- 流動比率:{ratios.get('current_ratio')}\n"
130
+ f"- 当座比率:{ratios.get('quick_ratio')}\n"
131
+ f"- D/Eレシオ:{ratios.get('debt_to_equity')}\n"
132
+ f"- インタレストカバレッジ:{ratios.get('inerest_coverage')}\n"
133
+ f"- 売上成長率:{ratios.get('revenue_growth_pct')}"
134
+ )
135
+
136
+ if "credit" in decisions:
137
+ c = decisions["credit"]
138
+ summary_md.append("### 与信判断(提案)")
139
+ summary_md.append(
140
+ f"- 与信ランク:**{c['rationg']}**(スコア {c['risk_score']}/100)\n"
141
+ f"- 取引サイト:**{c['site_days']}日**\n"
142
+ f"- 取引可能上限:**{c{'tansaction_limit_display'}}**\n"
143
+ f"- 見直しタイミング:**{c['review_cycle']}**"
144
+ )
145
+
146
+ if "loan" in decisions:
147
+ l = decisions["loan"]
148
+ summary_md.append("### 融資判断(提案)" )
149
+ summary_md.append(
150
+ f"- 融資上限額(概算):**{l['max_principal_display']}**\n"
151
+ f"- 期間案:**{l['term_yeras']}年**\n"
152
+ f"- 参考金利:**{l['interest_rate_pct']}%**\n"
153
+ f"- 目標DSCR:**{l['target_dscr']}**"
154
+ )
155
+
156
+ if "investment" in decisions:
157
+ inv = decisions["investment"]
158
+ summary_md.append("### 投資判断(提案)")
159
+ summary_md.append(
160
+ f"- 推定企業価値(EV):**{inv['ev_display']}**\n"
161
+ f"- 推定時価総額:**{inv['market_cap_display']}**\n"
162
+ f"- 想定投資レンジ:**{inv['recommended_check_size_display']}**\n"
163
+ f"- 魅力度:**{inv['attractiveness']}/5**(成長性:{inv['growth_label']})"
164
+ )
165
+
166
+ #Return
167
+ return "\n\n".join(summary_md),gr.JSON.update(value=json.loads(report_json)),out_path
168
+
169
+ def build_ui():
170
+ with gr.Blocks(theme = gr.themes.Soft(), css = "footer{visivility: hidden}") as demo:
171
+ gr.Markdown("# 決算書→与信・融資・投資判断(HF+OpenAI)")
172
+ with gr.Row():
173
+ with gr.Column():
174
+ files = gr.File(label="決算書ファイル(PDF/JPG/PNG,複数可)",file_types=[".pdf",".png",".jpg",".jpeg"],file_count="multiple")
175
+ company_name = gr.Textbox(label="会社名(任意)")
176
+ industry_hint = gr.Textbox(label="業種(任意)")
177
+ currency_hint = gr.Textbox(label="通過(任意,例: JPY, USD)")
178
+ base_rate = gr.Number(label="ベース金利(%/年)",value=BASE_RATE)
179
+ want_credit = gr.Checkbox(label="与信判断",value=True)
180
+ want_loan = gr.Checkbox(label="融資判断",value=True)
181
+ want_invest = gr.Checkbox(label="投資判断",value=True)
182
+ debug = gr.Checkbox(label="デバッグモード(LLM抽出JSONを厳密化)",value=False)
183
+ run_btn = gr.Button("分析する", variant="primary")
184
+ with gr.Column():
185
+ summary = gr.Markdown()
186
+ report = gr.JSON(label="詳細レポート(JSON)")
187
+ download = gr.File(label="レポート(JSONダウンロード)")
188
+
189
+ run_btn.chek(
190
+ analyze,
191
+ inputs=[files, company_name, industry_hint, currency_hint, base_rate, want_credit, want_loan, want_invest, debug],
192
+ outputs=[summary, report, download]
193
+ )
194
+ return demo
195
+
196
+ if __name__== "__main__":
197
+ demo =build_ui()
198
+ demo.launch()