import json from pathlib import Path from typing import List, Dict, Any from datetime import datetime # Path to the processed meetings data DATA_DIR = Path(__file__).parents[2] / "data" MEETINGS_FILE = DATA_DIR / "fed_processed_meetings.json" def _load_meetings_data() -> List[Dict[str, Any]]: """Load processed meetings data from JSON file""" try: if MEETINGS_FILE.exists(): with open(MEETINGS_FILE, 'r', encoding='utf-8') as f: data = json.load(f) return sorted(data, key=lambda x: x.get('date', ''), reverse=True) else: return [] except Exception as e: return [] def search_meetings(query: str, limit: int = 3) -> Dict[str, Any]: """ Search across all FOMC meeting data for relevant information. Args: query (str): Search term or phrase to look for in meetings limit (int): Maximum number of meetings to return (default: 3) Returns: Dict containing: - success (bool): Whether the search succeeded - query (str): The original search query - results (List[Dict]): List of matching meetings - count (int): Number of results returned - total_matches (int): Total number of meetings that matched """ meetings_data = _load_meetings_data() if not meetings_data: return { "success": False, "error": "No meetings data available", "results": [], "count": 0 } query_lower = query.lower() scored_meetings = [] for meeting in meetings_data: score = 0 matched_fields = [] search_fields = { 'date': 2, 'title': 1, 'action': 3, 'rate': 3, 'magnitude': 2, 'forward_guidance': 2, 'economic_outlook': 1, 'market_impact': 1, 'key_economic_factors': 1 } for field, weight in search_fields.items(): field_value = meeting.get(field, '') if isinstance(field_value, list): field_value = ' '.join(field_value) if field_value and query_lower in str(field_value).lower(): score += weight matched_fields.append(field) if score > 0: scored_meetings.append({ 'meeting': meeting, 'score': score, 'matched_fields': matched_fields }) scored_meetings.sort(key=lambda x: x['score'], reverse=True) top_results = scored_meetings[:limit] return { "success": True, "query": query, "results": [result['meeting'] for result in top_results], "match_details": [{'score': r['score'], 'matched_fields': r['matched_fields']} for r in top_results], "count": len(top_results), "total_matches": len(scored_meetings) } def get_rate_decision(date: str) -> Dict[str, Any]: """ Get details about a specific FOMC meeting's rate decision. Args: date (str): Meeting date in YYYY-MM-DD format (e.g., "2025-06-18") Returns: Dict containing: - success (bool): Whether the meeting was found - meeting (Dict): Complete meeting data if found - exact_match (bool): True if exact date match, False if closest match - requested_date (str): The date that was requested """ meetings_data = _load_meetings_data() if not meetings_data: return { "success": False, "error": "No meetings data available" } target_meeting = None for meeting in meetings_data: if meeting.get('date') == date: target_meeting = meeting break if not target_meeting and date: try: target_date = datetime.strptime(date, '%Y-%m-%d') closest_meeting = None min_diff = float('inf') for meeting in meetings_data: try: meeting_date = datetime.strptime(meeting.get('date', ''), '%Y-%m-%d') diff = abs((meeting_date - target_date).days) if diff < min_diff and diff <= 30: min_diff = diff closest_meeting = meeting except ValueError: continue target_meeting = closest_meeting except ValueError: pass if target_meeting: return { "success": True, "requested_date": date, "meeting": target_meeting, "exact_match": target_meeting.get('date') == date } else: return { "success": False, "error": f"No meeting found for date {date}", "requested_date": date } def compare_meetings(date1: str, date2: str) -> Dict[str, Any]: """ Compare two FOMC meetings side by side to analyze differences and similarities. Args: date1 (str): First meeting date in YYYY-MM-DD format date2 (str): Second meeting date in YYYY-MM-DD format Returns: Dict containing: - success (bool): Whether both meetings were found - meeting1/meeting2 (Dict): Data for each meeting - differences (Dict): Fields that differ between meetings - similarities (Dict): Fields that are the same - factor_analysis (Dict): Analysis of key economic factors """ meeting1_result = get_rate_decision(date1) meeting2_result = get_rate_decision(date2) if not meeting1_result["success"]: return { "success": False, "error": f"Could not find meeting for {date1}: {meeting1_result.get('error')}" } if not meeting2_result["success"]: return { "success": False, "error": f"Could not find meeting for {date2}: {meeting2_result.get('error')}" } meeting1 = meeting1_result["meeting"] meeting2 = meeting2_result["meeting"] # Compare key fields comparison = { "success": True, "meeting1": { "date": meeting1.get('date'), "title": meeting1.get('title'), "data": meeting1 }, "meeting2": { "date": meeting2.get('date'), "title": meeting2.get('title'), "data": meeting2 }, "differences": {}, "similarities": {} } # Compare specific fields compare_fields = ['action', 'rate', 'magnitude', 'forward_guidance', 'economic_outlook', 'market_impact'] for field in compare_fields: val1 = meeting1.get(field, '') val2 = meeting2.get(field, '') if val1 != val2: comparison["differences"][field] = { "meeting1_value": val1, "meeting2_value": val2 } else: comparison["similarities"][field] = val1 # Compare key economic factors factors1 = set(meeting1.get('key_economic_factors', [])) factors2 = set(meeting2.get('key_economic_factors', [])) comparison["factor_analysis"] = { "common_factors": list(factors1.intersection(factors2)), "unique_to_meeting1": list(factors1 - factors2), "unique_to_meeting2": list(factors2 - factors1) } return comparison def get_latest_meeting() -> Dict[str, Any]: """ Get the most recent FOMC meeting data. Returns: Dict containing: - success (bool): Whether data was retrieved successfully - meeting (Dict): The most recent meeting data - total_meetings (int): Total number of meetings in database """ meetings_data = _load_meetings_data() if not meetings_data: return { "success": False, "error": "No meetings data available" } # Data is already sorted by date (newest first) latest_meeting = meetings_data[0] return { "success": True, "meeting": latest_meeting, "total_meetings": len(meetings_data) }