# generators/summary.py from __future__ import annotations from typing import List, Tuple from irpr.deps import search, generate_chat SYS = "あなたは日本語のIRアナリストです。引用の根拠から経営サマリを作ります。冗長な敬語は避け、事実ベースで簡潔に。マークダウンで出力。" TPL = """以下は関連文書の抜粋です。これを根拠に、投資家向けの経営サマリを作成してください。 # 出力フォーマット 業績ハイライト: - 箇条書きで3-5項目 見通し: - 2-4項目 セグメント: - 主要セグメントごとに1-2行 財務: - 売上/利益、CF、BSの要点 株主還元: - 配当/自社株買い等 ESG: - 重要事項があれば簡潔に リスク: - 2-3項目 # 根拠抜粋 {context} """ def make_summary(query: str, k: int = 12) -> Tuple[str, List[str]]: hits = search(query, top_k=k) links, ctx_lines = [], [] for i, h in enumerate(hits, 1): src = h.get("source_url") or "" if src and src not in links: links.append(src) # 1抜粋1200字まで ctx_lines.append(f"[{i}] {h.get('title') or ''} {src}\n{h['text'][:1200]}") context = "\n\n".join(ctx_lines) if ctx_lines else "(根拠なし)" # OpenAIで生成(失敗時は抽出フォールバック) try: text = generate_chat( [{"role":"system","content":SYS}, {"role":"user","content":TPL.format(context=context)}], max_new_tokens=900 ) if text.strip(): return text.strip(), links except Exception: pass # フォールバック(抽出) if not hits: return "根拠が見つかりませんでした。", links bullets = [] for h in hits[:5]: for line in (h["text"][:500]).splitlines(): line = line.strip() if 6 <= len(line) <= 120: bullets.append(f"- {line}") if len(bullets) >= 5: break if len(bullets) >= 5: break text = "業績ハイライト:\n" + "\n".join(bullets) + "\n\n見通し:\n- (抽出フォールバック)" return text, links