From 2ae5a10f8742537801a8f507f5fd597776bb93d7 Mon Sep 17 00:00:00 2001 From: Nestor Amesty Date: Fri, 16 Feb 2024 19:28:38 +0100 Subject: [PATCH 01/10] Separated relevancy from impact & funding --- workers/fund_public_goods/api/run.py | 53 +++++++++++------ .../db/tables/strategy_entries.py | 8 +-- .../lib/strategy/models/project_scores.py | 24 ++++++++ ...ted_project.py => smart_ranked_project.py} | 3 +- .../lib/strategy/utils/calculate_weights.py | 20 +++---- ....py => generate_impact_funding_reports.py} | 28 +++------ .../utils/generate_relevancy_reports.py | 48 +++++++++++++++ ...ts.py => score_projects_impact_funding.py} | 22 ++----- .../utils/score_projects_relevancy.py | 58 +++++++++++++++++++ .../workflows/create_embeddings/__init__.py | 0 .../create_embeddings/functions/__init__.py | 0 .../functions/create_embeddings.py | 44 ++++++++++++++ 12 files changed, 237 insertions(+), 71 deletions(-) rename workers/fund_public_goods/lib/strategy/models/{weighted_project.py => smart_ranked_project.py} (89%) rename workers/fund_public_goods/lib/strategy/utils/{evaluate_projects.py => generate_impact_funding_reports.py} (58%) create mode 100644 workers/fund_public_goods/lib/strategy/utils/generate_relevancy_reports.py rename workers/fund_public_goods/lib/strategy/utils/{score_projects.py => score_projects_impact_funding.py} (73%) create mode 100644 workers/fund_public_goods/lib/strategy/utils/score_projects_relevancy.py create mode 100644 workers/fund_public_goods/workflows/create_embeddings/__init__.py create mode 100644 workers/fund_public_goods/workflows/create_embeddings/functions/__init__.py create mode 100644 workers/fund_public_goods/workflows/create_embeddings/functions/create_embeddings.py diff --git a/workers/fund_public_goods/api/run.py b/workers/fund_public_goods/api/run.py index dc53a03a..04866f92 100644 --- a/workers/fund_public_goods/api/run.py +++ b/workers/fund_public_goods/api/run.py @@ -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_weights 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 APIRouter, Header, HTTPException @@ -62,7 +65,6 @@ async def run(params: Params, authorization: Optional[str] = Header(None)) -> Re value=None, ) - projects_with_answers = [] try: projects_with_answers = fetch_matching_projects(prompt) tables.logs.update( @@ -78,19 +80,33 @@ async def run(params: Params, authorization: Optional[str] = Header(None)) -> Re ) return Response(status="Internal error") - 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))] + + relevancy_reports = generate_relevancy_reports(prompt, projects_with_answers) + projects_with_relevancy_reports = [(projects_with_answers[i][0], relevancy_reports[i]) for i in range(len(relevancy_reports))] + relevancy_scores = score_projects_relevancy(projects_with_relevancy_reports, prompt) + + impact_funding_reports = generate_impact_funding_reports(projects_with_answers) + projects_with_impact_funding_reports = [(projects_with_answers[i][0], impact_funding_reports[i]) for i in range(len(impact_funding_reports))] + impact_funding_scores = score_projects_impact_funding(projects_with_impact_funding_reports) + + project_scores = [ProjectScores( + projectId=relevancy_scores[i].project_id, + promptMatch=relevancy_scores[i].prompt_match, + impact=impact_funding_scores[i].impact, + fundingNeeded=impact_funding_scores[i].funding_needed + ) for i in range(len(relevancy_scores) + )] + 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: tables.logs.update( @@ -100,20 +116,19 @@ async def run(params: Params, authorization: Optional[str] = Header(None)) -> Re ) return Response(status="Internal error") - 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) + projects_with_scores = [(projects_with_answers[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: tables.logs.update( @@ -123,21 +138,25 @@ async def run(params: Params, authorization: Optional[str] = Header(None)) -> Re ) return Response(status="Internal error") + 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_answers if not p.short_description] + projects_with_short_desc = [p for (p, _) in projects_with_answers 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) + + full_reports = [f"{relevancy_reports[i]}\n\n{impact_funding_reports[i]}" for i in range(len(relevancy_reports))] + 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, diff --git a/workers/fund_public_goods/db/tables/strategy_entries.py b/workers/fund_public_goods/db/tables/strategy_entries.py index 888e81c3..3baca0a1 100644 --- a/workers/fund_public_goods/db/tables/strategy_entries.py +++ b/workers/fund_public_goods/db/tables/strategy_entries.py @@ -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 @@ -15,7 +15,7 @@ def insert( "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( [ @@ -24,10 +24,10 @@ def insert_multiple(run_id: str, strategies: list[WeightedProject]) -> None: "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() diff --git a/workers/fund_public_goods/lib/strategy/models/project_scores.py b/workers/fund_public_goods/lib/strategy/models/project_scores.py index e7a2112f..9955c412 100644 --- a/workers/fund_public_goods/lib/strategy/models/project_scores.py +++ b/workers/fund_public_goods/lib/strategy/models/project_scores.py @@ -1,5 +1,29 @@ from pydantic import BaseModel, ConfigDict, Field + +class ProjectRelevancyScores(BaseModel): + project_id: str = Field(..., alias="projectId") + prompt_match: float = Field(..., alias="promptMatch") + + def __getitem__(self, item): + return getattr(self, item) + + model_config = ConfigDict( + populate_by_name=True, + ) + +class ProjectImpactFundingScores(BaseModel): + project_id: str = Field(..., alias="projectId") + impact: float + funding_needed: float = Field(..., alias="fundingNeeded") + + def __getitem__(self, item): + return getattr(self, item) + + model_config = ConfigDict( + populate_by_name=True, + ) + class ProjectScores(BaseModel): project_id: str = Field(..., alias="projectId") prompt_match: float = Field(..., alias="promptMatch") diff --git a/workers/fund_public_goods/lib/strategy/models/weighted_project.py b/workers/fund_public_goods/lib/strategy/models/smart_ranked_project.py similarity index 89% rename from workers/fund_public_goods/lib/strategy/models/weighted_project.py rename to workers/fund_public_goods/lib/strategy/models/smart_ranked_project.py index d54e7df6..887bb35b 100644 --- a/workers/fund_public_goods/lib/strategy/models/weighted_project.py +++ b/workers/fund_public_goods/lib/strategy/models/smart_ranked_project.py @@ -2,9 +2,8 @@ from pydantic import BaseModel, ConfigDict, Field from fund_public_goods.lib.strategy.models.project_scores import ProjectScores -class WeightedProject(BaseModel): +class SmartRankedProject(BaseModel): project: Projects - report: str scores: ProjectScores smart_ranking: float = Field(..., alias="smartRanking") diff --git a/workers/fund_public_goods/lib/strategy/utils/calculate_weights.py b/workers/fund_public_goods/lib/strategy/utils/calculate_weights.py index a7bef3a8..05f932d5 100644 --- a/workers/fund_public_goods/lib/strategy/utils/calculate_weights.py +++ b/workers/fund_public_goods/lib/strategy/utils/calculate_weights.py @@ -1,43 +1,37 @@ -import math from typing import Any from fund_public_goods.db.entities import Projects from fund_public_goods.lib.strategy.models.project_scores import ProjectScores -from fund_public_goods.lib.strategy.models.weighted_project import WeightedProject +from fund_public_goods.lib.strategy.models.smart_ranked_project import SmartRankedProject PROMPT_MATCH_WEIGHT = 1/3 IMPACT_WEIGHT = 1/3 FUNDING_NEEDED_WEIGHT = 1/3 -def calculate_weights(projects_with_reports: list[tuple[Projects, str]], projects_scores: list[ProjectScores]) -> list[WeightedProject]: - projects_by_id = { project_with_report[0].id: project_with_report for project_with_report in projects_with_reports } +def calculate_smart_rankings(projects_with_scores: list[tuple[Projects, ProjectScores]]) -> list[SmartRankedProject]: smart_ranked_projects: list[dict[str, Any]] = [] - for project_scores in projects_scores: + for (project, project_scores) in projects_with_scores: smart_ranking = ( (project_scores.prompt_match * PROMPT_MATCH_WEIGHT) + (project_scores.impact * IMPACT_WEIGHT) + (project_scores.funding_needed * FUNDING_NEEDED_WEIGHT) ) - (project, report) = projects_by_id[project_scores.project_id] - smart_ranked_projects.append( { "project": project, - "report": report, "scores": project_scores, "smart_ranking": smart_ranking } ) - weighted_projects: list[WeightedProject] = [ - WeightedProject( + ranked_projects: list[SmartRankedProject] = [ + SmartRankedProject( project=smart_ranked_project["project"], - report=smart_ranked_project["report"], scores=smart_ranked_project["scores"], - smart_ranking=round(smart_ranked_project["smart_ranking"], 2) + smartRanking=round(smart_ranked_project["smart_ranking"], 2) ) for smart_ranked_project in smart_ranked_projects ] - return weighted_projects + return ranked_projects diff --git a/workers/fund_public_goods/lib/strategy/utils/evaluate_projects.py b/workers/fund_public_goods/lib/strategy/utils/generate_impact_funding_reports.py similarity index 58% rename from workers/fund_public_goods/lib/strategy/utils/evaluate_projects.py rename to workers/fund_public_goods/lib/strategy/utils/generate_impact_funding_reports.py index 5f9186d1..bbd1c5cf 100644 --- a/workers/fund_public_goods/lib/strategy/utils/evaluate_projects.py +++ b/workers/fund_public_goods/lib/strategy/utils/generate_impact_funding_reports.py @@ -6,14 +6,10 @@ from langchain_core.output_parsers import StrOutputParser -evaluation_prompt_template = """ +reports_prompt_template = """ As a professional evaluator of public goods projects, your task involves analyzing project information to prepare a concise report on: -- Relevance: Assess how closely a project aligns with the user's prompt, -critically examining the project description for genuine relevance versus promotional language. -Identify key points of alignment, discrepancies, and provide a rationale for the degree of match. - - Impact: Evaluate the project's impact based on concrete evidence of past achievements. Summarize verifiable accomplishments, assess the significance of these outcomes, and critically analyze the project's tangible impact. If no concrete proof is available, note this. @@ -22,17 +18,12 @@ Identify genuine funding needs linked to project goals and assess fund usage effectiveness. Provide a rationale for the exact funding needed to maximize impact efficiently. -Your objective is to critically sift through self-reported data to determine project alignment with user interests, verify past impact, and accurately assess funding needs, focusing on factual evidence and realistic project outcomes. - -User's prompt: {prompt} +Your objective is to critically sift through self-reported data to verify past impact, and accurately assess funding needs, focusing on factual evidence and realistic project outcomes. Project: {project} Your output should be in markdown format with the following structure: -## Relevance -... - ## Impact ... @@ -40,18 +31,17 @@ .. """ -def evaluate_projects(prompt: str, projects: list[tuple[Projects, list[Answer]]]) -> list[str]: - evaluation_prompt = ChatPromptTemplate.from_messages([ - ("system", evaluation_prompt_template), +def generate_impact_funding_reports(projects: list[tuple[Projects, list[Answer]]]) -> list[str]: + reports_prompt = ChatPromptTemplate.from_messages([ + ("system", reports_prompt_template), ]) - llm = ChatOpenAI(model="gpt-3.5-turbo-0125") # type: ignore + llm = ChatOpenAI(model="gpt-3.5-turbo-0125", max_tokens=500) - evaluation_chain = evaluation_prompt | llm | StrOutputParser() + reports_chain = reports_prompt | llm | StrOutputParser() - evaluation_reports = evaluation_chain.batch([{ - "prompt": prompt, + reports_reports = reports_chain.batch([{ "project": get_project_text(project) } for project in projects]) - return evaluation_reports + return reports_reports diff --git a/workers/fund_public_goods/lib/strategy/utils/generate_relevancy_reports.py b/workers/fund_public_goods/lib/strategy/utils/generate_relevancy_reports.py new file mode 100644 index 00000000..d8d3af3f --- /dev/null +++ b/workers/fund_public_goods/lib/strategy/utils/generate_relevancy_reports.py @@ -0,0 +1,48 @@ +from fund_public_goods.db.entities import Projects +from fund_public_goods.lib.strategy.models.answer import Answer +from fund_public_goods.lib.strategy.utils.utils import get_project_text +from langchain_openai import ChatOpenAI +from langchain_core.prompts import ChatPromptTemplate +from langchain_core.output_parsers import StrOutputParser + + +reports_prompt_template = """ + +As a professional evaluator of public goods projects, your task involves analyzing project information to prepare a +concise report on relevance. Assess how closely a project aligns with the user's prompt, +critically examining the project description for genuine relevance versus promotional language. +Identify key points of alignment, discrepancies, and provide a rationale for the degree of match. + +Your objective is to critically sift through self-reported data to determine project alignment with user interests. + +User's prompt: {prompt} + +Project: {project} + +Your output should be in markdown format with the following structure: + +## Relevance + +{{ Your output goes here}} + +""" + +def generate_relevancy_reports(prompt: str, projects: list[tuple[Projects, list[Answer]]]) -> list[str]: + reports_prompt = ChatPromptTemplate.from_messages([ + ("system", reports_prompt_template), + ]) + + llm = ChatOpenAI(model="gpt-3.5-turbo-0125", max_tokens=250) + + reports_chain = ( + reports_prompt | + llm | + StrOutputParser() + ) + + reports_reports = reports_chain.batch([{ + "prompt": prompt, + "project": get_project_text(project) + } for project in projects]) + + return reports_reports diff --git a/workers/fund_public_goods/lib/strategy/utils/score_projects.py b/workers/fund_public_goods/lib/strategy/utils/score_projects_impact_funding.py similarity index 73% rename from workers/fund_public_goods/lib/strategy/utils/score_projects.py rename to workers/fund_public_goods/lib/strategy/utils/score_projects_impact_funding.py index 2dd1add5..0f1ab2db 100644 --- a/workers/fund_public_goods/lib/strategy/utils/score_projects.py +++ b/workers/fund_public_goods/lib/strategy/utils/score_projects_impact_funding.py @@ -2,17 +2,12 @@ from langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers.json import JsonOutputParser -from fund_public_goods.lib.strategy.models.project_scores import ProjectScores +from fund_public_goods.lib.strategy.models.project_scores import ProjectImpactFundingScores, ProjectScores score_projects_prompt_template = """ As an agent tasked with numerically scoring public goods projects, you will use the evaluator's reports to rate each project on the following criteria: -- Alignment with User's Prompt: Score the project's alignment with the user's prompt on a scale of 0 to 1 using 2 decimals, -where 0 indicates no alignment and 1 represents perfect alignment. -Consider the project's relevance to the user's interests, the genuine use of specific terms over buzzwords, -and the depth of commitment to the prompt's themes. - - Impact: Rate the project's demonstrated impact based on concrete, verifiable achievements from 0 to 1 using 2 decimals. A score of 0 suggests no proven impact, while 1 indicates significant, well-documented contributions. Focus on the evidence of past outcomes, the scale of these achievements, and the consistency of reported success. @@ -23,28 +18,24 @@ For each criterion, provide a brief justification for your score, referencing specific aspects of the evaluator's report that influenced your decision. -Your goal is to offer a quantitative assessment that reflects a comprehensive and critical analysis of the project's alignment with user prompts, -its impact, and its funding needs. +Your goal is to offer a quantitative assessment that reflects a comprehensive and critical analysis of the project's impact, and its funding needs. You will return a single JSON object: {{ project_id: str, - prompt_match: float, impact: float, funding_needed: float }} Do not include any other contents in your response. Always use snake case. All fields are required -User prompt: {prompt} - Project report: {report} """ -def score_projects(projects_with_report: list[tuple[Projects, str]], prompt: str) -> list[ProjectScores]: +def score_projects_impact_funding(projects_with_report: list[tuple[Projects, str]]) -> list[ProjectImpactFundingScores]: reports = [f"Project ID: {project.id}\n\n{report}" for (project, report) in projects_with_report] score_projects_prompt = ChatPromptTemplate.from_messages([ @@ -56,13 +47,12 @@ def score_projects(projects_with_report: list[tuple[Projects, str]], prompt: str scoring_chain = score_projects_prompt | llm | JsonOutputParser() raw_scored_projects = scoring_chain.batch([{ - "report": report, - "prompt": prompt + "report": report } for report in reports ]) - scored_projects: list[ProjectScores] = [] + scored_projects: list[ProjectImpactFundingScores] = [] for raw_scored_project in raw_scored_projects: - scored_project = ProjectScores(**raw_scored_project) + scored_project = ProjectImpactFundingScores(**raw_scored_project) scored_projects.append(scored_project) return scored_projects \ No newline at end of file diff --git a/workers/fund_public_goods/lib/strategy/utils/score_projects_relevancy.py b/workers/fund_public_goods/lib/strategy/utils/score_projects_relevancy.py new file mode 100644 index 00000000..c99de1fd --- /dev/null +++ b/workers/fund_public_goods/lib/strategy/utils/score_projects_relevancy.py @@ -0,0 +1,58 @@ +from fund_public_goods.db.entities import Projects +from langchain_openai import ChatOpenAI +from langchain_core.prompts import ChatPromptTemplate +from langchain_core.output_parsers.json import JsonOutputParser +from fund_public_goods.lib.strategy.models.project_scores import ProjectRelevancyScores, ProjectScores + + +score_projects_relevancy_prompt_template = """ +As an agent tasked with numerically scoring public goods projects, you will use the evaluator's reports to a project on +its alignment with user's prompt. + +Score the project's alignment with the user's prompt on a scale of 0 to 1 using 2 decimals, +where 0 indicates no alignment and 1 represents perfect alignment. + +Consider the project's relevance to the user's interests, the genuine use of specific terms over buzzwords, +and the depth of commitment to the prompt's themes. + +Provide a brief justification for your score, referencing specific aspects of the evaluator's report that influenced your decision. +Your goal is to offer a quantitative assessment that reflects a comprehensive and critical analysis of the project's alignment with user prompts. + +You will return a single JSON object: + +{{ + project_id: str, + prompt_match: float, +}} + +Do not include any other contents in your response. Always use snake case. All fields are required + +User prompt: {prompt} + +Project report: + +{report} +""" + +def score_projects_relevancy(projects_with_report: list[tuple[Projects, str]], prompt: str) -> list[ProjectRelevancyScores]: + reports = [f"Project ID: {project.id}\n\n{report}" for (project, report) in projects_with_report] + + score_projects_relevancy_prompt = ChatPromptTemplate.from_messages([ + ("system", score_projects_relevancy_prompt_template), + ]) + + llm = ChatOpenAI(model="gpt-4-1106-preview", temperature=0, model_kwargs={'seed': 10}) # type: ignore + + scoring_chain = score_projects_relevancy_prompt | llm | JsonOutputParser() + + raw_scored_projects = scoring_chain.batch([{ + "report": report, + "prompt": prompt + } for report in reports ]) + + scored_projects: list[ProjectRelevancyScores] = [] + for raw_scored_project in raw_scored_projects: + scored_project = ProjectRelevancyScores(**raw_scored_project) + scored_projects.append(scored_project) + + return scored_projects \ No newline at end of file diff --git a/workers/fund_public_goods/workflows/create_embeddings/__init__.py b/workers/fund_public_goods/workflows/create_embeddings/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/workers/fund_public_goods/workflows/create_embeddings/functions/__init__.py b/workers/fund_public_goods/workflows/create_embeddings/functions/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/workers/fund_public_goods/workflows/create_embeddings/functions/create_embeddings.py b/workers/fund_public_goods/workflows/create_embeddings/functions/create_embeddings.py new file mode 100644 index 00000000..24339cc7 --- /dev/null +++ b/workers/fund_public_goods/workflows/create_embeddings/functions/create_embeddings.py @@ -0,0 +1,44 @@ +import inngest +from fund_public_goods.workflows.index_gitcoin.events import IndexGitcoinPageEvent +from fund_public_goods.db.tables.gitcoin import get_non_running_job, is_any_job_running, start_job + + +@inngest.create_function( + fn_id="create_embeddings" +) +async def start_index_gitcoin( + ctx: inngest.Context, + step: inngest.Step, +) -> str: + any_job_running = await step.run("is_any_job_running", lambda: is_any_job_running()) + + if any_job_running: + return "A job is already running" + + def get_not_running_job_step(): + job = get_non_running_job() + if not job: + return None + else: + return job + + job = await step.run("get_not_running_job", get_not_running_job_step) + + if not job: + return "No non-running job found" + + await step.run("start_job", lambda: start_job(job["id"])) + + await step.send_event( + "index_gitcoin_page", + IndexGitcoinPageEvent.Data( + url = job["url"], + network_id = job["networkId"], + project_page_size = 100, + skip_rounds = job["skipRounds"], + skip_projects = job["skipProjects"], + job_id=job["id"] + ).to_event() + ) + + return "Started job: ID=" + job["id"] + ", URL=" + job["url"] From 3a7dab3eb0d99eb60c10e7e32b2af21df4556d49 Mon Sep 17 00:00:00 2001 From: Nestor Amesty Date: Fri, 16 Feb 2024 19:30:13 +0100 Subject: [PATCH 02/10] Removed create embeddings workflow --- .../workflows/create_embeddings/__init__.py | 0 .../create_embeddings/functions/__init__.py | 0 .../functions/create_embeddings.py | 44 ------------------- 3 files changed, 44 deletions(-) delete mode 100644 workers/fund_public_goods/workflows/create_embeddings/__init__.py delete mode 100644 workers/fund_public_goods/workflows/create_embeddings/functions/__init__.py delete mode 100644 workers/fund_public_goods/workflows/create_embeddings/functions/create_embeddings.py diff --git a/workers/fund_public_goods/workflows/create_embeddings/__init__.py b/workers/fund_public_goods/workflows/create_embeddings/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/workers/fund_public_goods/workflows/create_embeddings/functions/__init__.py b/workers/fund_public_goods/workflows/create_embeddings/functions/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/workers/fund_public_goods/workflows/create_embeddings/functions/create_embeddings.py b/workers/fund_public_goods/workflows/create_embeddings/functions/create_embeddings.py deleted file mode 100644 index 24339cc7..00000000 --- a/workers/fund_public_goods/workflows/create_embeddings/functions/create_embeddings.py +++ /dev/null @@ -1,44 +0,0 @@ -import inngest -from fund_public_goods.workflows.index_gitcoin.events import IndexGitcoinPageEvent -from fund_public_goods.db.tables.gitcoin import get_non_running_job, is_any_job_running, start_job - - -@inngest.create_function( - fn_id="create_embeddings" -) -async def start_index_gitcoin( - ctx: inngest.Context, - step: inngest.Step, -) -> str: - any_job_running = await step.run("is_any_job_running", lambda: is_any_job_running()) - - if any_job_running: - return "A job is already running" - - def get_not_running_job_step(): - job = get_non_running_job() - if not job: - return None - else: - return job - - job = await step.run("get_not_running_job", get_not_running_job_step) - - if not job: - return "No non-running job found" - - await step.run("start_job", lambda: start_job(job["id"])) - - await step.send_event( - "index_gitcoin_page", - IndexGitcoinPageEvent.Data( - url = job["url"], - network_id = job["networkId"], - project_page_size = 100, - skip_rounds = job["skipRounds"], - skip_projects = job["skipProjects"], - job_id=job["id"] - ).to_event() - ) - - return "Started job: ID=" + job["id"] + ", URL=" + job["url"] From f79de7d9f2a5268c775779b53a325ee2291671aa Mon Sep 17 00:00:00 2001 From: Nestor Amesty Date: Fri, 16 Feb 2024 19:31:21 +0100 Subject: [PATCH 03/10] Renamed calculate weights --- workers/fund_public_goods/api/run.py | 2 +- .../utils/{calculate_weights.py => calculate_smart_rankings.py} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename workers/fund_public_goods/lib/strategy/utils/{calculate_weights.py => calculate_smart_rankings.py} (100%) diff --git a/workers/fund_public_goods/api/run.py b/workers/fund_public_goods/api/run.py index 04866f92..c739b0c1 100644 --- a/workers/fund_public_goods/api/run.py +++ b/workers/fund_public_goods/api/run.py @@ -4,7 +4,7 @@ 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.models.project_scores import ProjectScores -from fund_public_goods.lib.strategy.utils.calculate_weights import calculate_smart_rankings +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 diff --git a/workers/fund_public_goods/lib/strategy/utils/calculate_weights.py b/workers/fund_public_goods/lib/strategy/utils/calculate_smart_rankings.py similarity index 100% rename from workers/fund_public_goods/lib/strategy/utils/calculate_weights.py rename to workers/fund_public_goods/lib/strategy/utils/calculate_smart_rankings.py From f028c149197b6bb275d3b15a3f5d00a3b1787d91 Mon Sep 17 00:00:00 2001 From: Nestor Amesty Date: Fri, 16 Feb 2024 19:39:21 +0100 Subject: [PATCH 04/10] Added impact and funding scores and reports to projects table from strat --- web/supabase/dbTypes.ts | 15 +++++++------ .../20240216183826_caching_impact_funding.sql | 21 +++++++++++++++++++ 2 files changed, 30 insertions(+), 6 deletions(-) create mode 100644 web/supabase/migrations/20240216183826_caching_impact_funding.sql diff --git a/web/supabase/dbTypes.ts b/web/supabase/dbTypes.ts index b9188d55..74c04e4b 100644 --- a/web/supabase/dbTypes.ts +++ b/web/supabase/dbTypes.ts @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 diff --git a/web/supabase/migrations/20240216183826_caching_impact_funding.sql b/web/supabase/migrations/20240216183826_caching_impact_funding.sql new file mode 100644 index 00000000..02fa46d4 --- /dev/null +++ b/web/supabase/migrations/20240216183826_caching_impact_funding.sql @@ -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"; \ No newline at end of file From f7cf734637f5bbcc9b004c782de54340ef8cbf58 Mon Sep 17 00:00:00 2001 From: Nestor Amesty Date: Mon, 19 Feb 2024 23:46:44 +0100 Subject: [PATCH 05/10] Untested e2e --- workers/fund_public_goods/api/run.py | 49 +++++++++++++------ workers/fund_public_goods/db/entities.py | 3 ++ .../fund_public_goods/db/tables/projects.py | 33 ++----------- .../utils/generate_impact_funding_reports.py | 4 +- .../utils/score_projects_impact_funding.py | 4 +- 5 files changed, 45 insertions(+), 48 deletions(-) diff --git a/workers/fund_public_goods/api/run.py b/workers/fund_public_goods/api/run.py index c739b0c1..eabe8969 100644 --- a/workers/fund_public_goods/api/run.py +++ b/workers/fund_public_goods/api/run.py @@ -87,21 +87,24 @@ async def run(params: Params, authorization: Optional[str] = Header(None)) -> Re value=None, ) - relevancy_reports = generate_relevancy_reports(prompt, projects_with_answers) - projects_with_relevancy_reports = [(projects_with_answers[i][0], relevancy_reports[i]) for i in range(len(relevancy_reports))] - relevancy_scores = score_projects_relevancy(projects_with_relevancy_reports, prompt) + # Only generate impact & funding reports and scores for those that need it - impact_funding_reports = generate_impact_funding_reports(projects_with_answers) - projects_with_impact_funding_reports = [(projects_with_answers[i][0], impact_funding_reports[i]) for i in range(len(impact_funding_reports))] - impact_funding_scores = score_projects_impact_funding(projects_with_impact_funding_reports) + 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] - project_scores = [ProjectScores( - projectId=relevancy_scores[i].project_id, - promptMatch=relevancy_scores[i].prompt_match, - impact=impact_funding_scores[i].impact, - fundingNeeded=impact_funding_scores[i].funding_needed - ) for i in range(len(relevancy_scores) - )] + 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))] + + 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 + + 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, @@ -122,7 +125,21 @@ async def run(params: Params, authorization: Optional[str] = Header(None)) -> Re log_id=log_ids[StepName.ANALYZE_FUNDING], value=None, ) - projects_with_scores = [(projects_with_answers[i][0], project_scores[i]) for i in range(len(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))] + + relevancy_scores = score_projects_relevancy(projects_with_relevancy_reports, prompt) + + project_scores = [ProjectScores( + projectId=relevancy_scores[i].project_id, + promptMatch=relevancy_scores[i].prompt_match, + impact=impact_funding_scores[i].impact, + fundingNeeded=impact_funding_scores[i].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( @@ -145,8 +162,8 @@ async def run(params: Params, authorization: Optional[str] = Header(None)) -> Re value=None ) - projects_without_short_desc = [p for (p, _) in projects_with_answers if not p.short_description] - projects_with_short_desc = [p for (p, _) in projects_with_answers 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) diff --git a/workers/fund_public_goods/db/entities.py b/workers/fund_public_goods/db/entities.py index 9aac207d..9e33ad8b 100644 --- a/workers/fund_public_goods/db/entities.py +++ b/workers/fund_public_goods/db/entities.py @@ -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 diff --git a/workers/fund_public_goods/db/tables/projects.py b/workers/fund_public_goods/db/tables/projects.py index 95aa108f..7e5b45d3 100644 --- a/workers/fund_public_goods/db/tables/projects.py +++ b/workers/fund_public_goods/db/tables/projects.py @@ -39,39 +39,13 @@ def upsert_multiple( "logo": row.logo } 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 get_projects(range_from: int, range_to: int) -> PostgrestAPIResponse[Dict[str, Any]]: db = create_admin() return ( db.table("projects") .select( - "id, updated_at, title, description, website, keywords, categories, short_description, twitter, logo, applications(id, recipient, round, answers)" + "id, updated_at, title, description, website, keywords, categories, short_description, twitter, logo, funding_needed, impact, impact_funding_report, applications(id, recipient, round, answers)" ) .range(range_from, range_to) .execute() @@ -121,7 +95,10 @@ def fetch_projects_data() -> list[tuple[Projects, list[Answer]]]: 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), + fundingNeeded=project_data.get("funding_needed", None), + impact=project_data.get("impact", None), + impactReport=project_data.get("impact_report", None), ) projects_with_answers.append((project, answers)) diff --git a/workers/fund_public_goods/lib/strategy/utils/generate_impact_funding_reports.py b/workers/fund_public_goods/lib/strategy/utils/generate_impact_funding_reports.py index bbd1c5cf..3a38a0c5 100644 --- a/workers/fund_public_goods/lib/strategy/utils/generate_impact_funding_reports.py +++ b/workers/fund_public_goods/lib/strategy/utils/generate_impact_funding_reports.py @@ -40,8 +40,8 @@ def generate_impact_funding_reports(projects: list[tuple[Projects, list[Answer]] reports_chain = reports_prompt | llm | StrOutputParser() - reports_reports = reports_chain.batch([{ + reports = reports_chain.batch([{ "project": get_project_text(project) } for project in projects]) - return reports_reports + return reports diff --git a/workers/fund_public_goods/lib/strategy/utils/score_projects_impact_funding.py b/workers/fund_public_goods/lib/strategy/utils/score_projects_impact_funding.py index 0f1ab2db..78c4ad94 100644 --- a/workers/fund_public_goods/lib/strategy/utils/score_projects_impact_funding.py +++ b/workers/fund_public_goods/lib/strategy/utils/score_projects_impact_funding.py @@ -35,8 +35,8 @@ {report} """ -def score_projects_impact_funding(projects_with_report: list[tuple[Projects, str]]) -> list[ProjectImpactFundingScores]: - reports = [f"Project ID: {project.id}\n\n{report}" for (project, report) in projects_with_report] +def score_projects_impact_funding(projects_with_report: list[Projects]) -> list[ProjectImpactFundingScores]: + reports = [f"Project ID: {project.id}\n\n{project.impact_funding_report}" for project in projects_with_report] score_projects_prompt = ChatPromptTemplate.from_messages([ ("system", score_projects_prompt_template), From 28664089493939975abaf917f863ca99035c9b26 Mon Sep 17 00:00:00 2001 From: Nestor Amesty Date: Mon, 19 Feb 2024 23:57:05 +0100 Subject: [PATCH 06/10] Fixed typos --- workers/fund_public_goods/db/tables/projects.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/workers/fund_public_goods/db/tables/projects.py b/workers/fund_public_goods/db/tables/projects.py index 7e5b45d3..6531d143 100644 --- a/workers/fund_public_goods/db/tables/projects.py +++ b/workers/fund_public_goods/db/tables/projects.py @@ -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( @@ -36,7 +39,10 @@ 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() @@ -87,6 +93,8 @@ def fetch_projects_data() -> list[tuple[Projects, list[Answer]]]: project = Projects( id=project_data.get("id", ""), + updatedAt=project_data.get("updated_at", ""), + shortDescription=project_data.get("short_description", ""), title=project_data.get("title", ""), description=project_data.get("description", ""), updated_at=project_data.get("updated_at", None), @@ -98,7 +106,7 @@ def fetch_projects_data() -> list[tuple[Projects, list[Answer]]]: short_description=project_data.get("short_description", None), fundingNeeded=project_data.get("funding_needed", None), impact=project_data.get("impact", None), - impactReport=project_data.get("impact_report", None), + impactFundingReport=project_data.get("impact_funding_report", None), ) projects_with_answers.append((project, answers)) From 37942213f51e8226174a835ac0c040825b8f9b24 Mon Sep 17 00:00:00 2001 From: Nestor Amesty Date: Tue, 20 Feb 2024 02:43:37 +0100 Subject: [PATCH 07/10] E2E working --- workers/fund_public_goods/api/run.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/workers/fund_public_goods/api/run.py b/workers/fund_public_goods/api/run.py index eabe8969..d7943be2 100644 --- a/workers/fund_public_goods/api/run.py +++ b/workers/fund_public_goods/api/run.py @@ -78,6 +78,7 @@ async def run(params: Params, authorization: Optional[str] = Header(None)) -> Re log_id=log_ids[StepName.FETCH_PROJECTS], value=f"An error occurred: {type(error).__name__} - {str(error)} ", ) + print(error) return Response(status="Internal error") try: @@ -95,6 +96,9 @@ async def run(params: Params, authorization: Optional[str] = Header(None)) -> Re 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]) @@ -102,6 +106,7 @@ async def run(params: Params, authorization: Optional[str] = Header(None)) -> Re 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 @@ -117,6 +122,7 @@ async def run(params: Params, authorization: Optional[str] = Header(None)) -> Re log_id=log_ids[StepName.EVALUATE_PROJECTS], value=f"An error occurred: {type(error).__name__} - {str(error)} ", ) + print(error) return Response(status="Internal error") try: @@ -128,6 +134,7 @@ async def run(params: Params, authorization: Optional[str] = Header(None)) -> Re 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) @@ -153,6 +160,8 @@ async def run(params: Params, authorization: Optional[str] = Header(None)) -> Re log_id=log_ids[StepName.ANALYZE_FUNDING], value=f"An error occurred: {type(error).__name__} - {str(error)} ", ) + print(cb) + print(error) return Response(status="Internal error") @@ -170,7 +179,6 @@ async def run(params: Params, authorization: Optional[str] = Header(None)) -> Re upsert_multiple(projects_with_short_desc) - full_reports = [f"{relevancy_reports[i]}\n\n{impact_funding_reports[i]}" for i in range(len(relevancy_reports))] ranked_projects_with_reports = [(smart_ranked_projects[i], full_reports[i]) for i in range(len(smart_ranked_projects))] insert_multiple(run_id, ranked_projects_with_reports) From 6915718691712782a21d1b8d39d725cd55e98ba2 Mon Sep 17 00:00:00 2001 From: dOrgJelli Date: Tue, 20 Feb 2024 08:50:02 +0100 Subject: [PATCH 08/10] chore: fix build errors --- .../fund_public_goods/db/tables/projects.py | 7 +++---- .../fund_public_goods/lib/strategy/create.py | 21 +++++++++++-------- .../utils/calculate_smart_rankings.py | 4 ++-- .../workflows/egress_gitcoin/upsert.py | 4 +++- 4 files changed, 20 insertions(+), 16 deletions(-) diff --git a/workers/fund_public_goods/db/tables/projects.py b/workers/fund_public_goods/db/tables/projects.py index e9e87c0c..ad0cb5d2 100644 --- a/workers/fund_public_goods/db/tables/projects.py +++ b/workers/fund_public_goods/db/tables/projects.py @@ -63,8 +63,7 @@ def sanitize_projects_information(projects: list[dict[str, Any]]) -> list[tuple[ project = Projects( id=project_data.get("id", ""), - updatedAt=project_data.get("updated_at", ""), - shortDescription=project_data.get("short_description", ""), + updated_at=project_data.get("updated_at", ""), title=project_data.get("title", ""), description=project_data.get("description", ""), website=project_data.get("website", ""), @@ -73,9 +72,9 @@ def sanitize_projects_information(projects: list[dict[str, Any]]) -> list[tuple[ keywords=project_data.get("keywords", []), categories=project_data.get("categories", []), short_description=project_data.get("short_description", None), - fundingNeeded=project_data.get("funding_needed", None), + funding_needed=project_data.get("funding_needed", None), impact=project_data.get("impact", None), - impactFundingReport=project_data.get("impact_funding_report", None), + impact_funding_report=project_data.get("impact_funding_report", None), ) projects_with_answers.append((project, answers)) diff --git a/workers/fund_public_goods/lib/strategy/create.py b/workers/fund_public_goods/lib/strategy/create.py index 42fc16b1..8c57eb2d 100644 --- a/workers/fund_public_goods/lib/strategy/create.py +++ b/workers/fund_public_goods/lib/strategy/create.py @@ -62,13 +62,14 @@ 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 ) print(error) - return Response(status="Internal error") + raise HTTPException(status_code=400, detail=details) try: tables.logs.update( @@ -106,13 +107,14 @@ def create(run_id: str, authorization: Optional[str] = Header(None)): 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 ) print(error) - return Response(status="Internal error") + raise HTTPException(status_code=400, detail=details) try: tables.logs.update( @@ -128,10 +130,10 @@ def create(run_id: str, authorization: Optional[str] = Header(None)): relevancy_scores = score_projects_relevancy(projects_with_relevancy_reports, prompt) project_scores = [ProjectScores( - projectId=relevancy_scores[i].project_id, - promptMatch=relevancy_scores[i].prompt_match, + project_id=relevancy_scores[i].project_id, + prompt_match=relevancy_scores[i].prompt_match, impact=impact_funding_scores[i].impact, - fundingNeeded=impact_funding_scores[i].funding_needed + funding_needed=impact_funding_scores[i].funding_needed ) for i in range(len(relevancy_scores) )] @@ -144,13 +146,14 @@ def create(run_id: str, authorization: Optional[str] = Header(None)): value=f"Computed smart rankings for {len(smart_ranked_projects)} projects", ) except Exception as error: + 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 ) print(error) - return Response(status="Internal error") + raise HTTPException(status_code=400, detail=details) tables.logs.update( diff --git a/workers/fund_public_goods/lib/strategy/utils/calculate_smart_rankings.py b/workers/fund_public_goods/lib/strategy/utils/calculate_smart_rankings.py index 05f932d5..6e64e412 100644 --- a/workers/fund_public_goods/lib/strategy/utils/calculate_smart_rankings.py +++ b/workers/fund_public_goods/lib/strategy/utils/calculate_smart_rankings.py @@ -30,8 +30,8 @@ def calculate_smart_rankings(projects_with_scores: list[tuple[Projects, ProjectS SmartRankedProject( project=smart_ranked_project["project"], scores=smart_ranked_project["scores"], - smartRanking=round(smart_ranked_project["smart_ranking"], 2) + smart_ranking=round(smart_ranked_project["smart_ranking"], 2) ) for smart_ranked_project in smart_ranked_projects ] - + return ranked_projects diff --git a/workers/fund_public_goods/workflows/egress_gitcoin/upsert.py b/workers/fund_public_goods/workflows/egress_gitcoin/upsert.py index 4897df41..f05ac7c1 100644 --- a/workers/fund_public_goods/workflows/egress_gitcoin/upsert.py +++ b/workers/fund_public_goods/workflows/egress_gitcoin/upsert.py @@ -21,7 +21,9 @@ def upsert_project(project: GitcoinProjects, keywords: list[str], categories: li logo=project.data.get("logoImg", ""), short_description=None, keywords=keywords, - categories=categories + categories=categories, + impact_funding_report=None, + funding_needed=None ) tables.projects.upsert(entity) From 127690b656063f638179c01aa460524df9ffa5fe Mon Sep 17 00:00:00 2001 From: dOrgJelli Date: Tue, 20 Feb 2024 08:51:58 +0100 Subject: [PATCH 09/10] chore: update migration timestamp --- ...pact_funding.sql => 20240220203532_caching_impact_funding.sql} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename web/supabase/migrations/{20240216183826_caching_impact_funding.sql => 20240220203532_caching_impact_funding.sql} (100%) diff --git a/web/supabase/migrations/20240216183826_caching_impact_funding.sql b/web/supabase/migrations/20240220203532_caching_impact_funding.sql similarity index 100% rename from web/supabase/migrations/20240216183826_caching_impact_funding.sql rename to web/supabase/migrations/20240220203532_caching_impact_funding.sql From b4da5541ca9f0af4270c312fca6fd3fb5b262dd2 Mon Sep 17 00:00:00 2001 From: dOrgJelli Date: Tue, 20 Feb 2024 09:15:17 +0100 Subject: [PATCH 10/10] chore: minor runtime fixes --- workers/fund_public_goods/db/tables/strategy_entries.py | 3 --- workers/fund_public_goods/lib/strategy/create.py | 6 +++--- .../workflows/index_gitcoin/functions/index_gitcoin_page.py | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/workers/fund_public_goods/db/tables/strategy_entries.py b/workers/fund_public_goods/db/tables/strategy_entries.py index 3baca0a1..4cb0cabf 100644 --- a/workers/fund_public_goods/db/tables/strategy_entries.py +++ b/workers/fund_public_goods/db/tables/strategy_entries.py @@ -10,7 +10,6 @@ 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() @@ -21,9 +20,7 @@ def insert_multiple(run_id: str, strategies: list[tuple[SmartRankedProject, str] [ { "run_id": run_id, - "impact": entry.scores.impact, "interest": entry.scores.prompt_match, - "funding_needed": entry.scores.funding_needed, "report": report, "project_id": entry.project.id, "smart_ranking": entry.smart_ranking, diff --git a/workers/fund_public_goods/lib/strategy/create.py b/workers/fund_public_goods/lib/strategy/create.py index 8c57eb2d..2b61e679 100644 --- a/workers/fund_public_goods/lib/strategy/create.py +++ b/workers/fund_public_goods/lib/strategy/create.py @@ -132,8 +132,8 @@ def create(run_id: str, authorization: Optional[str] = Header(None)): project_scores = [ProjectScores( project_id=relevancy_scores[i].project_id, prompt_match=relevancy_scores[i].prompt_match, - impact=impact_funding_scores[i].impact, - funding_needed=impact_funding_scores[i].funding_needed + 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) )] @@ -146,7 +146,7 @@ def create(run_id: str, authorization: Optional[str] = Header(None)): value=f"Computed smart rankings for {len(smart_ranked_projects)} projects", ) except Exception as error: - f"An error occurred: {type(error).__name__} - {str(error)} " + details = f"An error occurred: {type(error).__name__} - {str(error)} " tables.logs.update( status=StepStatus.ERRORED, log_id=log_ids[StepName.ANALYZE_FUNDING], diff --git a/workers/fund_public_goods/workflows/index_gitcoin/functions/index_gitcoin_page.py b/workers/fund_public_goods/workflows/index_gitcoin/functions/index_gitcoin_page.py index 6242fcb9..7a54b550 100644 --- a/workers/fund_public_goods/workflows/index_gitcoin/functions/index_gitcoin_page.py +++ b/workers/fund_public_goods/workflows/index_gitcoin/functions/index_gitcoin_page.py @@ -85,7 +85,7 @@ async def index_gitcoin_page( project_data = await step.run("fetch_json_from_ipfs_" + str(i), lambda: fetch_json_from_ipfs(project_pointer)) project = GitcoinProjects( id = app_data["application"]["project"]["id"], - protocol = app_data["application"]["project"]["metaPtr"]["protocol"], + protocol = app_data["application"]["project"]["metaPtr"].get("protocol", 1), pointer = project_pointer, data = json.dumps(project_data), )