samsonleegh's picture
Update app.py
4c7d98b verified
import os
import shutil
import pathlib
import subprocess
from datetime import datetime
import gradio as gr
from agents import Agent, Runner
from agents.mcp import MCPServerStdio
DEFAULT_EXCHANGE = os.getenv("EXCHANGE_NAME", "binance")
REPO_DIR = pathlib.Path("crypto-indicators-mcp")
REPO_URL = "https://github.com/kukapay/crypto-indicators-mcp.git"
REPO_ENTRY = REPO_DIR / "index.js"
REPO_NODE_MODULES = REPO_DIR / "node_modules"
def _cmd_exists(name: str) -> bool:
return shutil.which(name) is not None
def _run(cmd, **kwargs):
# Prints output to logs so you can debug from Space build/run logs
print(f"[boot] $ {' '.join(cmd)}")
subprocess.run(cmd, check=True, **kwargs)
def ensure_repo_ready():
print("[boot] ensuring prerequisites...")
if not _cmd_exists("git"):
raise RuntimeError("git not found. Add `git` to packages.txt.")
if not _cmd_exists("node"):
raise RuntimeError("node not found. Add `nodejs` to packages.txt.")
if not _cmd_exists("npm"):
raise RuntimeError("npm not found. Add `npm` to packages.txt.")
print("[boot] syncing repo...")
if not REPO_DIR.exists():
_run(["git", "clone", "--depth=1", REPO_URL, str(REPO_DIR)])
else:
_run(["git", "-C", str(REPO_DIR), "fetch", "--depth=1", "origin"])
_run(["git", "-C", str(REPO_DIR), "reset", "--hard", "origin/HEAD"])
# Install npm deps only if needed (faster cold starts)
if not REPO_NODE_MODULES.exists():
print("[boot] installing npm deps...")
lock = REPO_DIR / "package-lock.json"
cmd = ["npm", "ci"] if lock.exists() else ["npm", "install", "--omit=dev"]
_run(cmd, cwd=str(REPO_DIR))
else:
print("[boot] node_modules present; skipping npm install.")
if not REPO_ENTRY.exists():
raise FileNotFoundError(f"Cannot find {REPO_ENTRY}; check repository structure.")
# Run once at import time to keep UI responsive later
ensure_repo_ready()
async def handle_request(request: str):
instructions = f"""You are a cryptocurrency perpetuals trading researcher. You have the tools for trend/momentum/volatility/volume technical indicators and strategies.
Default analysis interval is 1h, and default lookback period is 36.
Default indicators/strategies you have are:
- EMA (20, 200)
- MACD (12, 26, 9)
- stochastic RSI (14, 14, 3, 3)
- Accumulation/Distribution (ADL)
- Volume
Based on the indicators, look for possible long/short opportunities, and propose a strategy.
The current datetime is {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}"""
params = {
"command": "node",
"args": [str(REPO_ENTRY)],
"env": {
"EXCHANGE_NAME": DEFAULT_EXCHANGE
}
}
# First call may take longer; give it room
async with MCPServerStdio(params=params, client_session_timeout_seconds=180) as mcp_server:
agent = Agent(
name="crypto_technical_researcher",
instructions=instructions,
model="gpt-4.1-mini",
mcp_servers=[mcp_server],
)
result = await Runner.run(agent, request)
return result.final_output
iface = gr.Interface(
fn=handle_request, # async is fine; Gradio supports it
inputs=gr.Textbox(label="Request", placeholder="e.g., Get the latest indicators on BTC"),
outputs=gr.Textbox(label="Response", lines=12),
title="Crypto Technical Researcher",
description="Ask for technical analysis via an MCP-powered toolchain."
)
if __name__ == "__main__":
# In Spaces, Gradio auto-binds to $PORT; defaults are okay.
iface.launch()