ESF_IR_reporter / app.py
Corin1998's picture
Upload 11 files
4329b20 verified
import gradio as gr
from pathlib import Path
import tempfile, datetime, json, shutil
from core import generate_report
try:
import openai, httpx
print("[deps] openai:", openai.__version__)
print("[deps] httpx:", httpx.__version__)
except Exception as _e:
print("[deps] version check failed:", _e)
TITLE = "IR/ESG Report Generator (HF Space, LLM+Translation)"
DESC = "CSV/YAML をアップロードして IR/ESG レポート(HTML/PDF/DOCX)を生成します。LLM要約+翻訳に OPENAI_API_KEY2 を使用します。"
TEMPLATES_DIR = str((Path(__file__).resolve().parent / "templates").absolute())
def _to_path(upload_obj, tmpdir: Path, filename: str) -> Path:
"""
Gradio File が返す型の揺れを吸収し、必ず tmpdir/filename に保存してパスを返す。
対応: str/Path, gradio.NamedString(.name), file-like(.read), dict({"name"|"data"}).
"""
dst = tmpdir / filename
if isinstance(upload_obj, (str, Path)):
src = Path(upload_obj)
if src.exists():
shutil.copy(src, dst)
return dst
if hasattr(upload_obj, "name") and isinstance(upload_obj.name, (str, Path)):
src = Path(upload_obj.name)
if src.exists():
shutil.copy(src, dst)
return dst
if hasattr(upload_obj, "read"):
data = upload_obj.read()
if isinstance(data, str):
data = data.encode("utf-8")
elif not isinstance(data, (bytes, bytearray)):
try:
upload_obj.seek(0)
data = upload_obj.read()
except Exception:
pass
if isinstance(data, str):
data = data.encode("utf-8")
if data:
dst.write_bytes(bytes(data))
return dst
if isinstance(upload_obj, dict):
if "name" in upload_obj:
src = Path(upload_obj["name"])
if src.exists():
shutil.copy(src, dst)
return dst
if "data" in upload_obj and upload_obj["data"] is not None:
data = upload_obj["data"]
if isinstance(data, str):
data = data.encode("utf-8")
dst.write_bytes(bytes(data))
return dst
raise TypeError(f"Unsupported upload object type: {type(upload_obj)}; expected filepath/file-like/dict.")
def run(company_yaml, financials_csv, esg_csv, use_llm, lang):
try:
if company_yaml is None or financials_csv is None or esg_csv is None:
return "全てのファイルをアップロードしてください。", None, None, None, None
with tempfile.TemporaryDirectory() as td:
tdir = Path(td)
cpath = _to_path(company_yaml, tdir, "company.yaml")
fpath = _to_path(financials_csv, tdir, "financials.csv")
epath = _to_path(esg_csv, tdir, "esg.csv")
outdir = tdir / "out"
outdir.mkdir(parents=True, exist_ok=True)
llm = None
if use_llm:
try:
from llm import OpenAILLM
llm = OpenAILLM()
except Exception as e:
return f"LLM初期化エラー: {e}", None, None, None, None
html, pdf, docx, meta_json = generate_report(
company_yaml=str(cpath),
financials_csv=str(fpath),
esg_csv=str(epath),
templates_dir=TEMPLATES_DIR,
template_name="report.html.j2",
out_html=str(outdir / "report.html"),
out_pdf=str(outdir / "report.pdf"),
out_docx=str(outdir / "report.docx"),
lang=lang,
llm=llm
)
repo_tmp = Path("./tmp")
repo_tmp.mkdir(exist_ok=True)
ts = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
html_out = repo_tmp / f"report-{ts}.html"
pdf_out = repo_tmp / f"report-{ts}.pdf"
docx_out = repo_tmp / f"report-{ts}.docx"
meta_out = repo_tmp / f"report-{ts}.json"
shutil.copy(html, html_out)
shutil.copy(pdf, pdf_out)
shutil.copy(docx, docx_out)
Path(meta_out).write_text(json.dumps(meta_json, ensure_ascii=False, indent=2), encoding="utf-8")
return "生成が完了しました。", str(html_out), str(pdf_out), str(docx_out), str(meta_out)
except Exception as e:
import traceback
tb = traceback.format_exc(limit=12)
return f"エラー: {e}\n--- trace ---\n{tb}", None, None, None, None
with gr.Blocks(title=TITLE) as demo:
gr.Markdown(f"# {TITLE}\n{DESC}")
with gr.Row():
company_yaml = gr.File(label="company.yaml(会社情報・年度等)", file_types=[".yaml", ".yml"])
financials_csv = gr.File(label="financials.csv(財務KPI)", file_types=[".csv"])
esg_csv = gr.File(label="esg_metrics.csv(ESG指標)", file_types=[".csv"])
with gr.Row():
use_llm = gr.Checkbox(label="LLMで要約/翻訳を行う(OPENAI_API_KEY2 必須)", value=True)
lang = gr.Dropdown(choices=["ja","en","zh","ko","de","fr"], value="ja", label="出力言語")
run_btn = gr.Button("レポート生成")
status = gr.Textbox(label="ステータス", interactive=False)
html_file = gr.File(label="HTMLダウンロード")
pdf_file = gr.File(label="PDFダウンロード")
docx_file = gr.File(label="DOCXダウンロード")
meta_file = gr.File(label="メタ情報(JSON)")
run_btn.click(
fn=run,
inputs=[company_yaml, financials_csv, esg_csv, use_llm, lang],
outputs=[status, html_file, pdf_file, docx_file, meta_file]
)
if __name__ == "__main__":
demo.launch()