From 7bd79b81dca288d8977e8c302cb8fd0d0160c92a Mon Sep 17 00:00:00 2001 From: Dawood Mehmood Date: Fri, 7 Feb 2025 19:29:05 +0500 Subject: [PATCH 1/5] frontend changes --- insights-ui/src/util/regenerate.ts | 3 +++ insights-ui/src/util/submit-project.ts | 2 ++ 2 files changed, 5 insertions(+) diff --git a/insights-ui/src/util/regenerate.ts b/insights-ui/src/util/regenerate.ts index 21a9936d2..844174a36 100644 --- a/insights-ui/src/util/regenerate.ts +++ b/insights-ui/src/util/regenerate.ts @@ -1,3 +1,5 @@ +import { getAuthKey } from './auth/authKey'; + export async function regenerateReport(projectId: string, model: string, reportType?: string): Promise<{ success: boolean; message: string }> { const baseURL = process.env.NEXT_PUBLIC_AGENT_APP_URL?.toString() || ''; const url: string = reportType ? `reports/${reportType}/regenerate` : `reports/regenerate`; @@ -8,6 +10,7 @@ export async function regenerateReport(projectId: string, model: string, reportT method: 'POST', headers: { 'Content-Type': 'application/json', + 'x-admin-key': getAuthKey(), }, body: JSON.stringify({ model }), }); diff --git a/insights-ui/src/util/submit-project.ts b/insights-ui/src/util/submit-project.ts index 85e0334e6..a25e62ee7 100644 --- a/insights-ui/src/util/submit-project.ts +++ b/insights-ui/src/util/submit-project.ts @@ -1,4 +1,5 @@ import { ProjectSubmissionData } from '@/types/project/project'; +import { getAuthKey } from './auth/authKey'; export async function submitProject(projectDetails: ProjectSubmissionData): Promise<{ success: boolean; message: string }> { const baseURL = process.env.NEXT_PUBLIC_AGENT_APP_URL?.toString() || ''; @@ -8,6 +9,7 @@ export async function submitProject(projectDetails: ProjectSubmissionData): Prom method: 'POST', headers: { 'Content-Type': 'application/json', + 'x-admin-key': getAuthKey(), }, body: JSON.stringify({ projectId: projectDetails.projectId, From a695f9d06fe2cf035b5f62893b6c86165eda71e7 Mon Sep 17 00:00:00 2001 From: Dawood Mehmood Date: Fri, 7 Feb 2025 19:29:14 +0500 Subject: [PATCH 2/5] python backend changes --- .../cf_analysis_agent/agent_state.py | 1 + .../cf_analysis_agent/app.py | 32 +++++++++++++++---- .../cf_analysis_agent/controller.py | 16 ++++++++-- .../reports/execution_and_speed.py | 3 +- .../cf_analysis_agent/reports/final_report.py | 3 +- .../reports/financial_health.py | 3 +- .../reports/financial_review_agent.py | 3 +- .../reports/founder_and_team.py | 3 +- .../cf_analysis_agent/reports/general_info.py | 3 +- .../reports/market_opportunity.py | 3 +- .../reports/relevant_links.py | 3 +- .../cf_analysis_agent/reports/traction.py | 3 +- .../cf_analysis_agent/reports/valuation.py | 3 +- .../cf_analysis_agent/utils/agent_utils.py | 26 ++++++++++++++- .../cf_analysis_agent/utils/report_utils.py | 26 +++++++++------ 15 files changed, 102 insertions(+), 29 deletions(-) diff --git a/ai-agents/crowd-fund-analysis/cf_analysis_agent/agent_state.py b/ai-agents/crowd-fund-analysis/cf_analysis_agent/agent_state.py index f7e207450..2a269fa72 100644 --- a/ai-agents/crowd-fund-analysis/cf_analysis_agent/agent_state.py +++ b/ai-agents/crowd-fund-analysis/cf_analysis_agent/agent_state.py @@ -99,6 +99,7 @@ class AgentState(TypedDict): processed_project_info: ProcessedProjectInfo | None config: Config final_report: FinalReport | None + triggered_by: str def get_combined_content(state: AgentState) -> str: diff --git a/ai-agents/crowd-fund-analysis/cf_analysis_agent/app.py b/ai-agents/crowd-fund-analysis/cf_analysis_agent/app.py index a564b32b5..f00c71c32 100644 --- a/ai-agents/crowd-fund-analysis/cf_analysis_agent/app.py +++ b/ai-agents/crowd-fund-analysis/cf_analysis_agent/app.py @@ -6,7 +6,7 @@ from flask import Flask, render_template, request, redirect, url_for, jsonify from flask_cors import CORS from cf_analysis_agent.utils.env_variables import BUCKET_NAME, OPEN_AI_DEFAULT_MODEL, REGION, ADMIN_CODES -from cf_analysis_agent.utils.agent_utils import generate_hashed_key +from cf_analysis_agent.utils.agent_utils import generate_hashed_key, get_admin_name_from_request # # Add the parent directory of app.py to the Python path this maybe temporary we can change it later for that we will have to change docker file as well sys.path.append(os.path.dirname(os.path.abspath(__file__))) @@ -75,6 +75,11 @@ def api_submit(): """ Handles JSON-based form submission, starts processing, and returns a JSON response. """ + # Get admin name from request + admin_name, error_response = get_admin_name_from_request() + if error_response: + return error_response # If there's an error, return it + if not request.is_json: return jsonify({"error": "Invalid request. JSON expected."}), 400 @@ -103,7 +108,7 @@ def api_submit(): } # Initialize project (store in S3 or DB) - initialize_project_in_s3(project_id=project_id, project_details=project_details) + initialize_project_in_s3(project_id=project_id, project_details=project_details, triggered_by=admin_name) # Prepare command to run Python script asynchronously command = [ @@ -120,6 +125,9 @@ def api_submit(): # Append the selected model as an argument command.extend(["--model", OPEN_AI_DEFAULT_MODEL]) + + # Append the admin name as an argument + command.extend(["--admin", admin_name]) # Run the command asynchronously subprocess.Popen(command) @@ -159,11 +167,16 @@ def regenerate_reports(projectId): Regenerates reports for a given project using values from agent-status.json in S3. """ try: + # Get admin name from request + admin_name, error_response = get_admin_name_from_request() + if error_response: + return error_response # If there's an error, return it + data = request.get_json(silent=True) or {} # Handle case if no body was sent model = data.get("model", OPEN_AI_DEFAULT_MODEL) - update_status_to_not_started_for_all_reports(project_id=projectId) - command = prepare_processing_command(projectId, model) + update_status_to_not_started_for_all_reports(project_id=projectId, triggered_by=admin_name) + command = prepare_processing_command(projectId, model, admin_name) # Start the subprocess subprocess.Popen(command) @@ -190,12 +203,17 @@ def regenerate_specific_report(projectId, report_type): Regenerates a specific report for a given project. """ try: + # Get admin name from request + admin_name, error_response = get_admin_name_from_request() + if error_response: + return error_response # If there's an error, return it + data = request.get_json(silent=True) or {} # Handle case if no body was sent model = data.get("model", OPEN_AI_DEFAULT_MODEL) - + # Prepare the command to start processing - update_report_status_in_progress(project_id=projectId, report_type=report_type) - command = prepare_processing_command(projectId, model) + update_report_status_in_progress(project_id=projectId, report_type=report_type, triggered_by=admin_name) + command = prepare_processing_command(projectId, model, admin_name) # Add the report_type to the command command.extend(["--report_type", report_type]) diff --git a/ai-agents/crowd-fund-analysis/cf_analysis_agent/controller.py b/ai-agents/crowd-fund-analysis/cf_analysis_agent/controller.py index 27557cbba..dbca66200 100644 --- a/ai-agents/crowd-fund-analysis/cf_analysis_agent/controller.py +++ b/ai-agents/crowd-fund-analysis/cf_analysis_agent/controller.py @@ -8,7 +8,7 @@ from cf_analysis_agent.utils.process_project_utils import ensure_processed_project_info -def prepare_processing_command(project_id, model, script_path="cf_analysis_agent/controller.py"): +def prepare_processing_command(project_id, model, admin): """ Prepares the command to start processing based on variables extracted from S3. @@ -20,6 +20,8 @@ def prepare_processing_command(project_id, model, script_path="cf_analysis_agent Returns: list: The prepared command as a list of arguments. """ + script_path="cf_analysis_agent/controller.py" + # Extract variables from S3 variables: ProjectInfo = get_project_info_from_s3(project_id) @@ -39,6 +41,9 @@ def prepare_processing_command(project_id, model, script_path="cf_analysis_agent # Append the selected model as an argument command.extend(["--model", model]) + + # Append the admin name as an argument + command.extend(["--admin", admin]) return command @@ -68,6 +73,11 @@ def parse_arguments() -> AgentState: help="Optional: Specify the model to use for regeneration (e.g., 'gpt-4o' or 'gpt-4o-mini').", default=None # Default to None if not provided ) + parser.add_argument( + "--admin", + help="Optional: Specify the admin name to use for regeneration.", + default=None # Default to None if not provided + ) args = parser.parse_args() @@ -80,6 +90,7 @@ def parse_arguments() -> AgentState: additional_links = [link.strip() for link in args.additional_links.split(",") if link.strip()] report_type = args.report_type.strip().strip('"') if args.report_type else "all" model = args.model.strip().strip('"') if args.model else "gpt-4o-mini" + admin = args.admin.strip().strip('"') if args.model else "" project_info: ProjectInfo = { "project_id": project_id, @@ -103,7 +114,8 @@ def parse_arguments() -> AgentState: }, "reports_to_generate": None, "processed_project_info": processed_project_info, - "final_report": None + "final_report": None, + "triggered_by" : admin } return state diff --git a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/execution_and_speed.py b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/execution_and_speed.py index 64ae90b12..0a4e91806 100644 --- a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/execution_and_speed.py +++ b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/execution_and_speed.py @@ -88,8 +88,9 @@ def generate_execution_and_speed_report(state: AgentState) -> StructuredReportRe def create_execution_and_speed_report(state: AgentState) -> None: print("Generating execution and speed report") project_id = state.get("project_info").get("project_id") + triggered_by = state.get("triggered_by") try: - update_report_status_in_progress(project_id, ReportType.EXECUTION_AND_SPEED) + update_report_status_in_progress(project_id, ReportType.EXECUTION_AND_SPEED, triggered_by) report_output = generate_execution_and_speed_report(state) update_report_with_structured_output(project_id, ReportType.EXECUTION_AND_SPEED, report_output) except Exception as e: diff --git a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/final_report.py b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/final_report.py index 01cd138fd..6e352598d 100644 --- a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/final_report.py +++ b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/final_report.py @@ -173,8 +173,9 @@ def generate_project_info_report(state: AgentState, combined_reports: str): def create_final_report_test(state: AgentState) -> None: print("Generating final report") project_id = state.get("project_info").get("project_id") + triggered_by = state.get("triggered_by") try: - update_report_status_in_progress(project_id, REPORT_NAME) + update_report_status_in_progress(project_id, REPORT_NAME, triggered_by) combined_reports = get_combined_reports_from_s3(project_id) report_content = generate_project_info_report(state, combined_reports) upload_to_s3( diff --git a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/financial_health.py b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/financial_health.py index 45b2d5cdd..955576365 100644 --- a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/financial_health.py +++ b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/financial_health.py @@ -86,8 +86,9 @@ def generate_financial_health_report(state: AgentState) -> StructuredReportRespo def create_financial_health_report(state: AgentState) -> None: print("Generating financial health report") project_id = state.get("project_info").get("project_id") + triggered_by = state.get("triggered_by") try: - update_report_status_in_progress(project_id, ReportType.FINANCIAL_HEALTH) + update_report_status_in_progress(project_id, ReportType.FINANCIAL_HEALTH, triggered_by) report_output = generate_financial_health_report(state) update_report_with_structured_output(project_id, ReportType.FINANCIAL_HEALTH, report_output) except Exception as e: diff --git a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/financial_review_agent.py b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/financial_review_agent.py index df8f63f82..4fca1fd6f 100644 --- a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/financial_review_agent.py +++ b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/financial_review_agent.py @@ -261,9 +261,10 @@ def create_financial_review_report(state: AgentState) -> None: Orchestrates the entire green flags analysis process. """ project_id = state.get("project_info").get("project_id") + triggered_by = state.get("triggered_by") print("Generating financial review report") try: - update_report_status_in_progress(project_id, REPORT_NAME) + update_report_status_in_progress(project_id, REPORT_NAME, triggered_by) combined_text = state.get("processed_project_info").get("combined_scrapped_content") sec_content = state.get("processed_project_info").get("sec_scraped_content") form_c_data = extract_data_from_sec_node(sec_content,state.get("config")) diff --git a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/founder_and_team.py b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/founder_and_team.py index 189660a2c..cf4bbdfde 100644 --- a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/founder_and_team.py +++ b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/founder_and_team.py @@ -264,10 +264,11 @@ def create_founder_and_team_report(state: AgentState) -> None: Orchestrates the entire team info analysis process. """ project_id = state.get("project_info").get("project_id") + triggered_by = state.get("triggered_by") print("Generating team info") try: combined_text = state.get("processed_project_info").get("combined_scrapped_content") - update_report_status_in_progress(project_id, ReportType.FOUNDER_AND_TEAM) + update_report_status_in_progress(project_id, ReportType.FOUNDER_AND_TEAM, triggered_by) startup_info: StartupAndTeamInfoStructure = find_startup_info(state.get("config"), combined_text) linkedin_urls = find_linkedin_urls(startup_info) raw_profiles = scrape_linkedin_profiles(linkedin_urls) diff --git a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/general_info.py b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/general_info.py index 1568de745..c753cca91 100644 --- a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/general_info.py +++ b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/general_info.py @@ -46,8 +46,9 @@ def generate_project_info_report(state: AgentState): def create_general_info_report(state: AgentState) -> None: print("Generating general info report") project_id = state.get("project_info").get("project_id") + triggered_by = state.get("triggered_by") try: - update_report_status_in_progress(project_id, REPORT_NAME) + update_report_status_in_progress(project_id, REPORT_NAME, triggered_by) report_content = generate_project_info_report(state) create_report_file_and_upload_to_s3(project_id, REPORT_NAME, report_content) except Exception as e: diff --git a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/market_opportunity.py b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/market_opportunity.py index e8023ed4c..288b5eb5c 100644 --- a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/market_opportunity.py +++ b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/market_opportunity.py @@ -70,8 +70,9 @@ def generate_market_opportunity_report(state: AgentState) -> StructuredReportRes def create_market_opportunity_report(state: AgentState) -> None: print("Generating market opportunity report") project_id = state.get("project_info").get("project_id") + triggered_by = state.get("triggered_by") try: - update_report_status_in_progress(project_id, ReportType.MARKET_OPPORTUNITY) + update_report_status_in_progress(project_id, ReportType.MARKET_OPPORTUNITY, triggered_by) report_output = generate_market_opportunity_report(state) update_report_with_structured_output(project_id, ReportType.MARKET_OPPORTUNITY, report_output) except Exception as e: diff --git a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/relevant_links.py b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/relevant_links.py index 4bbb62fb2..d7c481e08 100644 --- a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/relevant_links.py +++ b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/relevant_links.py @@ -158,10 +158,11 @@ def create_relevant_links_report(state: AgentState) -> None: Orchestrates the entire relevant links search process. """ project_id = state.get("project_info").get("project_id") + triggered_by = state.get("triggered_by") print("Generating relevant links") try: combined_text = state.get("processed_project_info").get("combined_scrapped_content") - update_report_status_in_progress(project_id, REPORT_NAME) + update_report_status_in_progress(project_id, REPORT_NAME, triggered_by) startup_info = find_startup_info(state.get("config"), combined_text) all_google_results = search_startup_on_google(startup_info) summaries = summarize_google_search_results(state.get("config"), all_google_results) diff --git a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/traction.py b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/traction.py index 634412159..073b50ce4 100644 --- a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/traction.py +++ b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/traction.py @@ -51,8 +51,9 @@ def generate_traction_report(state: AgentState) -> StructuredReportResponse: def create_traction_report(state: AgentState) -> None: print("Generating traction report") project_id = state.get("project_info").get("project_id") + triggered_by = state.get("triggered_by") try: - update_report_status_in_progress(project_id, ReportType.TRACTION) + update_report_status_in_progress(project_id, ReportType.TRACTION, triggered_by) report_output = generate_traction_report(state) update_report_with_structured_output(project_id, ReportType.TRACTION, report_output) except Exception as e: diff --git a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/valuation.py b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/valuation.py index d822d4a0f..93f922e45 100644 --- a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/valuation.py +++ b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/valuation.py @@ -82,8 +82,9 @@ def generate_valuation_report(state: AgentState) -> StructuredReportResponse: def create_valuation_report(state: AgentState) -> None: print("Generating valuation report") project_id = state.get("project_info").get("project_id") + triggered_by = state.get("triggered_by") try: - update_report_status_in_progress(project_id, ReportType.VALUATION) + update_report_status_in_progress(project_id, ReportType.VALUATION, triggered_by) report_output = generate_valuation_report(state) update_report_with_structured_output(project_id, ReportType.VALUATION, report_output) except Exception as e: diff --git a/ai-agents/crowd-fund-analysis/cf_analysis_agent/utils/agent_utils.py b/ai-agents/crowd-fund-analysis/cf_analysis_agent/utils/agent_utils.py index b606c8b85..058f13f5b 100644 --- a/ai-agents/crowd-fund-analysis/cf_analysis_agent/utils/agent_utils.py +++ b/ai-agents/crowd-fund-analysis/cf_analysis_agent/utils/agent_utils.py @@ -1,5 +1,7 @@ import hashlib from cf_analysis_agent.utils.env_variables import SECRET_KEY +from flask import request, jsonify +from cf_analysis_agent.utils.env_variables import ADMIN_CODES def combine_partial_state(state: dict, partial: dict) -> dict: """ @@ -13,4 +15,26 @@ def combine_partial_state(state: dict, partial: dict) -> dict: def generate_hashed_key(code): """Generate a hashed key using SHA256""" hash_obj = hashlib.sha256(f"{code}{SECRET_KEY}".encode()) - return hash_obj.hexdigest() \ No newline at end of file + return hash_obj.hexdigest() + +def extract_admin_name(code): + """Extract admin name from admin code (everything before '-')""" + return code.split("-")[0] # Get the part before '-' + +def get_admin_name_from_request(): + """Extract admin name from request headers""" + hashed_key = request.headers.get("x-admin-key") + + if not hashed_key: + return None, (jsonify({"status": "error", "message": "Unauthorized"}), 401) + + # Find the matching admin code by checking if its hash matches + admin_code = next((code for code in ADMIN_CODES if generate_hashed_key(code) == hashed_key), None) + + if not admin_code: + return None, (jsonify({"status": "error", "message": "Invalid code"}), 401) + + # Extract the admin name (everything before '-') + admin_name = extract_admin_name(admin_code) + + return admin_name, None # Return admin_name if found, otherwise None diff --git a/ai-agents/crowd-fund-analysis/cf_analysis_agent/utils/report_utils.py b/ai-agents/crowd-fund-analysis/cf_analysis_agent/utils/report_utils.py index 80d5d718d..ead335726 100644 --- a/ai-agents/crowd-fund-analysis/cf_analysis_agent/utils/report_utils.py +++ b/ai-agents/crowd-fund-analysis/cf_analysis_agent/utils/report_utils.py @@ -49,6 +49,7 @@ class ReportSchema(TypedDict, total=False): under certain conditions. """ status: ProcessingStatus + lastTriggeredBy: NotRequired[Optional[str]] markdownLink: Optional[str] startTime: str estimatedTimeInSec: int @@ -178,21 +179,26 @@ def get_project_info_from_s3(project_id: str) -> ProjectInfo: } -def get_init_data_for_report(report_type: ReportType) -> ReportSchema: +def get_init_data_for_report(report_type: ReportType, triggered_by = '') -> ReportSchema: """ Returns an initialized ReportSchema dictionary for the given report_type. """ - return { + report_data = { "status": ProcessingStatus.NOT_STARTED, "markdownLink": None, "startTime": datetime.now().isoformat(), "estimatedTimeInSec": 240 if report_type in [ReportType.FOUNDER_AND_TEAM, ReportType.FINANCIAL_HEALTH] else 150, "performanceChecklist": [] } + + if triggered_by: + report_data["lastTriggeredBy"] = triggered_by + + return report_data -def initialize_project_in_s3(project_id: str, project_details: ProjectInfo): +def initialize_project_in_s3(project_id: str, project_details: ProjectInfo, triggered_by = ''): """ Creates or re-initializes the agent-status.json file for a project, setting all reports to 'in_progress' along with basic metadata. @@ -203,7 +209,7 @@ def initialize_project_in_s3(project_id: str, project_details: ProjectInfo): # Initialize all reports reports_data = {} for r_type in ALL_REPORT_TYPES: - reports_data[r_type] = get_init_data_for_report(r_type) + reports_data[r_type] = get_init_data_for_report(r_type, triggered_by) # Construct the status data project_file_contents: ProjectStatusFileSchema = { "id": project_id, @@ -271,6 +277,8 @@ def update_project_file(project_id: str, project_file_contents: ProjectStatusFil "confidence": report.get("confidence"), "performanceChecklist": new_performance_checklist } + if report.get("lastTriggeredBy"): + new_report["lastTriggeredBy"] = report["lastTriggeredBy"] new_reports[report_type] = new_report sec_info = project_file_contents["processedProjectInfo"].get("secInfo") or {} @@ -335,14 +343,14 @@ def update_project_file(project_id: str, project_file_contents: ProjectStatusFil f"Updated status file: https://{BUCKET_NAME}.s3.us-east-1.amazonaws.com/crowd-fund-analysis/{agent_status_file_path}") -def update_report_status_in_progress(project_id: str, report_type: ReportType): +def update_report_status_in_progress(project_id: str, report_type: ReportType, triggered_by = ''): """ Updates the `agent-status.json` file in S3 to set a report's status to "in_progress". Handles both individual reports and `finalReport`. """ project_file_contents = get_project_file(project_id) - project_file_contents["reports"][report_type] = get_init_data_for_report(report_type) + project_file_contents["reports"][report_type] = get_init_data_for_report(report_type, triggered_by) project_file_contents["reports"][report_type]["status"] = ProcessingStatus.IN_PROGRESS update_project_file(project_id, project_file_contents) @@ -427,14 +435,14 @@ def update_report_status_failed(project_id: str, report_type: ReportType, error_ print(f"Updated status of report '{report_type}' to 'failed' with error message: {error_message}") -def update_status_to_not_started_for_all_reports(project_id): +def update_status_to_not_started_for_all_reports(project_id, triggered_by): agent_status_file_path = f"{project_id}/agent-status.json" project_file_contents = get_project_file(project_id) # Initialize all reports to "in_progress" and set timestamps for report_type in ALL_REPORT_TYPES: - project_file_contents["reports"][report_type] = get_init_data_for_report(report_type) + project_file_contents["reports"][report_type] = get_init_data_for_report(report_type, triggered_by) print(f"Set status of report '{report_type}' to 'not_started'. Initialized startTime and estimatedTimeInSec.") print(f"Set status of report 'finalReport' to 'not_started'. Initialized startTime and estimatedTimeInSec.") @@ -444,7 +452,7 @@ def update_status_to_not_started_for_all_reports(project_id): f"Updated status file: https://{BUCKET_NAME}.s3.us-east-1.amazonaws.com/crowd-fund-analysis/{agent_status_file_path}") -def create_report_file_and_upload_to_s3(project_id: str, report_type: ReportType, report_content: str, summary: str = ""): +def create_report_file_and_upload_to_s3(project_id: str, report_type: ReportType, report_content: str): report_file_path = f"{project_id}/{report_type}.md" upload_to_s3(report_content, report_file_path) # Update status file to "completed" From e7778d604f766c35cca28b0e73973b1c9935e66b Mon Sep 17 00:00:00 2001 From: Dawood Mehmood Date: Fri, 7 Feb 2025 20:42:36 +0500 Subject: [PATCH 3/5] handle trigger by at one place --- .../cf_analysis_agent/agent_state.py | 2 -- .../crowd-fund-analysis/cf_analysis_agent/app.py | 9 +++------ .../cf_analysis_agent/controller.py | 12 +----------- .../reports/execution_and_speed.py | 3 +-- .../cf_analysis_agent/reports/final_report.py | 3 +-- .../cf_analysis_agent/reports/financial_health.py | 3 +-- .../reports/financial_review_agent.py | 3 +-- .../cf_analysis_agent/reports/founder_and_team.py | 3 +-- .../cf_analysis_agent/reports/general_info.py | 3 +-- .../reports/market_opportunity.py | 3 +-- .../cf_analysis_agent/reports/relevant_links.py | 3 +-- .../cf_analysis_agent/reports/traction.py | 3 +-- .../cf_analysis_agent/reports/valuation.py | 3 +-- .../cf_analysis_agent/utils/report_utils.py | 15 +++++++++++++-- 14 files changed, 27 insertions(+), 41 deletions(-) diff --git a/ai-agents/crowd-fund-analysis/cf_analysis_agent/agent_state.py b/ai-agents/crowd-fund-analysis/cf_analysis_agent/agent_state.py index 2a269fa72..ac552c40f 100644 --- a/ai-agents/crowd-fund-analysis/cf_analysis_agent/agent_state.py +++ b/ai-agents/crowd-fund-analysis/cf_analysis_agent/agent_state.py @@ -99,8 +99,6 @@ class AgentState(TypedDict): processed_project_info: ProcessedProjectInfo | None config: Config final_report: FinalReport | None - triggered_by: str - def get_combined_content(state: AgentState) -> str: """ diff --git a/ai-agents/crowd-fund-analysis/cf_analysis_agent/app.py b/ai-agents/crowd-fund-analysis/cf_analysis_agent/app.py index f00c71c32..8df0e2b33 100644 --- a/ai-agents/crowd-fund-analysis/cf_analysis_agent/app.py +++ b/ai-agents/crowd-fund-analysis/cf_analysis_agent/app.py @@ -125,9 +125,6 @@ def api_submit(): # Append the selected model as an argument command.extend(["--model", OPEN_AI_DEFAULT_MODEL]) - - # Append the admin name as an argument - command.extend(["--admin", admin_name]) # Run the command asynchronously subprocess.Popen(command) @@ -176,7 +173,7 @@ def regenerate_reports(projectId): model = data.get("model", OPEN_AI_DEFAULT_MODEL) update_status_to_not_started_for_all_reports(project_id=projectId, triggered_by=admin_name) - command = prepare_processing_command(projectId, model, admin_name) + command = prepare_processing_command(projectId, model) # Start the subprocess subprocess.Popen(command) @@ -210,10 +207,10 @@ def regenerate_specific_report(projectId, report_type): data = request.get_json(silent=True) or {} # Handle case if no body was sent model = data.get("model", OPEN_AI_DEFAULT_MODEL) - + # Prepare the command to start processing update_report_status_in_progress(project_id=projectId, report_type=report_type, triggered_by=admin_name) - command = prepare_processing_command(projectId, model, admin_name) + command = prepare_processing_command(projectId, model) # Add the report_type to the command command.extend(["--report_type", report_type]) diff --git a/ai-agents/crowd-fund-analysis/cf_analysis_agent/controller.py b/ai-agents/crowd-fund-analysis/cf_analysis_agent/controller.py index dbca66200..8026132a0 100644 --- a/ai-agents/crowd-fund-analysis/cf_analysis_agent/controller.py +++ b/ai-agents/crowd-fund-analysis/cf_analysis_agent/controller.py @@ -8,7 +8,7 @@ from cf_analysis_agent.utils.process_project_utils import ensure_processed_project_info -def prepare_processing_command(project_id, model, admin): +def prepare_processing_command(project_id, model): """ Prepares the command to start processing based on variables extracted from S3. @@ -41,9 +41,6 @@ def prepare_processing_command(project_id, model, admin): # Append the selected model as an argument command.extend(["--model", model]) - - # Append the admin name as an argument - command.extend(["--admin", admin]) return command @@ -73,11 +70,6 @@ def parse_arguments() -> AgentState: help="Optional: Specify the model to use for regeneration (e.g., 'gpt-4o' or 'gpt-4o-mini').", default=None # Default to None if not provided ) - parser.add_argument( - "--admin", - help="Optional: Specify the admin name to use for regeneration.", - default=None # Default to None if not provided - ) args = parser.parse_args() @@ -90,7 +82,6 @@ def parse_arguments() -> AgentState: additional_links = [link.strip() for link in args.additional_links.split(",") if link.strip()] report_type = args.report_type.strip().strip('"') if args.report_type else "all" model = args.model.strip().strip('"') if args.model else "gpt-4o-mini" - admin = args.admin.strip().strip('"') if args.model else "" project_info: ProjectInfo = { "project_id": project_id, @@ -115,7 +106,6 @@ def parse_arguments() -> AgentState: "reports_to_generate": None, "processed_project_info": processed_project_info, "final_report": None, - "triggered_by" : admin } return state diff --git a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/execution_and_speed.py b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/execution_and_speed.py index 0a4e91806..64ae90b12 100644 --- a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/execution_and_speed.py +++ b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/execution_and_speed.py @@ -88,9 +88,8 @@ def generate_execution_and_speed_report(state: AgentState) -> StructuredReportRe def create_execution_and_speed_report(state: AgentState) -> None: print("Generating execution and speed report") project_id = state.get("project_info").get("project_id") - triggered_by = state.get("triggered_by") try: - update_report_status_in_progress(project_id, ReportType.EXECUTION_AND_SPEED, triggered_by) + update_report_status_in_progress(project_id, ReportType.EXECUTION_AND_SPEED) report_output = generate_execution_and_speed_report(state) update_report_with_structured_output(project_id, ReportType.EXECUTION_AND_SPEED, report_output) except Exception as e: diff --git a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/final_report.py b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/final_report.py index 6e352598d..01cd138fd 100644 --- a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/final_report.py +++ b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/final_report.py @@ -173,9 +173,8 @@ def generate_project_info_report(state: AgentState, combined_reports: str): def create_final_report_test(state: AgentState) -> None: print("Generating final report") project_id = state.get("project_info").get("project_id") - triggered_by = state.get("triggered_by") try: - update_report_status_in_progress(project_id, REPORT_NAME, triggered_by) + update_report_status_in_progress(project_id, REPORT_NAME) combined_reports = get_combined_reports_from_s3(project_id) report_content = generate_project_info_report(state, combined_reports) upload_to_s3( diff --git a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/financial_health.py b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/financial_health.py index 955576365..45b2d5cdd 100644 --- a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/financial_health.py +++ b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/financial_health.py @@ -86,9 +86,8 @@ def generate_financial_health_report(state: AgentState) -> StructuredReportRespo def create_financial_health_report(state: AgentState) -> None: print("Generating financial health report") project_id = state.get("project_info").get("project_id") - triggered_by = state.get("triggered_by") try: - update_report_status_in_progress(project_id, ReportType.FINANCIAL_HEALTH, triggered_by) + update_report_status_in_progress(project_id, ReportType.FINANCIAL_HEALTH) report_output = generate_financial_health_report(state) update_report_with_structured_output(project_id, ReportType.FINANCIAL_HEALTH, report_output) except Exception as e: diff --git a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/financial_review_agent.py b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/financial_review_agent.py index 4fca1fd6f..df8f63f82 100644 --- a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/financial_review_agent.py +++ b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/financial_review_agent.py @@ -261,10 +261,9 @@ def create_financial_review_report(state: AgentState) -> None: Orchestrates the entire green flags analysis process. """ project_id = state.get("project_info").get("project_id") - triggered_by = state.get("triggered_by") print("Generating financial review report") try: - update_report_status_in_progress(project_id, REPORT_NAME, triggered_by) + update_report_status_in_progress(project_id, REPORT_NAME) combined_text = state.get("processed_project_info").get("combined_scrapped_content") sec_content = state.get("processed_project_info").get("sec_scraped_content") form_c_data = extract_data_from_sec_node(sec_content,state.get("config")) diff --git a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/founder_and_team.py b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/founder_and_team.py index cf4bbdfde..189660a2c 100644 --- a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/founder_and_team.py +++ b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/founder_and_team.py @@ -264,11 +264,10 @@ def create_founder_and_team_report(state: AgentState) -> None: Orchestrates the entire team info analysis process. """ project_id = state.get("project_info").get("project_id") - triggered_by = state.get("triggered_by") print("Generating team info") try: combined_text = state.get("processed_project_info").get("combined_scrapped_content") - update_report_status_in_progress(project_id, ReportType.FOUNDER_AND_TEAM, triggered_by) + update_report_status_in_progress(project_id, ReportType.FOUNDER_AND_TEAM) startup_info: StartupAndTeamInfoStructure = find_startup_info(state.get("config"), combined_text) linkedin_urls = find_linkedin_urls(startup_info) raw_profiles = scrape_linkedin_profiles(linkedin_urls) diff --git a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/general_info.py b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/general_info.py index c753cca91..1568de745 100644 --- a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/general_info.py +++ b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/general_info.py @@ -46,9 +46,8 @@ def generate_project_info_report(state: AgentState): def create_general_info_report(state: AgentState) -> None: print("Generating general info report") project_id = state.get("project_info").get("project_id") - triggered_by = state.get("triggered_by") try: - update_report_status_in_progress(project_id, REPORT_NAME, triggered_by) + update_report_status_in_progress(project_id, REPORT_NAME) report_content = generate_project_info_report(state) create_report_file_and_upload_to_s3(project_id, REPORT_NAME, report_content) except Exception as e: diff --git a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/market_opportunity.py b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/market_opportunity.py index 288b5eb5c..e8023ed4c 100644 --- a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/market_opportunity.py +++ b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/market_opportunity.py @@ -70,9 +70,8 @@ def generate_market_opportunity_report(state: AgentState) -> StructuredReportRes def create_market_opportunity_report(state: AgentState) -> None: print("Generating market opportunity report") project_id = state.get("project_info").get("project_id") - triggered_by = state.get("triggered_by") try: - update_report_status_in_progress(project_id, ReportType.MARKET_OPPORTUNITY, triggered_by) + update_report_status_in_progress(project_id, ReportType.MARKET_OPPORTUNITY) report_output = generate_market_opportunity_report(state) update_report_with_structured_output(project_id, ReportType.MARKET_OPPORTUNITY, report_output) except Exception as e: diff --git a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/relevant_links.py b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/relevant_links.py index d7c481e08..4bbb62fb2 100644 --- a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/relevant_links.py +++ b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/relevant_links.py @@ -158,11 +158,10 @@ def create_relevant_links_report(state: AgentState) -> None: Orchestrates the entire relevant links search process. """ project_id = state.get("project_info").get("project_id") - triggered_by = state.get("triggered_by") print("Generating relevant links") try: combined_text = state.get("processed_project_info").get("combined_scrapped_content") - update_report_status_in_progress(project_id, REPORT_NAME, triggered_by) + update_report_status_in_progress(project_id, REPORT_NAME) startup_info = find_startup_info(state.get("config"), combined_text) all_google_results = search_startup_on_google(startup_info) summaries = summarize_google_search_results(state.get("config"), all_google_results) diff --git a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/traction.py b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/traction.py index 073b50ce4..634412159 100644 --- a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/traction.py +++ b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/traction.py @@ -51,9 +51,8 @@ def generate_traction_report(state: AgentState) -> StructuredReportResponse: def create_traction_report(state: AgentState) -> None: print("Generating traction report") project_id = state.get("project_info").get("project_id") - triggered_by = state.get("triggered_by") try: - update_report_status_in_progress(project_id, ReportType.TRACTION, triggered_by) + update_report_status_in_progress(project_id, ReportType.TRACTION) report_output = generate_traction_report(state) update_report_with_structured_output(project_id, ReportType.TRACTION, report_output) except Exception as e: diff --git a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/valuation.py b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/valuation.py index 93f922e45..d822d4a0f 100644 --- a/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/valuation.py +++ b/ai-agents/crowd-fund-analysis/cf_analysis_agent/reports/valuation.py @@ -82,9 +82,8 @@ def generate_valuation_report(state: AgentState) -> StructuredReportResponse: def create_valuation_report(state: AgentState) -> None: print("Generating valuation report") project_id = state.get("project_info").get("project_id") - triggered_by = state.get("triggered_by") try: - update_report_status_in_progress(project_id, ReportType.VALUATION, triggered_by) + update_report_status_in_progress(project_id, ReportType.VALUATION) report_output = generate_valuation_report(state) update_report_with_structured_output(project_id, ReportType.VALUATION, report_output) except Exception as e: diff --git a/ai-agents/crowd-fund-analysis/cf_analysis_agent/utils/report_utils.py b/ai-agents/crowd-fund-analysis/cf_analysis_agent/utils/report_utils.py index ead335726..8ebe868af 100644 --- a/ai-agents/crowd-fund-analysis/cf_analysis_agent/utils/report_utils.py +++ b/ai-agents/crowd-fund-analysis/cf_analysis_agent/utils/report_utils.py @@ -349,10 +349,21 @@ def update_report_status_in_progress(project_id: str, report_type: ReportType, t Handles both individual reports and `finalReport`. """ project_file_contents = get_project_file(project_id) + existing_report_data = project_file_contents["reports"].get(report_type, {}) + + # Get default values (including "lastTriggeredBy" if provided) + updated_fields = get_init_data_for_report(report_type, triggered_by) + + # Only update fields that exist in `updated_fields` + for field, value in updated_fields.items(): + existing_report_data[field] = value - project_file_contents["reports"][report_type] = get_init_data_for_report(report_type, triggered_by) - project_file_contents["reports"][report_type]["status"] = ProcessingStatus.IN_PROGRESS + # Ensure status is always updated to IN_PROGRESS + existing_report_data["status"] = ProcessingStatus.IN_PROGRESS + # Save updated report data + project_file_contents["reports"][report_type] = existing_report_data + update_project_file(project_id, project_file_contents) print(f"Updated status of report '{report_type}' to 'in_progress'.") From f7ec4e2cff07abb980c3e049ccc97bf06ceec065 Mon Sep 17 00:00:00 2001 From: Dawood Mehmood Date: Fri, 7 Feb 2025 20:45:04 +0500 Subject: [PATCH 4/5] revert controller changes --- .../crowd-fund-analysis/cf_analysis_agent/controller.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ai-agents/crowd-fund-analysis/cf_analysis_agent/controller.py b/ai-agents/crowd-fund-analysis/cf_analysis_agent/controller.py index 8026132a0..27557cbba 100644 --- a/ai-agents/crowd-fund-analysis/cf_analysis_agent/controller.py +++ b/ai-agents/crowd-fund-analysis/cf_analysis_agent/controller.py @@ -8,7 +8,7 @@ from cf_analysis_agent.utils.process_project_utils import ensure_processed_project_info -def prepare_processing_command(project_id, model): +def prepare_processing_command(project_id, model, script_path="cf_analysis_agent/controller.py"): """ Prepares the command to start processing based on variables extracted from S3. @@ -20,8 +20,6 @@ def prepare_processing_command(project_id, model): Returns: list: The prepared command as a list of arguments. """ - script_path="cf_analysis_agent/controller.py" - # Extract variables from S3 variables: ProjectInfo = get_project_info_from_s3(project_id) @@ -105,7 +103,7 @@ def parse_arguments() -> AgentState: }, "reports_to_generate": None, "processed_project_info": processed_project_info, - "final_report": None, + "final_report": None } return state From 69a2a7e867ec1538c371df0a2f8ba99e632ffa3d Mon Sep 17 00:00:00 2001 From: Dawood Mehmood Date: Fri, 7 Feb 2025 20:46:24 +0500 Subject: [PATCH 5/5] revert agent state change --- ai-agents/crowd-fund-analysis/cf_analysis_agent/agent_state.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ai-agents/crowd-fund-analysis/cf_analysis_agent/agent_state.py b/ai-agents/crowd-fund-analysis/cf_analysis_agent/agent_state.py index ac552c40f..f7e207450 100644 --- a/ai-agents/crowd-fund-analysis/cf_analysis_agent/agent_state.py +++ b/ai-agents/crowd-fund-analysis/cf_analysis_agent/agent_state.py @@ -100,6 +100,7 @@ class AgentState(TypedDict): config: Config final_report: FinalReport | None + def get_combined_content(state: AgentState) -> str: """ Combines all the content from different reports into a single report.