Investigate targets in parallel using asyncio.gather(). Parameters ---------- targets: List of OSINT targets (emails, usernames, domains, IPs, names). Maximum ``MAX_TARGETS`` entries. api_key: Anthropic API key. Falls back to ``ANTHROPIC_API_KEY`` env v
(
targets: list[str],
api_key: str | None = None,
is_pdf_disabled: bool = False,
)
| 103 | |
| 104 | |
| 105 | async def run_multi_target( |
| 106 | targets: list[str], |
| 107 | api_key: str | None = None, |
| 108 | is_pdf_disabled: bool = False, |
| 109 | ) -> str: |
| 110 | """ |
| 111 | Investigate targets in parallel using asyncio.gather(). |
| 112 | |
| 113 | Parameters |
| 114 | ---------- |
| 115 | targets: |
| 116 | List of OSINT targets (emails, usernames, domains, IPs, names). |
| 117 | Maximum ``MAX_TARGETS`` entries. |
| 118 | api_key: |
| 119 | Anthropic API key. Falls back to ``ANTHROPIC_API_KEY`` env var. |
| 120 | is_pdf_disabled: |
| 121 | When True, skip PDF generation for the summary report. |
| 122 | |
| 123 | Returns |
| 124 | ------- |
| 125 | str |
| 126 | Markdown summary report (also written to ``reports/``). |
| 127 | |
| 128 | Raises |
| 129 | ------ |
| 130 | ValueError |
| 131 | If more than ``MAX_TARGETS`` targets are supplied. |
| 132 | """ |
| 133 | if len(targets) > MAX_TARGETS: |
| 134 | raise ValueError( |
| 135 | f"Multi-target investigation supports at most {MAX_TARGETS} targets; " |
| 136 | f"got {len(targets)}. Split into smaller batches." |
| 137 | ) |
| 138 | if not targets: |
| 139 | return "No targets provided." |
| 140 | |
| 141 | reports_dir = Path("reports") |
| 142 | reports_dir.mkdir(exist_ok=True) |
| 143 | date_prefix = datetime.now().strftime("%Y-%m-%d") |
| 144 | |
| 145 | tasks = [_investigate_one(target, api_key, reports_dir, date_prefix) for target in targets] |
| 146 | results: list[tuple[str, AgentResponse]] = await asyncio.gather(*tasks) |
| 147 | |
| 148 | summary = _build_summary(results, date_prefix) |
| 149 | |
| 150 | summary_path = reports_dir / f"{date_prefix}_summary.md" |
| 151 | summary_path.write_text(summary, encoding="utf-8") |
| 152 | logger.info("Summary report: %s", summary_path) |
| 153 | |
| 154 | if not is_pdf_disabled: |
| 155 | try: |
| 156 | from openosint.pdf_report import generate_pdf_report |
| 157 | |
| 158 | await generate_pdf_report(summary_path) |
| 159 | except Exception: |
| 160 | logger.debug("PDF skipped for summary.", exc_info=True) |
| 161 | |
| 162 | return summary |