Generate context-aware, human-like LinkedIn comments in real time using a LangGraph multi-agent workflow with Groq Llama 3.3 and Gemini fallback.
Features | Architecture | Quick Start | Testing | API Reference | Extension Setup
LinkedIn AI Comment Copilot is a full-stack application consisting of a Chrome Extension and a FastAPI backend that work together to analyze LinkedIn posts and generate high-quality, context-aware comments. The system uses a LangGraph multi-agent workflow with four specialized agents β each powered by the optimal LLM for its task β to ensure every comment is relevant, professional, and human-sounding.
Key highlights:
- No database required
- No user authentication
- No data storage β everything runs in real time
- ChatLiteLLMRouter for automatic model fallback (Groq primary, Gemini fallback)
- LangSmith observability for full trace visibility
- Multiple comment tones to match your style
- Comment card with Copy, Insert, and Dismiss actions
- One-click deploy to Render
| Feature | Description |
|---|---|
| Post Detection | Automatically detects all visible LinkedIn posts using action-bar-first strategy |
| AI Comment Button | Injects exactly one "Generate AI Comment" button per post (no duplicates) |
| Comment Card | Displays generated comment in a prominent card with Copy, Insert, and Dismiss buttons |
| Insert to LinkedIn | Automatically opens LinkedIn's comment box and fills it with the generated comment |
| Tone Selector | Choose from 10 comment tones: Professional, Technical, Supportive, Networking, Thoughtful, Friendly, Encouraging, Curious, Founder, Recruiter |
| Per-Agent Model Routing | Each agent uses the optimal LLM β Groq Llama 3.3 70B primary, Gemini 2.5 Flash fallback via ChatLiteLLMRouter |
| LangSmith Observability | Full trace visibility for every request through the multi-agent pipeline |
| One-Click Copy | Copy generated comments to clipboard instantly |
| Regenerate | Generate alternative variations with a single click |
| Quality Review | Built-in reviewer agent scores and approves comments before delivery |
| LLM Cost Tracking | Built-in cost measurement β test single-call cost via /test-cost endpoint |
graph TD
A[LinkedIn Page] -->|Detects Posts| B[Chrome Extension]
B -->|Extracts Content| C[Content Script]
C -->|"Click 'Generate AI Comment'"| D[Background Service Worker]
D -->|"POST /generate-comment"| E[FastAPI Backend]
E -->|Configures| LS[LangSmith Tracing]
E -->|Invokes| F[LangGraph Workflow]
F --> G["1. Analyzer Agent<br/><i>Groq Llama 3.3 70B</i><br/><small>Gemini fallback</small>"]
G -->|post_type, category, sentiment| H["2. Planner Agent<br/><i>Groq Llama 3.3 70B</i><br/><small>Gemini fallback</small>"]
H -->|strategy| I["3. Writer Agent<br/><i>Groq Llama 3.3 70B</i><br/><small>Gemini fallback</small>"]
I -->|generated_comment| J["4. Reviewer Agent<br/><i>Groq Llama 3.3 70B</i><br/><small>Gemini fallback</small>"]
J -->|Approved| K[Return Comment]
J -->|Rejected| I
K --> E
E -->|Response| D
D -->|Broadcast| L[Comment Card]
L -->|Copy / Insert| M[User Action]
style A fill:#0A66C2,color:#fff
style F fill:#FF6B35,color:#fff
style G fill:#F55036,color:#fff
style H fill:#F55036,color:#fff
style I fill:#F55036,color:#fff
style J fill:#F55036,color:#fff
style LS fill:#6C47FF,color:#fff
sequenceDiagram
participant User as LinkedIn User
participant CS as Content Script
participant BG as Background Worker
participant API as FastAPI Backend
participant Card as Comment Card
User->>CS: Click "Generate AI Comment"
CS->>CS: Extract post content
CS->>BG: sendMessage(GENERATE_COMMENT)
BG->>API: POST /generate-comment
API-->>BG: {comment: "..."}
BG->>BG: Persist to chrome.storage.local
BG-->>CS: {success: true, comment}
CS->>Card: showCommentNotification(comment)
Card-->>User: Display comment card with Copy/Insert
User->>Card: Click "Insert Comment"
Card->>CS: insertCommentIntoLinkedIn(comment)
CS->>CS: Poll for comment box, insert text
linkedin-ai-comment-copilot/
βββ backend/
β βββ main.py # FastAPI application entry point
β βββ agents/
β β βββ analyzer.py # Post classification agent
β β βββ planner.py # Comment strategy planner
β β βββ writer.py # Comment generation agent
β β βββ reviewer.py # Quality assurance agent
β βββ graph/
β β βββ comment_graph.py # LangGraph workflow definition
β βββ models/
β β βββ llm.py # LLM configs + cost tracking + ChatLiteLLMRouter
β β βββ model_router.py # Model selection utilities
β βββ prompts/
β β βββ analyzer_prompt.py # Analyzer system prompt
β β βββ planner_prompt.py # Planner system prompt
β β βββ writer_prompt.py # Writer system prompt
β β βββ reviewer_prompt.py # Reviewer system prompt
β βββ schemas/
β β βββ request.py # Pydantic request models
β β βββ response.py # Pydantic response models
β βββ tests/ # pytest test suite (126 tests)
β β βββ conftest.py # Shared fixtures & test config
β β βββ test_schemas.py # Pydantic schema validation tests
β β βββ test_model_router.py # Model routing & keyword detection
β β βββ test_llm.py # LLM config, pricing & cost calculation
β β βββ test_prompts.py # Prompt template validation
β β βββ test_analyzer.py # Analyzer agent tests
β β βββ test_planner.py # Planner agent tests
β β βββ test_writer.py # Writer agent tests
β β βββ test_reviewer.py # Reviewer agent tests
β β βββ test_comment_graph.py # LangGraph workflow tests
β β βββ test_api.py # FastAPI endpoint tests
β βββ test_models.py # Model connectivity test script
β βββ requirements.txt # Python dependencies
β βββ .env.example # Environment variable template
β
βββ doc/
β βββ ARCHITECTURE.md # System architecture & mermaid diagrams
β βββ LANGGRAPH_WORKFLOW.md # Detailed agent pipeline documentation
β βββ MODEL_AND_LLM_INTEGRATION.md # LLM configuration & model docs
β βββ ENVIRONMENT_SETUP.md # Environment setup guide
β βββ API_REFERENCE.md # Complete API documentation
β
βββ extension/
β βββ manifest.json # Chrome Extension Manifest V3
β βββ content.js # LinkedIn page injection script
β βββ content.css # Injected button styles
β βββ popup.html # Extension popup UI
β βββ popup.js # Popup logic & API calls
β βββ popup.css # Popup styles
β βββ background.js # Service worker for API calls
β βββ icons/ # Extension icons (16/32/48/128px)
β
βββ README.md
| Component | Technology | Purpose |
|---|---|---|
| Framework | FastAPI | Async API server |
| AI Orchestration | LangGraph | Multi-agent workflow |
| LLM Integration | LangChain + LiteLLM + ChatLiteLLMRouter | Prompt management, LLM calls & automatic fallback |
| Primary LLM | Llama 3.3 70B (Groq) | Fast, reliable comment generation & analysis |
| Fallback LLM | Gemini 2.5 Flash (Google AI) | Automatic fallback when Groq is unavailable |
| Observability | LangSmith | Tracing, monitoring & debugging |
| Validation | Pydantic | Request/response schemas |
| Server | Uvicorn | ASGI server |
| Component | Technology | Purpose |
|---|---|---|
| Manifest | V3 | Chrome Extension standard |
| Frontend | Vanilla JS + HTML/CSS | Lightweight, no dependencies |
| API | Chrome Extension APIs | Tab management, storage, messaging |
| Permissions | activeTab, storage, clipboardWrite |
Minimal required permissions |
All agents use Groq Llama 3.3 70B as primary with Gemini 2.5 Flash as automatic fallback via ChatLiteLLMRouter.
| Agent | Primary Model | Fallback Model | Temperature | Purpose |
|---|---|---|---|---|
| Analyzer | groq/llama-3.3-70b-versatile |
gemini/gemini-2.5-flash |
0.3 | Post classification, sentiment analysis |
| Planner | groq/llama-3.3-70b-versatile |
gemini/gemini-2.5-flash |
0.5 | Comment strategy determination |
| Writer | groq/llama-3.3-70b-versatile |
gemini/gemini-2.5-flash |
0.7 | Comment generation |
| Reviewer | groq/llama-3.3-70b-versatile |
gemini/gemini-2.5-flash |
0.3 | Quality scoring & approval |
- Python 3.11 or higher
- Google Chrome browser
- Groq API key (free tier available) β Required
- (Optional) Google AI API key β Enables Gemini fallback
- (Optional) LangSmith API key for tracing
git clone https://github.com/himanshu231204/linkedin-ai-comment-copilot.git
cd linkedin-ai-comment-copilot# Navigate to backend
cd backend
# Create virtual environment
python -m venv venv
# Activate virtual environment
# Windows:
venv\Scripts\activate
# macOS/Linux:
source venv/bin/activate
# Install dependencies
pip install -r requirements.txt
# Create environment file
cp .env.example .env
# Add your API keys to .envEdit backend/.env with your API keys:
# Required β Groq (all agents primary)
GROQ_API_KEY=your_groq_api_key_here
# Optional β Google AI (Gemini fallback when Groq fails)
GOOGLE_API_KEY=your_google_api_key_here
# Optional β LangSmith tracing
LANGSMITH_API_KEY=your_langsmith_api_key_here
LANGSMITH_PROJECT=linkedin-ai-comment-copilotcd backend
python -m pytest tests/ -vAll 126 tests should pass. No API keys are needed β all LLM calls are mocked.
python -m backend.test_modelsYou should see all models pass (requires API keys in .env):
[+] Direct: Analyzer (Groq Llama 3.3 70B): PASS
[+] Direct: Planner (Groq Llama 3.3 70B): PASS
[+] Direct: Writer (Groq Llama 3.3 70B): PASS
[+] Direct: Reviewer (Groq Llama 3.3 70B): PASS
[+] Router: Groq to Gemini: PASS
[+] Router Fallback: PASS
[+] Agent: Analyzer: PASS
[+] Agent: Planner: PASS
[+] Agent: Writer: PASS
[+] Agent: Reviewer: PASS
# Option 1 β From the backend directory:
cd backend
uvicorn main:app --reload --host 0.0.0.0 --port 8000
# Option 2 β From the project root:
uvicorn backend.main:app --reload --host 0.0.0.0 --port 8000The API will be available at http://localhost:8000. Verify it's running:
curl http://localhost:8000/health
# {"status": "healthy"}- Open Chrome and navigate to
chrome://extensions/ - Enable Developer mode (toggle in top-right corner)
- Click Load unpacked
- Select the
extension/folder from this project - The extension icon will appear in your Chrome toolbar
- Navigate to linkedin.com/feed
- Open the extension popup by clicking the icon in your toolbar
- Select your preferred comment tone
- Click "Generate AI Comment" on any post
- A comment card appears with the generated comment
- Click Copy to copy to clipboard, or Insert Comment to paste into LinkedIn's comment box
Generate a LinkedIn comment using the multi-agent workflow.
Request Body:
{
"post_content": "Just started my new role as Software Engineer at Google! Excited for this new chapter.",
"tone": "professional"
}Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
post_content |
string | Yes | LinkedIn post content (1-5000 chars) |
tone |
string | Yes | Comment tone/style |
Available Tones:
| Tone | Description |
|---|---|
professional |
Business-appropriate, formal |
technical |
Technical depth and expertise |
supportive |
Encouraging and empathetic |
networking |
Relationship-building focused |
thoughtful |
Deep, reflective insights |
friendly |
Warm and approachable |
encouraging |
Motivating and uplifting |
curious |
Question-driven engagement |
founder |
Entrepreneurial perspective |
recruiter |
Talent-focused messaging |
Response:
{
"comment": "Congratulations on the new role! Wishing you an exciting and impactful journey at Google."
}Check API health status.
Response:
{
"status": "healthy"
}Measure the cost of a single LLM call.
Parameters:
| Param | Values | Model Tested |
|---|---|---|
agent |
analyzer, planner |
Gemini 2.5 Flash |
agent |
writer, reviewer |
Groq Llama 3.3 70B |
Example:
curl -X POST http://localhost:8000/test-cost?agent=analyzerResponse:
{
"model": "gemini/gemini-2.5-flash",
"prompt_tokens": 150,
"completion_tokens": 50,
"total_tokens": 200,
"input_cost_usd": 0.000045,
"output_cost_usd": 0.000125,
"total_cost_usd": 0.00017
}The backend includes built-in LLM cost measurement. Every LLM call can be tracked for token usage and USD cost.
sequenceDiagram
participant Client
participant API as FastAPI
participant LLM as LLM Provider
participant Cost as Cost Tracker
Client->>API: POST /test-cost?agent=analyzer
API->>LLM: Send sample prompt to Gemini 2.5 Flash
LLM-->>API: Response + token usage
API->>Cost: get_llm_cost(response, model_name)
Cost-->>API: LLMCostResult (tokens + USD cost)
API-->>Client: {model, tokens, cost_usd}
# Test Gemini Flash (analyzer/planner)
curl -X POST http://localhost:8000/test-cost?agent=analyzer
# Test Groq Llama (writer/reviewer)
curl -X POST http://localhost:8000/test-cost?agent=writerfrom backend.models.llm import get_llm_cost, create_llm, get_analyzer_llm_config
config = get_analyzer_llm_config()
llm = create_llm(config)
response = await llm.ainvoke(messages)
cost = get_llm_cost(response, config.model_name)
print(f"Model: {cost.model}")
print(f"Tokens: {cost.prompt_tokens} in / {cost.completion_tokens} out")
print(f"Cost: ${cost.total_cost_usd}")| Model | Input (per 1M tokens) | Output (per 1M tokens) |
|---|---|---|
gemini/gemini-2.5-flash |
$0.15 | $0.60 |
groq/llama-3.3-70b-versatile |
$0.59 | $0.79 |
The content script uses an action-bar-first strategy to detect LinkedIn posts:
- Finds all social buttons (Like, Comment, Share) by text content
- Walks up the DOM to find the action bar container
- Walks further up to find the post container using heuristics
- Injects exactly one button per post using a
WeakSetto track processed action bars
This approach works with LinkedIn's obfuscated CSS-in-JS DOM because it relies on button text content (which never changes) rather than class names (which change every deploy).
When the button is clicked:
- Content Script sends
GENERATE_COMMENTmessage to Background Worker - Background Worker calls the FastAPI API
- LangGraph Pipeline executes 4 agents sequentially (each with automatic GroqβGemini fallback via ChatLiteLLMRouter):
- Analyzer (Groq Llama 3.3 70B): Classifies post type, category, sentiment
- Planner (Groq Llama 3.3 70B): Determines comment strategy
- Writer (Groq Llama 3.3 70B): Generates the comment
- Reviewer (Groq Llama 3.3 70B): Scores and approves/rejects
- Background Worker persists the comment and broadcasts to Content Script
- Content Script displays the comment in a card
The comment card provides:
- Copy: One-click copy to clipboard
- Insert Comment: Opens LinkedIn's comment box and fills it with the generated comment using polling to wait for the dynamic comment box
- Dismiss: Close the card (auto-dismisses after 60 seconds)
The Reviewer agent evaluates the generated comment on:
- Relevance to the post content
- Human-likeness and natural flow
- Spam score (low is better)
- Generic score (low is better)
- Professionalism and appropriateness
If the comment doesn't meet quality standards (score < 80), the workflow loops back to the Writer for regeneration.
All requests are automatically traced through LangSmith when configured. Each agent call, LLM invocation, and graph transition is logged.
Trace flow per request:
sequenceDiagram
participant Client
participant API as FastAPI
participant Graph as LangGraph
participant A as Analyzer
participant P as Planner
participant W as Writer
participant R as Reviewer
participant LS as LangSmith
Client->>API: POST /generate-comment
API->>Graph: ainvoke(state)
Graph->>A: analyze_post()
A->>A: Groq Llama 3.3 70B (or Gemini fallback)
A-->>LS: Trace: Analyzer
A-->>Graph: post_type, category, sentiment
Graph->>P: plan_strategy()
P->>P: Groq Llama 3.3 70B (or Gemini fallback)
P-->>LS: Trace: Planner
P-->>Graph: strategy
Graph->>W: write_comment()
W->>W: Groq Llama 3.3 70B (or Gemini fallback)
W-->>LS: Trace: Writer
W-->>Graph: generated_comment
Graph->>R: review_comment()
R->>R: Groq Llama 3.3 70B (or Gemini fallback)
R-->>LS: Trace: Reviewer
R-->>Graph: approved/score
Graph-->>API: final_comment
API-->>Client: {comment: "..."}
View traces at: https://smith.langchain.com
---| Variable | Required | Description |
|---|---|---|
GROQ_API_KEY |
Yes | Groq API key (primary LLM for all agents) |
GOOGLE_API_KEY |
No | Google AI API key (Gemini fallback when Groq fails) |
LANGSMITH_API_KEY |
No | LangSmith API key for tracing |
LANGSMITH_PROJECT |
No | LangSmith project name (default: linkedin-ai-comment-copilot) |
HOST |
No | Server host (default: 0.0.0.0) |
PORT |
No | Server port (default: 8000) |
The backend is pre-configured to accept requests from all origins (Chrome Extension, localhost, LinkedIn). For production, you may want to restrict allow_origins in main.py.
# Option 1 β Run from the backend directory:
cd backend
uvicorn main:app --reload
# Option 2 β Run from the project root:
uvicorn backend.main:app --reload
# API docs available at
# http://localhost:8000/docs (Swagger UI)
# http://localhost:8000/redoc (ReDoc)Note: Both run options work. All Python modules use dual imports (
try/except) so they work whether imported as a package (backend.main) or run directly (mainfrom insidebackend/).
After making changes to the extension:
- Go to
chrome://extensions/ - Click the refresh icon on your extension
- Hard refresh the LinkedIn page (
Ctrl+Shift+R)
The content script exposes debug utilities in the browser console (select the content script context from the DevTools dropdown):
// Check current state (posts found, buttons, login status)
AICopilotDebug()
// Test the full message flow (content β background β API)
AICopilotTestFlow()
// Inspect DOM structure around social buttons
AICopilotInspectButtons()The backend includes a comprehensive pytest test suite with 126 tests covering schemas, LLM configuration, model routing, prompts, all 4 agents, the LangGraph workflow, and FastAPI endpoints.
| Test File | Tests | Coverage |
|---|---|---|
test_schemas.py |
12 | Pydantic request/response validation |
test_model_router.py |
15 | Technical keyword detection & routing logic |
test_llm.py |
20 | LLMConfig, create_llm, pricing, cost calculation |
test_prompts.py |
15 | Prompt template variables & formatting |
test_analyzer.py |
6 | Post classification agent |
test_planner.py |
6 | Comment strategy planner |
test_writer.py |
5 | Comment generation agent |
test_reviewer.py |
5 | Quality review & approval |
test_comment_graph.py |
8 | LangGraph workflow & conditional routing |
test_api.py |
12 | FastAPI endpoints (health, generate, cost) |
| Total | 126 |
# Run all tests
cd backend
python -m pytest tests/ -v
# Run a specific test file
python -m pytest tests/test_llm.py -v
# Run a specific test class
python -m pytest tests/test_api.py::TestHealthEndpoint -v
# Run with coverage report
python -m pytest tests/ -v --cov=backend --cov-report=term-missing- No real API calls: All LLM and agent calls are mocked β no API keys required to run tests
- Deterministic: Tests use fixed mock responses, not random LLM output
- Fast: Full suite runs in ~30 seconds
- Isolated: Each test is independent with clean state
# Agent tests mock at the create_{agent}_agent_with_router level
with patch("backend.agents.analyzer.create_analyzer_agent_with_router", return_value=mock_agent):
result = await analyze_post("Excited to start my new role!")
# API tests mock the comment_graph to prevent real LLM calls
with patch("backend.main.comment_graph") as mock_graph:
mock_graph.ainvoke = AsyncMock(return_value={...})
# LLM pricing tests patch model_cost to use deterministic fallback pricing
with patch("backend.models.llm.model_cost", {}):
cost = get_llm_cost(response, "gemini/gemini-2.5-flash")| Document | Description |
|---|---|
| Architecture | System architecture with mermaid diagrams |
| LangGraph Workflow | Detailed agent pipeline & state management |
| Model & LLM Integration | LLM configuration, models & routing |
| Environment Setup | Environment variables & setup guide |
| API Reference | Complete API documentation |
- Reload the extension: Go to
chrome://extensions/β click refresh - Hard refresh LinkedIn: Press
Ctrl+Shift+R - Check console logs: Open DevTools β Console β look for
[AI Copilot]logs - Verify login: The extension only works on the LinkedIn feed when logged in
- Check backend is running:
curl http://localhost:8000/health - Check API keys: Run
python -m backend.test_models - Check background script logs: Go to
chrome://extensions/β click "Service Worker" link under your extension - Test API directly:
curl -X POST http://localhost:8000/generate-comment \ -H "Content-Type: application/json" \ -d '{"post_content": "Hello world", "tone": "professional"}'
- Click the Comment button first: The Insert feature needs the comment box to be open
- Wait for the comment box: LinkedIn loads it dynamically (the extension polls for 2 seconds)
- Check for errors: Look for red error notifications from the extension
If you see WARNING: LANGSMITH_API_KEY not set, ensure your .env file uses the new LangSmith environment variable names:
# Old (deprecated) β do NOT use
# LANGCHAIN_API_KEY=...
# LANGCHAIN_PROJECT=...
# New β use these
LANGSMITH_API_KEY=your_key_here
LANGSMITH_PROJECT=linkedin-ai-comment-copilotIf you encounter Cannot connect to host ... Could not contact DNS servers errors, this is a known Windows issue with aiodns (used by aiohttp/litellm for async DNS resolution).
Fix: Uninstall aiodns and pycares:
pip uninstall aiodns pycares -yThis forces aiohttp to fall back to the system DNS resolver, which works correctly on Windows.
If you see "Extension context invalidated" errors:
- Reload the extension from
chrome://extensions/ - Hard refresh the LinkedIn page (
Ctrl+Shift+R) - This happens when the extension is reloaded but the LinkedIn tab still has the old content script
- API Key Safety: API keys are stored only on the backend server β never exposed to the extension
- No Data Storage: No posts, comments, or user data are stored anywhere
- Minimal Permissions: The extension only requests
activeTab,storage, andclipboardWrite - CORS Protection: Backend only accepts requests from allowed origins
- Message Passing: Content script communicates with background service worker via Chrome's secure message passing
- Multi-agent comment generation with per-agent model routing
- Gemini 2.5 Flash for analysis & planning
- Llama 3.3 70B via Groq for writing & review
- 10 comment tones
- LangSmith observability
- LLM cost tracking with
/test-costendpoint - Comment card with Copy/Insert/Dismiss
- Insert into LinkedIn comment box with polling
- Quality review system
- Action-bar-first post detection with WeakSet deduplication
- Comprehensive test suite (126 tests, all mocked)
- Comment scoring & analytics
- Personal writing style learning
- RAG for domain-specific comments
- Team workspace
- LinkedIn engagement analytics
- Auto-comment suggestions
- Multi-language support
- Local Ollama integration
- Feedback-based learning
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License β see the LICENSE file for details.
Himanshu β LinkedIn | GitHub
Built with LangGraph, FastAPI, Gemini, Llama 3.3, and Chrome Extension APIs
No database. No auth. Just intelligent comments.



