Skip to content
bimal1023Public

About

A personal AI assistant and automation agent that searches the web, reads the latest news, fetches research papers, monitors GitHub trends, and takes real actions like sending emails and Discord messages — all in a clean, streaming chat interface

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

46 Commits

Folders and files

Repository files navigation

Pulse

A personal AI assistant and automation agent built for real-world use — searches the web, reads the news, hunts new grad jobs and scores them against a resume, generates cover letters, monitors GitHub trends, fetches research papers, summarizes YouTube videos, and runs a daily interview-prep curriculum over email and Discord.

Live: pulse-rust-eta.vercel.app · Backend: Render · Frontend: Vercel

Built with FastAPI · React + Vite · OpenAI GPT-4.1 mini · APScheduler · GitHub Actions · SQLite · Gmail SMTP · Discord Webhooks


Features

  • Autonomous tool-calling agent — decides which tool to use, chains multiple tools together, and streams the final answer in real time
  • Real-time token streaming — SSE-based streaming replicates ChatGPT-style response delivery
  • Voice input — speak your query via Web Speech API, text fills automatically
  • Markdown rendering — responses render with proper headings, lists, bold, tables, and code blocks
  • Conversation history — all sessions saved to SQLite and accessible from the sidebar
  • Email OTP authentication — 6-digit code sent to owner's email, 5-minute expiry, restricts access to authorized user only
  • New grad job matching — Adzuna and Greenhouse postings fanned out across six role queries, deduped, filtered to entry level, then GPT-scored against the resume and delivered 3× daily
  • System design lessons — one concept per day with trade-offs, numbers worth quoting, and a scenario-based interview question with the follow-up they'll ask
  • DSA revision drills — one topic per day with a recognition pattern, a reusable Python template, a named problem, and the key insight hidden behind a Discord spoiler
  • Daily AI briefing — polished AI news summary emailed every morning at 8:00 AM ET
  • Motivation messages — angle and quote source rotate daily so no two days repeat
  • Nightly research summary — one highlighted Arxiv paper summarized and sent to Discord
  • AI/ML concept of the night — one technical concept explained and sent to Discord
  • Cover letter generator — paste a job description, get a formatted PDF cover letter emailed as an attachment
  • YouTube summarization — drop in a link, Pulse pulls the transcript and explains the video
  • Externally triggered schedules — GitHub Actions wakes the backend and fires each job, so a sleeping free-tier container can't silently skip a day
  • Mobile responsive — hamburger sidebar, 2-column card grid, optimized for all screen sizes
  • Rate limiting — SlowAPI limits on the agent, OTP, and cron endpoints
  • Input validation — roles, lengths, and content validated via Pydantic

Tools

11 tools callable by the agent:

Tool Description
search_web Search the web via Tavily API
get_news Fetch latest news articles via GNews API
get_wikipedia_summary Get factual summaries from Wikipedia
get_github_trending Get trending GitHub repos by language
get_arxiv_papers Fetch latest research papers from Arxiv
send_email Send a summary email to the owner
send_discord Post to the owner's Discord, auto-splitting past the 2000-char limit
get_jobs Search job listings via Adzuna API, limited to recent postings
get_greenhouse_jobs Search open roles across 29 top tech companies on Greenhouse
get_youtube_transcript Fetch a video transcript for summarization
generate_cover_letter Generate a PDF cover letter and email it

Automated Pipelines

10 scheduled jobs per day (times in ET):

Time What Happens
8:00 AM AI news briefing → email
8:30 AM Morning motivation → Discord
9:00 AM Job matching (Adzuna + Greenhouse, GPT-scored) → Discord
12:00 PM System design concept + interview scenario → Discord
2:30 PM Job matching → Discord
7:00 PM DSA revision drill → Discord
8:00 PM Job matching → Discord
9:00 PM Evening motivation → Discord
1:00 AM AI/ML concept of the night → Discord
1:20 AM Nightly research paper summary → Discord

Why jobs are triggered externally

APScheduler runs in-process, and Render's free tier spins the service down after ~15 minutes idle — so a job scheduled for 9:00 AM never fires unless something woke the container first, and APScheduler's default misfire_grace_time discards it rather than running it late.

The workflows in .github/workflows/ wake the service and POST /cron/{job} on schedule, so delivery doesn't depend on the container happening to be awake. Set EXTERNAL_JOB_CRON=true in production so the in-process trigger doesn't fire a duplicate.

Curriculum rotation

Interview prep and motivation rotate deterministically by day-of-year rather than random.choice, so a full cycle covers every topic exactly once with no repeats and no gaps:

List Size
System design concepts 40
System design scenarios 26
DSA topics 34
Motivation themes 32
Motivation quote sources 10

Each completed cycle also bumps the difficulty on the next pass.


Tech Stack

Layer Technology
Backend FastAPI, Python 3.11
AI Model OpenAI GPT-4.1 mini
Web Search Tavily API
News GNews API
Knowledge Wikipedia REST API
GitHub GitHub REST API
Research Arxiv API
Job Search Adzuna API + Greenhouse API
Video youtube-transcript-api (Webshare residential proxy in prod)
PDF Generation ReportLab
Email Gmail SMTP
Discord Discord Webhooks
Authentication Email OTP (Gmail SMTP)
Scheduler APScheduler + GitHub Actions cron
Database SQLite
Frontend React 19, Vite, react-markdown
Rate Limiting SlowAPI
Deployment Render (backend) + Vercel (frontend)

Project Structure

pulse/
├── .github/
│   └── workflows/
│       ├── job-alerts.yml      # Wakes Render + triggers job matching 3x daily
│       └── interview-prep.yml  # Triggers system design + DSA lessons
├── backend/
│   ├── app/
│   │   ├── agent.py        # Agentic loop — tool calling + streaming
│   │   ├── config.py       # Env var loading
│   │   ├── database.py     # SQLite connection and schema
│   │   ├── history.py      # Save and load task history
│   │   ├── main.py         # FastAPI app, OTP + cron endpoints, routes
│   │   ├── schemas.py      # Pydantic request/message models
│   │   ├── scheduler.py    # All 10 scheduled pipelines + curricula
│   │   ├── tools.py        # All 11 agent tools
│   │   └── resume.txt      # Resume + role targeting for job scoring and cover letters
│   ├── Dockerfile
│   ├── .env                # Secrets (not committed)
│   └── requirements.txt
└── frontend/
    ├── src/
    │   ├── App.jsx         # Full chat UI — streaming, voice, history, OTP lock
    │   ├── main.jsx
    │   └── index.css       # CSS variables, dark mode, lock screen styles
    ├── public/
    ├── index.html
    └── package.json

resume.txt drives both job scoring and cover letter generation — its Looking For section is what retargets the job alert at different roles.


Getting Started

Prerequisites

  • Python 3.11+
  • Node.js 18+
  • API keys for OpenAI, Tavily, GNews, and Adzuna

1. Clone the repo

git clone https://github.com/bimal1023/Pulse.git
cd Pulse

2. Backend setup

cd backend
python3 -m venv venv
source venv/bin/activate      # Windows: venv\Scripts\activate
pip install -r requirements.txt

Create a .env file in backend/:

OPENAI_API_KEY=sk-...
TAVILY_API_KEY=tvly-...
GNEWS_API_KEY=...

# Email (Gmail SMTP — use App Password)
EMAIL_SENDER=your-gmail@gmail.com
EMAIL_PASSWORD=your-16-char-app-password
EMAIL_RECEIVER=your-email@gmail.com

# Discord
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/...

# Adzuna Job Search
ADZUNA_APP_ID=...
ADZUNA_APP_KEY=...

# External cron (needed in production, optional locally)
CRON_SECRET=                  # Shared secret for POST /cron/{job}
EXTERNAL_JOB_CRON=            # "true" in prod — stops APScheduler double-firing job alerts

# Optional: only needed in prod for get_youtube_transcript.
# YouTube blocks datacenter IPs, so deployed fetches route through a residential proxy.
WEBSHARE_PROXY_USERNAME=
WEBSHARE_PROXY_PASSWORD=

Start the server:

uvicorn app.main:app --reload --host 127.0.0.1 --port 8002

3. Frontend setup

cd ../frontend
npm install

Create a .env.local file:

VITE_API_BASE=http://127.0.0.1:8002

Start the dev server:

npm run dev

Open http://localhost:5173.


Authentication

Pulse uses email OTP authentication to restrict access to the owner only.

  1. Open the app → lock screen appears
  2. Click Send Verification Code → 6-digit code sent to owner's email
  3. Enter the code → access granted for the session
  4. Session expires when the browser tab is closed

The verified token lives in memory on the server, so it is cleared whenever the container restarts. Automated schedules therefore use /cron/{job} with a shared secret instead.


API Reference

POST /run-agent

Runs the agentic loop and streams the response as Server-Sent Events. Requires the X-Auth-Token header.

{ "messages": [{ "role": "user", "content": "What's happening in AI today?" }] }
Event Payload Description
step { "tool": "get_news" } Tool is being called
token { "content": "..." } Streamed answer token
done { "steps": [...], "final_answer": "..." } Run complete

POST /send-otp

Generates a 6-digit OTP and sends it to the owner's email.

POST /verify-otp

Verifies the submitted OTP. Returns { "token": "pulse_authenticated" } on success.

GET /history · GET /history/{task_id}

Returns saved task history, newest first, or a single task by ID.

POST /cron/{job}

Triggers a scheduled pipeline from outside the container. Authenticated with the X-Cron-Secret header matched against CRON_SECRET.

curl -X POST -H "X-Cron-Secret: $CRON_SECRET" \
  https://your-backend.onrender.com/cron/jobs

Valid jobs: jobs, briefing, research, concept, motivation-morning, motivation-evening, system-design, dsa.


Deployment

Backend (Render)

Set every variable from the .env block above, including CRON_SECRET and EXTERNAL_JOB_CRON=true. Render auto-detects the Dockerfile in backend/ and deploys automatically.

Frontend (Vercel)

VITE_API_BASE=https://your-render-backend.onrender.com

Vercel auto-detects Vite and builds correctly.

Scheduled jobs (GitHub Actions)

Add two repository secrets under Settings → Secrets and variables → Actions:

Secret Value
BACKEND_URL Your Render URL, no trailing slash
CRON_SECRET Same value set in Render

Both workflows support Run workflow from the Actions tab for manual testing. Note that GitHub's scheduled runs are often delayed several minutes under load, and scheduled workflows are disabled automatically after 60 days of repository inactivity.


Rate Limiting

Endpoint Limit
/run-agent 5 requests/minute per IP
/send-otp 5 requests/hour per IP
/cron/{job} 10 requests/hour per IP
{ "detail": "Too many requests. Please wait before trying again." }

License

MIT

About

A personal AI assistant and automation agent that searches the web, reads the latest news, fetches research papers, monitors GitHub trends, and takes real actions like sending emails and Discord messages — all in a clean, streaming chat interface

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages