Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Caching impact & funding reports #177

Merged
merged 11 commits into from
Feb 20, 2024
Merged
4 changes: 2 additions & 2 deletions web/components/ProjectModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,10 @@ const ProjectModal = ({
category: "Relevance",
value: strategy.interest,
},
{ category: "Impact", value: strategy.impact },
{ category: "Impact", value: strategy.project.impact },
{
category: "Funding Needs",
value: strategy.funding_needed,
value: strategy.project.funding_needed,
},
].map((item, i) => (
<div
Expand Down
15 changes: 9 additions & 6 deletions web/supabase/dbTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,10 @@ export interface Database {
Row: {
categories: string[]
description: string | null
funding_needed: number | null
id: string
impact: number | null
impact_funding_report: string | null
keywords: string[]
logo: string | null
short_description: string | null
Expand All @@ -177,7 +180,10 @@ export interface Database {
Insert: {
categories?: string[]
description?: string | null
funding_needed?: number | null
id: string
impact?: number | null
impact_funding_report?: string | null
keywords?: string[]
logo?: string | null
short_description?: string | null
Expand All @@ -189,7 +195,10 @@ export interface Database {
Update: {
categories?: string[]
description?: string | null
funding_needed?: number | null
id?: string
impact?: number | null
impact_funding_report?: string | null
keywords?: string[]
logo?: string | null
short_description?: string | null
Expand Down Expand Up @@ -232,9 +241,7 @@ export interface Database {
strategy_entries: {
Row: {
created_at: string
funding_needed: number | null
id: string
impact: number | null
interest: number | null
project_id: string
report: string | null
Expand All @@ -243,9 +250,7 @@ export interface Database {
}
Insert: {
created_at?: string
funding_needed?: number | null
id?: string
impact?: number | null
interest?: number | null
project_id: string
report?: string | null
Expand All @@ -254,9 +259,7 @@ export interface Database {
}
Update: {
created_at?: string
funding_needed?: number | null
id?: string
impact?: number | null
interest?: number | null
project_id?: string
report?: string | null
Expand Down
21 changes: 21 additions & 0 deletions web/supabase/migrations/20240220203532_caching_impact_funding.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
alter table "public"."strategy_entries" drop constraint "strategy_entries_funding_needed_check";

alter table "public"."strategy_entries" drop constraint "strategy_entries_impact_check";

alter table "public"."projects" add column "funding_needed" numeric;

alter table "public"."projects" add column "impact" numeric;

alter table "public"."projects" add column "impact_funding_report" text;

alter table "public"."strategy_entries" drop column "funding_needed";

alter table "public"."strategy_entries" drop column "impact";

alter table "public"."projects" add constraint "projects_funding_needed_check" CHECK (((funding_needed >= 0.00) AND (funding_needed <= 1.00))) not valid;

alter table "public"."projects" validate constraint "projects_funding_needed_check";

alter table "public"."projects" add constraint "projects_impact_check" CHECK (((impact >= 0.00) AND (impact <= 1.00))) not valid;

alter table "public"."projects" validate constraint "projects_impact_check";
3 changes: 3 additions & 0 deletions workers/fund_public_goods/db/entities.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@ class Projects(BaseModel):
twitter: Optional[str] = None
keywords: list[str] = []
categories: list[str] = []
impact_funding_report: Optional[str] = Field(..., alias="impactFundingReport")
impact: Optional[float] = None
funding_needed: Optional[float] = Field(..., alias="fundingNeeded")

model_config = ConfigDict(
populate_by_name=True
Expand Down
45 changes: 14 additions & 31 deletions workers/fund_public_goods/db/tables/projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ def upsert(
"short_description": row.short_description,
"keywords": row.keywords,
"categories": row.categories,
"logo": row.logo
"logo": row.logo,
"funding_needed": row.funding_needed,
"impact_funding_report": row.impact_funding_report,
"impact": row.impact
}).execute()

def upsert_multiple(
Expand All @@ -36,35 +39,12 @@ def upsert_multiple(
"short_description": row.short_description,
"keywords": row.keywords,
"categories": row.categories,
"logo": row.logo
"logo": row.logo,
"funding_needed": row.funding_needed,
"impact_funding_report": row.impact_funding_report,
"impact": row.impact
} for row in rows]).execute()

def get(
project_id: str
) -> Projects | None:
db = create_admin()
result = (db.table("projects")
.select("id", "updated_at", "title", "keywords", "categories", "description", "short_description", "website", "twitter", "logo")
.eq("id", project_id)
.execute())

if not result.data:
return None

data = result.data[0]

return Projects(
id=data["id"],
updated_at=data["updated_at"],
title=data["title"],
description=data["description"],
website=data["website"],
keywords=data['keywords'],
categories=data['categories'],
twitter=data["twitter"],
short_description=data["short_description"],
logo=data["logo"]
)

def sanitize_projects_information(projects: list[dict[str, Any]]) -> list[tuple[Projects, list[Answer]]]:
projects_with_answers: list[tuple[Projects, list[Answer]]] = []
Expand All @@ -83,15 +63,18 @@ def sanitize_projects_information(projects: list[dict[str, Any]]) -> list[tuple[

project = Projects(
id=project_data.get("id", ""),
updated_at=project_data.get("updated_at", ""),
title=project_data.get("title", ""),
description=project_data.get("description", ""),
updated_at=project_data.get("updated_at", None),
website=project_data.get("website", ""),
twitter=project_data.get("twitter", ""),
logo=project_data.get("logo", ""),
keywords=project_data.get("keywords", []),
categories=project_data.get("categories", []),
short_description=project_data.get("short_description", None)
short_description=project_data.get("short_description", None),
funding_needed=project_data.get("funding_needed", None),
impact=project_data.get("impact", None),
impact_funding_report=project_data.get("impact_funding_report", None),
)

projects_with_answers.append((project, answers))
Expand Down Expand Up @@ -124,7 +107,7 @@ def get_projects_from_description(categories: list[str]):
request = (
db.table("projects")
.select(
"id, updated_at, title, description, website, keywords, categories, short_description, twitter, logo, applications(id, recipient, round, answers)"
"* applications(id, recipient, round, answers)"
)
.ov("categories", categories)
.execute()
Expand Down
11 changes: 4 additions & 7 deletions workers/fund_public_goods/db/tables/strategy_entries.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from fund_public_goods.lib.strategy.models.weighted_project import WeightedProject
from fund_public_goods.lib.strategy.models.smart_ranked_project import SmartRankedProject
from fund_public_goods.db.entities import StrategyEntries
from fund_public_goods.db.app_db import create_admin

Expand All @@ -10,24 +10,21 @@ def insert(
db.table("strategy_entries").insert({
"run_id": str(row.run_id),
"project_id": row.project_id,
"impact": row.impact,
"interest": row.interest,
"smart_ranking": row.smart_ranking,
}).execute()

def insert_multiple(run_id: str, strategies: list[WeightedProject]) -> None:
def insert_multiple(run_id: str, strategies: list[tuple[SmartRankedProject, str]]) -> None:
db = create_admin()
db.table("strategy_entries").insert(
[
{
"run_id": run_id,
"impact": entry.scores.impact,
"interest": entry.scores.prompt_match,
"funding_needed": entry.scores.funding_needed,
"report": entry.report,
"report": report,
"project_id": entry.project.id,
"smart_ranking": entry.smart_ranking,
}
for entry in strategies
for (entry, report) in strategies
]
).execute()
92 changes: 69 additions & 23 deletions workers/fund_public_goods/lib/strategy/create.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
from fund_public_goods.db import tables, app_db
from fund_public_goods.db.entities import Projects, StepStatus, StepName, Logs
from fund_public_goods.db.entities import StepStatus, StepName, Logs
from fund_public_goods.db.tables.projects import upsert_multiple
from fund_public_goods.db.tables.runs import get_prompt
from fund_public_goods.db.tables.strategy_entries import insert_multiple
from fund_public_goods.lib.strategy.utils.evaluate_projects import evaluate_projects
from fund_public_goods.lib.strategy.utils.score_projects import score_projects
from fund_public_goods.lib.strategy.utils.calculate_weights import calculate_weights
from fund_public_goods.lib.strategy.models.project_scores import ProjectScores
from fund_public_goods.lib.strategy.utils.calculate_smart_rankings import calculate_smart_rankings
from fund_public_goods.lib.strategy.utils.fetch_matching_projects import fetch_matching_projects
from fund_public_goods.lib.strategy.utils.generate_impact_funding_reports import generate_impact_funding_reports
from fund_public_goods.lib.strategy.utils.generate_relevancy_reports import generate_relevancy_reports
from fund_public_goods.lib.strategy.utils.score_projects_impact_funding import score_projects_impact_funding
from fund_public_goods.lib.strategy.utils.score_projects_relevancy import score_projects_relevancy
from fund_public_goods.lib.strategy.utils.summarize_descriptions import summarize_descriptions
from supabase.lib.client_options import ClientOptions
from fastapi import Header, HTTPException
Expand Down Expand Up @@ -51,7 +54,6 @@ def create(run_id: str, authorization: Optional[str] = Header(None)):
value=None,
)

projects_with_answers = []
try:
projects_with_answers = fetch_matching_projects(prompt)
tables.logs.update(
Expand All @@ -60,73 +62,117 @@ def create(run_id: str, authorization: Optional[str] = Header(None)):
value=f"Found {len(projects_with_answers)} projects related to '{prompt}'",
)
except Exception as error:
details = f"An error occurred: {type(error).__name__} - {str(error)} "
tables.logs.update(
status=StepStatus.ERRORED,
log_id=log_ids[StepName.FETCH_PROJECTS],
value=f"An error occurred: {type(error).__name__} - {str(error)} ",
value=details
)
return
print(error)
raise HTTPException(status_code=400, detail=details)

projects_with_reports: list[tuple[Projects, str]] = []
try:
tables.logs.update(
status=StepStatus.IN_PROGRESS,
log_id=log_ids[StepName.EVALUATE_PROJECTS],
value=None,
)
reports = evaluate_projects(prompt, projects_with_answers)
projects_with_reports = [(projects_with_answers[i][0], reports[i]) for i in range(len(reports))]

# Only generate impact & funding reports and scores for those that need it

projects_without_funding_impact_reports = [(p, answers) for (p, answers) in projects_with_answers if not p.impact_funding_report]
projects_with_impact_funding_reports = [(p, answers) for (p, answers) in projects_with_answers if p.impact_funding_report]

if len(projects_without_funding_impact_reports) > 0:
impact_funding_reports = generate_impact_funding_reports(projects_without_funding_impact_reports)
projects_with_new_reports_and_answers = [projects_without_funding_impact_reports[i] for i in range(len(impact_funding_reports))]

for i in range(len(projects_with_new_reports_and_answers)):
projects_with_new_reports_and_answers[i][0].impact_funding_report = impact_funding_reports[i]

impact_funding_scores = score_projects_impact_funding([p for (p, _) in projects_with_new_reports_and_answers])

for i in range(len(impact_funding_scores)):
projects_with_new_reports_and_answers[i][0].impact = impact_funding_scores[i].impact
projects_with_new_reports_and_answers[i][0].funding_needed = impact_funding_scores[i].funding_needed

print([p.title for (p, _) in projects_with_new_reports_and_answers])
upsert_multiple([p for (p, _) in projects_with_new_reports_and_answers])

projects_with_impact_funding_reports += projects_with_new_reports_and_answers

tables.logs.update(
status=StepStatus.COMPLETED,
log_id=log_ids[StepName.EVALUATE_PROJECTS],
value=f"Generated impact & funding needs reports for {len(projects_with_reports)} projects",
value=f"Generated impact & funding needs reports for {len(projects_with_impact_funding_reports)} projects",
)
except Exception as error:
details = f"An error occurred: {type(error).__name__} - {str(error)} "
tables.logs.update(
status=StepStatus.ERRORED,
log_id=log_ids[StepName.EVALUATE_PROJECTS],
value=f"An error occurred: {type(error).__name__} - {str(error)} ",
value=details
)
return
print(error)
raise HTTPException(status_code=400, detail=details)

weighted_projects = []
try:
tables.logs.update(
status=StepStatus.IN_PROGRESS,
log_id=log_ids[StepName.ANALYZE_FUNDING],
value=None,
)
project_scores = score_projects(projects_with_reports, prompt)
weighted_projects = calculate_weights(projects_with_reports, project_scores)

relevancy_reports = generate_relevancy_reports(prompt, projects_with_impact_funding_reports)
projects_with_relevancy_reports = [(projects_with_impact_funding_reports[i][0], relevancy_reports[i]) for i in range(len(relevancy_reports))]
full_reports = [f"{relevancy_reports[i]}\n\n{projects_with_relevancy_reports[i][0].impact_funding_report}" for i in range(len(relevancy_reports))]

relevancy_scores = score_projects_relevancy(projects_with_relevancy_reports, prompt)

project_scores = [ProjectScores(
project_id=relevancy_scores[i].project_id,
prompt_match=relevancy_scores[i].prompt_match,
impact=projects_with_impact_funding_reports[i][0].impact,
funding_needed=projects_with_impact_funding_reports[i][0].funding_needed
) for i in range(len(relevancy_scores)
)]

projects_with_scores = [(projects_with_relevancy_reports[i][0], project_scores[i]) for i in range(len(project_scores))]
smart_ranked_projects = calculate_smart_rankings(projects_with_scores)

tables.logs.update(
status=StepStatus.COMPLETED,
log_id=log_ids[StepName.ANALYZE_FUNDING],
value=f"Computed smart rankings for {len(weighted_projects)} projects",
value=f"Computed smart rankings for {len(smart_ranked_projects)} projects",
)
except Exception as error:
details = f"An error occurred: {type(error).__name__} - {str(error)} "
tables.logs.update(
status=StepStatus.ERRORED,
log_id=log_ids[StepName.ANALYZE_FUNDING],
value=f"An error occurred: {type(error).__name__} - {str(error)} ",
value=details
)
return
print(error)
raise HTTPException(status_code=400, detail=details)


tables.logs.update(
status=StepStatus.IN_PROGRESS,
log_id=log_ids[StepName.SYNTHESIZE_RESULTS],
value=None
)
projects = [project for (project, _) in projects_with_answers]
projects_without_short_desc = [p for p in projects if not p.short_description]
projects_with_short_desc = [p for p in projects if p.short_description]

projects_without_short_desc = [p for (p, _) in projects_with_scores if not p.short_description]
projects_with_short_desc = [p for (p, _) in projects_with_scores if p.short_description]

if len(projects_without_short_desc) > 0:
projects_with_short_desc += summarize_descriptions(projects_without_short_desc)

upsert_multiple(projects_with_short_desc)

ranked_projects_with_reports = [(smart_ranked_projects[i], full_reports[i]) for i in range(len(smart_ranked_projects))]

insert_multiple(run_id, weighted_projects)
insert_multiple(run_id, ranked_projects_with_reports)

tables.logs.update(
status=StepStatus.COMPLETED,
Expand Down
Loading
Loading