Skip to content
Open

Slab #520

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified .gitignore
Binary file not shown.
3 changes: 3 additions & 0 deletions SLAB/Deadline_Detective_Backend_Webcmd/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
GEMINI_API_KEY=your_gemini_api_key_here
WEBCMD_PROFILE=default
MAX_PAGES=5
23 changes: 23 additions & 0 deletions SLAB/Deadline_Detective_Backend_Webcmd/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
FROM python:3.11-slim

WORKDIR /app

# Install Node.js (required for Webcmd)
RUN apt-get update && apt-get install -y curl && \
curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && \
apt-get install -y nodejs && \
rm -rf /var/lib/apt/lists/*

# Install Webcmd globally
RUN npm install -g @agentrhq/webcmd

# Install Python dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy application code
COPY . .

EXPOSE 8000

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
57 changes: 57 additions & 0 deletions SLAB/Deadline_Detective_Backend_Webcmd/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Deadline Detective – Backend (Webcmd Version)

AI Browser Agent that finds real college opportunities using **Webcmd** for browser automation.

## What changed
- Replaced raw Playwright with **Webcmd**
- Still uses FastAPI + Gemini for planning and analysis
- Browser control now goes through Webcmd sessions

## Tech Stack
- FastAPI
- Google Gemini
- **Webcmd** (self-learning browser infrastructure)
- Docker ready

## Prerequisites

1. Node.js 20+
2. Webcmd installed:
```bash
npm install -g @agentrhq/webcmd
webcmd doctor
```

## Local Setup

```bash
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -r requirements.txt

# Create .env
cp .env.example .env
# Edit .env and add your GEMINI_API_KEY

uvicorn main:app --reload --host 0.0.0.0 --port 8000
```

## API

- `POST /research` β†’ main agent endpoint
- `GET /health` β†’ health check
- Docs: http://localhost:8000/docs

## How it works

1. Gemini creates a research plan
2. Webcmd opens a browser session
3. Webcmd visits real websites and extracts content
4. Gemini analyzes eligibility + deadlines
5. Returns prioritized action plan

## Deploy on Render

- Use the included Dockerfile
- Add environment variable `GEMINI_API_KEY`
- Make sure the instance has enough memory (Webcmd + browser needs it)
Binary file not shown.
1 change: 1 addition & 0 deletions SLAB/Deadline_Detective_Backend_Webcmd/app/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Deadline Detective Backend
Binary file not shown.
Binary file not shown.
Binary file not shown.
17 changes: 17 additions & 0 deletions SLAB/Deadline_Detective_Backend_Webcmd/app/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from pydantic_settings import BaseSettings
from functools import lru_cache


class Settings(BaseSettings):
gemini_api_key: str
webcmd_profile: str = "default"
max_pages: int = 5

class Config:
env_file = ".env"
env_file_encoding = "utf-8"


@lru_cache()
def get_settings() -> Settings:
return Settings()
40 changes: 40 additions & 0 deletions SLAB/Deadline_Detective_Backend_Webcmd/app/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from pydantic import BaseModel, Field, HttpUrl
from typing import List, Optional
from enum import Enum


class StudentProfile(BaseModel):
year: Optional[str] = Field(None, example="1st Year")
branch: Optional[str] = Field(None, example="CSE / AI")
interests: Optional[str] = Field(None, example="hackathons, AI, web development")
location: Optional[str] = Field(None, example="India")


class ResearchRequest(BaseModel):
task: str = Field(
...,
min_length=10,
example="Find currently open opportunities for a first-year CSE/AI student. Check official pages, verify eligibility and deadline, and create a priority list of what I should apply for this week."
)
profile: Optional[StudentProfile] = None


class Opportunity(BaseModel):
title: str
eligible: bool
deadline: Optional[str] = None
what_to_do: str
source: str
reason: Optional[str] = None


class ResearchResponse(BaseModel):
opportunities: List[Opportunity]
next_3_actions: List[str]
summary: str
sources_checked: List[str] = []


class HealthResponse(BaseModel):
status: str
message: str
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Routers package
Binary file not shown.
Binary file not shown.
27 changes: 27 additions & 0 deletions SLAB/Deadline_Detective_Backend_Webcmd/app/routers/research.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from fastapi import APIRouter, HTTPException
from app.models import ResearchRequest, ResearchResponse, HealthResponse
from app.services.agent import DeadlineDetectiveAgent

router = APIRouter(tags=["Research"])

agent = DeadlineDetectiveAgent()


@router.post("/research", response_model=ResearchResponse)
async def run_research(request: ResearchRequest):
"""
Main endpoint: Run the Deadline Detective browser agent.
"""
if not request.task or len(request.task.strip()) < 10:
raise HTTPException(status_code=400, detail="Task must be at least 10 characters long.")

result = await agent.run(request)
return result


@router.get("/health", response_model=HealthResponse)
async def health_check():
return HealthResponse(
status="ok",
message="Deadline Detective backend is running"
)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Services package - Webcmd version
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
69 changes: 69 additions & 0 deletions SLAB/Deadline_Detective_Backend_Webcmd/app/services/agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
from app.services.gemini import GeminiService
from app.services.webcmd_service import WebcmdService
from app.models import ResearchRequest, ResearchResponse, Opportunity
from typing import List
import traceback


class DeadlineDetectiveAgent:
def __init__(self):
self.gemini = GeminiService()
self.webcmd = WebcmdService()

async def run(self, request: ResearchRequest) -> ResearchResponse:
try:
# Step 1: Gemini creates the research plan
plan = self.gemini.create_research_plan(
task=request.task,
profile=request.profile
)

# Step 2: Webcmd collects evidence from real websites
evidence = await self.webcmd.search_and_collect(plan)

if not evidence:
return ResearchResponse(
opportunities=[],
next_3_actions=["No opportunities found. Try a more specific query or check if Webcmd is installed."],
summary="The agent could not extract useful information. Make sure Webcmd is installed and working (`webcmd doctor`).",
sources_checked=[]
)

# Step 3: Gemini analyzes eligibility and ranks
analysis = self.gemini.analyze_and_rank(
task=request.task,
profile=request.profile,
extracted_data=evidence
)

# Step 4: Build final structured response
opportunities: List[Opportunity] = []
for item in analysis.get("opportunities", []):
opportunities.append(
Opportunity(
title=item.get("title", "Unknown"),
eligible=bool(item.get("eligible", False)),
deadline=item.get("deadline"),
what_to_do=item.get("what_to_do", "Check the official page"),
source=item.get("source", ""),
reason=item.get("reason")
)
)

sources = [e["url"] for e in evidence if e.get("url")]

return ResearchResponse(
opportunities=opportunities,
next_3_actions=analysis.get("next_3_actions", []),
summary=analysis.get("summary", "Research completed using Webcmd browser agent."),
sources_checked=sources
)

except Exception as e:
traceback.print_exc()
return ResearchResponse(
opportunities=[],
next_3_actions=[],
summary=f"An error occurred while running the agent: {str(e)[:300]}",
sources_checked=[]
)
Loading