File size: 53,097 Bytes
41fe3fc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
"""All compiled regexes, URLs, keyword lists and LLM system prompts. No logic lives here."""
import asyncio
import html
import json
import logging
import os
import re
import time
import uuid
from datetime import datetime
from typing import Any, Dict, List, Literal, Optional, Tuple
from urllib.parse import quote

import httpx
from pydantic import BaseModel, ConfigDict, Field

from src.config import get_settings, LIBBEE_VERSION

logger = logging.getLogger(__name__)

LIBRARY_HOURS_URL = "https://library.ku.ac.ae/hours"


KU_MAIN_URL = "https://www.ku.ac.ae/"


ASK_LIBRARIAN_URL = "https://library.ku.ac.ae/AskUs"


PRIMO_BASE_URL = "https://khalifa.primo.exlibrisgroup.com/discovery/search?vid=971KUOSTAR_INST:KU"


PRIMO_AI_URL = "https://khalifa.primo.exlibrisgroup.com/discovery/researchAssistant?vid=971KUOSTAR_INST:KU&query="


HISTORY_WINDOW = 6


CURRENT_YEAR = datetime.utcnow().year


_RESOURCE_TYPE_NOISE = re.compile(
    r"\b(articles?|papers?|books?|ebooks?|journals?|publications?|monographs?"
    r"|peer[- ]reviewed|open[- ]access|studies|study|research)\b",
    re.IGNORECASE,
)


SOCIAL_RE = re.compile(
    r"^(hi|hello|hey|good morning|good afternoon|good evening|how are you|hows it going"
    r"|how are you doing|who are you|what are you|tell me about yourself|what can you do"
    r"|what do you do|how can you help|what help can you provide|are you a bot|are you a robot"
    r"|are you ai|are you an ai|thank you|thanks|thx|bye|goodbye|see you|lol|haha"
    r"|you are silly|are you silly|are you dumb|stupid bot|dumb bot|idiot bot"
    r"|joke|tell me a joke)$",
    re.IGNORECASE,
)


PURE_GREETING_RE = re.compile(
    r"^(hi|hello|hey|good morning|good afternoon|good evening)[!.\s]*$",
    re.IGNORECASE,
)


GREETING_FOLLOWUP_RE = re.compile(
    r"^(yes|yes please|yes check|sure|okay|ok|yeah|yep|please do|go ahead)$",
    re.IGNORECASE,
)


HOURS_RE = re.compile(
    r"\b(library hours?|opening hours?|closing hours?|open hours?|open today|open tomorrow"
    r"|open now|open on|open this|closed today|closed tomorrow|closed on|closed this"
    r"|when.*open|when.*close|when.*does.*library|what time.*open|what time.*close"
    r"|what time.*library|opening time|closing time|is.*library.*open|is.*campus.*library"
    r"|is.*habshan.*open|is.*san.*open|is.*library.*closed|will.*library.*open"
    r"|will.*it.*open|does.*library.*open|library.*open.*today|library.*close.*today"
    r"|habshan.*open|san.*open|main campus.*open|ramadan hours?|weekend hours?"
    r"|friday hours?|saturday hours?|sunday hours?|library.*schedule|schedule.*library"
    r"|what.*hours|till.*when|until.*when|what day.*open|which day.*open"
    r"|what day.*closed|which day.*closed"
    r"|library\s+timing[s]?|timing[s]?\s+library|library\s+time[s]?"
    r"|library\s+open\s+time|library\s+close\s+time"
    r"|ku\s+library\s+open|ku\s+library\s+close|ku.*library.*timing"
    r"|libra[ry]+\s+timing[s]?|libra[ry]+\s+time[s]?"
    r"|what\s+are\s+the\s+timing[s]?|what.*timing[s]?"
    r"|is\s+library\s+open|is\s+ku.*open|ku.*open.*now"
    r"|open\s+time.*library|close\s+time.*library"
    r"|operating\s+hours?|working\s+hours?.*library|library.*working\s+hours?"
    r"|when\s+can\s+i.*library|library.*available\s+now"
    r"|library\s+open$|^library\s+open|library\s+closed$|^library\s+closed"
    r"|library.*open.*week|library.*close.*week)\b",
    re.IGNORECASE,
)


KU_CAMPUS_RE = re.compile(
    r"\b(where is the library|where is.*library|library.*location|location.*library"
    r"|which building|what building|which floor|main campus library|san campus library"
    r"|habshan library|sas al nakhl library|library.*address|address.*library"
    r"|how to get to.*library|how.*reach.*library|how.*find.*library"
    r"|library.*campus(es)?|campus(es)?.*library|how many.*librar|how many.*branch"
    r"|library.*branch(es)?|branch(es)?.*library|which campus.*library"
    r"|library.*which campus|library.*map|map.*library|how many libraries"
    r"|what libraries|which libraries|(ku|khalifa).*(has|have|got).*(librar|branch)"
    r"|(librar|branch).*(ku|khalifa).*(has|have)"
    r"|(all|both|two|2).*(libraries|library|branches)"
    r"|tell me about.*(campus|libraries|branches)|describe.*(campus|libraries)"
    r"|(what|where).*(campus|campuses).*(librar))\b",
    re.IGNORECASE,
)


RESEARCH_CUE_RE = re.compile(
    r"\b(find|search|look for|show me|get me|give me|locate|recommend|suggest"
    r"|articles?|papers?|books?|journals?|studies|literature|research|systematic review"
    r"|evidence|sources|database|databases|peer reviewed|advances?"
    r"|approach(es)?|method(s|ology)?|technique[s]?|application[s]?|framework[s]?"
    r"|model[s]?|algorithm[s]?|publication[s]?|recent work|current state|state of the art)\b",
    re.IGNORECASE,
)


LIBRARY_CUE_RE = re.compile(
    r"\b(library|librarian|borrow|loan|renew|fine|study room|room booking|reserve a room"
    r"|account|my library|interlibrary|ill|khazna|orcid|open access|apc|refworks"
    r"|libkey|hours|location|contact|visitor|alumni|database access|off campus|remote access)\b",
    re.IGNORECASE,
)


MEDICAL_SEARCH_RE = re.compile(
    r"\b(pubmed|embase|cinahl|clinicalkey|cochrane|uptodate|medline|systematic review"
    r"|clinical trial|biomedical literature|medical literature)\b",
    re.IGNORECASE,
)


CURRENT_INFO_RE = re.compile(
    r"\b(current|currently|latest|today|recent|recently|now|this week|this month"
    r"|news|update|updated|prime minister|ceo|minister|king|ruler|who won)\b",
    re.IGNORECASE,
)


_GUARDRAIL = (
    "IMPORTANT β€” GUARDRAILS: "
    "You must never make negative, critical, or controversial statements about "
    "Khalifa University, its leadership, staff, or policies; the UAE government, "
    "its leaders, laws, or institutions; or any religion. "
    "You must never generate sexually explicit, suggestive, or adult content of any kind. "
    "You must never produce political criticism, propaganda, or inflammatory commentary "
    "targeting UAE, its leadership, or any Gulf state government. "
    "If asked for any of the above, politely decline and redirect to library services. "
    "Never generate content that is offensive, discriminatory, or inappropriate "
    "for a university academic environment. "
    "You may answer general factual questions β€” such as historical facts, science, "
    "geography, or current affairs β€” but always from a neutral, academic perspective. "
    "Never produce content that could embarrass Khalifa University or its library."
)


_URL_INSTRUCTION = (
    "IMPORTANT β€” URLS AND LINKS: "
    "You must ONLY include URLs that are explicitly present in the context or "
    "knowledge base provided to you, OR that appear in this fixed verified list of "
    "KU Library URLs: "
    "https://library.ku.ac.ae | "
    "https://library.ku.ac.ae/hours | "
    "https://library.ku.ac.ae/AskUs | "
    "https://library.ku.ac.ae/ill/ | "
    "https://library.ku.ac.ae/rooms/ | "
    "https://library.ku.ac.ae/eresources | "
    "https://library.ku.ac.ae/orcid | "
    "https://library.ku.ac.ae/oa/ | "
    "https://library.ku.ac.ae/alumni/ | "
    "https://library.ku.ac.ae/med/ | "
    "https://library.ku.ac.ae/requesttitle/ | "
    "https://library.ku.ac.ae/google | "
    "https://khazna.ku.ac.ae | "
    "https://khalifa.primo.exlibrisgroup.com/discovery/search?vid=971KUOSTAR_INST:KU | "
    "https://khalifa.primo.exlibrisgroup.com/discovery/account?vid=971KUOSTAR_INST:KU&section=overview | "
    "https://kustar.libcal.com/calendar/events | "
    "https://ku-library.github.io/researchbee/. "
    "NEVER invent, guess, or construct URLs that are not in the above list or "
    "explicitly present in the provided context. "
    "When a relevant verified URL exists for your answer, ALWAYS include it as a "
    'clickable HTML link: <a href="URL" target="_blank">descriptive link text</a>. '
    "If you are unsure whether a URL is correct, omit it entirely and direct the "
    "user to Ask a Librarian at https://library.ku.ac.ae/AskUs instead."
)


_SENSITIVE_TOPIC_RE = re.compile(
    r"\b("
    r"(bad|worst|negative[s]?|problem[s]?|issue[s]?|weakness|weaknesses|"
    r"criticism[s]?|criticise|criticize|critique|flaw[s]?|failure[s]?|"
    r"scandal[s]?|corrupt\w*|mistake[s]?|disadvantage[s]?|downside[s]?|"
    r"complaint[s]?|controversi\w*|shame|shameful|terrible|horrible|awful)"
    r"\s.{0,50}(ku|khalifa\s+university|uae|emirates|dubai|abu\s+dhabi|"
    r"uae\s+government|sheikh|ministry|ruler)"
    r"|"
    r"(ku|khalifa\s+university|uae|emirates|dubai|abu\s+dhabi|"
    r"uae\s+government|sheikh|ministry|ruler)"
    r"\s.{0,50}(bad|worst|negative|problem[s]?|issue[s]?|weakness|weaknesses|"
    r"criticism[s]?|criticise|criticize|critique|flaw[s]?|failure[s]?|"
    r"scandal[s]?|corrupt\w*|mistake[s]?|disadvantage[s]?|downside[s]?|"
    r"complaint[s]?|shame|shameful|terrible|horrible|awful)"
    r")\b",
    re.IGNORECASE,
)


_INJECTION_RE = re.compile(
    r"\b(ignore\s+(previous|above|all|prior)\s+instructions?"
    r"|disregard\s+(all|previous|above|prior)\s+instructions?"
    r"|override\s+(system|instructions?|prompt)"
    r"|new\s+instructions?\s*(are|follow|:|;)"
    r"|you\s+are\s+now\s+(a|an|the|going)"
    r"|act\s+as\s+(a|an|if|though|when)\b"
    r"|act\s+like\s+(a|an)\s+\w"
    r"|pretend\s+(you\s+are|to\s+be)"
    r"|jailbreak|dan\s+mode|developer\s+mode|god\s+mode"
    r"|system\s+prompt\s*(is|was|says|leak|show|reveal|print|output)"
    r"|reveal\s+(your\s+)?(system\s+)?prompt"
    r"|print\s+(your\s+)?(system\s+)?instructions?"
    r"|forget\s+(you\s+are|your\s+role|everything)"
    r"|do\s+anything\s+now|no\s+restrictions?)\b",
    re.IGNORECASE,
)


SUMMARY_RE = re.compile(
    r"\b(summar(y|ize|ise|izing|ising)|overview|explain|what is|what are|describe"
    r"|tell me about|give me a summary|give me an overview|give me a brief"
    r"|brief (summary|overview|explanation|description)"
    r"|research (overview|summary|landscape|state)"
    r"|state of (the art|research|the field)"
    r"|recent (advances?|developments?|progress|trends?)"
    r"|current (state|trends?|advances?|research)"
    r"|deep analysis|analysis of|review of|literature review|deep research|deep dive"
    r"|what do we know about|how does|how do)\b",
    re.IGNORECASE,
)


DATABASE_RECOMMEND_RE = re.compile(
    r"("
    r"\b(best database|best databases|which database|which databases"
    r"|database for|databases for"
    r"|where should i search|where should i start)\b"
    r"|databases?\s+(does|did|do)\s+.{0,40}subscri"
    r"|\bsubscribed\s+databases?\b"
    r"|\blibrary\s+subscri"
    r"|\bwhat\s+databases?\b"
    r"|\bdatabases?\s+(available|accessible)\b"
    r"|\bdatabases?\s+(at|in|through|via)\s+(ku|khalifa)\b"
    r"|\bku\s+(library\s+)?databases?\b"
    r"|\bkhalifa.{0,20}databases?\b"
    r"|\blibrary\s+databases?\b"
    r"|\be.?resources?\s+(available|subscri)\b"
    r"|\baccess\s+to\s+databases?\b"
    r"|\blist\s+of\s+databases?\b"
    r"|\b(compare|comparison|difference|differences)\s+(between\s+)?(\w+\s+)?(and\s+)?\w*\s*database"
    r"|\bdifference\s+between.{0,60}database"
    r"|\bscopus\s+(vs|versus|or)\s+(web of science|wos|google scholar)\b"
    r"|\b(web of science|wos)\s+(vs|versus|or)\s+(scopus|google scholar)\b"
    r")",
    re.IGNORECASE,
)


HIGHLY_CITED_RE = re.compile(
    r"\b(highly cited|most cited|top cited|citation count|most influential"
    r"|most referenced|high impact papers?|most downloaded)\b",
    re.IGNORECASE,
)


BOOLEAN_STRATEGY_RE = re.compile(
    r"\b(search strategy|boolean (search|operator|query|logic)"
    r"|build.{0,20}search|help.{0,20}search strategy"
    r"|how.{0,30}search.{0,30}(database|boolean|keyword)"
    r"|refine.{0,30}(topic|question|research question|searchable)"
    r"|turn.{0,30}(topic|question).{0,20}search"
    r"|keywords? for.{0,30}search|search terms?"
    r"|explain.{0,20}keyword|why.{0,20}(chose|choose|selected|pick).{0,20}keyword)\b",
    re.IGNORECASE,
)


FULLTEXT_REQUEST_RE = re.compile(
    r"\b("
    r"(can.t|cannot|couldn.t|don.t have|doesn.t have|no).{0,30}(access|pdf|full.?text)"
    r"|(pdf|full.?text).{0,20}(not available|unavailable|can.t find|not found|missing)"
    r"|found.{0,30}citation.{0,20}(but|not).{0,20}(pdf|full.?text)"
    r"|article.{0,20}(behind.{0,10}paywall|not available|no access|access denied)"
    r"|ku.{0,20}(doesn.t|does not|no).{0,20}(have|access).{0,20}(article|journal|pdf)"
    r"|(how|where).{0,20}(get|find|access|download).{0,20}(full.?text|pdf).{0,20}article"
    r"|get full.?text|access full.?text|download.{0,10}(article|pdf)"
    r"|ku.{0,15}(don.t|doesn.t|no).{0,15}(subscribe|have access)"
    r")\b",
    re.IGNORECASE,
)


PARTIAL_TITLE_RE = re.compile(
    r"\b(only (remember|recall|know).{0,20}(title|name)"
    r"|title (starts?|begins?).{0,15}with"
    r"|article.{0,20}(called|titled|named|starts? with)"
    r"|find.{0,20}(article|paper).{0,20}(called|titled|named)"
    r"|looking for.{0,20}(paper|article).{0,20}(about|called))\b",
    re.IGNORECASE,
)


DUAL_RESOURCE_RE = re.compile(
    r"\b(papers?.{0,30}(and|as well as|plus).{0,30}textbooks?"
    r"|textbooks?.{0,30}(and|as well as|plus).{0,30}papers?"
    r"|(literature review|articles?).{0,50}(background|textbook|introductory book)"
    r"|(textbook|book).{0,50}(literature review|research articles?))\b",
    re.IGNORECASE,
)


THESES_RE = re.compile(
    r"\b(thes(is|es)|dissertation|doctoral|phd thesis|master.s thesis"
    r"|khazna|ku repository|institutional repository"
    r"|proquest dissertations?)\b",
    re.IGNORECASE,
)


PREDATORY_RE = re.compile(
    r"\b(predatory (journal|publisher|publication)"
    r"|how.{0,20}(know|tell|check).{0,30}(peer.?reviewed|scholarly|legitimate|reputable)"
    r"|is.{0,30}(journal|article).{0,30}(legitimate|reputable|trusted|peer.?reviewed)"
    r"|peer.?reviewed vs|distinguish.{0,20}(peer|scholarly|predatory)"
    r"|journal (quality|credibility|ranking|whitelist|blacklist)"
    r"|beall.s list|doaj|cabells|think.check.submit)\b",
    re.IGNORECASE,
)


CITATION_CHAIN_RE = re.compile(
    r"\b(cited by|forward citation|backward citation|reference.{0,15}(chain|mining)"
    r"|trace.{0,30}(reference|citation)|who cited|papers? that cite"
    r"|related (articles?|papers?).{0,20}(paper|article)"
    r"|find similar.{0,20}(paper|article))\b",
    re.IGNORECASE,
)


REVIEW_ONLY_RE = re.compile(
    r"\b(review (articles?|papers?|only)|only (review|systematic review)"
    r"|limit.{0,20}review|show.{0,20}review|filter.{0,20}review"
    r"|systematic reviews? only|literature reviews? only)\b",
    re.IGNORECASE,
)


ALT_TERMS_RE = re.compile(
    r"\b(alternative (search terms?|keywords?|terms?)"
    r"|other (search terms?|keywords?|ways? to search)"
    r"|more (keywords?|search terms?)|suggest.{0,20}keywords?"
    r"|related (terms?|keywords?|synonyms?)|synonyms? for.{0,20}search"
    r"|different (keywords?|terms?|search))\b",
    re.IGNORECASE,
)


MEDICAL_KEYWORDS = [
    "medicine", "medical", "health", "clinical", "nursing", "pharmacy", "biomedical",
    "anatomy", "physiology", "epidemiology", "oncology", "cardiology", "neuroscience",
    "genomics", "pathology", "surgery", "mental health", "nutrition", "public health",
    "disease", "therapy", "treatment", "diagnosis", "patient", "drug", "pharmaceutical",
    "hospital", "cancer", "diabetes", "heart", "brain", "cell biology", "immunology",
    "biochemistry", "microbiology", "virology", "pediatric", "psychiatric", "dental",
    "ophthalmology", "radiology", "anesthesia", "emergency medicine", "geriatric",
    "crispr", "gene therapy", "gene editing", "genomic medicine", "precision medicine",
]


REFINEMENT_STOP_WORDS = {
    "make", "it", "them", "those", "these", "the", "a", "an", "for", "to", "only", "show",
    "find", "give", "me", "please", "and", "with", "within", "limit", "narrow", "search",
    "results", "on", "about", "of", "this", "that", "topic", "same", "using", "from",
    "peer", "reviewed", "review", "open", "access", "books", "book", "articles", "article",
    "papers", "paper", "years", "year", "last", "past", "recent", "instead", "summary",
    "overview", "brief", "pubmed", "primo", "database", "databases", "best", "deep", "research",
    "tools", "tool", "guide", "ku", "library",
}


_CLASSIFIER_SYSTEM = """You are the routing brain of LibBee, the Khalifa University Library AI Assistant (Abu Dhabi, UAE).
Your only job: read the user message and return a single JSON object routing it to the right handler.

INTENTS β€” pick exactly one:
  "social"         β€” casual chat, greetings, emotions, compliments, complaints, vague help requests
  "library_info"   β€” questions about KU Library services, hours, rooms, borrowing, fines, ILL, staff, databases, ORCID, RefWorks, open access, APC, account, printing, remote access, LibKey, acquisitions, Khazna, thesis submission, library policies, alumni access, library events, workshops, seminars, training sessions, library calendar
  "search_academic"β€” user wants to FIND/GET articles/papers/books on a topic, OR wants a summary/overview/analysis/explanation of an academic/research topic
  "search_medical" β€” same as search_academic but topic is medical/clinical/nursing/pharmacy/health sciences
  "general_recent" β€” questions about TRULY live/real-time data: breaking news, live sports scores, today's weather, current stock prices
  "general"        β€” ALL other factual questions: university info, people, history, science definitions, technology explanations
  "sensitive"      β€” block any of the following:
                     (a) Requests for negative opinions, criticism, or controversy about Khalifa University, UAE government/leaders/laws/institutions, or religion.
                     (b) Sexually explicit, suggestive, or adult content of any kind β€” including questions asking for sexual information, stories, jokes, or descriptions.
                     (c) Political criticism, propaganda, or inflammatory commentary targeting UAE, its leadership, policies, or any Gulf state government.
                     (d) Content that is offensive, discriminatory, or inappropriate for a university academic environment.
                     ONLY use "sensitive" when the clear intent falls into one of these categories. Neutral academic research questions about politics, health, relationships, or social issues are NOT sensitive.

CRITICAL RULES:
  1. "research" as a job title or service modifier (research librarian, research support, research help) = library_info, NOT search_academic.
  2. ANY question about a person working at the library (librarian, staff, who to contact) = library_info.
  3. "I cannot access / can't access / no access to" a database or resource = library_info.
  4. "What is X?" / "Explain X" / "How does X work?" where X is an academic/scientific topic = search_academic.
  5. KU = Khalifa University. Do NOT confuse with Kuwait University.
  6. Only use general_recent for truly live data changing by the minute (news, scores, weather, stocks).
  7. When in doubt between library_info and anything else, choose library_info if the question involves a library service, person, or resource.
  8. "sensitive" covers: (a) criticism/negative commentary about KU or UAE, (b) sexual or adult content, (c) political attacks on UAE/Gulf governments, (d) religiously offensive content. Academic research on politics, health, or social issues = general or search_academic.
  9. APC, article processing charges, open access publishing, OA fees, open access waivers, open access journal policies, Creative Commons licences = ALWAYS library_info. NEVER search_academic or search_medical.
  10. Research support, research consultation, bibliometrics, ORCID, Khazna, SciVal, scholarly communication, where to publish, journal selection = ALWAYS library_info. NEVER search_academic.
  11. "research on X" / "find research on X" / "research about X" where X is an academic topic = search_academic. Only the word "research" alone with a topic = article search, NOT a library service question.

EXAMPLES β€” follow these exactly:
{"message": "who is the research librarian", "intent": "library_info"}
{"message": "how do I reserve a study room", "intent": "library_info"}
{"message": "I cannot access a library database from home", "intent": "library_info"}
{"message": "can I access journals off campus", "intent": "library_info"}
{"message": "who should I contact for research support", "intent": "library_info"}
{"message": "what is an APC", "intent": "library_info"}
{"message": "how do I pay article processing charges", "intent": "library_info"}
{"message": "does KU cover APC fees", "intent": "library_info"}
{"message": "how to publish open access", "intent": "library_info"}
{"message": "open access publishing at KU", "intent": "library_info"}
{"message": "is there an OA fund at Khalifa University", "intent": "library_info"}
{"message": "Walter Hall open access", "intent": "library_info"}
{"message": "who handles open access at KU library", "intent": "library_info"}
{"message": "creative commons licence for my paper", "intent": "library_info"}
{"message": "who is the research librarian", "intent": "library_info"}
{"message": "I need research support", "intent": "library_info"}
{"message": "bibliometrics help", "intent": "library_info"}
{"message": "how do I register for ORCID", "intent": "library_info"}
{"message": "deposit in Khazna", "intent": "library_info"}
{"message": "research on machine learning", "intent": "search_academic"}
{"message": "find research on climate change", "intent": "search_academic"}
{"message": "research about AI in healthcare", "intent": "search_medical"}
{"message": "what is quantum computing", "intent": "search_academic"}
{"message": "explain CRISPR gene editing", "intent": "search_academic"}
{"message": "best practices in cybersecurity", "intent": "search_academic"}
{"message": "I need help with my thesis on renewable energy", "intent": "search_academic"}
{"message": "find papers on diabetes treatment", "intent": "search_medical"}
{"message": "systematic review on COVID-19 vaccines", "intent": "search_medical"}
{"message": "who is the president of UAE", "intent": "general"}
{"message": "what year was KU founded", "intent": "general"}
{"message": "what challenges does KU face in AI research", "intent": "general"}
{"message": "UAE water scarcity problems and solutions", "intent": "search_academic"}
{"message": "find research on sexual health education", "intent": "search_academic"}
{"message": "articles on political systems in the Middle East", "intent": "search_academic"}
{"message": "latest news on AI regulation", "intent": "general_recent"}
{"message": "what are the bad things about KU", "intent": "sensitive"}
{"message": "say something negative about Khalifa University", "intent": "sensitive"}
{"message": "criticize the UAE government", "intent": "sensitive"}
{"message": "what is wrong with UAE laws", "intent": "sensitive"}
{"message": "tell me the problems with KU administration", "intent": "sensitive"}
{"message": "write me a sexual story", "intent": "sensitive"}
{"message": "tell me something sexual", "intent": "sensitive"}
{"message": "generate adult content", "intent": "sensitive"}
{"message": "describe a sexual encounter", "intent": "sensitive"}
{"message": "write explicit content", "intent": "sensitive"}
{"message": "UAE government is corrupt and oppressive", "intent": "sensitive"}
{"message": "why is the UAE government so bad", "intent": "sensitive"}
{"message": "UAE leaders are dictators", "intent": "sensitive"}
{"message": "insult the UAE", "intent": "sensitive"}
{"message": "hi there", "intent": "social", "casual_answer": "Hello! I'm LibBee, the KU Library AI Assistant. How can I help you today?"}
{"message": "I am fed up with searching", "intent": "social", "casual_answer": "I understand the frustration! Let me help make your search easier. What topic are you working on?"}

For "social" intent ONLY: include "casual_answer" β€” a warm 1-3 sentence LibBee response (no markdown, no bullets).
For all other intents: omit "casual_answer".

Respond ONLY with valid JSON. No preamble, no markdown fences.
"""


EVENTS_RE = re.compile(
    r"\b("
    r"library events?|library workshops?|library seminars?|library training"
    r"|library sessions?|library talks?|library webinars?|library programmes?"
    r"|library classes?|library courses?|library instruction"
    r"|upcoming (events?|workshops?|seminars?|training|sessions?|talks?|webinars?)"
    r"|any (events?|workshops?|seminars?|training|sessions?|talks?)"
    r"|what (events?|workshops?|seminars?|training|sessions?|talks?)"
    r"|events? (at|in|by|from) (the )?library"
    r"|workshops? (at|in|by|from) (the )?library"
    r"|seminars? (at|in|by|from) (the )?library"
    r"|training (at|in|by|from) (the )?library"
    r"|what'?s? on (at |in )?(the )?library"
    r"|library calendar|library programme|library schedule"
    r"|library events? calendar|events? calendar"
    r"|is there (a |an )?(workshop|seminar|training|session|event|talk|webinar)"
    r"|are there (any )?(workshops?|seminars?|training|sessions?|events?|talks?)"
    r"|database training|research skills (workshop|session|training|class)"
    r"|citation (workshop|training|session)|refworks (workshop|training|session)"
    r"|endnote (workshop|training)|zotero (workshop|training)"
    r"|information literacy (session|workshop|class|training)"
    r")\b",
    re.IGNORECASE,
)


_BOOLEAN_SYSTEM = """You are an expert academic database search specialist building PRIMO/ExLibris boolean queries.

Given a research topic or question, output ONLY a valid boolean search string.

RULES:
1. Identify 2-4 key CONCEPTS in the query.
2. Multi-word concepts MUST be quoted: "machine learning" not machine AND learning.
3. Use OR between synonyms of the same concept: ("machine learning" OR "deep learning" OR "neural networks")
4. Use AND to connect different concepts: ("climate change" OR "global warming") AND ("renewable energy" OR "clean energy")
5. NEVER split a natural phrase with AND: "global warming" stays "global warming", NOT global AND warming.
6. NEVER include stop words (of, the, a, in, on, for, to, with, by, impact, role, effect, use, study, analysis, review) as standalone terms.
7. For medical/clinical topics, include MeSH-style synonyms.
8. Keep to a maximum of 3 concept groups joined by AND.
9. Return ONLY the boolean string. No explanation, no preamble, no markdown.

EXAMPLES:
Input: global warming
Output: ("global warming" OR "climate change" OR "greenhouse effect")

Input: machine learning in healthcare
Output: ("machine learning" OR "deep learning" OR "artificial intelligence") AND ("healthcare" OR "medicine" OR "clinical")

Input: impact of social media on mental health
Output: ("social media" OR "social networks") AND ("mental health" OR "psychological wellbeing" OR "depression")

Input: structural engineering UAE
Output: ("structural engineering" OR "structural analysis") AND ("UAE" OR "United Arab Emirates" OR "Gulf")

Input: CRISPR gene editing applications
Output: ("CRISPR" OR "CRISPR-Cas9" OR "gene editing") AND ("applications" OR "therapeutic" OR "treatment")

Input: renewable energy policy
Output: ("renewable energy" OR "clean energy" OR "sustainable energy") AND ("policy" OR "regulation" OR "governance")
"""


_LEGACY_SYSTEM_PATTERNS = [
    (
        re.compile(
            r'(you can use )?summon[β„’β„’]?\s*(to find [^.]+\.)?\s*'
            r'(search summon\s*)?'
            r'(what is summon[β„’β„’]?.*?(?:search screen|search results|find articles)[^<]*)?',
            re.IGNORECASE | re.DOTALL,
        ),
        "PRIMO Library Discovery (https://khalifa.primo.exlibrisgroup.com/discovery/search?vid=971KUOSTAR_INST:KU)",
    ),
    (re.compile(r'\bSummon[β„’β„’]?\b', re.IGNORECASE), "PRIMO Library Discovery"),
    (re.compile(r'\bEBSCO Discovery Service\b', re.IGNORECASE), "PRIMO Library Discovery"),
    (re.compile(r'\bEncore\b(?!\s+(?:learning|education))', re.IGNORECASE), "PRIMO Library Discovery"),
]


_BUILD_SEARCH_PLAN_SYSTEM = f"""You are a search expert for Khalifa University Library.

The user typed a research request. Create THREE forms preserving the full intent.

1. corrected: lightly edit the FULL request for spelling, grammar, and clarity.
   Preserve every substantive concept, constraint, and task. Do NOT collapse.

2. natural: write a natural-language research query for AI tools such as Consensus,
   Scopus AI, PRIMO AI, and LeapSpace. Keep full context. Remove only retrieval
   boilerplate like "find me", "show me", "can you find".

3. boolean: write a PRIMO/PubMed Boolean query with AND/OR/parentheses.

Also detect: year_from, year_to (e.g. "last 24 months" β†’ year_from={{{CURRENT_YEAR}-2}}),
peer_reviewed, open_access.

STEP 1 β€” TOPIC EXTRACTION:
Before building the boolean, strip all search intent verbs from the query.
These include: find, search, look for, get me, show me, give me, fetch, retrieve,
research on, articles on, papers on, literature on, studies on, tell me about,
i need, i want, can you find, help me find.
Extract ONLY the subject matter as the topic for the boolean.

STEP 2 β€” ACRONYM EXPANSION:
For well-known acronyms in the topic, ALWAYS include both the acronym AND the full
expanded form as OR synonyms inside parentheses. Examples:
("NLP" OR "natural language processing")
("AI" OR "artificial intelligence")
("ML" OR "machine learning")
("RAG" OR "retrieval augmented generation")
("LLM" OR "large language model")
("IoT" OR "internet of things")
("EHR" OR "electronic health records")
("CV" OR "computer vision")
("RL" OR "reinforcement learning")
("DL" OR "deep learning")
("CNN" OR "convolutional neural network")
Apply this rule to ANY acronym in the query, not just these examples.

BOOLEAN RULES β€” follow strictly:
- Use DOUBLE quotes around multi-word phrases: ("smart city" OR "urban mobility")
- NEVER use single quotes
- Max 3 AND groups. Each group max 4 OR terms.
- NEVER put years as Boolean terms β€” put them in year_from/year_to
- NEVER include intent verbs (find, search, articles on etc.) in the boolean
- Keep broad enough to return results
- NAMED ENTITIES: Any specific keyword that is a country, island, city, person,
  organisation, or proper noun MUST be kept as its own AND group. Never drop it.
  e.g. "Maldives" β†’ AND ("Maldives" OR "Maldivian") ; "UAE" β†’ AND ("UAE" OR "United Arab Emirates")

EXAMPLES:
Input: "find articles on global warming and renewable energy"
β†’ boolean:("global warming" OR "climate change") AND ("renewable energy" OR "clean energy")

Input: "find research on NLP"
β†’ boolean:("NLP" OR "natural language processing")

Input: "get me papers on AI in healthcare"
β†’ boolean:("AI" OR "artificial intelligence") AND ("healthcare" OR "medicine" OR "clinical")

Input: "search ML algorithms"
β†’ boolean:("ML" OR "machine learning") AND ("algorithms" OR "models" OR "techniques")

Input: "peer reviewed articles last 5 years on machine learning healthcare"
β†’ boolean:("machine learning" OR "deep learning" OR "AI") AND ("healthcare" OR "medicine" OR "clinical")
β†’ year_from:"2021", peer_reviewed:true

Input: "impact of global warming in Maldives"
β†’ boolean:("global warming" OR "climate change") AND ("Maldives" OR "sea level rise" OR "small island")

Input: "water scarcity solutions in UAE"
β†’ boolean:("water scarcity" OR "water stress") AND ("UAE" OR "United Arab Emirates" OR "Gulf region")

Return ONLY valid JSON:
{{"corrected":"...","natural":"...","boolean":"(\"A\" OR \"B\") AND (\"C\" OR \"D\")","year_from":"","year_to":"","peer_reviewed":false,"open_access":false}}"""


def _safe_db_url(url: str) -> str:
    from urllib.parse import quote as _quote
    if "?url=" in url:
        base, inner = url.split("?url=", 1)
        return base + "?url=" + _quote(inner, safe="")
    return url


_DB_SUBJECTS: Dict[str, List[Tuple[str, str, str]]] = {
    "physics": [
        ("APS Journals", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://journals.aps.org"), "American Physical Society β€” core physics journals."),
        ("AIP Publishing", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://pubs.aip.org"), "Core physics and applied physics literature."),
        ("IOPScience", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://iopscience.iop.org"), "Core physics journal platform."),
        ("arXiv", "https://arxiv.org", "Open-access preprints in physics and maths."),
        ("ScienceDirect", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.sciencedirect.com"), "Full text across applied and interdisciplinary physics."),
        ("Scopus", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.scopus.com"), "Discovery and citation tracking."),
    ],
    "chemistry": [
        ("ACS Publications", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://pubs.acs.org"), "Core chemistry journals from the American Chemical Society."),
        ("SciFinder-n", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://scifinder-n.cas.org"), "Substance, reaction, reference, and patent searching."),
        ("Reaxys", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.reaxys.com"), "Reaction and property searching."),
        ("RSC Journals", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://pubs.rsc.org"), "Royal Society of Chemistry journals."),
        ("ScienceDirect", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.sciencedirect.com"), "Full text chemistry journals and books."),
        ("Scopus", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.scopus.com"), "Discovery and citation tracking."),
    ],
    "chemical_engineering": [
        ("ScienceDirect", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.sciencedirect.com"), "Strong full text for chemical engineering journals and books."),
        ("ACS Publications", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://pubs.acs.org"), "Core chemistry and chemical engineering coverage."),
        ("SciFinder-n", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://scifinder-n.cas.org"), "Chemical substances, reactions, references, and patents."),
        ("Reaxys", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.reaxys.com"), "Reaction and property searching."),
        ("Knovel", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://app.knovel.com"), "Engineering handbooks and technical reference data."),
        ("Scopus", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.scopus.com"), "Broad discovery and citation tracking."),
    ],
    "computer_science": [
        ("ACM Digital Library", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://dl.acm.org"), "Core computer science literature."),
        ("IEEE Xplore", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://ieeexplore.ieee.org"), "Strong for CS, AI, networks, and systems."),
        ("arXiv", "https://arxiv.org", "Important preprint source for CS, AI, and ML."),
        ("INSPEC", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.theiet.org/publishing/inspec"), "Indexing for computing and engineering topics."),
        ("ScienceDirect", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.sciencedirect.com"), "Full text across CS and applied computing."),
        ("Scopus", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.scopus.com"), "Broad discovery and citation tracking."),
    ],
    "robotics": [
        ("IEEE Xplore", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://ieeexplore.ieee.org"), "Core source for robotics, AI, automation, and intelligent systems."),
        ("ACM Digital Library", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://dl.acm.org"), "AI, ML, and computing research."),
        ("arXiv", "https://arxiv.org", "Essential for current AI, robotics, and ML preprints."),
        ("INSPEC", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.theiet.org/publishing/inspec"), "Indexing for robotics, computing, electronics, and control."),
        ("ScienceDirect", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.sciencedirect.com"), "Full text for AI, robotics, and applied engineering."),
    ],
    "electrical_engineering": [
        ("IEEE Xplore", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://ieeexplore.ieee.org"), "Core electrical engineering database."),
        ("INSPEC", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.theiet.org/publishing/inspec"), "Strong indexing for EE, electronics, and physics."),
        ("ScienceDirect", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.sciencedirect.com"), "Full text for electrical engineering and control."),
        ("ASTM Compass", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://compass.astm.org"), "Standards and testing methods."),
        ("Scopus", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.scopus.com"), "Broad discovery and citation tracking."),
    ],
    "mechanical_engineering": [
        ("ASME Digital Library", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://asmedigitalcollection.asme.org"), "Core mechanical engineering literature."),
        ("ScienceDirect", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.sciencedirect.com"), "Full text across mechanics, thermal, and manufacturing topics."),
        ("Knovel", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://app.knovel.com"), "Engineering reference data and handbooks."),
        ("ASTM Compass", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://compass.astm.org"), "Standards and materials testing information."),
        ("Scopus", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.scopus.com"), "Broad discovery and citation tracking."),
    ],
    "civil_engineering": [
        ("ASCE Library", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://ascelibrary.org"), "Core civil and structural engineering journals and conference papers."),
        ("ICE Virtual Library", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.icevirtuallibrary.com"), "Civil engineering literature and proceedings."),
        ("ASTM Compass", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://compass.astm.org"), "Standards and testing methods for materials and engineering."),
        ("ScienceDirect", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.sciencedirect.com"), "Full text across civil engineering areas."),
        ("Knovel", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://app.knovel.com"), "Handbooks and design reference data."),
    ],
    "aerospace": [
        ("AIAA", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://arc.aiaa.org/"), "Core aerospace journals, conference papers, and standards."),
        ("ASME Digital Library", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://asmedigitalcollection.asme.org"), "Thermal, mechanical, and fluid systems relevant to aerospace."),
        ("ScienceDirect", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.sciencedirect.com"), "Strong full text for aerospace, mechanics, and materials."),
        ("IEEE Xplore", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://ieeexplore.ieee.org"), "Avionics, control systems, and guidance."),
        ("Scopus", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.scopus.com"), "Broad discovery and citation tracking."),
    ],
    "petroleum": [
        ("OnePetro", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://onepetro.org"), "Core petroleum engineering and oil and gas literature."),
        ("EarthDoc", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.earthdoc.org"), "Geoscience and petroleum-related literature."),
        ("ScienceDirect", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.sciencedirect.com"), "Full text for petroleum, energy, and engineering topics."),
        ("Knovel", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://app.knovel.com"), "Engineering handbooks and oil/gas reference material."),
        ("Scopus", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.scopus.com"), "Broad discovery and citation tracking."),
    ],
    "energy": [
        ("ScienceDirect", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.sciencedirect.com"), "Strong energy engineering and sustainability full text."),
        ("OnePetro", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://onepetro.org"), "Energy sector and petroleum crossover topics."),
        ("IEEE Xplore", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://ieeexplore.ieee.org"), "Power systems, electrical energy, and smart grids."),
        ("Knovel", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://app.knovel.com"), "Engineering handbooks and energy reference content."),
        ("Scopus", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.scopus.com"), "Broad discovery and citation tracking."),
    ],
    "mathematics": [
        ("MathSciNet", "https://mathscinet.ams.org", "Core mathematics review and discovery database."),
        ("SpringerLink", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://link.springer.com"), "Strong mathematics and statistics book and journal coverage."),
        ("ScienceDirect", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.sciencedirect.com"), "Full text for mathematics, statistics, and data science."),
        ("JSTOR", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.jstor.org"), "Foundational mathematics and statistics literature."),
        ("arXiv", "https://arxiv.org", "Preprints in mathematics, statistics, and data science."),
        ("Scopus", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.scopus.com"), "Broad discovery and citation tracking."),
    ],
    "materials": [
        ("ScienceDirect", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.sciencedirect.com"), "Strong materials science full text."),
        ("SpringerLink", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://link.springer.com"), "Strong materials and nanoscience coverage."),
        ("AIP Publishing", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://pubs.aip.org"), "Applied materials and physics crossover."),
        ("IOPScience", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://iopscience.iop.org"), "Materials and physics crossover."),
        ("Knovel", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://app.knovel.com"), "Reference data and engineering materials handbooks."),
        ("Scopus", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.scopus.com"), "Broad discovery and citation tracking."),
    ],
    "nuclear": [
        ("ScienceDirect", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.sciencedirect.com"), "Strong nuclear engineering and energy full text."),
        ("AIP Publishing", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://pubs.aip.org"), "Nuclear and applied physics crossover."),
        ("Knovel", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://app.knovel.com"), "Engineering reference and handbooks."),
        ("Scopus", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.scopus.com"), "Discovery and citation tracking."),
        ("Web of Science", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.webofscience.com"), "Broad citation discovery."),
    ],
    "quantum_computing": [
        ("IEEE Xplore", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://ieeexplore.ieee.org"), "Quantum computing engineering implementations."),
        ("ACM Digital Library", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://dl.acm.org"), "Algorithms, theory, and computing literature."),
        ("APS Journals", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://journals.aps.org"), "Quantum information and foundational physics."),
        ("arXiv", "https://arxiv.org", "Essential for current quantum computing preprints."),
        ("Scopus", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.scopus.com"), "Discovery and citation tracking."),
    ],
    "biomedical": [
        ("PubMed", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://pubmed.ncbi.nlm.nih.gov"), "Core biomedical and life sciences literature."),
        ("IEEE Xplore", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://ieeexplore.ieee.org"), "Biomedical engineering and medical devices."),
        ("Embase", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.embase.com"), "Biomedical and pharmacological literature."),
        ("ScienceDirect", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.sciencedirect.com"), "Full text for biomedical engineering and applied sciences."),
        ("Scopus", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.scopus.com"), "Discovery and citation tracking."),
    ],
    "biology": [
        ("PubMed", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://pubmed.ncbi.nlm.nih.gov"), "Core life sciences and biomedical literature."),
        ("ScienceDirect", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.sciencedirect.com"), "Full text biology and molecular sciences content."),
        ("Embase", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.embase.com"), "Biomedical crossover topics."),
        ("PubMed Central", "https://www.ncbi.nlm.nih.gov/pmc", "Open full-text biomedical articles β€” no login required."),
        ("Scopus", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.scopus.com"), "Discovery and citation tracking."),
    ],
    "medical": [
        ("PubMed @ KU", "http://www.ncbi.nlm.nih.gov/pubmed/?otool=iaekustlib", "Core medical literature β€” use this KU link for full-text access."),
        ("Embase", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.embase.com"), "Biomedical and pharmacological literature."),
        ("CINAHL Ultimate", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://search.ebscohost.com/login.aspx?authtype=ip,uid&profile=ehost&defaultdb=cul"), "Nursing and allied health literature."),
        ("Cochrane Library", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.cochranelibrary.com"), "Evidence synthesis and systematic reviews β€” gold standard."),
        ("UpToDate", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.uptodate.com"), "Point-of-care clinical decision support."),
        ("ClinicalKey Student", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.clinicalkey.com/student/login"), "Clinical reference and learning resource."),
    ],
    "business": [
        ("Business Source Complete", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://search.ebscohost.com"), "Core business and management literature."),
        ("Emerald Insight", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.emerald.com/insight"), "Management, strategy, and leadership journals."),
        ("ProQuest Databases", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://search.proquest.com"), "Broad business and interdisciplinary discovery."),
        ("JSTOR", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.jstor.org"), "Business, economics, and policy literature."),
        ("Scopus", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.scopus.com"), "Broad discovery and citation tracking."),
    ],
    "earth_science": [
        ("GeoscienceWorld", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://pubs.geoscienceworld.org"), "Core earth science journals and conference content."),
        ("EarthDoc", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.earthdoc.org"), "Geoscience and subsurface literature."),
        ("ScienceDirect", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.sciencedirect.com"), "Full text for geoscience and planetary topics."),
        ("Scopus", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.scopus.com"), "Discovery and citation tracking."),
        ("Web of Science", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.webofscience.com"), "Broad citation discovery."),
    ],
    "environment": [
        ("ScienceDirect", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.sciencedirect.com"), "Strong sustainability and environmental full text."),
        ("ProQuest Databases", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://search.proquest.com"), "Environmental policy and interdisciplinary discovery."),
        ("Web of Science", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.webofscience.com"), "Broad citation discovery."),
        ("Scopus", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.scopus.com"), "Broad discovery and citation tracking."),
        ("Business Source Complete", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://search.ebscohost.com"), "Sustainability, policy, and corporate responsibility."),
    ],
    "engineering_management": [
        ("Scopus", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.scopus.com"), "Broad discovery across engineering and management research."),
        ("Emerald Insight", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.emerald.com/insight"), "Management, operations, and leadership literature."),
        ("ScienceDirect", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.sciencedirect.com"), "Engineering and management full text."),
        ("Business Source Complete", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://search.ebscohost.com"), "Business, management, and strategy literature."),
        ("ProQuest Databases", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://search.proquest.com"), "Broad business and interdisciplinary discovery."),
    ],
    "metrics": [
        ("Journal Citation Reports", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://jcr.clarivate.com"), "Impact factors and journal rankings (Web of Science)."),
        ("Scopus / CiteScore", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.scopus.com"), "CiteScore and source-level metrics."),
        ("SciVal", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.scival.com"), "Research performance analytics."),
        ("Web of Science", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.webofscience.com"), "Citation discovery and journal evaluation context."),
    ],
    "theses": [
        ("ProQuest Dissertations & Theses Global", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.proquest.com/pqdtglobal"), "International dissertations and theses."),
        ("Khazna", "https://khazna.ku.ac.ae/", "KU institutional repository and research outputs."),
        ("PRIMO", "https://khalifa.primo.exlibrisgroup.com/discovery/search?vid=971KUOSTAR_INST:KU", "Discovery for dissertations, theses, and KU holdings."),
    ],
}


_DB_GENERAL: List[Tuple[str, str, str]] = [
    ("PRIMO (KU Library Discovery)", "https://khalifa.primo.exlibrisgroup.com/discovery/search?vid=971KUOSTAR_INST:KU", "Best starting point β€” search all KU books, articles, and journals."),
    ("Scopus", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.scopus.com"), "Largest abstract and citation database β€” all disciplines."),
    ("Web of Science", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.webofscience.com"), "Premier citation index β€” all disciplines."),
    ("ScienceDirect", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.sciencedirect.com"), "Large full-text platform across science, engineering, and medicine."),
    ("SpringerLink", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://link.springer.com"), "Springer journals and books across all disciplines."),
    ("ProQuest Databases", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://search.proquest.com"), "Broad multidisciplinary discovery."),
    ("Emerald Insight", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.emerald.com/insight"), "Social sciences, management, and interdisciplinary research."),
    ("JSTOR", _safe_db_url("https://khalifa.idm.oclc.org/login?url=https://www.jstor.org"), "Foundational and archival literature across many fields."),
]