Update src/api/agent.py
Browse files- src/api/agent.py +122 -38
src/api/agent.py
CHANGED
|
@@ -1861,22 +1861,120 @@ def _ai_tools_footer(context):
|
|
| 1861 |
if is_med and pubmed_url:
|
| 1862 |
platforms.append(("PubMed", pubmed_url))
|
| 1863 |
|
| 1864 |
-
|
| 1865 |
-
|
| 1866 |
-
|
| 1867 |
-
|
| 1868 |
-
|
| 1869 |
-
|
| 1870 |
-
|
| 1871 |
-
|
| 1872 |
-
|
| 1873 |
-
|
| 1874 |
-
|
| 1875 |
-
|
| 1876 |
-
|
| 1877 |
-
|
| 1878 |
-
|
| 1879 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1880 |
|
| 1881 |
def _btn(label, url, favicon=None):
|
| 1882 |
style = (
|
|
@@ -1935,10 +2033,11 @@ def _ai_tools_footer(context):
|
|
| 1935 |
all_lower = ((context.ai_tool_query or "") + " " + (context.topic or "")).lower()
|
| 1936 |
|
| 1937 |
def _db_row(name, url, desc, favicon=None):
|
|
|
|
| 1938 |
return (
|
| 1939 |
'<div style="display:flex;align-items:center;gap:8px;'
|
| 1940 |
'padding:7px 0;border-bottom:1px solid #f3f4f6">'
|
| 1941 |
-
+
|
| 1942 |
'<div><a href="' + url + '" target="_blank" '
|
| 1943 |
'style="font-size:.8rem;font-weight:700;color:#003366;text-decoration:none">'
|
| 1944 |
+ name + '</a>'
|
|
@@ -2786,27 +2885,6 @@ async def _search_follow_up(
|
|
| 2786 |
"action": "articles_only",
|
| 2787 |
"context_id": context.context_id,
|
| 2788 |
})
|
| 2789 |
-
filter_suggestions.append({
|
| 2790 |
-
"label": f"Limit {topic} to the last 5 years",
|
| 2791 |
-
"question": f"Limit {topic} to the last 5 years",
|
| 2792 |
-
"action": "last_5_years",
|
| 2793 |
-
"context_id": context.context_id,
|
| 2794 |
-
})
|
| 2795 |
-
else:
|
| 2796 |
-
if not context.peer_reviewed and context.source == "primo":
|
| 2797 |
-
filter_suggestions.append({
|
| 2798 |
-
"label": "Peer reviewed only",
|
| 2799 |
-
"question": f"Make the {topic} search peer reviewed only",
|
| 2800 |
-
"action": "peer_reviewed_only",
|
| 2801 |
-
"context_id": context.context_id,
|
| 2802 |
-
})
|
| 2803 |
-
if not (context.year_from and context.year_to == str(CURRENT_YEAR)):
|
| 2804 |
-
filter_suggestions.append({
|
| 2805 |
-
"label": "Last 5 years",
|
| 2806 |
-
"question": f"Limit {topic} to the last 5 years",
|
| 2807 |
-
"action": "last_5_years",
|
| 2808 |
-
"context_id": context.context_id,
|
| 2809 |
-
})
|
| 2810 |
if context.intent == "search_medical" and context.source != "pubmed":
|
| 2811 |
filter_suggestions.append({
|
| 2812 |
"label": "Search PubMed instead",
|
|
@@ -2917,6 +2995,12 @@ async def _run_search_mode(
|
|
| 2917 |
filters = _filters_summary(context)
|
| 2918 |
if filters:
|
| 2919 |
answer += f"<br><br><strong>Active filters:</strong> {_escape(filters)}."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2920 |
answer += _source_badge("primo", source_url)
|
| 2921 |
answer += _ai_tools_footer(context)
|
| 2922 |
|
|
|
|
| 1861 |
if is_med and pubmed_url:
|
| 1862 |
platforms.append(("PubMed", pubmed_url))
|
| 1863 |
|
| 1864 |
+
# Inline SVG mascots — unique per database type, no network requests
|
| 1865 |
+
_SVGS = {
|
| 1866 |
+
"bee": (
|
| 1867 |
+
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16" style="flex-shrink:0">'
|
| 1868 |
+
'<ellipse cx="4.5" cy="6.5" rx="3.5" ry="2" fill="#c7d9f0" opacity=".9"/>'
|
| 1869 |
+
'<ellipse cx="11.5" cy="6.5" rx="3.5" ry="2" fill="#c7d9f0" opacity=".9"/>'
|
| 1870 |
+
'<ellipse cx="8" cy="10" rx="4" ry="4.5" fill="#F5A623"/>'
|
| 1871 |
+
'<rect x="4.2" y="8.5" width="7.6" height="1.4" rx=".5" fill="#3d2000" opacity=".7"/>'
|
| 1872 |
+
'<rect x="4.2" y="10.8" width="7.6" height="1.4" rx=".5" fill="#3d2000" opacity=".7"/>'
|
| 1873 |
+
'<circle cx="8" cy="5" r="2.5" fill="#F5A623"/>'
|
| 1874 |
+
'<circle cx="7" cy="4.7" r=".5" fill="#1a1a2e"/>'
|
| 1875 |
+
'<circle cx="9" cy="4.7" r=".5" fill="#1a1a2e"/>'
|
| 1876 |
+
'<line x1="7" y1="2.5" x2="5.5" y2="1.2" stroke="#3d2000" stroke-width=".8" stroke-linecap="round"/>'
|
| 1877 |
+
'<line x1="9" y1="2.5" x2="10.5" y2="1.2" stroke="#3d2000" stroke-width=".8" stroke-linecap="round"/>'
|
| 1878 |
+
'<circle cx="5.5" cy="1.2" r=".6" fill="#3d2000"/>'
|
| 1879 |
+
'<circle cx="10.5" cy="1.2" r=".6" fill="#3d2000"/>'
|
| 1880 |
+
'</svg>'
|
| 1881 |
+
),
|
| 1882 |
+
"book": (
|
| 1883 |
+
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16" style="flex-shrink:0">'
|
| 1884 |
+
'<rect x="2" y="2" width="9" height="12" rx="1" fill="#2563eb"/>'
|
| 1885 |
+
'<rect x="3" y="2" width="1.5" height="12" fill="#1d4ed8"/>'
|
| 1886 |
+
'<rect x="4" y="4" width="5" height="1" rx=".5" fill="#bfdbfe"/>'
|
| 1887 |
+
'<rect x="4" y="6" width="5" height="1" rx=".5" fill="#bfdbfe"/>'
|
| 1888 |
+
'<rect x="4" y="8" width="3" height="1" rx=".5" fill="#bfdbfe"/>'
|
| 1889 |
+
'<rect x="11" y="3" width="3" height="10" rx="1" fill="#1e40af"/>'
|
| 1890 |
+
'</svg>'
|
| 1891 |
+
),
|
| 1892 |
+
"microscope": (
|
| 1893 |
+
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16" style="flex-shrink:0">'
|
| 1894 |
+
'<rect x="7" y="1" width="2" height="5" rx="1" fill="#6b7280"/>'
|
| 1895 |
+
'<ellipse cx="8" cy="1.5" rx="2.5" ry="1.5" fill="#9ca3af"/>'
|
| 1896 |
+
'<rect x="6.5" y="5" width="3" height="5" rx=".5" fill="#374151"/>'
|
| 1897 |
+
'<rect x="5" y="9.5" width="6" height="1.5" rx=".5" fill="#374151"/>'
|
| 1898 |
+
'<rect x="3" y="13" width="10" height="1.5" rx=".5" fill="#374151"/>'
|
| 1899 |
+
'<line x1="8" y1="11" x2="8" y2="13" stroke="#374151" stroke-width="1.5"/>'
|
| 1900 |
+
'<circle cx="8" cy="6" r="1.5" fill="#60a5fa" opacity=".8"/>'
|
| 1901 |
+
'</svg>'
|
| 1902 |
+
),
|
| 1903 |
+
"circuit": (
|
| 1904 |
+
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16" style="flex-shrink:0">'
|
| 1905 |
+
'<rect x="1" y="1" width="14" height="14" rx="2" fill="#1e293b"/>'
|
| 1906 |
+
'<circle cx="4" cy="4" r="1.5" fill="#22d3ee"/>'
|
| 1907 |
+
'<circle cx="12" cy="4" r="1.5" fill="#22d3ee"/>'
|
| 1908 |
+
'<circle cx="4" cy="12" r="1.5" fill="#22d3ee"/>'
|
| 1909 |
+
'<circle cx="12" cy="12" r="1.5" fill="#22d3ee"/>'
|
| 1910 |
+
'<circle cx="8" cy="8" r="2" fill="#06b6d4"/>'
|
| 1911 |
+
'<line x1="4" y1="4" x2="8" y2="8" stroke="#22d3ee" stroke-width=".8"/>'
|
| 1912 |
+
'<line x1="12" y1="4" x2="8" y2="8" stroke="#22d3ee" stroke-width=".8"/>'
|
| 1913 |
+
'<line x1="4" y1="12" x2="8" y2="8" stroke="#22d3ee" stroke-width=".8"/>'
|
| 1914 |
+
'<line x1="12" y1="12" x2="8" y2="8" stroke="#22d3ee" stroke-width=".8"/>'
|
| 1915 |
+
'</svg>'
|
| 1916 |
+
),
|
| 1917 |
+
"leaf": (
|
| 1918 |
+
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16" style="flex-shrink:0">'
|
| 1919 |
+
'<path d="M8 14 C8 14 2 10 2 5 C2 2 5 1 8 1 C11 1 14 2 14 5 C14 10 8 14 8 14Z" fill="#16a34a"/>'
|
| 1920 |
+
'<line x1="8" y1="1" x2="8" y2="14" stroke="#bbf7d0" stroke-width=".8"/>'
|
| 1921 |
+
'<line x1="8" y1="5" x2="5" y2="7" stroke="#bbf7d0" stroke-width=".6"/>'
|
| 1922 |
+
'<line x1="8" y1="7" x2="5" y2="9" stroke="#bbf7d0" stroke-width=".6"/>'
|
| 1923 |
+
'<line x1="8" y1="5" x2="11" y2="7" stroke="#bbf7d0" stroke-width=".6"/>'
|
| 1924 |
+
'<line x1="8" y1="7" x2="11" y2="9" stroke="#bbf7d0" stroke-width=".6"/>'
|
| 1925 |
+
'</svg>'
|
| 1926 |
+
),
|
| 1927 |
+
"gear": (
|
| 1928 |
+
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16" style="flex-shrink:0">'
|
| 1929 |
+
'<path d="M6.5 1h3l.5 1.5a5 5 0 011.2.7l1.5-.5 1.5 2.6-1.2 1a5 5 0 010 1.4l1.2 1-1.5 2.6-1.5-.5a5 5 0 01-1.2.7L9.5 15h-3l-.5-1.5a5 5 0 01-1.2-.7l-1.5.5L1.8 10.8l1.2-1a5 5 0 010-1.4l-1.2-1L3.3 4.8l1.5.5A5 5 0 016 4.5L6.5 1z" fill="#64748b"/>'
|
| 1930 |
+
'<circle cx="8" cy="8" r="2.5" fill="#f1f5f9"/>'
|
| 1931 |
+
'<circle cx="8" cy="8" r="1.2" fill="#64748b"/>'
|
| 1932 |
+
'</svg>'
|
| 1933 |
+
),
|
| 1934 |
+
"chart": (
|
| 1935 |
+
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16" style="flex-shrink:0">'
|
| 1936 |
+
'<rect x="1" y="1" width="14" height="14" rx="1.5" fill="#f0fdf4"/>'
|
| 1937 |
+
'<rect x="3" y="9" width="2" height="5" rx=".5" fill="#16a34a"/>'
|
| 1938 |
+
'<rect x="7" y="6" width="2" height="8" rx=".5" fill="#15803d"/>'
|
| 1939 |
+
'<rect x="11" y="3" width="2" height="11" rx=".5" fill="#166534"/>'
|
| 1940 |
+
'<line x1="1" y1="13.5" x2="15" y2="13.5" stroke="#166534" stroke-width=".8"/>'
|
| 1941 |
+
'</svg>'
|
| 1942 |
+
),
|
| 1943 |
+
"atom": (
|
| 1944 |
+
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16" style="flex-shrink:0">'
|
| 1945 |
+
'<ellipse cx="8" cy="8" rx="7" ry="3" fill="none" stroke="#7c3aed" stroke-width=".9"/>'
|
| 1946 |
+
'<ellipse cx="8" cy="8" rx="7" ry="3" fill="none" stroke="#7c3aed" stroke-width=".9" transform="rotate(60 8 8)"/>'
|
| 1947 |
+
'<ellipse cx="8" cy="8" rx="7" ry="3" fill="none" stroke="#7c3aed" stroke-width=".9" transform="rotate(120 8 8)"/>'
|
| 1948 |
+
'<circle cx="8" cy="8" r="1.8" fill="#7c3aed"/>'
|
| 1949 |
+
'</svg>'
|
| 1950 |
+
),
|
| 1951 |
+
"medical": (
|
| 1952 |
+
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16" style="flex-shrink:0">'
|
| 1953 |
+
'<rect x="1" y="1" width="14" height="14" rx="2" fill="#dc2626"/>'
|
| 1954 |
+
'<rect x="6.5" y="3" width="3" height="10" rx="1" fill="white"/>'
|
| 1955 |
+
'<rect x="3" y="6.5" width="10" height="3" rx="1" fill="white"/>'
|
| 1956 |
+
'</svg>'
|
| 1957 |
+
),
|
| 1958 |
+
"wrench": (
|
| 1959 |
+
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16" style="flex-shrink:0">'
|
| 1960 |
+
'<path d="M13 2a3 3 0 00-3 3c0 .4.1.8.2 1.1L2.6 13.7a1 1 0 001.4 1.4L11.7 7.8c.3.1.7.2 1.1.2a3 3 0 000-6z" fill="#d97706"/>'
|
| 1961 |
+
'<circle cx="12" cy="4" r="1.2" fill="#fef3c7"/>'
|
| 1962 |
+
'</svg>'
|
| 1963 |
+
),
|
| 1964 |
+
}
|
| 1965 |
+
# Per-database mascot map
|
| 1966 |
+
_DB_MASCOT = {
|
| 1967 |
+
"PubMed@KU": "microscope", "Embase": "medical", "CINAHL Ultimate": "medical",
|
| 1968 |
+
"Cochrane Library": "microscope", "UpToDate": "medical",
|
| 1969 |
+
"IEEE Xplore": "circuit", "ACM Digital Library": "circuit",
|
| 1970 |
+
"ScienceDirect": "microscope", "Scopus": "microscope",
|
| 1971 |
+
"Web of Science": "microscope", "SpringerLink": "book",
|
| 1972 |
+
"ACS Publications": "atom", "APS Journals": "atom", "Knovel": "wrench",
|
| 1973 |
+
"Business Source Complete": "chart", "Emerald Insight": "chart",
|
| 1974 |
+
"Taylor & Francis": "book", "EBSCO": "book",
|
| 1975 |
+
}
|
| 1976 |
+
_BEE = _SVGS["bee"] # default for platform buttons
|
| 1977 |
+
|
| 1978 |
|
| 1979 |
def _btn(label, url, favicon=None):
|
| 1980 |
style = (
|
|
|
|
| 2033 |
all_lower = ((context.ai_tool_query or "") + " " + (context.topic or "")).lower()
|
| 2034 |
|
| 2035 |
def _db_row(name, url, desc, favicon=None):
|
| 2036 |
+
icon = _SVGS.get(_DB_MASCOT.get(name, "bee"), _SVGS["bee"])
|
| 2037 |
return (
|
| 2038 |
'<div style="display:flex;align-items:center;gap:8px;'
|
| 2039 |
'padding:7px 0;border-bottom:1px solid #f3f4f6">'
|
| 2040 |
+
+ icon +
|
| 2041 |
'<div><a href="' + url + '" target="_blank" '
|
| 2042 |
'style="font-size:.8rem;font-weight:700;color:#003366;text-decoration:none">'
|
| 2043 |
+ name + '</a>'
|
|
|
|
| 2885 |
"action": "articles_only",
|
| 2886 |
"context_id": context.context_id,
|
| 2887 |
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2888 |
if context.intent == "search_medical" and context.source != "pubmed":
|
| 2889 |
filter_suggestions.append({
|
| 2890 |
"label": "Search PubMed instead",
|
|
|
|
| 2995 |
filters = _filters_summary(context)
|
| 2996 |
if filters:
|
| 2997 |
answer += f"<br><br><strong>Active filters:</strong> {_escape(filters)}."
|
| 2998 |
+
answer += (
|
| 2999 |
+
f"<br><br>🔍 Your search on <strong>{_escape(context.display_topic or context.topic)}</strong> "
|
| 3000 |
+
"has been prepared across multiple platforms below. "
|
| 3001 |
+
f'Click <a href="{source_url}" target="_blank" style="color:#003366;font-weight:700">'
|
| 3002 |
+
"PRIMO Library Discovery</a> to view your results, or explore any platform below."
|
| 3003 |
+
)
|
| 3004 |
answer += _source_badge("primo", source_url)
|
| 3005 |
answer += _ai_tools_footer(context)
|
| 3006 |
|