Commit ·
17ad76f
1
Parent(s): 215502f
Fix citation links and PDF viewer for HF Spaces via APP_PUBLIC_URL env var
Browse files- Dockerfile +4 -0
- backend/rag/langgraph/nodes/generator.py +5 -1
- frontend/pages/viewer.py +14 -3
Dockerfile
CHANGED
|
@@ -55,6 +55,10 @@ RUN mkdir -p \
|
|
| 55 |
ENV PYTHONUNBUFFERED=1
|
| 56 |
ENV UPLOAD_DIR=/tmp/uploads/documents
|
| 57 |
ENV HF_HOME=/home/appuser/.cache/huggingface
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
|
| 59 |
# HF Spaces exposes a single port
|
| 60 |
EXPOSE 7860
|
|
|
|
| 55 |
ENV PYTHONUNBUFFERED=1
|
| 56 |
ENV UPLOAD_DIR=/tmp/uploads/documents
|
| 57 |
ENV HF_HOME=/home/appuser/.cache/huggingface
|
| 58 |
+
# Set APP_PUBLIC_URL to your HF Space URL so citation links and the PDF viewer work.
|
| 59 |
+
# Example: ENV APP_PUBLIC_URL=https://salvirezwan-research-paper-rag-chatbot.hf.space
|
| 60 |
+
# Leave empty to default to localhost (local dev).
|
| 61 |
+
ENV APP_PUBLIC_URL=""
|
| 62 |
|
| 63 |
# HF Spaces exposes a single port
|
| 64 |
EXPOSE 7860
|
backend/rag/langgraph/nodes/generator.py
CHANGED
|
@@ -3,6 +3,7 @@ Generator node: build a context-augmented prompt from retrieved chunks,
|
|
| 3 |
call Groq LLM, and produce a cited research answer.
|
| 4 |
"""
|
| 5 |
|
|
|
|
| 6 |
from typing import List, Dict, Any
|
| 7 |
from urllib.parse import quote
|
| 8 |
|
|
@@ -13,7 +14,10 @@ from backend.rag.llm_client import get_chat_model
|
|
| 13 |
from backend.core.config import settings
|
| 14 |
from backend.core.logging import logger
|
| 15 |
|
| 16 |
-
|
|
|
|
|
|
|
|
|
|
| 17 |
|
| 18 |
_SYSTEM_PROMPT = """You are an expert academic research assistant.
|
| 19 |
|
|
|
|
| 3 |
call Groq LLM, and produce a cited research answer.
|
| 4 |
"""
|
| 5 |
|
| 6 |
+
import os
|
| 7 |
from typing import List, Dict, Any
|
| 8 |
from urllib.parse import quote
|
| 9 |
|
|
|
|
| 14 |
from backend.core.config import settings
|
| 15 |
from backend.core.logging import logger
|
| 16 |
|
| 17 |
+
# In HF Spaces set APP_PUBLIC_URL=https://<space-name>.hf.space
|
| 18 |
+
# Locally defaults to http://localhost:<streamlit_port>
|
| 19 |
+
_app_public_url = os.environ.get("APP_PUBLIC_URL", "").rstrip("/")
|
| 20 |
+
_VIEWER_BASE = f"{_app_public_url}/viewer" if _app_public_url else f"http://localhost:{settings.STREAMLIT_PORT}/viewer"
|
| 21 |
|
| 22 |
_SYSTEM_PROMPT = """You are an expert academic research assistant.
|
| 23 |
|
frontend/pages/viewer.py
CHANGED
|
@@ -6,6 +6,7 @@ URL query params:
|
|
| 6 |
?page=<int> — optional, scroll to this 1-based page number
|
| 7 |
"""
|
| 8 |
import json
|
|
|
|
| 9 |
import traceback
|
| 10 |
from urllib.parse import unquote
|
| 11 |
|
|
@@ -13,7 +14,14 @@ import requests
|
|
| 13 |
import streamlit as st
|
| 14 |
import streamlit.components.v1 as components
|
| 15 |
|
| 16 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
|
| 18 |
st.set_page_config(page_title="Document Viewer", layout="wide")
|
| 19 |
|
|
@@ -116,7 +124,10 @@ if not paper_id:
|
|
| 116 |
|
| 117 |
st.stop()
|
| 118 |
|
| 119 |
-
|
|
|
|
|
|
|
|
|
|
| 120 |
|
| 121 |
# Build JS search terms from section_id if no explicit page given
|
| 122 |
search_terms_js = "[]"
|
|
@@ -131,7 +142,7 @@ target_page_js = json.dumps(page_number)
|
|
| 131 |
|
| 132 |
try:
|
| 133 |
with st.spinner("Loading document…"):
|
| 134 |
-
resp = requests.get(
|
| 135 |
|
| 136 |
if resp.status_code == 404:
|
| 137 |
st.error("❌ Document not found. It may have been deleted.")
|
|
|
|
| 6 |
?page=<int> — optional, scroll to this 1-based page number
|
| 7 |
"""
|
| 8 |
import json
|
| 9 |
+
import os
|
| 10 |
import traceback
|
| 11 |
from urllib.parse import unquote
|
| 12 |
|
|
|
|
| 14 |
import streamlit as st
|
| 15 |
import streamlit.components.v1 as components
|
| 16 |
|
| 17 |
+
# Internal backend URL (server-side Python requests — always localhost inside the container)
|
| 18 |
+
BACKEND_URL = os.environ.get("INTERNAL_BACKEND_URL", "http://localhost:8000")
|
| 19 |
+
|
| 20 |
+
# Public-facing base URL used by the browser (PDF.js fetches the PDF client-side)
|
| 21 |
+
# In HF Spaces: set APP_PUBLIC_URL=https://<space-name>.hf.space
|
| 22 |
+
# Locally: defaults to http://localhost:8000 (direct backend, or same as BACKEND_URL)
|
| 23 |
+
_app_public_url = os.environ.get("APP_PUBLIC_URL", "").rstrip("/")
|
| 24 |
+
PUBLIC_BACKEND_URL = _app_public_url if _app_public_url else BACKEND_URL
|
| 25 |
|
| 26 |
st.set_page_config(page_title="Document Viewer", layout="wide")
|
| 27 |
|
|
|
|
| 124 |
|
| 125 |
st.stop()
|
| 126 |
|
| 127 |
+
# Used for server-side fetching (Python) — always internal
|
| 128 |
+
pdf_url_internal = f"{BACKEND_URL}/api/v1/uploads/{paper_id}/view"
|
| 129 |
+
# Used by PDF.js in the browser — must be publicly reachable
|
| 130 |
+
pdf_url = f"{PUBLIC_BACKEND_URL}/api/v1/uploads/{paper_id}/view"
|
| 131 |
|
| 132 |
# Build JS search terms from section_id if no explicit page given
|
| 133 |
search_terms_js = "[]"
|
|
|
|
| 142 |
|
| 143 |
try:
|
| 144 |
with st.spinner("Loading document…"):
|
| 145 |
+
resp = requests.get(pdf_url_internal, stream=True, timeout=15)
|
| 146 |
|
| 147 |
if resp.status_code == 404:
|
| 148 |
st.error("❌ Document not found. It may have been deleted.")
|