Spaces:
Running
Running
Thang6822 commited on
Commit Β·
5981eff
1
Parent(s): 61373b9
rebrand: remove Kronos refs, use AI Forecast
Browse files- backend/launcher.py +6 -6
- backend/main.py +5 -5
- backend/startup_utils.py +12 -12
- frontend/index.html +3 -3
- frontend/workspace.js +3 -3
backend/launcher.py
CHANGED
|
@@ -16,18 +16,18 @@ logging.basicConfig(
|
|
| 16 |
level=logging.INFO,
|
| 17 |
format="%(asctime)s | %(levelname)s | %(message)s",
|
| 18 |
)
|
| 19 |
-
logger = logging.getLogger("
|
| 20 |
|
| 21 |
DEFAULT_HOST: str = "127.0.0.1"
|
| 22 |
SERVER_BOOT_DELAY_SECONDS: float = 2.5
|
| 23 |
PROJECT_ROOT: Path = Path(__file__).resolve().parent.parent
|
| 24 |
|
| 25 |
BANNER = r"""
|
| 26 |
-
|
| 27 |
-
|
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
"""
|
| 32 |
|
| 33 |
|
|
|
|
| 16 |
level=logging.INFO,
|
| 17 |
format="%(asctime)s | %(levelname)s | %(message)s",
|
| 18 |
)
|
| 19 |
+
logger = logging.getLogger("aiforecast-launcher")
|
| 20 |
|
| 21 |
DEFAULT_HOST: str = "127.0.0.1"
|
| 22 |
SERVER_BOOT_DELAY_SECONDS: float = 2.5
|
| 23 |
PROJECT_ROOT: Path = Path(__file__).resolve().parent.parent
|
| 24 |
|
| 25 |
BANNER = r"""
|
| 26 |
+
_ _____ _____ _
|
| 27 |
+
/ \ |_ _\ \ / / ___|__ _ __ ___ ___ __ _| |_
|
| 28 |
+
/ _ \ | | \ V /| |_ / _ \| '__/ _ \/ __/ _` | __|
|
| 29 |
+
/ ___ \ | | | | | _| (_) | | | __/ (_| (_| | |_
|
| 30 |
+
/_/ \_\___| |_| |_| \___/|_| \___|\___\__,_|\__|
|
| 31 |
"""
|
| 32 |
|
| 33 |
|
backend/main.py
CHANGED
|
@@ -127,7 +127,7 @@ except Exception as exc:
|
|
| 127 |
torch = None # type: ignore[assignment]
|
| 128 |
TORCH_IMPORT_ERROR = str(exc)
|
| 129 |
|
| 130 |
-
DEFAULT_ADMIN_TOKEN = "
|
| 131 |
|
| 132 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 133 |
# Architecture v5: Configuration Management (C-1)
|
|
@@ -149,7 +149,7 @@ class Settings(BaseModel):
|
|
| 149 |
# App Config
|
| 150 |
host: str = os.getenv("HOST", "0.0.0.0")
|
| 151 |
port: int = int(os.getenv("PORT", 8000))
|
| 152 |
-
|
| 153 |
cache_version: str = os.getenv("CACHE_VERSION", "v12")
|
| 154 |
cors_allow_origins_raw: str = os.getenv("CORS_ALLOW_ORIGINS", "*")
|
| 155 |
|
|
@@ -416,7 +416,7 @@ if IS_FROZEN:
|
|
| 416 |
else:
|
| 417 |
logger.info("Running in DEV mode. PROJECT_ROOT: %s", PROJECT_ROOT)
|
| 418 |
|
| 419 |
-
# TimesFM 2.5 β
|
| 420 |
TIMESFM_AVAILABLE = False
|
| 421 |
TIMESFM_IMPORT_ERROR: Optional[str] = None
|
| 422 |
|
|
@@ -460,7 +460,7 @@ class StructuredLogger:
|
|
| 460 |
logger.info(msg) # Keeping standard log for dev, but payload is ready for JSON
|
| 461 |
|
| 462 |
persistent_cache = PersistentCache(
|
| 463 |
-
db_path=os.path.join(PROJECT_ROOT, "data", "
|
| 464 |
cache_version_getter=lambda: settings.cache_version,
|
| 465 |
logger=logger,
|
| 466 |
)
|
|
@@ -4418,7 +4418,7 @@ def _clear_ip_limits():
|
|
| 4418 |
@asynccontextmanager
|
| 4419 |
async def lifespan(app: FastAPI):
|
| 4420 |
# Startup logic
|
| 4421 |
-
logger.info("Starting
|
| 4422 |
background_tasks: List[asyncio.Task[Any]] = []
|
| 4423 |
|
| 4424 |
def _start_background_task(coro: Any, name: str) -> None:
|
|
|
|
| 127 |
torch = None # type: ignore[assignment]
|
| 128 |
TORCH_IMPORT_ERROR = str(exc)
|
| 129 |
|
| 130 |
+
DEFAULT_ADMIN_TOKEN = "aiforecast_v6_default_secret"
|
| 131 |
|
| 132 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 133 |
# Architecture v5: Configuration Management (C-1)
|
|
|
|
| 149 |
# App Config
|
| 150 |
host: str = os.getenv("HOST", "0.0.0.0")
|
| 151 |
port: int = int(os.getenv("PORT", 8000))
|
| 152 |
+
preload_timesfm: bool = os.getenv("PRELOAD_TIMESFM", "True").lower() == "true"
|
| 153 |
cache_version: str = os.getenv("CACHE_VERSION", "v12")
|
| 154 |
cors_allow_origins_raw: str = os.getenv("CORS_ALLOW_ORIGINS", "*")
|
| 155 |
|
|
|
|
| 416 |
else:
|
| 417 |
logger.info("Running in DEV mode. PROJECT_ROOT: %s", PROJECT_ROOT)
|
| 418 |
|
| 419 |
+
# TimesFM 2.5 β foundation model for OHLC4 forecasting
|
| 420 |
TIMESFM_AVAILABLE = False
|
| 421 |
TIMESFM_IMPORT_ERROR: Optional[str] = None
|
| 422 |
|
|
|
|
| 460 |
logger.info(msg) # Keeping standard log for dev, but payload is ready for JSON
|
| 461 |
|
| 462 |
persistent_cache = PersistentCache(
|
| 463 |
+
db_path=os.path.join(PROJECT_ROOT, "data", "aiforecast.db"),
|
| 464 |
cache_version_getter=lambda: settings.cache_version,
|
| 465 |
logger=logger,
|
| 466 |
)
|
|
|
|
| 4418 |
@asynccontextmanager
|
| 4419 |
async def lifespan(app: FastAPI):
|
| 4420 |
# Startup logic
|
| 4421 |
+
logger.info("Starting AI Forecast Backend v%s...", APP_VERSION)
|
| 4422 |
background_tasks: List[asyncio.Task[Any]] = []
|
| 4423 |
|
| 4424 |
def _start_background_task(coro: Any, name: str) -> None:
|
backend/startup_utils.py
CHANGED
|
@@ -77,23 +77,23 @@ async def run_source_selftest(
|
|
| 77 |
logger.warning("[selftest] %-15s FAILED: %s", name, ex)
|
| 78 |
|
| 79 |
|
| 80 |
-
async def
|
| 81 |
*,
|
| 82 |
forecaster: ForecasterLike,
|
| 83 |
-
|
| 84 |
logger: LoggerLike,
|
| 85 |
) -> None:
|
| 86 |
-
|
| 87 |
-
|
| 88 |
try:
|
| 89 |
await forecaster._lazy_load()
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
logger.info("[startup]
|
| 93 |
except Exception as ex:
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
logger.warning("[startup]
|
| 98 |
finally:
|
| 99 |
-
|
|
|
|
| 77 |
logger.warning("[selftest] %-15s FAILED: %s", name, ex)
|
| 78 |
|
| 79 |
|
| 80 |
+
async def warmup_timesfm(
|
| 81 |
*,
|
| 82 |
forecaster: ForecasterLike,
|
| 83 |
+
startup_timesfm_state: MutableMapping[str, Any],
|
| 84 |
logger: LoggerLike,
|
| 85 |
) -> None:
|
| 86 |
+
startup_timesfm_state["warming"] = True
|
| 87 |
+
startup_timesfm_state["last_error"] = None
|
| 88 |
try:
|
| 89 |
await forecaster._lazy_load()
|
| 90 |
+
startup_timesfm_state["loaded"] = forecaster.is_ready
|
| 91 |
+
startup_timesfm_state["device"] = forecaster.device
|
| 92 |
+
logger.info("[startup] TimesFM warmup finished on %s", forecaster.device)
|
| 93 |
except Exception as ex:
|
| 94 |
+
startup_timesfm_state["loaded"] = False
|
| 95 |
+
startup_timesfm_state["device"] = forecaster.device
|
| 96 |
+
startup_timesfm_state["last_error"] = str(ex)
|
| 97 |
+
logger.warning("[startup] TimesFM warmup failed: %s", ex)
|
| 98 |
finally:
|
| 99 |
+
startup_timesfm_state["warming"] = False
|
frontend/index.html
CHANGED
|
@@ -3383,7 +3383,7 @@
|
|
| 3383 |
|
| 3384 |
<!-- Futuristic Overlays -->
|
| 3385 |
<div class="chart-bg-overlay"></div>
|
| 3386 |
-
<div class="chart-logo-overlay">
|
| 3387 |
|
| 3388 |
<!-- Workspace Grid Container -->
|
| 3389 |
<div id="workspaceGrid" class="workspace-grid layout-1">
|
|
@@ -5596,7 +5596,7 @@
|
|
| 5596 |
|
| 5597 |
document.getElementById('themeToggleBtn').onclick = () => {
|
| 5598 |
const newTheme = document.body.classList.contains('dark-theme') ? 'light' : 'dark';
|
| 5599 |
-
localStorage.setItem('
|
| 5600 |
applyTheme(newTheme);
|
| 5601 |
};
|
| 5602 |
|
|
@@ -6167,7 +6167,7 @@
|
|
| 6167 |
/* ββ Bootstrap ββ */
|
| 6168 |
(async () => {
|
| 6169 |
// Restore theme preference (Default: light)
|
| 6170 |
-
const savedTheme = localStorage.getItem('
|
| 6171 |
applyTheme(savedTheme);
|
| 6172 |
applyHeaderVisibility(resolveInitialHeaderVisibility());
|
| 6173 |
|
|
|
|
| 3383 |
|
| 3384 |
<!-- Futuristic Overlays -->
|
| 3385 |
<div class="chart-bg-overlay"></div>
|
| 3386 |
+
<div class="chart-logo-overlay">AI FORECAST</div>
|
| 3387 |
|
| 3388 |
<!-- Workspace Grid Container -->
|
| 3389 |
<div id="workspaceGrid" class="workspace-grid layout-1">
|
|
|
|
| 5596 |
|
| 5597 |
document.getElementById('themeToggleBtn').onclick = () => {
|
| 5598 |
const newTheme = document.body.classList.contains('dark-theme') ? 'light' : 'dark';
|
| 5599 |
+
localStorage.setItem('aiforecast_theme', newTheme);
|
| 5600 |
applyTheme(newTheme);
|
| 5601 |
};
|
| 5602 |
|
|
|
|
| 6167 |
/* ββ Bootstrap ββ */
|
| 6168 |
(async () => {
|
| 6169 |
// Restore theme preference (Default: light)
|
| 6170 |
+
const savedTheme = localStorage.getItem('aiforecast_theme') || 'light';
|
| 6171 |
applyTheme(savedTheme);
|
| 6172 |
applyHeaderVisibility(resolveInitialHeaderVisibility());
|
| 6173 |
|
frontend/workspace.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
| 7 |
*/
|
| 8 |
|
| 9 |
/* ββ Constants ββββββββββββββββββββββββββββββββββββββ */
|
| 10 |
-
const WORKSPACE_STORAGE_KEY = '
|
| 11 |
const CHART_HISTORY_LIMIT_WS = 500;
|
| 12 |
const MAX_CONCURRENT_FETCHES = 4;
|
| 13 |
const WS_RECONNECT_DELAY = 5000;
|
|
@@ -307,7 +307,7 @@ const StreamManager = {
|
|
| 307 |
return entry.ws;
|
| 308 |
}
|
| 309 |
|
| 310 |
-
const apiBase = window.
|
| 311 |
const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
| 312 |
const wsUrl = `${apiBase.replace(/^https?:\/\//, wsProtocol)}/ws/price/${symbol}?interval=${encodeURIComponent(interval)}`;
|
| 313 |
console.log(`[StreamManager] New WS: ${wsUrl} (pane ${paneId})`);
|
|
@@ -421,7 +421,7 @@ const DataCoordinator = {
|
|
| 421 |
return apiRequest(path, { signal });
|
| 422 |
}
|
| 423 |
// Fallback if apiRequest not yet defined
|
| 424 |
-
const apiBase = window.
|
| 425 |
const sep = path.includes('?') ? '&' : '?';
|
| 426 |
const url = `${apiBase}${path}${sep}_t=${Date.now()}`;
|
| 427 |
return fetch(url, { signal }).then(r => {
|
|
|
|
| 7 |
*/
|
| 8 |
|
| 9 |
/* ββ Constants ββββββββββββββββββββββββββββββββββββββ */
|
| 10 |
+
const WORKSPACE_STORAGE_KEY = 'aiforecast_workspace';
|
| 11 |
const CHART_HISTORY_LIMIT_WS = 500;
|
| 12 |
const MAX_CONCURRENT_FETCHES = 4;
|
| 13 |
const WS_RECONNECT_DELAY = 5000;
|
|
|
|
| 307 |
return entry.ws;
|
| 308 |
}
|
| 309 |
|
| 310 |
+
const apiBase = window.__AIFORECAST_API_BASE || '';
|
| 311 |
const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
| 312 |
const wsUrl = `${apiBase.replace(/^https?:\/\//, wsProtocol)}/ws/price/${symbol}?interval=${encodeURIComponent(interval)}`;
|
| 313 |
console.log(`[StreamManager] New WS: ${wsUrl} (pane ${paneId})`);
|
|
|
|
| 421 |
return apiRequest(path, { signal });
|
| 422 |
}
|
| 423 |
// Fallback if apiRequest not yet defined
|
| 424 |
+
const apiBase = window.__AIFORECAST_API_BASE || '';
|
| 425 |
const sep = path.includes('?') ? '&' : '?';
|
| 426 |
const url = `${apiBase}${path}${sep}_t=${Date.now()}`;
|
| 427 |
return fetch(url, { signal }).then(r => {
|