From 0765cca90db38724b3646ff4fd4fa21e6f31a067 Mon Sep 17 00:00:00 2001 From: michael Date: Wed, 15 Oct 2025 17:58:31 +0000 Subject: [PATCH] refactor: Improve handling of optional fields and enhance compatibility score calculations --- app/main.py | 2 +- app/schemas/project_schemas.py | 2 +- app/services/compatibility_score.py | 4 +-- app/services/insight.py | 4 ++- app/services/querying.py | 2 +- app/services/report_gen.py | 39 ++++++++++++++++------------ investors.db | Bin 27054080 -> 27054080 bytes 7 files changed, 31 insertions(+), 22 deletions(-) diff --git a/app/main.py b/app/main.py index c1105ee..86f67bd 100644 --- a/app/main.py +++ b/app/main.py @@ -122,4 +122,4 @@ app.include_router(report_route.router) if __name__ == "__main__": import uvicorn - uvicorn.run(app="main:app", host="0.0.0.0", port=8585, reload=True) + uvicorn.run(app="main:app", host="0.0.0.0", port=8585) diff --git a/app/schemas/project_schemas.py b/app/schemas/project_schemas.py index 51663a3..c084fd1 100644 --- a/app/schemas/project_schemas.py +++ b/app/schemas/project_schemas.py @@ -30,7 +30,7 @@ class InvestorSchema(BaseModel): check_size_lower: int | None check_size_upper: int | None geographic_focus: str | None - stage_focus: InvestmentStage + stage_focus: Optional[InvestmentStage] = None number_of_investments: int | None created_at: Optional[datetime] = None updated_at: Optional[datetime] = None diff --git a/app/services/compatibility_score.py b/app/services/compatibility_score.py index 4bb7e6c..6821a1a 100644 --- a/app/services/compatibility_score.py +++ b/app/services/compatibility_score.py @@ -127,7 +127,7 @@ def _calculate_project_fund_compatibility( geo_score = 0 if project.location and fund.geographic_focus: project_location_lower = project.location.lower() - fund_geo_lower = fund.geographic_focus.lower() + fund_geo_lower = (fund.geographic_focus or "").lower() # Exact match if project_location_lower == fund_geo_lower: @@ -223,7 +223,7 @@ def _calculate_project_investor_direct_compatibility( geo_score = 0 if project.location and investor.geographic_focus: project_location_lower = project.location.lower() - investor_geo_lower = investor.geographic_focus.lower() + investor_geo_lower = (investor.geographic_focus or "").lower() if project_location_lower == investor_geo_lower: geo_score = 20 diff --git a/app/services/insight.py b/app/services/insight.py index c4e9387..7e25de3 100644 --- a/app/services/insight.py +++ b/app/services/insight.py @@ -26,7 +26,7 @@ class QueryProcessor: self.llm = ChatOpenAI( api_key=OPENROUTER_API_KEY, base_url="https://openrouter.ai/api/v1", - model="openai/gpt-5-nano", + model="openai/gpt-4o-mini", temperature=0, ) self.agent = create_react_agent( @@ -107,6 +107,8 @@ class QueryProcessor: - If you cannot find sufficient data after searching, make reasonable inferences based on available information - DO NOT state that data is unavailable or ambiguous - provide the best analysis possible with what you find - Focus on ACTIONABLE insights, not disclaimers + - Only call the tool twice at most, be strategic in your searches + - Summarize your findings concisely and clearly Provide insights in the InsightResponse schema format: diff --git a/app/services/querying.py b/app/services/querying.py index 98d109f..f94e9ba 100644 --- a/app/services/querying.py +++ b/app/services/querying.py @@ -28,7 +28,7 @@ class QueryProcessor: self.llm = ChatOpenAI( api_key=os.getenv("OPENROUTER_API_KEY"), base_url="https://openrouter.ai/api/v1", - model="x-ai/grok-4-fast", + model="openai/gpt-4o-mini", temperature=0, ) self.toolkit = SQLDatabaseToolkit(db=db, llm=self.llm) diff --git a/app/services/report_gen.py b/app/services/report_gen.py index 2651e55..a3945bb 100644 --- a/app/services/report_gen.py +++ b/app/services/report_gen.py @@ -95,16 +95,16 @@ class ReportGenerator: score += weights["stage"] # Geography match - investor_geo = investor_data.get("geographic_focus", "").lower() - project_geo = project_data.get("location", "").lower() + investor_geo = (investor_data.get("geographic_focus") or "").lower() + project_geo = (project_data.get("location") or "").lower() if investor_geo and project_geo and investor_geo in project_geo: score += weights["geography"] # Check size match project_valuation = project_data.get("valuation", 0) - check_lower = investor_data.get("check_size_lower", 0) - check_upper = investor_data.get("check_size_upper", float("inf")) - if check_lower <= project_valuation <= check_upper: + check_lower = investor_data.get("check_size_lower") or 0 + check_upper = investor_data.get("check_size_upper") or float("inf") + if check_lower and check_upper and check_lower <= project_valuation <= check_upper: score += weights["check_size"] # Thesis alignment (simplified) @@ -151,14 +151,21 @@ class ReportGenerator: ) # Geography criterion - investor_geo = investor_data.get("geographic_focus", "N/A") - project_geo = project_data.get("location", "N/A") - geo_match = ( - "Strong" - if investor_geo.lower() in project_geo.lower() - or project_geo.lower() in investor_geo.lower() - else "Mismatch" - ) + investor_geo = investor_data.get("geographic_focus") or "N/A" + project_geo = project_data.get("location") or "N/A" + + # Safe comparison handling None values + if investor_geo == "N/A" or project_geo == "N/A": + geo_match = "N/A" if investor_geo == "N/A" and project_geo == "N/A" else "Mismatch" + else: + investor_geo_lower = investor_geo.lower() + project_geo_lower = project_geo.lower() + geo_match = ( + "Strong" + if investor_geo_lower in project_geo_lower + or project_geo_lower in investor_geo_lower + else "Mismatch" + ) criteria.append( { "name": "Geography", @@ -170,8 +177,8 @@ class ReportGenerator: ) # Check Size criterion - check_lower = investor_data.get("check_size_lower", 0) - check_upper = investor_data.get("check_size_upper", 0) + check_lower = investor_data.get("check_size_lower") or 0 + check_upper = investor_data.get("check_size_upper") or 0 project_val = project_data.get("valuation", 0) check_evidence = "N/A" @@ -184,7 +191,7 @@ class ReportGenerator: check_match = ( "Perfect" - if check_lower <= project_val <= check_upper + if check_lower and check_upper and check_lower <= project_val <= check_upper else "Strong" if project_val > 0 else "N/A" diff --git a/investors.db b/investors.db index e9027d1f33daccdc43bc95cf7af35f2253509f8e..59ed697527cff793d423e3fa59d167e40eba2b28 100644 GIT binary patch delta 2019 zcmaLVXLwXa6vpwb#1P0OKtP)ODK?b2*^m%pBal#{1Ox%GK};4S-4H}k2&lXwDuOf> z)Yv0QS+VT-p|{-^{<^+lbTVz&8~+3O_(SyDJ-gsWQDp$b31e^EiDKQ|Fb%h zLH~Z~0?TLCO`Dz?oT{2!Ut3*Om)a(^t4S7k6=iMz{)URmvY{1aL(Be2nEzk5k}UYIh;K5#s3gB{N$bL*=Alq17HkRyTY~R{ zuYyhMa@?N@Tl-TVZx@e-!?9R;jz-gSBod8gX5MsPtY1z>@M0+VDcBr*8oVED3^oK! zIgL*&jQ!Q$RqpS`;#fvBoEeEVi)Myn-k+HnkEIhv;?eZdEFMWG&WMN8OQfYMi3FR| zNt;T?XD^6s^Q&YhiGHF~^cMp}nJ5yHM4gx+>cvcPte7Q^6UU3$;skM`m?P$j1~E^}7bl66#VKNekT_K=6sL(r z;&gF_I8!VZXNe_ZsW@9K6U)U4u~MuO=ZJH~d1AF#BhD8WhzmudxJX#S`L5@sxO4JR_bJ&xz;73*trbl6YCXBG!vn#Rl=3cwM|9-V|?% zjpA+bj(AtRC*Btyh!4d_;$!iN*d#s`pNY@K7vf9tmH1k07T<_(#dqR+@q_qL{3L!B zzlbg3SMi(peG%csge_uGi&@;7S%z(AnbzF0tcA6-YzwTFtvm+i|t@tEq#7B>ux=)r|oDv+0M3$?P|SjH{0EMTb}J<3Cp*n6<8lDv?A+k#kQxF z*j~1`?PL4ee%8-Qt-lShGAp-%Hpm9s5Ua5L?Eo8Ul{UeBl1;WLHr1xtbUViCY=+g_Ogq+Q*>QHf z&9)QlM4MxCt-M+fLR1 delta 1858 zcmW;MWpox)9Ds3Oct;L4IySm%bdA~=-QCUTuF)`Zi~-x|5Eu-lMZ_+!TTsFP0~Bn1 z726rljK|L2}_&$(ajP0qR-o{WsBKx}4oLRjoQF-fUs6SEGU3x;wc4us+Z!K1;7 zfynIOg}Cfsh&2?M!Ul37H-ZR59^^$nY^TEP#+D@5RK3nP0$q0&>St$60vB7)@Xya zXoon&qdgMP0Ugl^ozVqd(GA_v13l3Tz0n7K(GUGG00S`ygE0g{F$}{o0wXaBqcH|! zF%ILAhzXd8Ntlc&n2Kqbjv1JVS(uGEn2ULsj|E7=LM*~!EWuJN!*Z;^N+e?yR$~p; zVjb2a1sjlxjYz{LY{nL(BLkV(if!1A9oUIo*o{5di+#8k`*8pVk%dDzjBFgieYhV- zaSX?C0w-|_r||&J;6a?lLpXBVGN!DFGSQ}-DQ_y6|L<4Hsj{hJs+wx1 zx~XAmnp&o|sblJzdM3uyHw{cf)5tV7O-xhM%rrMGOiL4MTA9|SjcIGznK%<~+M5K^ z!E`j8OlQ-@bT!>fchkf4G`&o3)5r8R{Y-x|zzj5l%wRLb3^l{da5KV;G^5ODGscWH z