mirror of
https://github.com/RightNow-AI/openfang.git
synced 2026-04-26 01:35:10 +02:00
Open-source Agent OS built in Rust. - 14 crates, 1,767+ tests, zero clippy warnings - 7 autonomous Hands (Clip, Lead, Collector, Predictor, Researcher, Twitter, Browser) - 16 security systems (WASM sandbox, Merkle audit trail, taint tracking, Ed25519 signing, SSRF protection, secret zeroization, HMAC-SHA256 mutual auth, and more) - 30 pre-built agents across 4 performance tiers - 40 channel adapters (Telegram, Discord, Slack, WhatsApp, Teams, and 35 more) - 38 built-in tools + MCP client/server + A2A protocol - 26 LLM providers with intelligent routing and cost tracking - 60+ bundled skills with FangHub marketplace - Tauri 2.0 native desktop app - 140+ REST/WS/SSE API endpoints with Alpine.js dashboard - OpenAI-compatible /v1/chat/completions endpoint - One-command install, production-ready
133 lines
4.2 KiB
Rust
133 lines
4.2 KiB
Rust
//! Embedded WebChat UI served as static HTML.
|
|
//!
|
|
//! The production dashboard is assembled at compile time from separate
|
|
//! HTML/CSS/JS files under `static/` using `include_str!()`. This keeps
|
|
//! single-binary deployment while allowing organized source files.
|
|
//!
|
|
//! Features:
|
|
//! - Alpine.js SPA with hash-based routing (10 panels)
|
|
//! - Dark/light theme toggle with system preference detection
|
|
//! - Responsive layout with collapsible sidebar
|
|
//! - Markdown rendering + syntax highlighting (bundled locally)
|
|
//! - WebSocket real-time chat with HTTP fallback
|
|
//! - Agent management, workflows, memory browser, audit log, and more
|
|
|
|
use axum::http::header;
|
|
use axum::response::IntoResponse;
|
|
|
|
/// Compile-time ETag based on the crate version.
|
|
const ETAG: &str = concat!("\"openfang-", env!("CARGO_PKG_VERSION"), "\"");
|
|
|
|
/// Embedded logo PNG for single-binary deployment.
|
|
const LOGO_PNG: &[u8] = include_bytes!("../static/logo.png");
|
|
|
|
/// Embedded favicon ICO for browser tabs.
|
|
const FAVICON_ICO: &[u8] = include_bytes!("../static/favicon.ico");
|
|
|
|
/// GET /logo.png — Serve the OpenFang logo.
|
|
pub async fn logo_png() -> impl IntoResponse {
|
|
(
|
|
[
|
|
(header::CONTENT_TYPE, "image/png"),
|
|
(header::CACHE_CONTROL, "public, max-age=86400, immutable"),
|
|
],
|
|
LOGO_PNG,
|
|
)
|
|
}
|
|
|
|
/// GET /favicon.ico — Serve the OpenFang favicon.
|
|
pub async fn favicon_ico() -> impl IntoResponse {
|
|
(
|
|
[
|
|
(header::CONTENT_TYPE, "image/x-icon"),
|
|
(header::CACHE_CONTROL, "public, max-age=86400, immutable"),
|
|
],
|
|
FAVICON_ICO,
|
|
)
|
|
}
|
|
|
|
/// GET / — Serve the OpenFang Dashboard single-page application.
|
|
///
|
|
/// Returns the full SPA with ETag header based on package version for caching.
|
|
pub async fn webchat_page() -> impl IntoResponse {
|
|
(
|
|
[
|
|
(header::CONTENT_TYPE, "text/html; charset=utf-8"),
|
|
(header::ETAG, ETAG),
|
|
(
|
|
header::CACHE_CONTROL,
|
|
"public, max-age=3600, must-revalidate",
|
|
),
|
|
],
|
|
WEBCHAT_HTML,
|
|
)
|
|
}
|
|
|
|
/// The embedded HTML/CSS/JS for the OpenFang Dashboard.
|
|
///
|
|
/// Assembled at compile time from organized static files.
|
|
/// All vendor libraries (Alpine.js, marked.js, highlight.js) are bundled
|
|
/// locally — no CDN dependency. Alpine.js is included LAST because it
|
|
/// immediately processes x-data directives and fires alpine:init on load.
|
|
const WEBCHAT_HTML: &str = concat!(
|
|
include_str!("../static/index_head.html"),
|
|
"<style>\n",
|
|
include_str!("../static/css/theme.css"),
|
|
"\n",
|
|
include_str!("../static/css/layout.css"),
|
|
"\n",
|
|
include_str!("../static/css/components.css"),
|
|
"\n",
|
|
include_str!("../static/vendor/github-dark.min.css"),
|
|
"\n</style>\n",
|
|
include_str!("../static/index_body.html"),
|
|
// Vendor libs: marked + highlight first (used by app.js)
|
|
"<script>\n",
|
|
include_str!("../static/vendor/marked.min.js"),
|
|
"\n</script>\n",
|
|
"<script>\n",
|
|
include_str!("../static/vendor/highlight.min.js"),
|
|
"\n</script>\n",
|
|
// App code
|
|
"<script>\n",
|
|
include_str!("../static/js/api.js"),
|
|
"\n",
|
|
include_str!("../static/js/app.js"),
|
|
"\n",
|
|
include_str!("../static/js/pages/overview.js"),
|
|
"\n",
|
|
include_str!("../static/js/pages/chat.js"),
|
|
"\n",
|
|
include_str!("../static/js/pages/agents.js"),
|
|
"\n",
|
|
include_str!("../static/js/pages/workflows.js"),
|
|
"\n",
|
|
include_str!("../static/js/pages/workflow-builder.js"),
|
|
"\n",
|
|
include_str!("../static/js/pages/channels.js"),
|
|
"\n",
|
|
include_str!("../static/js/pages/skills.js"),
|
|
"\n",
|
|
include_str!("../static/js/pages/hands.js"),
|
|
"\n",
|
|
include_str!("../static/js/pages/scheduler.js"),
|
|
"\n",
|
|
include_str!("../static/js/pages/settings.js"),
|
|
"\n",
|
|
include_str!("../static/js/pages/usage.js"),
|
|
"\n",
|
|
include_str!("../static/js/pages/sessions.js"),
|
|
"\n",
|
|
include_str!("../static/js/pages/logs.js"),
|
|
"\n",
|
|
include_str!("../static/js/pages/wizard.js"),
|
|
"\n",
|
|
include_str!("../static/js/pages/approvals.js"),
|
|
"\n</script>\n",
|
|
// Alpine.js MUST be last — it processes x-data and fires alpine:init
|
|
"<script>\n",
|
|
include_str!("../static/vendor/alpine.min.js"),
|
|
"\n</script>\n",
|
|
"</body></html>"
|
|
);
|