Spaces:
Runtime error
Runtime error
File size: 9,155 Bytes
a663682 cbc259d a663682 87600b0 cbc259d 87600b0 cbc259d 87600b0 cbc259d a663682 cbc259d a663682 87600b0 a663682 cbc259d a663682 cbc259d a663682 cbc259d a663682 cbc259d a663682 87600b0 a663682 cbc259d a663682 cbc259d a663682 cbc259d a663682 cbc259d a663682 cbc259d a663682 cbc259d a663682 cbc259d a663682 | 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 217 218 219 220 221 222 223 224 225 226 227 228 229 | """
FastAPI + Gradio server for the Cashflow Multi-Agent RL Environment.
"""
from fastapi import FastAPI
import gradio as gr
import pandas as pd
import time
import json
from openenv.core.env_server.http_server import create_app
import sys
import os
print(f"DEBUG: Starting server from CWD: {os.getcwd()}")
root_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
print(f"DEBUG: Root dir added to path: {root_dir}")
sys.path.insert(0, root_dir)
print(f"DEBUG: sys.path[0]: {sys.path[0]}")
try:
from models import CashflowmanagerAction, CashflowmanagerObservation
from server.cashflowmanager_environment import CashflowmanagerEnvironment
print("DEBUG: Successfully imported from root level")
except ImportError as e:
print(f"DEBUG: Root import failed: {e}")
try:
from cashflowmanager.models import CashflowmanagerAction, CashflowmanagerObservation
from cashflowmanager.server.cashflowmanager_environment import CashflowmanagerEnvironment
print("DEBUG: Successfully imported from cashflowmanager package")
except ImportError as e2:
print(f"DEBUG: Package import failed: {e2}")
from ..models import CashflowmanagerAction, CashflowmanagerObservation
from .cashflowmanager_environment import CashflowmanagerEnvironment
print("DEBUG: Using relative imports")
app: FastAPI = create_app(
CashflowmanagerEnvironment,
CashflowmanagerAction,
CashflowmanagerObservation,
env_name="cashflowmanager",
max_concurrent_envs=1,
)
print("DEBUG: FastAPI App created successfully")
try:
from server.client import groq_policy, clear_action_cache
except ImportError:
try:
from cashflowmanager.server.client import groq_policy, clear_action_cache
except ImportError:
from .client import groq_policy, clear_action_cache
# Global state for the interactive UI
_env_instance = None
_last_obs = None
_history = []
def get_env(seed=42, difficulty="medium"):
global _env_instance, _last_obs, _history
if _env_instance is None:
_env_instance = CashflowmanagerEnvironment()
clear_action_cache()
_last_obs = _env_instance.reset(seed=seed, difficulty=difficulty)
_history = []
return _env_instance, _last_obs
def format_invoices(invoices):
if not invoices:
return "No active invoices."
rows = []
for inv in invoices:
urgency = "π΄ OVERDUE" if inv.due_in <= 0 else "π‘ URGENT" if inv.due_in <= 2 else "π’ OK"
rows.append(f"{urgency} | {inv.id} | βΉ{inv.amount:.0f} | Due: {inv.due_in}d | Vendor: {inv.vendor_id}")
return "\n".join(rows)
def format_receivables(receivables):
if not receivables:
return "No expected inflows."
rows = []
for rec in receivables:
rows.append(f"βΉ{rec.amount:.0f} from {rec.customer_id} in {rec.expected_in}d (prob: {rec.probability*100:.0f}%)")
return "\n".join(rows)
def process_step(action_type, invoice_id=None, amount=0.0, memo=None):
global _env_instance, _last_obs, _history
env, obs = get_env()
if obs.done:
return update_ui()
# Create action
action = CashflowmanagerAction(type=action_type, invoice_id=invoice_id, amount=amount, memo=memo)
# Step environment
new_obs = env.step(action)
# Log to history
entry = {
"Step": env.state.step_count,
"Day": new_obs.day,
"Action": f"{action.type}({action.invoice_id or 'N/A'})",
"Amount": f"βΉ{action.amount:.0f}" if action.amount else "N/A",
"Cash": f"βΉ{new_obs.cash:.0f}",
"Reward": round(new_obs.reward, 2),
"Reasoning": action.memo or "Manual Action",
"Events": " | ".join(new_obs.world_events) if new_obs.world_events else "None"
}
_history.insert(0, entry)
_last_obs = new_obs
return update_ui()
def ai_step():
global _last_obs
if _last_obs is None or _last_obs.done:
return update_ui()
# Let the policy decide
action = groq_policy(_last_obs, [])
return process_step(action.type, action.invoice_id, action.amount, memo=action.memo)
def reset_sim(seed, difficulty):
global _env_instance, _last_obs, _history
_env_instance = None
get_env(seed=int(seed), difficulty=difficulty)
return update_ui()
def update_ui():
global _last_obs, _history
obs = _last_obs
history_df = pd.DataFrame(_history)
status = f"### Day {obs.day} | Step {obs.metadata.get('step', 0)}\n"
status += f"**Cash:** βΉ{obs.cash:.0f} | **Credit Used:** βΉ{obs.credit_used:.0f}/{obs.credit_limit:.0f}\n"
if obs.done:
status += "## π EPISODE FINISHED\n"
memos = "#### π€ Advisor Memos\n"
for agent, msg in obs.advisor_messages.items():
memos += f"- **{agent}:** {msg}\n"
world = "#### π World Events\n"
if obs.world_events:
for e in obs.world_events:
world += f"- {e}\n"
else:
world += "- No events this step."
invoice_list = [inv.id for inv in obs.invoices]
return (
status,
memos,
world,
format_invoices(obs.invoices),
format_receivables(obs.receivables),
history_df,
gr.Dropdown(choices=invoice_list, value=invoice_list[0] if invoice_list else None)
)
def build_ui():
with gr.Blocks(title="Cashflow Multi-Agent RL Simulator") as demo:
gr.Markdown("# π’ Cashflow Management Dashboard")
with gr.Row():
seed_input = gr.Number(value=42, label="Sim Seed", precision=0, scale=1)
difficulty_input = gr.Dropdown(choices=["easy", "medium", "hard"], value="medium", label="Difficulty", scale=1)
reset_btn = gr.Button("π Reset", variant="secondary", scale=1)
ai_btn = gr.Button("π€ AI Next Step", variant="primary", scale=2)
with gr.Row():
# --- Left: Data View ---
with gr.Column(scale=3):
status_md = gr.Markdown("### π° Financial Status")
with gr.Tabs():
with gr.TabItem("π Active Invoices"):
invoice_display = gr.Code(label="Debts", language="markdown")
with gr.TabItem("π Receivables"):
receivable_display = gr.Code(label="Expected Inflows", language="markdown")
with gr.Group():
gr.Markdown("#### πΉοΈ Manual Action")
with gr.Row():
target_inv = gr.Dropdown(label="Select Invoice", choices=[], scale=2)
pay_amount = gr.Number(label="Amount (βΉ)", value=0, scale=1)
with gr.Row():
pay_btn = gr.Button("Pay Full", variant="stop")
neg_btn = gr.Button("Negotiate", variant="primary")
credit_btn = gr.Button("Draw Credit")
defer_btn = gr.Button("Defer Step")
# --- Right: Intelligence ---
with gr.Column(scale=2):
memo_md = gr.Markdown("#### π€ Advisor Intelligence")
world_md = gr.Markdown("#### π World Events")
gr.Markdown("---")
history_table = gr.Dataframe(
headers=["Step", "Day", "Action", "Amount", "Cash", "Reward", "Reasoning", "Events"],
interactive=False
)
# Event handlers
demo.load(reset_sim, inputs=[seed_input, difficulty_input], outputs=[status_md, memo_md, world_md, invoice_display, receivable_display, history_table, target_inv])
reset_btn.click(reset_sim, inputs=[seed_input, difficulty_input], outputs=[status_md, memo_md, world_md, invoice_display, receivable_display, history_table, target_inv])
difficulty_input.change(reset_sim, inputs=[seed_input, difficulty_input], outputs=[status_md, memo_md, world_md, invoice_display, receivable_display, history_table, target_inv])
ai_btn.click(ai_step, outputs=[status_md, memo_md, world_md, invoice_display, receivable_display, history_table, target_inv])
pay_btn.click(lambda id, amt: process_step("pay", id, amt), inputs=[target_inv, pay_amount], outputs=[status_md, memo_md, world_md, invoice_display, receivable_display, history_table, target_inv])
neg_btn.click(lambda id: process_step("negotiate", id), inputs=[target_inv], outputs=[status_md, memo_md, world_md, invoice_display, receivable_display, history_table, target_inv])
credit_btn.click(lambda amt: process_step("credit", amount=amt), inputs=[pay_amount], outputs=[status_md, memo_md, world_md, invoice_display, receivable_display, history_table, target_inv])
defer_btn.click(lambda: process_step("defer"), outputs=[status_md, memo_md, world_md, invoice_display, receivable_display, history_table, target_inv])
return demo
gradio_app = build_ui()
app = gr.mount_gradio_app(app, gradio_app, path="/ui")
def main():
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=7861)
if __name__ == "__main__":
main() |