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.
Binary file not shown.
+4
View File
@@ -34,6 +34,10 @@ def read_companies(db: Session = Depends(get_db)):
"""Get all companies with their investor relationships"""
companies = (
db.query(CompanyTable)
.filter(
CompanyTable.name.isnot(None),
CompanyTable.description.isnot(None)
)
.options(
selectinload(CompanyTable.investors),
selectinload(CompanyTable.members),
+68
View File
@@ -7,6 +7,7 @@ from fastapi import APIRouter, Depends, HTTPException, Query
from schemas.router_schemas import InvestmentStage, InvestorData
from pydantic import BaseModel
from sqlalchemy.orm import Session, selectinload
from services.querying import QueryProcessor
router = APIRouter(tags=["Investor Routes"])
@@ -234,3 +235,70 @@ def delete_investor(investor_id: int, db: Session = Depends(get_db)):
return {"message": "Investor deleted successfully"}
@router.get("/investors/{investor_id}/similar", response_model=List[InvestorData])
def find_similar_investors(investor_id: int, db: Session = Depends(get_db)):
"""Find investors similar to a given investor"""
# First, get the target investor
target_investor = (
db.query(InvestorTable)
.options(
selectinload(InvestorTable.portfolio_companies),
selectinload(InvestorTable.team_members),
selectinload(InvestorTable.sectors),
)
.filter(InvestorTable.id == investor_id)
.first()
)
if not target_investor:
raise HTTPException(status_code=404, detail="Investor not found")
# Build query to find similar investors
query = db.query(InvestorTable).options(
selectinload(InvestorTable.portfolio_companies),
selectinload(InvestorTable.team_members),
selectinload(InvestorTable.sectors),
).filter(InvestorTable.id != investor_id) # Exclude the target investor
# Filter by same stage focus
query = query.filter(InvestorTable.stage_focus == target_investor.stage_focus)
# Filter by similar geographic focus (partial match)
query = query.filter(InvestorTable.geographic_focus.ilike(f"%{target_investor.geographic_focus}%"))
# Filter by overlapping check size ranges
query = query.filter(
InvestorTable.check_size_upper >= target_investor.check_size_lower,
InvestorTable.check_size_lower <= target_investor.check_size_upper
)
# Filter by similar AUM (within 50% range)
aum_lower = int(target_investor.aum * 0.5)
aum_upper = int(target_investor.aum * 1.5)
query = query.filter(
InvestorTable.aum >= aum_lower,
InvestorTable.aum <= aum_upper
)
# Filter by common sectors
target_sector_names = [sector.name for sector in target_investor.sectors]
if target_sector_names:
query = query.join(InvestorTable.sectors).filter(
SectorTable.name.in_(target_sector_names)
)
investors = query.all()
# Transform to InvestorData format
investor_data_list = []
for investor in investors:
investor_data = InvestorData(
investor=investor,
portfolio_companies=investor.portfolio_companies,
team_members=investor.team_members,
sectors=investor.sectors,
)
investor_data_list.append(investor_data)
return investor_data_list