chat / README.md
incognitolm's picture
Initial
5383ef0 verified
|
Raw
History Blame
5.65 kB

InferencePort AI β€” Web Interface

HuggingFace Docker Space β€” Node.js WebSocket chat interface for InferencePort AI.

Environment Variables

Set these as Secrets in your HuggingFace Space settings:

Variable Required Description
SUPABASE_ANON_KEY Optional Supabase anon key (falls back to hardcoded value from app)
PUBLIC_URL Recommended Full public URL of your Space, e.g. https://your-user-your-space.hf.space

No SUPABASE_SERVICE_ROLE_KEY is needed β€” all DB operations use the user's own access token via RLS.

HuggingFace Space Setup

  1. Create a new Docker Space on HuggingFace
  2. Push this repository to the Space
  3. Set PUBLIC_URL secret to your space URL (needed for share links)
  4. The app listens on port 7860 which HuggingFace maps automatically

Supabase Tables Required

Run this SQL in your Supabase project's SQL Editor:

-- Web sessions (separate from Electron app's chat_sessions)
CREATE TABLE IF NOT EXISTS public.web_sessions (
  id          uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id     uuid NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
  name        text NOT NULL DEFAULT 'New Chat',
  history     jsonb DEFAULT '[]',
  model       text,
  created_at  timestamptz DEFAULT now(),
  updated_at  timestamptz DEFAULT now()
);

ALTER TABLE public.web_sessions ENABLE ROW LEVEL SECURITY;

CREATE POLICY "Users can manage their own web sessions"
  ON public.web_sessions FOR ALL
  USING (auth.uid() = user_id)
  WITH CHECK (auth.uid() = user_id);

-- Shared sessions (readable by anyone, writable by owner)
CREATE TABLE IF NOT EXISTS public.shared_sessions (
  id               uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  token            text UNIQUE NOT NULL,
  owner_id         uuid REFERENCES auth.users(id) ON DELETE CASCADE,
  session_snapshot jsonb NOT NULL,
  created_at       timestamptz DEFAULT now()
);

ALTER TABLE public.shared_sessions ENABLE ROW LEVEL SECURITY;

CREATE POLICY "Anyone can read shared sessions"
  ON public.shared_sessions FOR SELECT USING (true);

CREATE POLICY "Owners can insert shared sessions"
  ON public.shared_sessions FOR INSERT
  WITH CHECK (auth.uid() = owner_id);

-- User settings (theme, tool toggles)
CREATE TABLE IF NOT EXISTS public.user_settings (
  user_id    uuid PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
  settings   jsonb DEFAULT '{}',
  updated_at timestamptz DEFAULT now()
);

ALTER TABLE public.user_settings ENABLE ROW LEVEL SECURITY;

CREATE POLICY "Users manage own settings"
  ON public.user_settings FOR ALL
  USING (auth.uid() = user_id)
  WITH CHECK (auth.uid() = user_id);

The profiles table already exists from the Electron app and is reused as-is.

File Structure

inferenceport-web/
β”œβ”€β”€ Dockerfile
β”œβ”€β”€ package.json
β”œβ”€β”€ README.md
β”œβ”€β”€ server/
β”‚   β”œβ”€β”€ index.js          β€” Express + WebSocket server entry point
β”‚   β”œβ”€β”€ wsHandler.js      β€” All WebSocket message routing
β”‚   β”œβ”€β”€ sessionStore.js   β€” In-memory + Supabase session storage
β”‚   β”œβ”€β”€ chatStream.js     β€” Lightning API streaming + tool execution
β”‚   β”œβ”€β”€ auth.js           β€” Supabase auth verification, profile, subscription
β”‚   └── rateLimiter.js    β€” Simple sliding-window rate limiter
└── public/
    β”œβ”€β”€ index.html         β€” Single page app shell
    β”œβ”€β”€ oauth-callback.html β€” OAuth redirect handler
    β”œβ”€β”€ css/
    β”‚   β”œβ”€β”€ tokens.css     β€” CSS variables (colors, spacing, fonts)
    β”‚   β”œβ”€β”€ base.css       β€” Reset, global styles, animations
    β”‚   β”œβ”€β”€ sidebar.css    β€” Collapsible sidebar, session list
    β”‚   β”œβ”€β”€ chat.css       β€” Chat messages, code blocks, media
    β”‚   β”œβ”€β”€ input.css      β€” Center and bottom input bars
    β”‚   └── modals.css     β€” Modal overlays, settings, auth forms
    └── js/
        β”œβ”€β”€ ws.js          β€” WebSocket client (auto-reconnect, request/response)
        β”œβ”€β”€ auth.js        β€” Auth state, Supabase sign-in/out, OAuth
        β”œβ”€β”€ sessions.js    β€” Session list management and rendering
        β”œβ”€β”€ chat.js        β€” Chat rendering, streaming, versioning, editing
        β”œβ”€β”€ ui.js          β€” Notifications, context menus, markdown renderer
        β”œβ”€β”€ modals.js      β€” All modal dialogs (auth, share, settings, tool detail)
        β”œβ”€β”€ settings.js    β€” Settings modal, theme application
        └── app.js         β€” Bootstrap, input handling, sidebar, paste/attach

Architecture Notes

  • WebSocket is the primary transport for all chat, auth, and session operations
  • Server memory stores active sessions; Supabase is the persistence layer for logged-in users
  • Guest users get a tempId stored in localStorage; sessions live in server memory for 12h inactivity / 24h max, with a 15-message daily limit
  • On login, temp sessions are transferred to the user's Supabase account automatically
  • Chat versioning: each message stores versions[], where each version contains the message content plus the tail (all following messages at time of edit). Navigating versions via the β€Ή 1/N β€Ί arrows replays the stored tail
  • Device sessions are tracked in server memory only (lost on restart) β€” no service role key needed
  • Lightning at https://sharktide-lightning.hf.space/gen is used for all chat streaming and media generation

Local Development

npm install
PUBLIC_URL=http://localhost:7860 npm run dev

Then open http://localhost:7860.