Spaces:
Running
Running
File size: 9,548 Bytes
900d7e8 f4ca844 d094ea0 22e33ed 4669a77 cf961a5 900d7e8 f4ca844 d094ea0 f4ca844 d094ea0 0d006a9 900d7e8 4618b90 0d006a9 3a65210 f6d1cff d094ea0 1b4db50 d094ea0 252c5e7 f6d1cff 4618b90 252c5e7 4618b90 22e33ed 4618b90 252c5e7 1b4db50 f6d1cff 4618b90 f6d1cff 4618b90 900d7e8 f4ca844 3a65210 f4ca844 4669a77 f4ca844 6e9984b cf961a5 6e9984b cf961a5 6e9984b cf961a5 6e9984b cf961a5 6e9984b cf961a5 6e9984b cf961a5 6e9984b cf961a5 6e9984b cf961a5 d094ea0 6e9984b cf961a5 6e9984b d094ea0 f4ca844 6e9984b cf961a5 6e9984b f4ca844 6e9984b cf961a5 6e9984b cf961a5 f4ca844 3a65210 6e9984b cf961a5 6e9984b cf961a5 6e9984b cf961a5 3a65210 cf961a5 3a65210 001487b cf961a5 d094ea0 252c5e7 cf961a5 f4ca844 6e9984b f4ca844 4618b90 f4ca844 d094ea0 cf961a5 d094ea0 cf961a5 d094ea0 cf961a5 d094ea0 cf961a5 d094ea0 252c5e7 900d7e8 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 |
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()
API_KEY = os.getenv("FIREWORKS_API_KEY")
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 = None):
"""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,
)
# 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
),
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()
|