File size: 2,872 Bytes
4b21338
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a585654
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
---
title: LibBee
emoji: 🐝
colorFrom: blue
colorTo: yellow
sdk: docker
app_file: app.py
pinned: false
---

# 🐝 LibBee β€” KU Library AI Assistant

An open-source, institution-aware AI library assistant for Khalifa University Library, Abu Dhabi, UAE.

Built with FastAPI, hybrid FAISS + BM25 RAG, and live LibCal integration.

**Live interface:** https://ku-library.github.io/LibBee  
**GitHub:** https://github.com/ku-library/LibBee

---

## Architecture

- **Backend:** FastAPI + Python 3.9 (this Space)
- **Frontend:** GitHub Pages (single-file HTML/JS)
- **RAG:** FAISS dense + BM25 sparse + RRF fusion
- **Live data:** LibCal API via Cloudflare Worker proxy
- **Analytics:** Cloudflare D1

## Secrets required

Set these in the Space **Settings β†’ Variables and Secrets**:

| Secret | Description |
|---|---|
| `OPENAI_API_KEY` | Required for classification and answering |
| `ANTHROPIC_API_KEY` | Optional β€” enables Claude Haiku toggle |
| `PRIMO_API_KEY` | Required for PRIMO discovery search |
| `ADMIN_PASSWORD` | Required for /admin dashboard |
| `CLOUDFLARE_WORKER_URL` | Required for live hours/events and analytics |
| `SESSION_SECRET` | Required for admin session |

## Version

**v3.7** β€” Navigation-first agentic AI. See GitHub for changelog.

## Architecture (v3.8)

The pipeline is split by stage under `src/agentcore/` - each module's docstring
explains its role:

| Module | Role |
|---|---|
| `models.py` | Pydantic I/O contracts |
| `constants.py` | Regexes, URLs, prompts (no logic) |
| `utils.py` | Shared helpers, LLM factory, query/URL builders |
| `classify.py` | Rule pre-classifier + LLM intent classifier |
| `libcal.py` | Live hours/events via Cloudflare Worker proxy |
| `scholarly.py` | OpenAlex, Semantic Scholar, Crossref, Unpaywall clients |
| `rendering.py` | HTML fragments (badges, trace blocks, AI-tools footer) |
| `intents_library.py` | library_info handlers |
| `intents_search.py` | search_academic / search_medical machinery |
| `intents_general.py` | general / social handlers |
| `orchestrator.py` | Injection gate, routing pipeline, analytics logging |

`src/api/agent.py` is a thin router. Tests: `pytest tests/ -q` (20 tests, no
API keys required).

## Environment variables (new in v3.8)

| Variable | Purpose |
|---|---|
| `CLOUDFLARE_WORKER_TOKEN` | Bearer token for the Worker analytics surface; must equal the Worker's `ANALYTICS_TOKEN` secret |
| `CONTACT_EMAIL` | Polite-pool contact sent to OpenAlex / Unpaywall / Crossref (default `library@ku.ac.ae`) |

## Privacy

Before any query reaches metrics or the D1 analytics store it passes
`_redact_for_analytics`: e-mail addresses and digit runs of 6+ are masked and
text is truncated to 200 characters. Answer excerpts logged for the daily
relevance agent get the same treatment. The Worker applies the identical
redaction server-side as defence in depth.