Spaces:
Sleeping
Sleeping
| 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() | |