Refactor investor and company schemas to allow optional fields; update filtering logic in read_companies function and add find_similar_investors endpoint; change LLM model in InvestorProcessor and QueryProcessor for improved performance.

This commit is contained in:
bolade
2025-09-27 10:45:08 +01:00
parent d36367fbe9
commit 6d902345c0
10 changed files with 234 additions and 46 deletions
Binary file not shown.
+159 -43
View File
@@ -19,13 +19,32 @@ class SectorSchema(BaseModel):
Leave name empty if uncertain about the sector classification.
"""
id: int = Field(
ge=0, description="Sector ID, must be 0 or greater. Use 0 if uncertain."
id: Optional[int] = Field(
default=None,
ge=0,
description="Sector ID, must be 0 or greater. Use 0 if uncertain.",
)
name: str = Field(
description="Sector name. Leave empty string if not clearly identifiable from the data."
name: Optional[str] = Field(
default=None,
description="Sector name. Leave empty string if not clearly identifiable from the data.",
)
@field_validator("name", mode="before")
@classmethod
def empty_string_to_none(cls, v):
"""Convert empty strings to None"""
if v == "" or (isinstance(v, str) and v.strip() == ""):
return None
return v
@field_validator("id", mode="before")
@classmethod
def zero_to_none(cls, v):
"""Convert 0 to None for optional id field"""
if v == 0:
return None
return v
class Config:
from_attributes = True
@@ -36,22 +55,45 @@ class InvestorMemberSchema(BaseModel):
Leave fields empty if uncertain about the member details.
"""
id: int = Field(
ge=0, description="Member ID, must be 0 or greater. Use 0 if uncertain."
id: Optional[int] = Field(
default=None,
ge=0,
description="Member ID, must be 0 or greater. Use 0 if uncertain.",
)
name: str = Field(
description="Team member name. Leave empty string if not clearly identifiable."
name: Optional[str] = Field(
default=None,
description="Team member name. Leave empty string if not clearly identifiable.",
)
role: str = Field(
description="Team member role/title. Leave empty string if not clearly identifiable."
role: Optional[str] = Field(
default=None,
description="Team member role/title. Leave empty string if not clearly identifiable.",
)
email: str = Field(
description="Team member email. Leave empty string if not clearly identifiable or not provided."
email: Optional[str] = Field(
default=None,
description="Team member email. Leave empty string if not clearly identifiable or not provided.",
)
investor_id: int = Field(
ge=0, description="Investor ID, must be 0 or greater. Use 0 if uncertain."
investor_id: Optional[int] = Field(
default=None,
ge=0,
description="Investor ID, must be 0 or greater. Use 0 if uncertain.",
)
@field_validator("name", "role", "email", mode="before")
@classmethod
def empty_string_to_none(cls, v):
"""Convert empty strings to None"""
if v == "" or (isinstance(v, str) and v.strip() == ""):
return None
return v
@field_validator("id", "investor_id", mode="before")
@classmethod
def zero_to_none(cls, v):
"""Convert 0 to None for optional integer fields"""
if v == 0:
return None
return v
class Config:
from_attributes = True
@@ -62,25 +104,45 @@ class CompanyMemberSchema(BaseModel):
Leave fields empty if uncertain about the member details.
"""
id: int = Field(
ge=0, description="Member ID, must be 0 or greater. Use 0 if uncertain."
id: Optional[int] = Field(
default=None,
ge=0,
description="Member ID, must be 0 or greater. Use 0 if uncertain.",
)
name: Optional[str] = Field(
default="",
default=None,
description="Company member name. Leave empty if not clearly identifiable.",
)
linkedin: Optional[str] = Field(
default="",
default=None,
description="LinkedIn profile URL. Leave empty if not provided or uncertain.",
)
role: Optional[str] = Field(
default="",
default=None,
description="Company member role/title. Leave empty if not clearly identifiable.",
)
company_id: int = Field(
ge=0, description="Company ID, must be 0 or greater. Use 0 if uncertain."
company_id: Optional[int] = Field(
default=None,
ge=0,
description="Company ID, must be 0 or greater. Use 0 if uncertain.",
)
@field_validator("name", "linkedin", "role", mode="before")
@classmethod
def empty_string_to_none(cls, v):
"""Convert empty strings to None"""
if v == "" or (isinstance(v, str) and v.strip() == ""):
return None
return v
@field_validator("id", "company_id", mode="before")
@classmethod
def zero_to_none(cls, v):
"""Convert 0 to None for optional integer fields"""
if v == 0:
return None
return v
class Config:
from_attributes = True
@@ -91,20 +153,25 @@ class CompanySchema(BaseModel):
Leave optional fields empty if uncertain. Integer values must be 0 or greater.
"""
id: int = Field(
ge=0, description="Company ID, must be 0 or greater. Use 0 if uncertain."
id: Optional[int] = Field(
default=None,
ge=0,
description="Company ID, must be 0 or greater. Use 0 if uncertain.",
)
name: str = Field(
description="Company name. Leave empty string if not clearly identifiable."
name: Optional[str] = Field(
default=None,
description="Company name. Leave empty string if not clearly identifiable.",
)
industry: str = Field(
description="Company industry/sector. Leave empty string if not clearly identifiable."
industry: Optional[str] = Field(
default=None,
description="Company industry/sector. Leave empty string if not clearly identifiable.",
)
location: str = Field(
description="Company location/address. Leave empty string if not clearly identifiable."
location: Optional[str] = Field(
default=None,
description="Company location/address. Leave empty string if not clearly identifiable.",
)
description: Optional[str] = Field(
default="",
default=None,
description="Company description. Leave empty if not clearly available or uncertain.",
)
founded_year: Optional[int] = Field(
@@ -113,10 +180,28 @@ class CompanySchema(BaseModel):
description="Year company was founded, must be 0 or greater. Leave None if not clearly identifiable or uncertain.",
)
website: Optional[str] = Field(
default="",
default=None,
description="Company website URL. Leave empty if not provided or uncertain.",
)
@field_validator(
"name", "industry", "location", "description", "website", mode="before"
)
@classmethod
def empty_string_to_none(cls, v):
"""Convert empty strings to None"""
if v == "" or (isinstance(v, str) and v.strip() == ""):
return None
return v
@field_validator("id", "founded_year", mode="before")
@classmethod
def zero_to_none(cls, v):
"""Convert 0 to None for founded_year"""
if v == 0:
return None
return v
@field_validator("founded_year", mode="before")
@classmethod
def validate_founded_year(cls, v):
@@ -141,40 +226,71 @@ class InvestorSchema(BaseModel):
Leave optional fields empty if uncertain. All numeric values must be 0 or greater.
"""
id: int = Field(
ge=0, description="Investor ID, must be 0 or greater. Use 0 if uncertain."
id: Optional[int] = Field(
default=None,
ge=0,
description="Investor ID, must be 0 or greater. Use 0 if uncertain.",
)
name: str = Field(
description="Investor name. Do not return any special characters, Just the name as a string."
name: Optional[str] = Field(
default=None,
description="Investor name. Do not return any special characters, Just the name as a string.",
)
description: Optional[str] = Field(
default="",
default=None,
description="Investor description. Leave empty if not clearly available or uncertain.",
)
aum: int | None = Field(
aum: Optional[int] = Field(
default=None,
ge=0,
description="Assets Under Management in USD, must be 0 or greater. Use 0 if not clearly identifiable or uncertain.",
)
check_size_lower: int | None = Field(
check_size_lower: Optional[int] = Field(
default=None,
ge=0,
description="Lower bound of typical investment check size in USD, must be 0 or greater. Use 0 if not clearly identifiable.",
)
check_size_upper: int | None = Field(
check_size_upper: Optional[int] = Field(
default=None,
ge=0,
description="Upper bound of typical investment check size in USD, must be 0 or greater. Use 0 if not clearly identifiable.",
)
geographic_focus: str | None = Field(
geographic_focus: Optional[str] = Field(
default=None,
description="Geographic investment focus. Do not return any special characters, Just locations separated by commas. Leave empty if not clearly identifiable.",
)
stage_focus: InvestmentStage = Field(
description="Investment stage focus. Use SEED as default if uncertain."
default=InvestmentStage.SEED,
description="Investment stage focus. Use SEED as default if uncertain.",
)
number_of_investments: int | None = Field(
number_of_investments: Optional[int] = Field(
default=None,
ge=0,
default=0,
description="Total number of investments made, must be 0 or greater. Use 0 if not clearly identifiable.",
)
@field_validator("name", "description", "geographic_focus", mode="before")
@classmethod
def empty_string_to_none(cls, v):
"""Convert empty strings to None"""
if v == "" or (isinstance(v, str) and v.strip() == ""):
return None
return v
@field_validator(
"id",
"aum",
"check_size_lower",
"check_size_upper",
"number_of_investments",
mode="before",
)
@classmethod
def zero_to_none(cls, v):
"""Convert 0 to None for optional integer fields"""
if v == 0:
return None
return v
class Config:
from_attributes = True