File size: 5,893 Bytes
9f491ec
 
 
 
 
 
 
 
 
 
8613a9c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9ca8ee5
cbd62a3
 
8613a9c
 
 
9ca8ee5
 
cbd62a3
 
 
8613a9c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9ca8ee5
cbd62a3
8613a9c
 
 
 
 
 
 
 
 
 
9ca8ee5
cbd62a3
8613a9c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9f491ec
 
 
 
 
 
 
5fd770b
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
---
title: ACL Anthology Search API
emoji: πŸ”Ž
sdk: docker
app_port: 7860
pinned: false
---

# ACL Anthology Search API

FastAPI service providing keyword (SQLite FTS5) and embedding-similarity (FAISS)
search over the full ACL Anthology corpus (~128k papers). Runs entirely on free
infrastructure (HF Spaces + HF Hub dataset repo + GitHub Actions). See
`docs/superpowers/specs/2026-07-03-acl-anthology-search-api-design.md` for the
full design.

## API reference

All endpoints return JSON. The service answers `503` on every route except
`/health` until the index/DB snapshot has finished loading on startup.

### `GET /health`

Liveness + readiness probe.

**Query:** none.

**Response:** `200`
```json
{
  "status": "ok",
  "index_size": 128618,
  "last_synced_at": "2026-07-04T15:06:00.654970+00:00"
}
```
Returns `503` when the snapshot is not yet loaded. `last_synced_at` is `null`
until the first sync has run.

### `GET /search/keyword?q=<query>&limit=<n>`

Keyword search over paper titles and abstracts via SQLite FTS5 (Porter-stemmed,
ranked by BM25).

**Query parameters:**

| Param   | Type | Default | Notes                                                                 |
|---------|------|---------|-----------------------------------------------------------------------|
| `q`     | str  | β€”       | Required. Raw FTS5 query (see below).                                 |
| `limit` | int  | `10`    | Max number of results.                                                |

**FTS5 query format:** space-separated terms are ANDed. Supports `"exact phrase"`,
`prefix*`, `term1 OR term2`, `term1 NOT term2`, and parentheses. Examples:
`q=transformer attention`, `q="neural machine"`, `q=translat*`, `q=(attention OR transformer) NOT survey`.

**Response:** `200` β€” array of `PaperResult`:
```json
[
  {
    "id": "1993.tc-1.6",
    "title": "Terminology and the computer - attention shifts to the micro",
    "abstract": "…",
    "authors": "Warren Weaver",
    "venue": "TC",
    "year": 1993,
    "url": "https://aclanthology.org/1993.tc-1.6/",
    "bibtex": "@inproceedings{weaver-1993-terminology,\n    title = \"Terminology and the computer - attention shifts to the micro\",\n    author = \"Weaver, Warren\",\n    booktitle = \"Proceedings of the …\",\n    year = \"1993\",\n    url = \"https://aclanthology.org/1993.tc-1.6/\"\n}",
    "pdf_url": "https://aclanthology.org/1993.tc-1.6.pdf"
  }
]
```
`year` is `null` when the anthology has no year for a paper. `bibtex` is the
canonical ACL Anthology BibTeX entry for the paper (empty when the anthology
has no citable entry, e.g. some frontmatter). `pdf_url` is the direct link to
the paper's PDF (empty when the anthology has no PDF reference). Inactive
(retracted) papers are excluded.

### `GET /search/similarity?q=<query>&k=<n>`

Embedding-similarity search. The query is embedded via the external embedding
API, then matched against the FAISS index (cosine similarity over normalized
vectors). Results are sorted by descending similarity.

**Query parameters:**

| Param | Type | Default | Notes                                            |
|-------|------|---------|--------------------------------------------------|
| `q`   | str  | β€”       | Required. Free-text query, no FTS5 syntax.        |
| `k`   | int  | `10`    | Number of nearest neighbors to return.           |

**Response:** `200` β€” array of `SimilarityResult` (a `PaperResult` plus a
similarity `score`):
```json
[
  {
    "id": "N18-3011",
    "title": "…",
    "abstract": "…",
    "authors": "…",
    "venue": "…",
    "year": 2018,
    "url": "https://aclanthology.org/N18-3011/",
    "bibtex": "@inproceedings{…}",
    "pdf_url": "https://aclanthology.org/N18-3011.pdf",
    "score": 0.8123
  }
]
```
`score` is cosine similarity in `[-1, 1]` (higher is more similar).

### `GET /paper/{paper_id}`

Metadata lookup by ACL Anthology paper id (e.g. `N18-3011`, `2023.acl-long.123`).

**Response:** `200` β€” a single `PaperResult` (shape as in `/search/keyword`),
including the canonical `bibtex` entry for citing the paper and its `pdf_url`.
Returns `404` if the id is unknown or the paper is inactive.

### Examples

```bash
# health
curl "http://localhost:8000/health"

# keyword search
curl "http://localhost:8000/search/keyword?q=transformer%20attention&limit=5"

# similarity search
curl "http://localhost:8000/search/similarity?q=attention%20mechanism&k=5"

# paper lookup
curl "http://localhost:8000/paper/1993.tc-1.6"
```

## Configuration

Settings are read from the environment (and, for local dev, from a `.env` file
in the working directory). Required:

- `HF_REPO_ID` β€” dataset repo holding `index.faiss` / `papers.db` / `state.json`
- `HF_TOKEN` β€” token with read access to that dataset repo
- `EMBEDDING_BASE_URL` β€” university embedding API base URL
- `EMBEDDING_API_KEY` β€” university embedding API key

Optional:

- `data_dir` β€” local directory for the downloaded snapshot (default `./data`)

## Local development

```bash
pip install -e ".[dev]"
python -m app          # serves on http://0.0.0.0:8000 with reload
```

On startup the service downloads the snapshot from the HF Hub dataset repo into
`data_dir` and loads it into memory (~1.3 GB index + ~300 MB DB). The only
outbound call at request time is to the embedding API, to embed
similarity-search queries.

## Required Space secrets

- `HF_REPO_ID` β€” dataset repo holding `index.faiss` / `papers.db` / `state.json`
- `HF_TOKEN` β€” token with read access to that dataset repo
- `EMBEDDING_BASE_URL` β€” university embedding API base URL
- `EMBEDDING_API_KEY` β€” university embedding API key

## Required GitHub Actions secrets

- `HF_REPO_ID`, `HF_TOKEN`, `EMBEDDING_BASE_URL`, `EMBEDDING_API_KEY` β€” same as the Space secrets above
- `HF_SPACE_ID` β€” e.g. `your-org/acl-anthology-search-api`, used to trigger a restart after sync