Spaces:
Running
Running
| """ | |
| GURMA.ai — TR Branch Tab | |
| Displays executive summaries and raw agent research data | |
| for the Turkey subsidiary setup. | |
| """ | |
| import json | |
| import os | |
| from datetime import datetime | |
| from pathlib import Path | |
| import streamlit as st | |
| # ============================================================ | |
| # Environment & Paths | |
| # ============================================================ | |
| IS_HF_SPACE = os.getenv("HF_SPACE") or Path("/app/research.py").exists() | |
| if IS_HF_SPACE: | |
| DATA_ROOT = Path("/app/data") | |
| DOCS_ROOT = Path("/app/docs") | |
| else: | |
| DATA_ROOT = Path(__file__).resolve().parent.parent.parent / "data" | |
| DOCS_ROOT = Path(__file__).resolve().parent.parent.parent / "docs" | |
| TR_DIRS = { | |
| "tr-mali": {"label": "Mali Müşavir", "description": "Company formation, tax, IP, regulatory"}, | |
| "tr-fonlar": {"label": "Fon Araştırma", "description": "TÜBİTAK, KOSGEB, EU/bilateral funding"}, | |
| } | |
| # ============================================================ | |
| # Data Loading | |
| # ============================================================ | |
| def _load_exec_summaries() -> list[dict]: | |
| """Load executive summary markdown files, newest first.""" | |
| if not DOCS_ROOT.exists(): | |
| return [] | |
| summaries = [] | |
| for f in sorted(DOCS_ROOT.glob("exec-summary-*.md"), reverse=True): | |
| try: | |
| content = f.read_text(encoding="utf-8") | |
| title_line = "" | |
| for line in content.split("\n"): | |
| if line.startswith("# "): | |
| title_line = line[2:].strip() | |
| break | |
| summaries.append({ | |
| "filename": f.name, | |
| "title": title_line or f.stem, | |
| "content": content, | |
| "mtime": datetime.fromtimestamp(f.stat().st_mtime), | |
| }) | |
| except Exception: | |
| continue | |
| return summaries | |
| def _load_tr_agent_stats() -> dict: | |
| """Load lightweight stats from TR agent JSON files (not full content).""" | |
| stats = {} | |
| for agent_key, cfg in TR_DIRS.items(): | |
| agent_dir = DATA_ROOT / agent_key | |
| if not agent_dir.exists(): | |
| stats[agent_key] = None | |
| continue | |
| json_files = sorted(agent_dir.glob("*.json"), reverse=True) | |
| if not json_files: | |
| stats[agent_key] = None | |
| continue | |
| try: | |
| with open(json_files[0]) as fh: | |
| data = json.load(fh) | |
| sections = data.get("sections", {}) | |
| total_findings = sum(len(s.get("findings", [])) for s in sections.values()) | |
| confirmed = sum( | |
| sum(1 for f in s.get("findings", []) if isinstance(f, dict) and f.get("confirmed")) | |
| for s in sections.values() | |
| ) | |
| total_gaps = sum(len(s.get("gaps", [])) for s in sections.values()) | |
| stats[agent_key] = { | |
| "timestamp": data.get("timestamp", "")[:16].replace("T", " "), | |
| "categories": len(sections), | |
| "findings": total_findings, | |
| "confirmed": confirmed, | |
| "gaps": total_gaps, | |
| "sections": sections, | |
| "filename": json_files[0].name, | |
| } | |
| except Exception: | |
| stats[agent_key] = None | |
| return stats | |
| # ============================================================ | |
| # Main Entry Point | |
| # ============================================================ | |
| def render_tr_tab(): | |
| """Main entry point — called from app.py.""" | |
| st.title("TR Branch") | |
| st.caption("Company formation research & funding intelligence for GURMA Turkey") | |
| summaries = _load_exec_summaries() | |
| agent_stats = _load_tr_agent_stats() | |
| # --- Executive Summaries (primary content) --- | |
| if summaries: | |
| for s in summaries: | |
| age = datetime.now() - s["mtime"] | |
| age_label = "today" if age.days == 0 else f"{age.days}d ago" | |
| st.markdown(f"##### {s['title']} <span style='color:#888;font-size:0.7em;'>({age_label})</span>", unsafe_allow_html=True) | |
| st.markdown(s["content"]) | |
| st.divider() | |
| else: | |
| st.info("No executive summaries found in `docs/exec-summary-*.md`. Run the synthesis workflow to generate reports.") | |
| # --- Agent Data Sources (collapsed) --- | |
| any_data = any(v is not None for v in agent_stats.values()) | |
| if any_data: | |
| with st.expander("Raw Research Data", expanded=False): | |
| st.caption("Source findings collected by the Mali and Fonlar agents. These are raw search results — see executive summaries above for the synthesized analysis.") | |
| for agent_key, cfg in TR_DIRS.items(): | |
| info = agent_stats.get(agent_key) | |
| if info is None: | |
| st.caption(f"**{cfg['label']}** — no data") | |
| continue | |
| spec_label = f"speculative" if info['findings'] - info['confirmed'] > 0 else "" | |
| st.markdown( | |
| f"**{cfg['label']}** — {info['findings']} findings " | |
| f"({info['confirmed']} official{', ' + str(info['findings'] - info['confirmed']) + ' ' + spec_label if spec_label else ''}) " | |
| f"· {info['gaps']} gaps · {info['categories']} categories " | |
| f"· <span style='color:#888;font-size:0.8em;'>Run: {info['timestamp']}</span>", | |
| unsafe_allow_html=True, | |
| ) | |
| for section_data in info["sections"].values(): | |
| label = section_data.get("label", "") | |
| findings = section_data.get("findings", []) | |
| gaps = section_data.get("gaps", []) | |
| if not findings and not gaps: | |
| continue | |
| confirmed_n = sum(1 for f in findings if isinstance(f, dict) and f.get("confirmed")) | |
| header = f"{label} ({len(findings)} findings" | |
| if confirmed_n: | |
| header += f", {confirmed_n} official" | |
| header += ")" | |
| with st.expander(header, expanded=False): | |
| for f in findings[:10]: | |
| if not isinstance(f, dict): | |
| continue | |
| text = f.get("text", "")[:200] | |
| source = f.get("source", "") | |
| is_confirmed = f.get("confirmed", False) | |
| tag = "✅" if is_confirmed else "⚠️" | |
| source_html = "" | |
| if source: | |
| try: | |
| from urllib.parse import urlparse | |
| domain = urlparse(source).netloc.removeprefix("www.") | |
| except Exception: | |
| domain = "" | |
| if domain: | |
| source_html = f" <a href='{source}' style='color:#666;font-size:0.75em;'>{domain}</a>" | |
| st.markdown(f"{tag} <span style='font-size:0.85em;'>{text}</span>{source_html}", unsafe_allow_html=True) | |
| if len(findings) > 10: | |
| st.caption(f"+ {len(findings) - 10} more") | |
| for g in gaps: | |
| gap_text = g.get("text", g) if isinstance(g, dict) else g | |
| st.caption(f"🔍 **Gap:** {gap_text}") | |
| st.markdown("") | |