Spaces:
Running
Running
| import gradio as gr | |
| import json | |
| from datetime import datetime | |
| from typing import List, Dict, Any | |
| import random | |
| import os | |
| from dotenv import load_dotenv | |
| from pathlib import Path | |
| load_dotenv() | |
| _FILE_PATH = Path(__file__).parents[1] | |
| # Load processed FOMC meetings data | |
| def load_processed_meetings(): | |
| """Load processed FOMC meetings from JSON file""" | |
| try: | |
| processed_file = _FILE_PATH / "data" / "fed_processed_meetings.json" | |
| with open(processed_file, 'r', encoding='utf-8') as f: | |
| data = json.load(f) | |
| # Transform to match expected format for the frontend | |
| meetings = [] | |
| for meeting in data: | |
| meetings.append({ | |
| "date": meeting.get("date", ""), | |
| "title": meeting.get("title", ""), | |
| "rate_decision": meeting.get("rate", ""), | |
| "summary": meeting.get("forward_guidance", ""), # Show full text | |
| "action": meeting.get("action", ""), | |
| "magnitude": meeting.get("magnitude", ""), | |
| "key_economic_factors": meeting.get("key_economic_factors", []), | |
| "economic_outlook": meeting.get("economic_outlook", ""), | |
| "market_impact": meeting.get("market_impact", ""), | |
| "full_text": meeting.get("full_text", "")[:500] + "..." if meeting.get("full_text") else "", | |
| "url": meeting.get("url", "") | |
| }) | |
| return meetings | |
| except FileNotFoundError: | |
| print("Fed processed meetings file not found. Using fallback data.") | |
| return [ | |
| { | |
| "date": "2025-06-18", | |
| "title": "FOMC Meeting 2025-06-18", | |
| "rate_decision": "4.25%-4.50%", | |
| "summary": "No processed data available. Please run the data pipeline first.", | |
| "action": "Unknown", | |
| "magnitude": "Unknown", | |
| "key_economic_factors": [], | |
| "economic_outlook": "Data not available", | |
| "market_impact": "Data not available", | |
| "full_text": "No data available", | |
| "url": "" | |
| } | |
| ] | |
| except Exception as e: | |
| print(f"Error loading processed meetings: {e}") | |
| return [] | |
| # Load the processed meetings | |
| FOMC_MEETINGS = load_processed_meetings() | |
| def simulate_llm_function_call(user_message: str, selected_model: str) -> Dict[str, Any]: | |
| """Simulate LLM function calls based on user intent""" | |
| message_lower = user_message.lower() | |
| # Determine which function to call | |
| if any(word in message_lower for word in ['rate', 'decision', 'interest']): | |
| return { | |
| "function": "get_rate_decision", | |
| "reasoning": [ | |
| "User is asking about interest rate decisions", | |
| "Analyzing FOMC meeting minutes for rate changes", | |
| "Extracting rate decisions from recent meetings" | |
| ], | |
| "result": "Based on the July 2024 FOMC meeting, the federal funds rate was maintained at 5.25-5.50%. This represents no change from the previous meeting in June 2024.", | |
| "confidence": 0.95, | |
| "sources": ["FOMC Minutes July 30-31, 2024"] | |
| } | |
| elif any(word in message_lower for word in ['compare', 'difference', 'between']): | |
| return { | |
| "function": "compare_meetings", | |
| "reasoning": [ | |
| "User wants to compare different FOMC meetings", | |
| "Identifying meetings from specified time periods", | |
| "Analyzing key differences in tone and decisions" | |
| ], | |
| "result": "Comparing July 2024 vs June 2024 meetings: Both maintained rates at 5.25-5.50%. Key difference: July meeting showed increased confidence in inflation trajectory, while June emphasized continued vigilance.", | |
| "confidence": 0.88, | |
| "sources": ["FOMC Minutes July 30-31, 2024", "FOMC Minutes June 11-12, 2024"] | |
| } | |
| elif any(word in message_lower for word in ['search', 'find', 'about', 'topic']): | |
| return { | |
| "function": "search_topic", | |
| "reasoning": [ | |
| "User is searching for specific topics in Fed minutes", | |
| "Performing contextual search across meeting transcripts", | |
| "Ranking results by relevance and date" | |
| ], | |
| "result": f"Found relevant discussions about '{user_message}' in recent FOMC meetings. The topic appeared most prominently in discussions about economic outlook and policy considerations.", | |
| "confidence": 0.82, | |
| "sources": ["FOMC Minutes July 30-31, 2024", "FOMC Minutes May 1, 2024"] | |
| } | |
| else: | |
| return { | |
| "function": "general_analysis", | |
| "reasoning": [ | |
| "Providing general analysis of Fed policy", | |
| "Drawing from recent FOMC meeting minutes", | |
| "Contextualizing current monetary policy stance" | |
| ], | |
| "result": f"Based on recent FOMC meetings, I can help analyze Fed policy. The current federal funds rate is 5.25-5.50%, maintained since July 2023. Recent meetings suggest officials are closely monitoring inflation data while remaining data-dependent on future decisions.", | |
| "confidence": 0.78, | |
| "sources": ["Recent FOMC Minutes"] | |
| } | |
| def format_response_with_reasoning(function_result: Dict[str, Any], model_name: str) -> str: | |
| """Format the response with expandable reasoning sections""" | |
| reasoning_steps = "\n".join([f"β’ {step}" for step in function_result["reasoning"]]) | |
| response = f""" | |
| **π Function Called:** `{function_result["function"]}` | |
| **π€ Model Used:** {model_name} | |
| **π Confidence:** {function_result["confidence"]:.0%} | |
| **π‘ Analysis Result:** | |
| {function_result["result"]} | |
| <details> | |
| <summary><b>π§ Reasoning Chain (Click to expand)</b></summary> | |
| {reasoning_steps} | |
| **π Sources:** | |
| {chr(10).join([f"β’ {source}" for source in function_result["sources"]])} | |
| </details> | |
| """ | |
| return response | |
| def respond_for_chat_interface( | |
| message: str, | |
| history: list[tuple[str, str]], | |
| api_key: str, | |
| ): | |
| """Enhanced response function for gr.ChatInterface with Fed AI Savant capabilities""" | |
| if not message.strip(): | |
| yield "Please enter a question about Federal Reserve policy or FOMC meetings." | |
| return | |
| if not api_key.strip(): | |
| yield "β Please enter your AI API key in the configuration panel to use the Fed AI Savant." | |
| return | |
| # Fixed model for Fed AI Savant | |
| model_name = "OAI OSS 120B" | |
| # Simulate function call and reasoning | |
| function_result = simulate_llm_function_call(message, model_name) | |
| # Format response with reasoning chain | |
| formatted_response = format_response_with_reasoning(function_result, model_name) | |
| # Simulate streaming response | |
| response = "" | |
| for char in formatted_response: | |
| response += char | |
| yield response | |
| # Small delay to simulate streaming | |
| import time | |
| time.sleep(0.01) | |
| def get_fomc_meetings_sidebar(): | |
| """Generate sidebar content with FOMC meeting details""" | |
| sidebar_content = "## π Recent FOMC Meetings\n\n" | |
| for meeting in FOMC_MEETINGS: | |
| sidebar_content += f""" | |
| **{meeting['date']}** | |
| *{meeting['title'][:50]}...* | |
| - **Rate:** {meeting['rate_decision']} | |
| - **Summary:** {meeting['summary'][:100]}... | |
| --- | |
| """ | |
| return sidebar_content | |
| def process_audio_input(audio_file): | |
| """Process audio input and convert to text""" | |
| if audio_file is None: | |
| return "No audio recorded. Please try again." | |
| # Simulate speech-to-text conversion | |
| # In a real implementation, you'd use libraries like openai-whisper, speech_recognition, etc. | |
| simulated_transcripts = [ | |
| "What was the federal funds rate decision in the last meeting?", | |
| "Compare the June and July FOMC meetings", | |
| "Tell me about inflation expectations", | |
| "What factors influenced recent policy decisions?", | |
| "Has the Fed's employment stance changed?" | |
| ] | |
| import random | |
| return random.choice(simulated_transcripts) | |
| def text_to_speech(text): | |
| """Convert text response to speech""" | |
| # Simulate text-to-speech functionality | |
| # In a real implementation, you'd use libraries like pyttsx3, gTTS, or cloud TTS services | |
| # Clean the text for better TTS (remove markdown formatting) | |
| import re | |
| clean_text = re.sub(r'\*\*.*?\*\*', '', text) # Remove bold markdown | |
| clean_text = re.sub(r'`.*?`', '', clean_text) # Remove code formatting | |
| clean_text = re.sub(r'<.*?>', '', clean_text) # Remove HTML tags | |
| clean_text = re.sub(r'[#β’]', '', clean_text) # Remove special characters | |
| clean_text = ' '.join(clean_text.split()) # Clean whitespace | |
| # For demo purposes, return a message about TTS | |
| return f"π Text-to-Speech: Would read aloud the response (length: {len(clean_text)} characters)" | |
| # Custom CSS for better styling | |
| custom_css = """ | |
| .gradio-container { | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| } | |
| .chat-message { | |
| border-radius: 10px; | |
| padding: 10px; | |
| margin: 5px 0; | |
| } | |
| .function-call { | |
| background-color: #f0f8ff; | |
| border-left: 4px solid #1e88e5; | |
| padding: 10px; | |
| margin: 10px 0; | |
| border-radius: 5px; | |
| } | |
| """ | |
| # Model options for dropdown | |
| MODEL_OPTIONS = [ | |
| "Claude 3.5 Sonnet", | |
| "GPT-4 Turbo", | |
| "Llama 3.1 70B", | |
| "Gemini Pro 1.5", | |
| "Mixtral 8x7B" | |
| ] | |
| # Function to create searchable FOMC meetings accordion | |
| def create_fomc_meetings_accordion(): | |
| """Create searchable accordion for FOMC meetings""" | |
| accordions = [] | |
| for meeting in FOMC_MEETINGS: | |
| title = f"{meeting['date']} - Rate: {meeting['rate_decision']}" | |
| content = f""" | |
| **Meeting Title:** {meeting['title']} | |
| **Rate Decision:** {meeting['rate_decision']} | |
| **Summary:** {meeting['summary']} | |
| --- | |
| *Click to expand for full meeting details* | |
| """ | |
| accordions.append((title, content)) | |
| return accordions | |
| # Create the enhanced interface | |
| with gr.Blocks(css=custom_css, title="Fed AI Savant", theme=gr.themes.Soft()) as demo: | |
| # Row 1: Title and Description | |
| with gr.Row(): | |
| with gr.Column(): | |
| gr.Markdown(""" | |
| # ποΈ Fed AI Savant ποΈ | |
| **Intelligent Analysis of Federal Reserve Policy and FOMC Meetings** | |
| Ask questions about interest rate decisions, monetary policy changes, and economic analysis based on Federal Reserve meeting minutes. | |
| """) | |
| # Row 2: API Key Configuration | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| gr.Markdown("### Powered by") | |
| gr.Image( | |
| value=str(_FILE_PATH / "assets" / "fireworks_logo.png"), | |
| height=60, | |
| width=200, | |
| show_label=False, | |
| show_download_button=False, | |
| container=False, | |
| show_fullscreen_button=False, | |
| show_share_button=False, | |
| ) | |
| with gr.Column(scale=1): | |
| gr.Markdown("### π Configuration") | |
| api_key = gr.Textbox( | |
| label="AI API Key", | |
| type="password", | |
| placeholder="Please enter your FireworksAI API key", | |
| value=os.getenv("FIREWORKS_API_KEY", ""), | |
| ) | |
| with gr.Column(scale=2): | |
| gr.Markdown("### π How to Use") | |
| gr.Markdown(""" | |
| 1. **Enter your AI API key** (OpenAI, Anthropic, etc.) | |
| 2. **Ask questions** about Fed policy, rate decisions, or FOMC meetings | |
| 3. **Review AI reasoning** with expandable explanations and sources | |
| 4. **Use voice input** by clicking the microphone button | |
| """) | |
| # Row 3: FOMC Meetings Accordion (Searchable by Date) | |
| with gr.Row(): | |
| with gr.Column(): | |
| gr.Markdown("### π Recent FOMC Meeting Minutes") | |
| # Date search | |
| date_search = gr.Textbox( | |
| placeholder="Search by date (e.g., 2024-07, July 2024)...", | |
| label="π Search Meetings by Date", | |
| lines=1 | |
| ) | |
| with gr.Accordion("FOMC Meetings", open=False): | |
| # Dynamic HTML generation for meetings | |
| def generate_meetings_html(meetings_list): | |
| """Generate HTML for meetings list""" | |
| if not meetings_list: | |
| return '<p style="color: #6b7280; text-align: center; padding: 20px;">No meetings available</p>' | |
| html_content = '<div style="space-y: 8px;">' | |
| for meeting in meetings_list: | |
| # Format key economic factors for display (show all factors) | |
| factors_html = "" | |
| if meeting.get('key_economic_factors') and len(meeting['key_economic_factors']) > 0: | |
| factors_html = "<p><strong>Key Factors:</strong></p><ul>" | |
| for factor in meeting['key_economic_factors']: # Show all factors | |
| factors_html += f"<li>{factor}</li>" | |
| factors_html += "</ul>" | |
| html_content += f""" | |
| <details style="border: 1px solid #e5e7eb; border-radius: 6px; padding: 12px; margin-bottom: 8px;"> | |
| <summary style="font-weight: 600; cursor: pointer; color: #1f2937;"> | |
| π {meeting['date']} - Rate: {meeting['rate_decision']} | |
| </summary> | |
| <div style="margin-top: 12px; padding-top: 12px; border-top: 1px solid #e5e7eb;"> | |
| <p><strong>Meeting:</strong> {meeting['title']}</p> | |
| <p><strong>Action:</strong> {meeting.get('action', 'N/A')}</p> | |
| <p><strong>Rate:</strong> {meeting['rate_decision']}</p> | |
| <p><strong>Magnitude:</strong> {meeting.get('magnitude', 'N/A')}</p> | |
| <p><strong>Forward Guidance:</strong> {meeting['summary']}</p> | |
| {factors_html} | |
| <p><strong>Economic Outlook:</strong> {meeting.get('economic_outlook', 'N/A')}</p> | |
| <p><strong>Market Impact:</strong> {meeting.get('market_impact', 'N/A')}</p> | |
| {f'<p><strong>Source:</strong> <a href="{meeting["url"]}" target="_blank">Fed Minutes PDF</a></p>' if meeting.get('url') else ''} | |
| </div> | |
| </details> | |
| """ | |
| html_content += '</div>' | |
| return html_content | |
| meetings_accordion = gr.HTML(generate_meetings_html(FOMC_MEETINGS)) | |
| # Row 4: Chat Interface using gr.ChatInterface | |
| with gr.Row(): | |
| with gr.Column(): | |
| gr.Markdown("### π¬ Fed AI Assistant") | |
| chat_interface = gr.ChatInterface( | |
| fn=respond_for_chat_interface, | |
| chatbot=gr.Chatbot(height=200, show_label=False), | |
| textbox=gr.Textbox(placeholder="Ask about Fed policy, rate decisions, or FOMC meetings...", scale=10), | |
| examples=[ | |
| "What was the rate decision in the last FOMC meeting?" | |
| "Compare June 2024 vs July 2024 FOMC meetings", | |
| "Tell me about inflation expectations", | |
| "Has the Fed's employment stance changed?", | |
| "What was the rate decision in the last FOMC meeting?", | |
| ], | |
| submit_btn="Send", | |
| ) | |
| # Search functionality for FOMC meetings | |
| def search_meetings(search_term): | |
| """Filter FOMC meetings based on search term""" | |
| if not search_term.strip(): | |
| # Return all meetings if no search term | |
| return generate_meetings_html(FOMC_MEETINGS) | |
| else: | |
| # Filter meetings based on search term | |
| filtered_meetings = [] | |
| search_lower = search_term.lower() | |
| for meeting in FOMC_MEETINGS: | |
| # Search in date, title, summary, economic factors, etc. | |
| search_fields = [ | |
| meeting.get('date', ''), | |
| meeting.get('title', ''), | |
| meeting.get('summary', ''), | |
| meeting.get('rate_decision', ''), | |
| meeting.get('action', ''), | |
| meeting.get('economic_outlook', ''), | |
| meeting.get('market_impact', ''), | |
| ' '.join(meeting.get('key_economic_factors', [])) | |
| ] | |
| if any(search_lower in field.lower() for field in search_fields): | |
| filtered_meetings.append(meeting) | |
| if filtered_meetings: | |
| return generate_meetings_html(filtered_meetings) | |
| else: | |
| return f'<p style="color: #6b7280; text-align: center; padding: 20px;">No meetings found matching "{search_term}"</p>' | |
| # Wire up search functionality | |
| date_search.change( | |
| search_meetings, | |
| inputs=date_search, | |
| outputs=meetings_accordion | |
| ) | |
| # Example buttons are now handled by ChatInterface examples parameter | |
| if __name__ == "__main__": | |
| demo.launch() | |