CoolFace
Apppublic

airi-utcn/press-review

sourceHugging Faceupdated 3mo agoView on Hugging Face
0likes
App README

AIRI@UTCN Press Review

Automated press review platform for the Artificial Intelligence Research Institute at the Technical University of Cluj-Napoca (UTCN).

Monitors Romanian press for mentions of the institute, affiliated researchers, and research units via RSS feeds and Google Search.


Quick start

bash
docker compose up --build
  • —Press review: http://localhost:8000/
  • —Social graph: http://localhost:8000/graph.html

A collection run fires at startup, then every 30 minutes (configurable in data/config.json).


Project layout

press-review/
├── app/           FastAPI service + scheduler + matching logic
├── data/          JSON files — config, articles, graph, people
├── static/        HTML frontend (no build step)
├── tests/         pytest test suite
└── reference/     Original manual press review (docx)

Configuration

RSS sources — data/config.json → sources

json
{ "name": "My Source", "rss_url": "https://example.com/feed.rss", "homepage": "https://example.com" }

Keywords — data/config.json → keywords

json
{
  "institute": ["AIRI", "AIRi@UTCN"],
  "university": ["UTCN", "Universitatea Tehnică din Cluj-Napoca"],
  "research_units": ["Trusted AI", "Robotics and IoT"]
}

Changes take effect on the next collection run; no restart needed.

People — data/people.json

Each entry:

json
{
  "name": "Firstname Lastname",
  "role": "researcher",
  "research_unit": "Trusted AI",
  "profile_url": "https://airi.utcluj.ro/people/slug",
  "aliases": ["Firstname Lastname", "F. Lastname", "LASTNAME, Firstname"]
}

Aliases can be generated automatically:

python
from app.people_importer import generate_aliases
generate_aliases("Doina Liana Pisla")

How matching works

  1. 1.Normalization — text and terms are NFD-decomposed and lower-cased, making matching diacritics-insensitive ("Călin" = "Calin").
  2. 2.Word boundaries — terms are matched with \b…\b so "UTCN" does not match "BUTCNA".
  3. 3.Relevance rules:
  4. 4.Any institute keyword → relevant.
  5. 5.Any research_units keyword → relevant.
  6. 6.Any university keyword and at least one tracked person → relevant.

matched_keywords and matched_persons on each article in data/articles.json show exactly what triggered inclusion.


Graph

The social graph (/graph.html) shows:

NodeColorDescription
PersonBlueResearcher mentioned in an article
ArticleOrangePress article
SourceGreenPublication
ResearchUnitPurpleLab/unit the researcher belongs to
KeywordAmberKeyword that triggered the match

Edges: MENTIONED_IN, PUBLISHED_BY, AFFILIATED_WITH, MATCHED_BY, CO_MENTIONED_WITH.

The date filter bar (Total / Lunar / Săptămânal / Zilnic) limits visible nodes to the selected period.


API

Read

EndpointDescription
GET /api/articlesPaginated articles. Params: date, source, person, page, page_size
`GET /api/digest?date=YYYY-MM-DD&period=day\week\month`Articles grouped by source for a period
GET /api/graphGraph JSON {nodes, edges}
GET /api/personsTracked persons list
GET /api/keywordsKeyword configuration
GET /api/sourcesRSS sources list

Write

EndpointBodyDescription
PUT /api/persons[{name, role, research_unit, profile_url, aliases?}, ...]Replace persons list
POST /api/persons{name, role, ...}Add or update a person
DELETE /api/persons/{name}—Remove a person
PUT /api/keywords{institute:[...], university:[...], research_units:[...]}Replace keywords
PUT /api/sources[{name, rss_url, homepage}, ...]Replace sources
POST /api/collect—Trigger RSS collection immediately
POST /api/search—Search Google and import new articles
POST /api/import{url, source_name?}Import a single article by URL

All write operations persist to data/ and take effect immediately without restart.


Running tests

bash
pip install -r requirements.txt pytest
pytest tests/ -v

Collection interval

KeyDefaultDescription
collection.poll_interval_minutes30RSS poll interval
collection.max_article_age_days7Ignore articles older than this
collection.request_delay_seconds1.0Delay between requests per domain
collection.user_agentAIRI-PressReview/1.0HTTP User-Agent