Initial commit: CI Agent competitive-intelligence monitoring app
FastAPI + Celery + Next.js + Postgres/Redis app with company monitoring, source collection, LLM-based change analysis, enrichment, and account security (Turnstile, escalating lockout, email verification).
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
"""Company-enrichment provider interface. Answers "what does a paid,
|
||||
first-party data vendor already know about this company?" - a richer,
|
||||
metered complement to the free SearchProvider/LLM discovery pipeline
|
||||
(app/services/discovery_service.py), never a replacement for it. Every
|
||||
method here maps to one NinjaPear (nubela.co) API endpoint; orchestration
|
||||
(call order, the leadership-lookup cap, partial-failure handling) lives in
|
||||
app/services/enrichment_service.py, not here - this Protocol is a dumb I/O
|
||||
layer, matching app/search/base.py's shape.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Protocol
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class LeadershipMember(BaseModel):
|
||||
name: str
|
||||
title: str | None = None
|
||||
work_email: str | None = None
|
||||
profile_url: str | None = None
|
||||
bio: str | None = None
|
||||
|
||||
|
||||
class CompanyDetails(BaseModel):
|
||||
description: str | None = None
|
||||
industry: str | None = None
|
||||
founded_year: int | None = None
|
||||
specialties: list[str] = Field(default_factory=list)
|
||||
leadership_team: list[LeadershipMember] = Field(default_factory=list)
|
||||
employee_count_range: str | None = None
|
||||
|
||||
|
||||
class FundingRound(BaseModel):
|
||||
round_name: str | None = None
|
||||
amount: str | None = None
|
||||
date: str | None = None
|
||||
investors: list[str] = Field(default_factory=list)
|
||||
|
||||
|
||||
class CompanyFunding(BaseModel):
|
||||
total_raised: str | None = None
|
||||
rounds: list[FundingRound] = Field(default_factory=list)
|
||||
|
||||
|
||||
class CompetitorWithReason(BaseModel):
|
||||
name: str
|
||||
reason: str | None = None
|
||||
|
||||
|
||||
class Product(BaseModel):
|
||||
name: str
|
||||
description: str | None = None
|
||||
category: str | None = None
|
||||
|
||||
|
||||
class RecentUpdate(BaseModel):
|
||||
type: str
|
||||
text: str
|
||||
url: str | None = None
|
||||
date: str | None = None
|
||||
|
||||
|
||||
class Customer(BaseModel):
|
||||
name: str
|
||||
relationship: str | None = None
|
||||
|
||||
|
||||
class EnrichmentProvider(Protocol):
|
||||
provider_name: str
|
||||
|
||||
async def get_company_details(self, name: str, website: str | None) -> CompanyDetails: ...
|
||||
|
||||
async def get_funding(self, name: str, website: str | None) -> CompanyFunding: ...
|
||||
|
||||
async def get_updates(self, name: str, website: str | None) -> list[RecentUpdate]: ...
|
||||
|
||||
async def get_competitors(
|
||||
self, name: str, website: str | None
|
||||
) -> list[CompetitorWithReason]: ...
|
||||
|
||||
async def get_products(self, name: str, website: str | None) -> list[Product]: ...
|
||||
|
||||
async def get_customers(self, name: str, website: str | None) -> list[Customer]: ...
|
||||
|
||||
async def get_work_email(self, person_name: str, company_website: str) -> str | None: ...
|
||||
|
||||
async def get_person_profile(
|
||||
self, person_name: str, company_website: str
|
||||
) -> tuple[str | None, str | None]:
|
||||
"""Returns (profile_url, bio)."""
|
||||
...
|
||||
Reference in New Issue
Block a user