Skip to content

rohambob212/exams

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Iran End-Term Exam Status

Tracks the status of end-term school exams across Iranian cities (cancelled / online / in-school) by aggregating multiple news sources.

Two folders, run independently:

  • frontend/ — Svelte + Vite single-page app
  • backend/ — FastAPI + JSON-file storage

Prerequisites

  • Node.js 18+
  • Python 3.10+
  • VS Code (the workspace ships with recommended extensions and launch configs)

First-time setup

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

# Frontend
cd frontend
npm install
cd ..

Run in development

The easiest way: open the folder in VS Code, then pick Run and Debug → "Run both (backend + frontend)" (or hit F5 on either individual config).

Or from two terminals:

# terminal 1
cd backend && source .venv/bin/activate && uvicorn app.main:app --reload
# terminal 2
cd frontend && npm run dev

Then open http://localhost:5173. Vite proxies /api/* to the backend on port 8000.

API

Method Path Description
GET /api/cities List status for all tracked cities
GET /api/cities/{id} Status for one city
POST /api/refresh Re-run the scrapers and update all cities

Swagger UI at http://127.0.0.1:8000/docs. There's also api.http at the repo root if you have the REST Client extension.

Project layout

exams/
├── frontend/
│   ├── src/
│   │   ├── App.svelte
│   │   ├── main.js
│   │   ├── app.css
│   │   ├── lib/api.js
│   │   └── components/
│   │       ├── CityCard.svelte
│   │       └── StatusFilter.svelte
│   ├── index.html
│   ├── vite.config.js          # proxies /api -> :8000
│   └── package.json
├── backend/
│   ├── app/
│   │   ├── main.py             # FastAPI app + CORS + lifespan
│   │   ├── routes/exams.py     # /api endpoints
│   │   ├── services/
│   │   │   ├── storage.py      # JSON-file storage
│   │   │   └── news_scraper.py # source stubs + status inference
│   │   └── models/exam_status.py
│   ├── data/                   # exam_status.json lives here at runtime
│   ├── requirements.txt
│   └── .env.example
├── .vscode/                    # extensions, settings, launch, tasks
├── api.http
├── .editorconfig
└── README.md

Adding a news source

Open backend/app/services/news_scraper.py and either fill in one of the stubs (IrnaStub, IsnaStub, MehrStub) or add a new NewsSource subclass:

class MyNewSource(NewsSource):
    name = "My Source"

    async def fetch_for_city(self, client, city):
        r = await client.get("https://example.com/search", params={"q": f"امتحان {city.name}"})
        # parse r.text with BeautifulSoup, return [Article(...)]
        return []

Then add an instance to the SOURCES list at the bottom of the same file. The aggregator handles parallel fetching, failures, and status inference automatically.

For better classification than keyword matching, replace infer_status with a smarter classifier (e.g. an LLM call or per-source regex).

Notes

  • The JSON file is seeded with 20 major cities on first run; edit DEFAULT_SEED in storage.py to change the list.
  • To swap JSON for SQLite/Postgres later, only app/services/storage.py needs to change — routes don't import the file directly.
  • CORS origins are set via CORS_ORIGINS in backend/.env.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors