Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| from agno.agent import Agent | |
| from agno.models.openai import OpenAIChat | |
| from agno.tools.decorator import tool | |
| from datetime import datetime, timedelta | |
| from dotenv import load_dotenv | |
| load_dotenv() | |
| # β Tool definition | |
| def get_treasury_data(input: str) -> str: | |
| today = datetime.now().strftime("%Y-%m-%d") | |
| due_date = (datetime.now() + timedelta(days=5)).strftime("%Y-%m-%d") | |
| return f""" | |
| As of {today}, here is the treasury snapshot: | |
| β Cash Balances: | |
| - USD Operating Account: $2,800,000 | |
| - EUR Revenue Account: β¬1,500,000 | |
| - GBP Payroll Account: Β£600,000 | |
| π FX Market Rates: | |
| - EUR/USD: 1.08 | |
| - GBP/USD: 1.27 | |
| π§Ύ Upcoming Liabilities: | |
| - USD Vendor Payments: $2,200,000 due on {due_date} | |
| - EUR Convertible Bond Maturity: β¬900,000 due on {due_date} | |
| - GBP Payroll Run: Β£500,000 due on {due_date} | |
| π Policy Thresholds: | |
| - Minimum USD liquidity buffer: $500,000 | |
| - FX hedge threshold for EUR: 70% exposure | |
| """ | |
| # β Agent definition | |
| agent = Agent( | |
| model=OpenAIChat(id="gpt-4o"), | |
| tools=[get_treasury_data], | |
| instructions=[ | |
| "You are a Treasury Analyst AI.", | |
| "Analyze liquidity and FX exposure.", | |
| "Recommend actions such as FX hedging, internal fund transfers, or delay of liabilities.", | |
| "Always ensure minimum liquidity buffers are met.", | |
| "Convert foreign currency exposures to USD for a consolidated view.", | |
| "Provide your analysis in bullet points with numbers.", | |
| ], | |
| markdown=True, | |
| ) | |
| def ask_agent(messages, history): | |
| print("====== DEBUG: ask_agent START ======") | |
| print("π₯ Incoming messages:", messages) | |
| print("π Chat history:", history) | |
| # β Handle Hugging Face's tendency to send just a string | |
| if isinstance(messages, str): | |
| messages = [{"role": "user", "content": messages}] | |
| elif isinstance(messages, list): | |
| # Defensive fix: if list of strings, wrap each | |
| if all(isinstance(m, str) for m in messages): | |
| messages = [{"role": "user", "content": m} for m in messages] | |
| # If it's a list but not valid messages, throw a descriptive error | |
| elif not all(isinstance(m, dict) and "role" in m and "content" in m for m in messages): | |
| print("β Malformed message list") | |
| return {"role": "assistant", "content": "Sorry, I couldn't understand the message format."} | |
| else: | |
| print("β Completely invalid input type") | |
| return {"role": "assistant", "content": "Sorry, I didn't understand that input."} | |
| try: | |
| latest_user_message = messages[-1]["content"] | |
| print(f"π¬ Latest user message: {latest_user_message}") | |
| except Exception as e: | |
| print(f"β Error extracting latest message: {e}") | |
| return {"role": "assistant", "content": "Sorry, I couldn't read your message."} | |
| try: | |
| response = agent.run(latest_user_message) | |
| print(f"β Agent response:\n{response}") | |
| return {"role": "assistant", "content": response.content} | |
| except Exception as e: | |
| print(f"β Agent failed: {e}") | |
| return {"role": "assistant", "content": "Something went wrong on my end. Try again?"} | |
| def yes(message, history): | |
| return "yes" | |
| # β Launch Gradio UI | |
| gr.ChatInterface( | |
| fn=ask_agent, | |
| title="AI Treasury Assistant", | |
| description="Ask about cash positions, FX risk, or liquidity outlook.", | |
| chatbot=gr.Chatbot(show_copy_button=True, type="messages"), # β Fix here | |
| type="messages" # β And here | |
| ).launch() | |