Spaces:
Running
Running
import gradio as gr | |
import os | |
from dotenv import load_dotenv | |
from pathlib import Path | |
from modules.utils import load_processed_meetings, load_prompt_library | |
from src.modules.fed_tools import search_meetings_by_date, FED_TOOLS | |
from src.modules.llm_completions import stream_fed_agent_response | |
load_dotenv() | |
_FILE_PATH = Path(__file__).parents[1] | |
FOMC_MEETINGS = load_processed_meetings() | |
PROMPT_LIBRARY = load_prompt_library() | |
_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; | |
} | |
""" | |
_EXAMPLES = [ | |
"What was the rate decision in the last FOMC meeting?", | |
"What is the most likely rate decision in the next FOMC meeting?", | |
"What does the economic outlook look like today?", | |
"Give me a table which summarized the last 5 FOMC meetings" | |
] | |
def convert_history_to_string(history: list) -> str: | |
previous_messages = "" | |
for msg in history: | |
previous_messages += f"{msg['role'].capitalize()}: {msg['content']}\n\n" | |
return previous_messages | |
def respond_for_chat_interface(message: str, history: list, api_key_input: str = ""): | |
"""Enhanced response function for gr.ChatInterface with Fed AI Savant capabilities""" | |
api_key = api_key_input.strip() if api_key_input else os.getenv("FIREWORKS_API_KEY", "") | |
if not api_key: | |
yield "β Please enter your Fireworks AI API key in the configuration section above." | |
return | |
message_with_history = convert_history_to_string(history) | |
try: | |
for messages in stream_fed_agent_response( | |
message=message, | |
api_key=api_key, | |
prompt_library=PROMPT_LIBRARY, | |
fed_tools=FED_TOOLS, | |
history=message_with_history | |
): | |
if isinstance(messages, list) and len(messages) > 0: | |
yield messages | |
else: | |
yield str(messages) | |
except Exception as e: | |
error_msg = f"β Error: {str(e)}" | |
yield error_msg | |
# 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") | |
val = os.getenv("FIREWORKS_API_KEY", "") | |
api_key_value = gr.Textbox( | |
label="Fireworks AI API Key", | |
type="password", | |
placeholder="Enter your Fireworks AI API key", | |
value=val, | |
info="Required for AI processing", | |
) | |
with gr.Column(scale=2): | |
gr.Markdown("### π How to Use") | |
gr.Markdown(""" | |
1. **Enter your AI API key** | |
2. **Ask questions** about Fed policy, rate decisions, or FOMC meetings | |
3. **Review AI reasoning** with expandable explanations and sources | |
""") | |
# 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., 2025-07, 'June 2024', etc)...", | |
label="π Search Meetings by Date", | |
lines=1 | |
) | |
with gr.Accordion("FOMC Meetings", open=False): | |
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: | |
date = meeting.get('date', 'Unknown Date') | |
rate_decision = meeting.get('rate_decision', 'N/A') | |
title = meeting.get('title', 'FOMC Meeting') | |
action = meeting.get('action', 'N/A') | |
magnitude = meeting.get('magnitude', 'N/A') | |
summary = meeting.get('summary', 'No summary available') | |
economic_outlook = meeting.get('economic_outlook', 'N/A') | |
market_impact = meeting.get('market_impact', 'N/A') | |
url = meeting.get('url', '') | |
factors_html = "" | |
key_factors = meeting.get('key_economic_factors', []) | |
if key_factors and len(key_factors) > 0: | |
factors_html = "<p><strong>Key Factors:</strong></p><ul>" | |
for factor in key_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;"> | |
π {date} - Rate: {rate_decision} | |
</summary> | |
<div style="margin-top: 12px; padding-top: 12px; border-top: 1px solid #e5e7eb;"> | |
<p><strong>Meeting:</strong> {title}</p> | |
<p><strong>Action:</strong> {action}</p> | |
<p><strong>Rate:</strong> {rate_decision}</p> | |
<p><strong>Magnitude:</strong> {magnitude}</p> | |
<p><strong>Forward Guidance:</strong> {summary}</p> | |
{factors_html} | |
<p><strong>Economic Outlook:</strong> {economic_outlook}</p> | |
<p><strong>Market Impact:</strong> {market_impact}</p> | |
{f'<p><strong>Source:</strong> <a href="{url}" target="_blank">Fed Minutes PDF</a></p>' if url else ''} | |
</div> | |
</details> | |
""" | |
html_content += '</div>' | |
return html_content | |
meetings_accordion = gr.HTML(generate_meetings_html(FOMC_MEETINGS)) | |
def search_and_format_meetings(query: str): | |
"""Search meetings and format them for HTML display""" | |
if not query.strip(): | |
return generate_meetings_html(FOMC_MEETINGS) | |
search_result = search_meetings_by_date(query) | |
if search_result.get("success") and search_result.get("results"): | |
return generate_meetings_html(search_result["results"]) | |
else: | |
return '<p style="color: #ef4444; text-align: center; padding: 20px;">No meetings found matching your search.</p>' | |
with gr.Row(): | |
with gr.Column(): | |
gr.Markdown("### π¬ Fed AI Assistant") | |
chat_interface = gr.ChatInterface( | |
fn=respond_for_chat_interface, | |
type="messages", | |
chatbot=gr.Chatbot(height=600, show_label=False, type="messages"), | |
textbox=gr.Textbox( | |
placeholder="Ask about Fed policy, rate decisions, or FOMC meetings...", scale=10 | |
), | |
additional_inputs=[api_key_value], | |
cache_examples=False, | |
submit_btn="Send", | |
) | |
with gr.Row(): | |
with gr.Column(scale=1): | |
example_1 = gr.Button(_EXAMPLES[0], size="md") | |
example_2= gr.Button( | |
_EXAMPLES[1], size="md" | |
) | |
with gr.Column(scale=1): | |
example_3 = gr.Button(_EXAMPLES[2], size="md") | |
example_4 = gr.Button(_EXAMPLES[3], size="md") | |
date_search.change( | |
search_and_format_meetings, | |
inputs=date_search, | |
outputs=meetings_accordion | |
) | |
def set_example_text(text): | |
return text | |
example_1.click( | |
lambda: _EXAMPLES[0], | |
outputs=chat_interface.textbox | |
) | |
example_2.click( | |
lambda: _EXAMPLES[1], | |
outputs=chat_interface.textbox | |
) | |
example_3.click( | |
lambda: _EXAMPLES[2], | |
outputs=chat_interface.textbox | |
) | |
example_4.click( | |
lambda: _EXAMPLES[3], | |
outputs=chat_interface.textbox | |
) | |
if __name__ == "__main__": | |
demo.launch() | |