Skip to content

Trishix/ubot

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

38 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

UBOT

UBOT is an intelligent platform that lets you clone your professional identity into an AI chatbot. It digests your Resume (PDF) and GitHub profile to create a conversational agent that speaks for you, answers recruiters' questions, and showcases your skillsβ€”24/7.

UBOT Terminal Interface

UBOT Terminal Interface UBOT Analytics/Settings

πŸ“ Class Diagram

classDiagram
    direction TB

    %% ── DATA MODELS (src/lib/types.ts) ──
    class PortfolioData {
        <<interface>>
        +name : string
        +role : string
        +bio : string
        +skills : string[]
        +github : string
        +socials? : Socials
    }

    class Profile {
        <<interface>>
        +id : string
        +username : string
        +portfolio_data : PortfolioData
        +created_at : string
    }

    class ChatMessage {
        <<type>>
        +role : "user" | "assistant" | "system"
        +content : string
    }

    class ContactEmailData {
        <<interface>>
        +name : string
        +email : string
        +subject : string
        +message : string
    }

    Profile *-- PortfolioData : contains

    %% ── DATABASE TABLES (Supabase) ──
    class ProfilesTable {
        <<Supabase Table>>
        +id : bigint
        +user_id : uuid
        +username : string
        +portfolio_data : jsonb
        +created_at : timestamp
    }

    class DocumentsTable {
        <<Supabase Table>>
        +id : bigint
        +user_id : uuid
        +content : text
        +metadata : jsonb
        +embedding : vector~3072~
    }

    class MatchDocuments {
        <<Supabase RPC>>
        +query_embedding : vector~3072~
        +match_threshold : float
        +match_count : int
        +filter_user_id : uuid
        returns(id, content, metadata, similarity)
    }

    ProfilesTable "1" --> "0..*" DocumentsTable : user_id
    DocumentsTable ..> MatchDocuments : queried via

    %% ── LIBRARY / SERVICES (src/lib/) ──
    class AIProvider {
        <<module: ai-provider.ts>>
        +MODELS : CHAT
        -GOOGLE_KEYS : string[]
        -groq : OpenAI-compatible client
        +withRetry~T~(fn, retries) T
        +generateEmbedding(text) number[]
        +generateEmbeddings(texts) number[][]
    }

    class SupabaseBrowserClient {
        <<module: supabase.ts>>
        +supabase : SupabaseClient
    }

    class SupabaseServerClient {
        <<module: supabase-server.ts>>
        +createClient() SupabaseClient
    }

    class EmailService {
        <<module: email.ts>>
        +sendContactEmail(data) void
        +sendContactConfirmationEmail(data) void
    }

    class EnvValidator {
        <<module: env.ts>>
        +validateEnv() bool
    }

    EmailService ..> ContactEmailData : uses

    %% ── MIDDLEWARE (src/middleware.ts) ──
    class Middleware {
        <<middleware.ts>>
        +middleware(request) Response
        #protects /dashboard
        #protects /api/ingest
        #protects /api/profile
    }

    Middleware ..> SupabaseServerClient : creates client

    %% ── API ROUTES (src/app/api/) ──
    class ChatAPI {
        <<api/chat/[username]>>
        +POST(req, params) StreamingResponse
        +OPTIONS() Response
    }

    class IngestAPI {
        <<api/ingest>>
        +POST(req) Response
        +OPTIONS() Response
    }

    class ProfileAPI {
        <<api/profile>>
        +GET(req) Response
        +DELETE(req) Response
    }

    class CheckUsernameAPI {
        <<api/check-username>>
        +GET(req) Response
    }

    class ContactAPI {
        <<api/contact>>
        +POST(req) Response
    }

    class AuthCallbackAPI {
        <<api/auth/callback>>
        +GET(request) Redirect
    }

    ChatAPI ..> AIProvider : withRetry, generateEmbedding
    ChatAPI ..> ChatMessage : uses
    ChatAPI ..> ProfilesTable : queries
    ChatAPI ..> DocumentsTable : vector search

    IngestAPI ..> AIProvider : withRetry, generateEmbeddings
    IngestAPI ..> ProfilesTable : upserts
    IngestAPI ..> DocumentsTable : inserts

    ProfileAPI ..> ProfilesTable : queries / deletes
    CheckUsernameAPI ..> ProfilesTable : queries

    ContactAPI ..> EmailService : sends email
    AuthCallbackAPI ..> SupabaseServerClient : creates client

    %% ── PAGE COMPONENTS (src/app/) ──
    class RootLayout {
        <<layout.tsx>>
        +children : ReactNode
    }

    class LandingPage {
        <<page.tsx>>
        -session : Session
    }

    class DashboardPage {
        <<dashboard/page.tsx>>
        -user : User
        -username : string
        -existingProfile : Profile
        +handleGenerate(e)
        +handleDelete()
        +handleLogout()
    }

    class PublicBotPage {
        <<chat/[username]/page.tsx>>
        -profile : Profile
        +renderMarkdown(text)
        +handleCustomSubmit(e)
    }

    class Navbar {
        <<components/Navbar.tsx>>
        -user : SupabaseUser
        +navLinks : NavLink[]
    }

    RootLayout *-- Navbar : renders
    RootLayout ..> EnvValidator : validateEnv

    LandingPage ..> SupabaseBrowserClient : auth state
    DashboardPage ..> SupabaseBrowserClient : auth state
    DashboardPage ..> IngestAPI : POST
    DashboardPage ..> ProfileAPI : GET / DELETE
    DashboardPage ..> CheckUsernameAPI : GET

    PublicBotPage ..> SupabaseBrowserClient : fetch profile
    PublicBotPage ..> ChatAPI : streaming chat

    Navbar ..> SupabaseBrowserClient : auth state
Loading

🧠 How It Works

1. Ingestion & Processing

  • Input: You upload a PDF Resume and optionally provide a GitHub username.
  • Parsing:
    • pdf-parse extracts text from your resume.
    • GitHub API fetches your profile, pinned repositories, and bio.
  • Persona Generation:
    • Groq (llama-3.3-70b-versatile) analyzes this raw data to build a structured JSON profile.
  • Vector Embeddings (RAG):
    • Google Gemini Embeddings: We use gemini-embedding-001 (3072 dimensions) for high-accuracy semantic search.
    • Key Rotation: To bypass free-tier quota limits, the system automatically rotates through up to 5 Google API keys.
    • Vectors are stored in Supabase (PostgreSQL + pgvector).
  • Source Attribution:
    • All ingested data is transparently tagged (e.g., [Source: Resume], [Source: GitHub]) so the bot knows where its knowledge comes from.

2. The Chat Experience

  • Retrieval Augmented Generation (RAG):
    • When a user asks a question, we generate a 3072-dim embedding for their query using rotated Google keys.
    • We perform a semantic search in Supabase retrieving up to 10 context chunks for breadth.
  • Response Generation:
    • The relevant context is fed into Groq, which answers in the first person ("I built...", "My experience...").
    • The system uses retry logic with the llama-3.3-70b-versatile model for reliability.
  • Markdown Rendering:
    • AI responses render bold, italic, inline code, bullet points, headings, and links as formatted text β€” not raw markdown.

πŸ› οΈ Compute Stack

Component Technology Description
Framework Next.js 16 App Router, Server Components.
LLM Inference Groq llama-3.3-70b-versatile for chat and persona generation.
Embeddings Google AI gemini-embedding-001 (3072 dims) with multi-key rotation.
Database Supabase PostgreSQL + pgvector for storage and semantic search.
Styling Tailwind CSS v4 Terminal/hacker glassmorphism aesthetic with CRT overlay effect.
Auth Supabase Auth Email/password and Google OAuth with session management.
Email Resend Transactional emails for contact forms.

β™Ώ Accessibility & UI/UX

UBOT follows industry-standard UI/UX best practices:

  • Focus States: Visible green focus rings on all interactive elements via focus-visible.
  • Keyboard Navigation: Skip-to-content link, aria-expanded on toggles, role="menu" on mobile nav.
  • Forms: All labels paired with inputs (htmlFor/id), required-field asterisks, autoComplete attributes.
  • Semantic HTML: <section>, <aside>, <main>, role="log", role="alert", aria-live regions.
  • Error States: Icon + colored background + actionable text (not color-only).
  • Typography: 16px body base, 1.6 line-height, minimum 14px for all visible text.
  • Tap Targets: All buttons and links meet 44Γ—44px minimum for mobile.
  • External Links: rel="noopener noreferrer" on all external links.

🚦 Getting Started

Prerequisites

  • Node.js 20+
  • Supabase Account (with vector extension enabled)
  • Groq API Key
  • Google AI Studio Keys (Free tier works! Get multiple for rotation)

Installation

  1. Clone & Install

    git clone https://github.com/Trishix/ubot.git
    cd ubot
    npm install
  2. Environment Setup Create .env.local:

    # Supabase
    NEXT_PUBLIC_SUPABASE_URL=...
    NEXT_PUBLIC_SUPABASE_ANON_KEY=...
    SUPABASE_SERVICE_ROLE_KEY=...
    
    # Groq (Chat & Persona)
    GROQ_API_KEY=...
    NEXT_PUBLIC_SITE_URL=https://your-domain.vercel.app
    
    # Google (Embeddings Key Rotation)
    FREE_API_KEY_1=...
    FREE_API_KEY_2=...
    FREE_API_KEY_3=...
    FREE_API_KEY_4=...
    FREE_API_KEY_5=...
    
    # Resend (Contact Form)
    RESEND_API_KEY=...
  3. Database Setup (SQL) Run this in your Supabase SQL Editor:

    -- Enable Vector Extension
    create extension if not exists vector;
    
    -- Documents Table for RAG
    create table documents (
      id bigserial primary key,
      content text,
      metadata jsonb,
      embedding vector(3072), -- Matches gemini-embedding-001 dimensions
      user_id uuid references auth.users not null
    );
    
    -- Search Function
    create or replace function match_documents (
      query_embedding vector(3072),
      match_threshold float,
      match_count int,
      filter_user_id uuid
    ) returns table (
      id bigint,
      content text,
      metadata jsonb,
      similarity float
    ) language plpgsql stable as $$
    begin
      return query select
        id,
        content,
        metadata,
        1 - (documents.embedding <=> query_embedding) as similarity
      from documents
      where 1 - (documents.embedding <=> query_embedding) > match_threshold
      and user_id = filter_user_id
      order by documents.embedding <=> query_embedding
      limit match_count;
    end;
    $$;
  4. Run Development Server

    npm run dev

πŸ“„ License

MIT License. Built for the future of work.

About

An AI chatbot generator for your Portfolio

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages