Skip to content

srinivasrk/Chatbot

Repository files navigation

title Portfolio profile chatbot
emoji 💬
colorFrom blue
colorTo indigo
sdk docker
app_port 7860
pinned false

Chat with my profile — portfolio assistant

Turn your resume or LinkedIn PDF into a small “ask me anything (professional)” widget for your site. This project runs a Gradio chat UI on FastAPI, uses Google Gemini to answer in your voice (first person), and only uses facts from your profile file. A scope gate blocks random questions; rate limits help control API cost.

What you need: Python 3.11+, uv, and a Gemini API key.


How it works

At a high level, every message goes through rate limiting, then a quick “is this about my career?” check with Gemini. Only if that passes does the app call Gemini again for the full answer, still grounded in your profile text.

flowchart TB
  subgraph visitor [Visitor]
    Browser[Browser or iframe]
  end
  subgraph server [Python server]
    Gradio[Gradio chat UI]
    FastAPI[FastAPI plus CSP headers]
    Limiter[Rate limiter per IP]
    Gate[Scope gate small Gemini call]
    Chat[Main Gemini reply]
    Profile[Profile PDF MD or env text]
  end
  subgraph gemini [Google Gemini API]
    API[Gemini models]
  end
  Browser --> Gradio
  Gradio --> FastAPI
  FastAPI --> Limiter
  Limiter -->|under limit| Gate
  Limiter -->|friendly refusal| Gradio
  Gate -->|on topic| Chat
  Gate -->|refusal no main call| Gradio
  Profile -.->|baked into prompt at startup| Chat
  Gate --> API
  Chat --> API
  Chat --> Gradio
  Gradio --> Browser
Loading

Notes

  • Profile is read when the process starts (from Profile.pdf, another file, or PROFILE_CONTEXT). Restart after you change it.
  • Off-topic questions never trigger the big reply model call (saves tokens).
  • Deploying (e.g. Hugging Face) uses the Dockerfile: same app, same flow.

Pick a setup

I want to… Jump to
Run it on my laptop Local setup
Host free on Hugging Face Hugging Face Spaces
Embed it in my portfolio site Iframe embedding

Local setup

  1. Clone the repo and open a terminal in the project folder.

  2. Install dependencies

    uv sync
  3. Create your env file

    cp .env.example .env

    Edit .env and set GOOGLE_API_KEY (or GEMINI_API_KEY). Tweak models and limits if you like — see Configuration.

  4. Add your profile

    • Put Profile.pdf in the project root (text-based PDFs work best), or
    • Set PROFILE_PATH to another .pdf, .md, or .txt, or
    • Set PROFILE_CONTEXT to paste profile text (overrides the file).
  5. Start the app

    uv run uvicorn app:app --host 0.0.0.0 --port 7860

    Or: uv run python app.py

  6. Open http://127.0.0.1:7860


Hugging Face Spaces (hosting)

Hugging Face hosts the app as a Docker Space. The Gradio “template” Space type is not used here — this app starts with Uvicorn + FastAPI.

1. Create the Space

  1. Go to Create a new Space.
  2. Choose Docker (not the Gradio SDK).
  3. Template: Blank.
  4. Hardware: CPU Basic is enough for a portfolio widget.
  5. Visibility: Public if you want a link and iframe anyone can use.

Your Space gets its own Git repo on Hugging Face (it is not auto-linked to GitHub).

2. Add your API key (required)

On the Space: Settings → Variables and secrets → add:

  • GOOGLE_API_KEY — your Gemini key

Optional (same names as .env.example): GEMINI_MODEL, FRAME_ANCESTORS, PROFILE_CONTEXT, etc.

3. Push this code to the Space

From your computer, in a clone of this repository:

git remote add hf https://huggingface.co/spaces/YOUR_USERNAME/YOUR_SPACE_NAME
git push hf main
  • Git will ask for credentials: use a Hugging Face access token (with write access), not your password.

  • First push often fails with “remote contains work you do not have” because the Space was created with a tiny seed commit. Overwrite only the Space (safe for GitHub):

    git push hf main --force

After a successful push, Hugging Face rebuilds the Docker image. Watch Build logs if something fails.

4. Profile on the Space

  • Commit Profile.pdf (or profile.md) in the repo you push to the Space, or
  • Put the text in PROFILE_CONTEXT as a Space secret/variable (if multiline is supported for your account).

Rebuild after changing profile or secrets.

5. App URL and port

  • Public URL: https://huggingface.co/spaces/YOUR_USERNAME/YOUR_SPACE_NAME
  • The container listens on 7860 (see Dockerfile); the YAML block at the top of this README sets app_port: 7860 for the Hub.

Keeping GitHub and Hugging Face in sync

There is no universal “Import from GitHub” button Space-side; mirror from GitHub with one of these:

  • Add hf as a second remote and push to both origin and hf (see step 3 above), or
  • Use GitHub Actions in this repo (details below), following the same Hugging Face ↔ Actions pattern.

Automated sync (this repository)

File What it does
.github/workflows/sync-huggingface.yml On every push to main (and on manual Actions → Sync to Hugging Face Space), force-pushes the repo to your Space’s main with Git LFS enabled.
.github/workflows/huggingface-file-size.yml On PRs into main, warns if any file exceeds 10 MB (Spaces limit for non–Git LFS blobs).

In your GitHub repo: Settings → Secrets and variables → Actions

Kind Name Value
Secret HF_TOKEN Hugging Face access token with write access.
Variable HF_USERNAME Hub user or org that owns the Space (same as YOUR_USERNAME in spaces/YOUR_USERNAME/YOUR_SPACE_NAME).
Variable HF_SPACE_NAME Space slug (same as YOUR_SPACE_NAME in that URL).

Create the Space on Hugging Face first; the workflow only pushes Git history and does not create the Space.


Configuration

Environment variables drive the app. Locally, copy .env.example to .env. On Hugging Face, use Settings → Variables and secrets.

Variable Purpose
GOOGLE_API_KEY / GEMINI_API_KEY Gemini API authentication (GOOGLE_API_KEY wins if both are set).
GEMINI_MODEL Main chat model (default gemini-2.5-flash).
SCOPE_GATE_MODEL Cheaper/smaller model for allow/refuse (defaults to GEMINI_MODEL).
PROFILE_PATH Profile file relative to project root (default Profile.pdf).
PROFILE_CONTEXT If set, used instead of the file.
MAX_MESSAGE_CHARS Max user message length.
MAX_OUTPUT_TOKENS Max length of each assistant reply.
CHAT_TEMPERATURE Creativity for main replies (default 0.65).
SCOPE_GATE_MAX_OUTPUT_TOKENS Cap for gate JSON output.
RATE_LIMIT_MAX_MESSAGES / RATE_LIMIT_WINDOW_SECONDS Sliding-window rate limit per IP.
FRAME_ANCESTORS Sites allowed to embed your app (comma-separated, or * for any). https://huggingface.co is always appended automatically (unless you use *) so the Space App tab on Hugging Face keeps working—Hugging Face loads *.hf.space inside an iframe on huggingface.co.
HOST / PORT Used when running python app.py locally.

Model names and billing: Gemini models · Pricing.


Embedding in your portfolio (iframe)

The app sends Content-Security-Policy: frame-ancestors … and removes X-Frame-Options from your Space responses. Your FRAME_ANCESTORS list is merged with https://huggingface.co / https://www.huggingface.co so the Space App tab on the hub still works.

Hugging Face: use the *.hf.space URL in iframes (important)

URL Use case
https://huggingface.co/spaces/USER/SPACE Opening in a new tab / sharing a link. Hugging Face’s HTML shell often sets X-Frame-Options: denydo not use this as your iframe src on another site.
https://USER-SPACE.hf.space/ Iframe src on your portfolio. This hits your container directly; your app’s headers allow embedding from origins you listed in FRAME_ANCESTORS.

On your Space page, open the “…” / Embed menu if needed; the hf.space address is the one to embed.

  1. Set FRAME_ANCESTORS (Space variables) to your origins, e.g.

    FRAME_ANCESTORS=http://localhost:3000,http://127.0.0.1:5173,https://srini.fyi
  2. Example embed (replace with your real *.hf.space URL):

    <iframe
      src="https://srinirk23-srini-chatbot.hf.space/"
      title="Profile assistant"
      loading="lazy"
      referrerpolicy="strict-origin-when-cross-origin"
      style="width:100%;max-width:900px;height:720px;border:0;border-radius:12px;display:block;margin:0 auto"
    ></iframe>

If the iframe is blank, check the console for CSP errors and confirm src is *.hf.space, not huggingface.co/spaces/....


Project layout

Path Role
app.py Gradio UI, Gemini calls, FastAPI mount, iframe-friendly headers
config.py Settings; loads profile from PDF / MD / TXT / env
guardrails/scope.py Scope gate (profile-related questions only)
limits/ratelimit.py Sliding-window rate limit
Dockerfile Production / Hugging Face image
pyproject.toml · uv.lock Dependencies (uv)
.env.example Copy to .env locally

Tips and caveats

  • Two Gemini calls per allowed message (gate + main). Off-topic input stops after the gate.
  • Restart the server after changing the profile file or PROFILE_CONTEXT.
  • Image-only PDFs may yield almost no text; prefer exported text PDFs or Markdown.
  • Do not commit .env or API keys. Treat Profile.pdf as sensitive if it contains PII.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors