RobertoBarrosoLuque
Update format and prettify for more professional look
cf961a5
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
from src.config.theme_config import CUSTOM_CSS, GRADIO_THEME, EXAMPLE_QUESTIONS
load_dotenv()
_FILE_PATH = Path(__file__).parents[1]
FOMC_MEETINGS = load_processed_meetings()
PROMPT_LIBRARY = load_prompt_library()
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
def generate_meetings_html(meetings_list):
"""Generate HTML for meetings list with Fireworks AI purple palette"""
if not meetings_list:
return '<p style="color: #64748B; text-align: center; padding: 20px;">No meetings available</p>'
html_content = '<div style="max-height: 600px; overflow-y: auto;">'
for meeting in meetings_list:
date = meeting.get('date', 'Unknown Date')
rate_decision = meeting.get('rate', 'N/A')
title = meeting.get('title', 'FOMC Meeting')
action = meeting.get('action', 'N/A')
magnitude = meeting.get('magnitude', 'N/A')
forward_guidance = meeting.get('forward_guidance')
economic_outlook = meeting.get('economic_outlook')
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 style='margin: 10px 0 6px 0; font-size: 0.9em; color: #0F172A; font-weight: 600;'>Key Factors:</p><ul style='margin: 4px 0; padding-left: 20px; font-size: 0.88em; color: #64748B;'>"
for factor in key_factors:
factors_html += f"<li style='margin: 4px 0;'>{factor}</li>"
factors_html += "</ul>"
html_content += f"""
<details class="meeting-details" style="border: 1px solid #E6EAF4; border-radius: 10px; margin: 10px 0; background: white; overflow: hidden; transition: all 0.25s ease;">
<summary class="meeting-summary" style="font-weight: 600; cursor: pointer; color: #0F172A; padding: 14px 18px; font-size: 0.95em; background: linear-gradient(90deg, transparent 0%, #F3F0FF 100%);">
{date} - {rate_decision}
</summary>
<div class="meeting-content" style="padding: 16px 18px; border-top: 1px solid #E6EAF4; background: #FAFBFC; font-size: 0.88em;">
<p style="margin: 6px 0; color: #0F172A;"><strong style="color: #6720FF;">Action:</strong> {action}</p>
<p style="margin: 6px 0; color: #0F172A;"><strong style="color: #6720FF;">Magnitude:</strong> {magnitude}</p>
<p style="margin: 10px 0 6px 0; color: #0F172A;"><strong style="color: #6720FF;">Forward Guidance:</strong></p>
<p style="margin: 0 0 10px 0; color: #64748B; line-height: 1.5;">{forward_guidance}</p>
{factors_html}
<p style="margin: 10px 0 6px 0; color: #0F172A;"><strong style="color: #6720FF;">Economic Outlook:</strong></p>
<p style="margin: 0 0 10px 0; color: #64748B; line-height: 1.5;">{economic_outlook}</p>
<p style="margin: 10px 0 6px 0; color: #0F172A;"><strong style="color: #6720FF;">Market Impact:</strong></p>
<p style="margin: 0 0 10px 0; color: #64748B; line-height: 1.5;">{market_impact}</p>
{f'<p style="margin: 10px 0 0 0;"><strong style="color: #6720FF;">Source:</strong> <a href="{url}" target="_blank" style="color: #6720FF; text-decoration: none; transition: color 0.2s ease;">Fed Minutes PDF</a></p>' if url else ''}
</div>
</details>
"""
html_content += '</div>'
return html_content
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.Blocks(css=CUSTOM_CSS, title="Fed AI Savant", theme=GRADIO_THEME) as demo:
gr.Markdown("""
<h1 class="header-title" style="font-size: 2.5em; margin-bottom: 0.5em;">Fed AI Savant</h1>
<p style="color: #64748B; font-size: 1.1em; margin-top: 0;">Intelligent Analysis of Federal Reserve Policy and FOMC Meetings with <a href="https://huggingface.co/openai/gpt-oss-120b" target="_blank" style="color: #6720FF;">gpt-oss 120B</a></p>
""")
with gr.Row():
# Sidebar for FOMC Meetings
with gr.Column(scale=1, min_width=300, elem_classes="meetings-container"):
gr.Markdown("### FOMC Meetings")
# Date search
date_search = gr.Textbox(
placeholder="Search by date...",
label="Search",
lines=1,
container=False,
elem_classes="search-box"
)
meetings_accordion = gr.HTML(generate_meetings_html(FOMC_MEETINGS))
# Main content area
with gr.Column(scale=2):
# Compact header with Fireworks AI logo and API key
with gr.Row(elem_classes="compact-header"):
with gr.Column(scale=1, min_width=150):
gr.Markdown("<p style='margin: 0; padding: 0; font-size: 0.85em; color: #64748B;'>Powered by</p>")
gr.Image(
value=str(_FILE_PATH / "assets" / "fireworks_logo.png"),
height=35,
width=140,
show_label=False,
show_download_button=False,
container=False,
show_fullscreen_button=False,
show_share_button=False,
)
with gr.Column(scale=2):
val = os.getenv("FIREWORKS_API_KEY", "")
api_key_value = gr.Textbox(
label="API Key",
type="password",
placeholder="Enter your Fireworks AI API key",
value=val,
container=True,
elem_classes="compact-input"
)
# Example Questions - compact version
with gr.Row(elem_classes="compact-examples"):
example_1 = gr.Button(EXAMPLE_QUESTIONS[0], size="sm", scale=1)
example_2 = gr.Button(EXAMPLE_QUESTIONS[1], size="sm", scale=1)
example_3 = gr.Button(EXAMPLE_QUESTIONS[2], size="sm", scale=1)
example_4 = gr.Button(EXAMPLE_QUESTIONS[3], size="sm", scale=1)
# Chat interface with more space
chat_interface = gr.ChatInterface(
fn=respond_for_chat_interface,
type="messages",
chatbot=gr.Chatbot(height=450, show_label=False, type="messages", elem_classes="chat-window"),
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"
)
date_search.change(
search_and_format_meetings,
inputs=date_search,
outputs=meetings_accordion
)
def set_example_text(text):
return text
example_1.click(
lambda: EXAMPLE_QUESTIONS[0],
outputs=chat_interface.textbox
)
example_2.click(
lambda: EXAMPLE_QUESTIONS[1],
outputs=chat_interface.textbox
)
example_3.click(
lambda: EXAMPLE_QUESTIONS[2],
outputs=chat_interface.textbox
)
example_4.click(
lambda: EXAMPLE_QUESTIONS[3],
outputs=chat_interface.textbox
)
if __name__ == "__main__":
demo.launch()