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:
Binary file not shown.
Binary file not shown.
@@ -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),
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user