72 lines
4.4 KiB
Python
72 lines
4.4 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
|
|
from django.core.management.base import BaseCommand
|
|
|
|
from agents.venture_discovery import VentureDiscoveryService
|
|
from model_router.providers import providers_from_resources
|
|
from model_router.router import ModelRouter
|
|
from research.searxng import SearxngSearchClient
|
|
|
|
|
|
class Command(BaseCommand):
|
|
help = "Run a single-company Venture Research smoke test."
|
|
|
|
def add_arguments(self, parser):
|
|
parser.add_argument("--depth", choices=["light", "deep"], default="deep")
|
|
parser.add_argument("--indent", type=int, default=2)
|
|
parser.add_argument("--searxng-url", default="")
|
|
|
|
def handle(self, *args, **options):
|
|
providers = providers_from_resources()
|
|
search_client = SearxngSearchClient(endpoint_url=str(options["searxng_url"])) if options["searxng_url"] else None
|
|
service = VentureDiscoveryService(ModelRouter(providers), web_research_available=True, search_client=search_client)
|
|
mandate = service.create_v0_mandate()
|
|
proposal = service.generate_single_company(
|
|
mandate,
|
|
payload={
|
|
"title": "AI Website Accessibility Regression Monitor",
|
|
"one_line_thesis": "A self-service monitor detects website accessibility regressions and sends automated prioritized reports.",
|
|
"description": "Customers submit a URL, Artifex crawls pages, detects accessibility regressions, verifies issues, and delivers a recurring report.",
|
|
"problem": "Small web teams need affordable continuous accessibility checks but cannot manually audit every change.",
|
|
"target_customer": "Small SaaS and ecommerce teams with public marketing sites.",
|
|
"proposed_solution": "Automated crawler, accessibility analysis, regression detection, report generation, and email/dashboard delivery.",
|
|
"business_model": "Self-service subscription plus a $49 validation scan.",
|
|
"pricing_hypothesis": "$49 validation scan, then $99/month subscription.",
|
|
"acquisition_strategy": "SEO/content around accessibility regression monitoring and self-service checkout.",
|
|
"validation_plan": "Offer a $49 automated scan with sample output before building a full dashboard.",
|
|
"capital_requested": "50",
|
|
"time_to_first_dollar_estimate": "1-7 days after approval",
|
|
"expected_margin": "85-95%",
|
|
"build_complexity": "LOW-MEDIUM",
|
|
"market_evidence": [],
|
|
"differentiation": "Autonomous recurring monitor with structured verification and self-service onboarding.",
|
|
"major_risks": ["Search demand may be low", "False positives may increase support"],
|
|
"confidence": 0.64,
|
|
},
|
|
source="research_smoke",
|
|
)
|
|
research = service.conduct_market_research(proposal, depth=str(options["depth"]))
|
|
proposal.refresh_from_db()
|
|
stored = proposal.metadata.get("research", {}) if isinstance(proposal.metadata, dict) else {}
|
|
payload = {
|
|
"proposal_id": str(proposal.id),
|
|
"title": proposal.title,
|
|
"search_result_count": stored.get("search_result_count", 0),
|
|
"page_fetch_count": stored.get("page_fetch_count", 0),
|
|
"accepted_source_count": stored.get("source_count", 0),
|
|
"rejected_source_count": stored.get("source_rejection_count", 0),
|
|
"accepted_categories": sorted({str(item.get("category", "")) for item in research.get("sources", []) if isinstance(item, dict) and item.get("url")}),
|
|
"coverage": stored.get("coverage", {}),
|
|
"coverage_ratio": stored.get("coverage_ratio", 0.0),
|
|
"provider": stored.get("provider", "none"),
|
|
"search_provider": stored.get("search_provider", "none"),
|
|
"search_diagnostics": stored.get("search_diagnostics", {}),
|
|
"persisted_url_count": len([item for item in proposal.market_evidence if isinstance(item, dict) and item.get("url")]),
|
|
"accepted_sources": research.get("sources", [])[:5],
|
|
"rejected_sources": research.get("source_rejections", [])[:5],
|
|
"explicit_research_failure": stored.get("explicit_research_failure", ""),
|
|
}
|
|
indent = None if int(options["indent"]) <= 0 else int(options["indent"])
|
|
self.stdout.write(json.dumps(payload, indent=indent, default=str))
|