Spaces:
Running
Running
Commit ·
4351cdd
1
Parent(s): dc84587
Deploy to Hugging Face Spaces - Remove Render, enable full features
Browse files- .dockerignore +5 -1
- .env +3 -0
- Dockerfile +2 -2
- Dockerfile.backend +0 -29
- Dockerfile.frontend +0 -26
- Dockerfile.render +0 -29
- README.md +46 -0
- app/api.py +36 -69
- config/config.py +2 -5
- render.yaml +0 -20
- requirements.txt +4 -5
- start.sh +0 -19
- startup.sh +3 -3
- supervisord.conf +0 -29
.dockerignore
CHANGED
|
@@ -1,6 +1,7 @@
|
|
| 1 |
# Git
|
| 2 |
.git
|
| 3 |
.gitignore
|
|
|
|
| 4 |
|
| 5 |
# Python
|
| 6 |
__pycache__
|
|
@@ -8,11 +9,11 @@ __pycache__
|
|
| 8 |
*$py.class
|
| 9 |
*.so
|
| 10 |
.Python
|
| 11 |
-
.env
|
| 12 |
.venv
|
| 13 |
env/
|
| 14 |
venv/
|
| 15 |
ENV/
|
|
|
|
| 16 |
|
| 17 |
# IDE
|
| 18 |
.vscode
|
|
@@ -28,4 +29,7 @@ Thumbs.db
|
|
| 28 |
|
| 29 |
# Docker
|
| 30 |
docker-compose*.yml
|
|
|
|
|
|
|
|
|
|
| 31 |
.dockerignore
|
|
|
|
| 1 |
# Git
|
| 2 |
.git
|
| 3 |
.gitignore
|
| 4 |
+
.gitattributes
|
| 5 |
|
| 6 |
# Python
|
| 7 |
__pycache__
|
|
|
|
| 9 |
*$py.class
|
| 10 |
*.so
|
| 11 |
.Python
|
|
|
|
| 12 |
.venv
|
| 13 |
env/
|
| 14 |
venv/
|
| 15 |
ENV/
|
| 16 |
+
.python-version
|
| 17 |
|
| 18 |
# IDE
|
| 19 |
.vscode
|
|
|
|
| 29 |
|
| 30 |
# Docker
|
| 31 |
docker-compose*.yml
|
| 32 |
+
|
| 33 |
+
# UV
|
| 34 |
+
uv.lock
|
| 35 |
.dockerignore
|
.env
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Environment variables
|
| 2 |
+
GROQ_API_KEY=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
|
| 3 |
+
TAVILY_API_KEY=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
|
Dockerfile
CHANGED
|
@@ -22,8 +22,8 @@ COPY . .
|
|
| 22 |
# Create directories for data persistence
|
| 23 |
RUN mkdir -p /app/workspace_data /app/chroma_db
|
| 24 |
|
| 25 |
-
#
|
| 26 |
-
EXPOSE
|
| 27 |
|
| 28 |
# Copy startup script
|
| 29 |
COPY startup.sh /app/startup.sh
|
|
|
|
| 22 |
# Create directories for data persistence
|
| 23 |
RUN mkdir -p /app/workspace_data /app/chroma_db
|
| 24 |
|
| 25 |
+
# Hugging Face Spaces uses port 7860
|
| 26 |
+
EXPOSE 7860
|
| 27 |
|
| 28 |
# Copy startup script
|
| 29 |
COPY startup.sh /app/startup.sh
|
Dockerfile.backend
DELETED
|
@@ -1,29 +0,0 @@
|
|
| 1 |
-
FROM python:3.11-slim
|
| 2 |
-
|
| 3 |
-
WORKDIR /app
|
| 4 |
-
|
| 5 |
-
# Install system dependencies
|
| 6 |
-
RUN apt-get update && apt-get install -y \
|
| 7 |
-
build-essential \
|
| 8 |
-
gcc \
|
| 9 |
-
curl \
|
| 10 |
-
&& rm -rf /var/lib/apt/lists/*
|
| 11 |
-
|
| 12 |
-
# Copy requirements first for caching
|
| 13 |
-
COPY requirements.txt .
|
| 14 |
-
|
| 15 |
-
# Install Python dependencies
|
| 16 |
-
RUN pip install --no-cache-dir --upgrade pip && \
|
| 17 |
-
pip install --no-cache-dir -r requirements.txt
|
| 18 |
-
|
| 19 |
-
# Copy application code
|
| 20 |
-
COPY . .
|
| 21 |
-
|
| 22 |
-
# Create directories for data persistence
|
| 23 |
-
RUN mkdir -p /app/workspace_data /app/chroma_db
|
| 24 |
-
|
| 25 |
-
# Expose port
|
| 26 |
-
EXPOSE 8000
|
| 27 |
-
|
| 28 |
-
# Run FastAPI
|
| 29 |
-
CMD ["uvicorn", "app.api:app", "--host", "0.0.0.0", "--port", "8000"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Dockerfile.frontend
DELETED
|
@@ -1,26 +0,0 @@
|
|
| 1 |
-
FROM python:3.11-slim
|
| 2 |
-
|
| 3 |
-
WORKDIR /app
|
| 4 |
-
|
| 5 |
-
# Install system dependencies
|
| 6 |
-
RUN apt-get update && apt-get install -y \
|
| 7 |
-
build-essential \
|
| 8 |
-
gcc \
|
| 9 |
-
curl \
|
| 10 |
-
&& rm -rf /var/lib/apt/lists/*
|
| 11 |
-
|
| 12 |
-
# Copy requirements first for caching
|
| 13 |
-
COPY requirements.txt .
|
| 14 |
-
|
| 15 |
-
# Install Python dependencies
|
| 16 |
-
RUN pip install --no-cache-dir --upgrade pip && \
|
| 17 |
-
pip install --no-cache-dir -r requirements.txt
|
| 18 |
-
|
| 19 |
-
# Copy application code
|
| 20 |
-
COPY . .
|
| 21 |
-
|
| 22 |
-
# Expose port
|
| 23 |
-
EXPOSE 8501
|
| 24 |
-
|
| 25 |
-
# Run Streamlit
|
| 26 |
-
CMD ["streamlit", "run", "streamlit_app.py", "--server.port=8501", "--server.address=0.0.0.0", "--server.headless=true"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Dockerfile.render
DELETED
|
@@ -1,29 +0,0 @@
|
|
| 1 |
-
FROM python:3.11-slim
|
| 2 |
-
|
| 3 |
-
WORKDIR /app
|
| 4 |
-
|
| 5 |
-
# Install system dependencies
|
| 6 |
-
RUN apt-get update && apt-get install -y --no-install-recommends \
|
| 7 |
-
curl \
|
| 8 |
-
dos2unix \
|
| 9 |
-
&& rm -rf /var/lib/apt/lists/* \
|
| 10 |
-
&& apt-get clean
|
| 11 |
-
|
| 12 |
-
# Copy and install Python dependencies (cached layer)
|
| 13 |
-
COPY requirements.txt .
|
| 14 |
-
RUN pip install --no-cache-dir --upgrade pip && \
|
| 15 |
-
pip install --no-cache-dir -r requirements.txt
|
| 16 |
-
|
| 17 |
-
# Copy ALL application code
|
| 18 |
-
COPY . .
|
| 19 |
-
|
| 20 |
-
# Create workspace directories
|
| 21 |
-
RUN mkdir -p /app/workspace_data /app/chroma_db
|
| 22 |
-
|
| 23 |
-
# Fix line endings and make startup script executable
|
| 24 |
-
RUN dos2unix /app/start.sh && chmod +x /app/start.sh
|
| 25 |
-
|
| 26 |
-
# Render requires port 10000
|
| 27 |
-
EXPOSE 10000
|
| 28 |
-
|
| 29 |
-
CMD ["/bin/bash", "/app/start.sh"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
README.md
CHANGED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: Perplexity AI Clone
|
| 3 |
+
emoji: 🔍
|
| 4 |
+
colorFrom: blue
|
| 5 |
+
colorTo: purple
|
| 6 |
+
sdk: docker
|
| 7 |
+
pinned: false
|
| 8 |
+
license: mit
|
| 9 |
+
---
|
| 10 |
+
|
| 11 |
+
# Perplexity AI Clone
|
| 12 |
+
|
| 13 |
+
An AI-powered search and research assistant with multiple modes:
|
| 14 |
+
|
| 15 |
+
- **Automatic**: Auto-routes to best mode based on query
|
| 16 |
+
- **Web Search**: Real-time web search with citations
|
| 17 |
+
- **RAG**: Search uploaded documents
|
| 18 |
+
- **Deep Research**: Multi-step research with synthesis
|
| 19 |
+
- **Agentic**: Multi-agent RAG with planning
|
| 20 |
+
- **Analysis**: Data analysis and insights
|
| 21 |
+
- **Summarize**: Summarize content and documents
|
| 22 |
+
|
| 23 |
+
## Features
|
| 24 |
+
|
| 25 |
+
- 🔍 Real-time web search with Tavily
|
| 26 |
+
- 📚 Document upload and RAG
|
| 27 |
+
- 🤖 LangGraph-powered pipelines
|
| 28 |
+
- 💡 Follow-up question suggestions
|
| 29 |
+
- 🖼️ Image search integration
|
| 30 |
+
- 📊 Knowledge panels
|
| 31 |
+
|
| 32 |
+
## Environment Variables
|
| 33 |
+
|
| 34 |
+
Set these secrets in your Hugging Face Space:
|
| 35 |
+
|
| 36 |
+
- `GROQ_API_KEY`: Your Groq API key
|
| 37 |
+
- `TAVILY_API_KEY`: Your Tavily API key
|
| 38 |
+
|
| 39 |
+
## Tech Stack
|
| 40 |
+
|
| 41 |
+
- FastAPI backend
|
| 42 |
+
- Streamlit frontend
|
| 43 |
+
- LangChain + LangGraph
|
| 44 |
+
- Groq LLM (llama3-70b-8192)
|
| 45 |
+
- FAISS vector store
|
| 46 |
+
- Sentence Transformers embeddings
|
app/api.py
CHANGED
|
@@ -54,12 +54,12 @@ app.add_middleware(
|
|
| 54 |
|
| 55 |
|
| 56 |
# =======================================================
|
| 57 |
-
# Health Check Endpoint
|
| 58 |
# =======================================================
|
| 59 |
@app.get("/health")
|
| 60 |
async def health_check():
|
| 61 |
"""Health check endpoint for container orchestration"""
|
| 62 |
-
return {"status": "healthy", "service": "perplexity-clone-api"
|
| 63 |
|
| 64 |
|
| 65 |
# =======================================================
|
|
@@ -76,47 +76,35 @@ browse_tool = BrowseTool()
|
|
| 76 |
image_search = TavilyImageSearch()
|
| 77 |
summarizer = SummarizerTool()
|
| 78 |
|
| 79 |
-
#
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
vector.create(demo_splits)
|
| 94 |
-
else:
|
| 95 |
-
reranker = None
|
| 96 |
-
knowledge_panel = None
|
| 97 |
-
vector = None
|
| 98 |
-
print("⚡ LITE_MODE: Skipping heavy embeddings to save memory")
|
| 99 |
|
| 100 |
# File manager for per-workspace document RAG
|
| 101 |
file_manager = FileManager(base_dir="workspace_data")
|
| 102 |
|
| 103 |
# =======================================================
|
| 104 |
-
# Initialize All LangGraph Pipelines
|
| 105 |
# =======================================================
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
agentic_graph = AgenticRAGGraph(file_manager, vector, image_search)
|
| 110 |
-
else:
|
| 111 |
-
deep_graph = None
|
| 112 |
-
rag_graph = None
|
| 113 |
-
agentic_graph = None
|
| 114 |
-
|
| 115 |
web_graph = WebSearchGraph()
|
| 116 |
analysis_graph = AnalysisGraph()
|
| 117 |
summarize_graph = SummarizeGraph()
|
| 118 |
|
| 119 |
-
print("✅ All LangGraph pipelines initialized!"
|
| 120 |
|
| 121 |
|
| 122 |
# =======================================================
|
|
@@ -487,15 +475,9 @@ def deep_research(req: ChatRequest):
|
|
| 487 |
memory.add(ws, "user", q)
|
| 488 |
|
| 489 |
try:
|
| 490 |
-
|
| 491 |
-
|
| 492 |
-
|
| 493 |
-
answer = state.get("answer", "No answer generated.")
|
| 494 |
-
sources = state.get("sources", [])
|
| 495 |
-
else:
|
| 496 |
-
state = deep_graph.run(q)
|
| 497 |
-
answer = state.get("final_answer", "No answer generated.")
|
| 498 |
-
sources = state.get("sources", [])
|
| 499 |
except Exception as e:
|
| 500 |
print(f"Deep research error: {e}")
|
| 501 |
answer = f"Deep research encountered an error. Please try again."
|
|
@@ -971,17 +953,11 @@ def rag_mode(req: ModeRequest):
|
|
| 971 |
memory.add(ws, "user", q)
|
| 972 |
|
| 973 |
try:
|
| 974 |
-
|
| 975 |
-
|
| 976 |
-
|
| 977 |
-
|
| 978 |
-
|
| 979 |
-
else:
|
| 980 |
-
# Run the RAGOnlyGraph pipeline
|
| 981 |
-
state = rag_graph.run(q, ws)
|
| 982 |
-
answer = state.get("answer", "No answer generated.")
|
| 983 |
-
sources = state.get("sources", [])
|
| 984 |
-
follow = state.get("followups", [])
|
| 985 |
except Exception as e:
|
| 986 |
print(f"RAG error: {e}")
|
| 987 |
answer = f"RAG mode encountered an error: {str(e)[:100]}"
|
|
@@ -1014,22 +990,13 @@ def agentic_mode(req: ModeRequest):
|
|
| 1014 |
print(f"\n🤖 AGENTIC MODE (LangGraph): {q}")
|
| 1015 |
|
| 1016 |
try:
|
| 1017 |
-
|
| 1018 |
-
|
| 1019 |
-
|
| 1020 |
-
|
| 1021 |
-
|
| 1022 |
-
|
| 1023 |
-
|
| 1024 |
-
follow = state.get("followups", [])
|
| 1025 |
-
else:
|
| 1026 |
-
# Run the AgenticRAGGraph pipeline
|
| 1027 |
-
state = agentic_graph.run(q, ws)
|
| 1028 |
-
answer = state.get("answer", "No answer generated.")
|
| 1029 |
-
sources = state.get("sources", [])
|
| 1030 |
-
links = state.get("links", [])
|
| 1031 |
-
images = state.get("images", [])
|
| 1032 |
-
follow = state.get("followups", [])
|
| 1033 |
except Exception as e:
|
| 1034 |
print(f"Agentic error: {e}")
|
| 1035 |
answer = f"Agentic mode encountered an error: {str(e)[:100]}"
|
|
|
|
| 54 |
|
| 55 |
|
| 56 |
# =======================================================
|
| 57 |
+
# Health Check Endpoint
|
| 58 |
# =======================================================
|
| 59 |
@app.get("/health")
|
| 60 |
async def health_check():
|
| 61 |
"""Health check endpoint for container orchestration"""
|
| 62 |
+
return {"status": "healthy", "service": "perplexity-clone-api"}
|
| 63 |
|
| 64 |
|
| 65 |
# =======================================================
|
|
|
|
| 76 |
image_search = TavilyImageSearch()
|
| 77 |
summarizer = SummarizerTool()
|
| 78 |
|
| 79 |
+
# Load all components
|
| 80 |
+
reranker = Reranker()
|
| 81 |
+
knowledge_panel = KnowledgePanel()
|
| 82 |
+
|
| 83 |
+
# RAG demo vectorstore
|
| 84 |
+
processor = DocumentProcessor(
|
| 85 |
+
chunk_size=Config.CHUNK_SIZE,
|
| 86 |
+
chunk_overlap=Config.CHUNK_OVERLAP,
|
| 87 |
+
)
|
| 88 |
+
demo_docs = processor.load_url("https://lilianweng.github.io/posts/2023-06-23-agent/")
|
| 89 |
+
demo_splits = processor.split(demo_docs)
|
| 90 |
+
|
| 91 |
+
vector = VectorStore()
|
| 92 |
+
vector.create(demo_splits)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 93 |
|
| 94 |
# File manager for per-workspace document RAG
|
| 95 |
file_manager = FileManager(base_dir="workspace_data")
|
| 96 |
|
| 97 |
# =======================================================
|
| 98 |
+
# Initialize All LangGraph Pipelines
|
| 99 |
# =======================================================
|
| 100 |
+
deep_graph = DeepResearchGraph(vector)
|
| 101 |
+
rag_graph = RAGOnlyGraph(file_manager)
|
| 102 |
+
agentic_graph = AgenticRAGGraph(file_manager, vector, image_search)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 103 |
web_graph = WebSearchGraph()
|
| 104 |
analysis_graph = AnalysisGraph()
|
| 105 |
summarize_graph = SummarizeGraph()
|
| 106 |
|
| 107 |
+
print("✅ All LangGraph pipelines initialized!")
|
| 108 |
|
| 109 |
|
| 110 |
# =======================================================
|
|
|
|
| 475 |
memory.add(ws, "user", q)
|
| 476 |
|
| 477 |
try:
|
| 478 |
+
state = deep_graph.run(q)
|
| 479 |
+
answer = state.get("final_answer", "No answer generated.")
|
| 480 |
+
sources = state.get("sources", [])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 481 |
except Exception as e:
|
| 482 |
print(f"Deep research error: {e}")
|
| 483 |
answer = f"Deep research encountered an error. Please try again."
|
|
|
|
| 953 |
memory.add(ws, "user", q)
|
| 954 |
|
| 955 |
try:
|
| 956 |
+
# Run the RAGOnlyGraph pipeline
|
| 957 |
+
state = rag_graph.run(q, ws)
|
| 958 |
+
answer = state.get("answer", "No answer generated.")
|
| 959 |
+
sources = state.get("sources", [])
|
| 960 |
+
follow = state.get("followups", [])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 961 |
except Exception as e:
|
| 962 |
print(f"RAG error: {e}")
|
| 963 |
answer = f"RAG mode encountered an error: {str(e)[:100]}"
|
|
|
|
| 990 |
print(f"\n🤖 AGENTIC MODE (LangGraph): {q}")
|
| 991 |
|
| 992 |
try:
|
| 993 |
+
# Run the AgenticRAGGraph pipeline
|
| 994 |
+
state = agentic_graph.run(q, ws)
|
| 995 |
+
answer = state.get("answer", "No answer generated.")
|
| 996 |
+
sources = state.get("sources", [])
|
| 997 |
+
links = state.get("links", [])
|
| 998 |
+
images = state.get("images", [])
|
| 999 |
+
follow = state.get("followups", [])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1000 |
except Exception as e:
|
| 1001 |
print(f"Agentic error: {e}")
|
| 1002 |
answer = f"Agentic mode encountered an error: {str(e)[:100]}"
|
config/config.py
CHANGED
|
@@ -8,14 +8,11 @@ class Config:
|
|
| 8 |
GROQ_API_KEY = os.getenv("GROQ_API_KEY")
|
| 9 |
TAVILY_API_KEY = os.getenv("TAVILY_API_KEY")
|
| 10 |
|
| 11 |
-
# Groq model
|
| 12 |
-
LLM_MODEL = os.getenv("LLM_MODEL", "
|
| 13 |
|
| 14 |
CHUNK_SIZE = 400
|
| 15 |
CHUNK_OVERLAP = 80
|
| 16 |
-
|
| 17 |
-
# Disable heavy features on free tier (512MB RAM limit)
|
| 18 |
-
LITE_MODE = os.getenv("LITE_MODE", "true").lower() == "true"
|
| 19 |
|
| 20 |
@classmethod
|
| 21 |
def get_llm(cls):
|
|
|
|
| 8 |
GROQ_API_KEY = os.getenv("GROQ_API_KEY")
|
| 9 |
TAVILY_API_KEY = os.getenv("TAVILY_API_KEY")
|
| 10 |
|
| 11 |
+
# Groq model - using llama3-70b-8192 for best performance
|
| 12 |
+
LLM_MODEL = os.getenv("LLM_MODEL", "llama3-70b-8192")
|
| 13 |
|
| 14 |
CHUNK_SIZE = 400
|
| 15 |
CHUNK_OVERLAP = 80
|
|
|
|
|
|
|
|
|
|
| 16 |
|
| 17 |
@classmethod
|
| 18 |
def get_llm(cls):
|
render.yaml
DELETED
|
@@ -1,20 +0,0 @@
|
|
| 1 |
-
services:
|
| 2 |
-
- type: web
|
| 3 |
-
name: perplexity-clone
|
| 4 |
-
env: docker
|
| 5 |
-
dockerfilePath: ./Dockerfile.render
|
| 6 |
-
dockerContext: .
|
| 7 |
-
plan: free
|
| 8 |
-
region: oregon
|
| 9 |
-
healthCheckPath: /health
|
| 10 |
-
envVars:
|
| 11 |
-
- key: GROQ_API_KEY
|
| 12 |
-
sync: false
|
| 13 |
-
- key: TAVILY_API_KEY
|
| 14 |
-
sync: false
|
| 15 |
-
- key: BACKEND_URL
|
| 16 |
-
value: http://localhost:8000
|
| 17 |
-
- key: LITE_MODE
|
| 18 |
-
value: "true"
|
| 19 |
-
- key: LLM_MODEL
|
| 20 |
-
value: "openai/gpt-oss-20b"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
requirements.txt
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
# =============================================
|
| 2 |
-
#
|
| 3 |
# =============================================
|
| 4 |
|
| 5 |
# Core LangChain (compatible versions)
|
|
@@ -26,9 +26,8 @@ streamlit==1.31.1
|
|
| 26 |
requests==2.31.0
|
| 27 |
httpx==0.26.0
|
| 28 |
|
| 29 |
-
# Embeddings
|
| 30 |
-
|
| 31 |
-
torch==2.2.0+cpu
|
| 32 |
sentence-transformers==2.3.1
|
| 33 |
|
| 34 |
# Vector search
|
|
@@ -37,7 +36,7 @@ faiss-cpu==1.7.4
|
|
| 37 |
# Web search
|
| 38 |
tavily-python==0.3.3
|
| 39 |
|
| 40 |
-
# Scraping
|
| 41 |
beautifulsoup4==4.12.3
|
| 42 |
lxml==5.1.0
|
| 43 |
|
|
|
|
| 1 |
# =============================================
|
| 2 |
+
# REQUIREMENTS FOR HUGGING FACE SPACES
|
| 3 |
# =============================================
|
| 4 |
|
| 5 |
# Core LangChain (compatible versions)
|
|
|
|
| 26 |
requests==2.31.0
|
| 27 |
httpx==0.26.0
|
| 28 |
|
| 29 |
+
# Embeddings
|
| 30 |
+
torch
|
|
|
|
| 31 |
sentence-transformers==2.3.1
|
| 32 |
|
| 33 |
# Vector search
|
|
|
|
| 36 |
# Web search
|
| 37 |
tavily-python==0.3.3
|
| 38 |
|
| 39 |
+
# Scraping
|
| 40 |
beautifulsoup4==4.12.3
|
| 41 |
lxml==5.1.0
|
| 42 |
|
start.sh
DELETED
|
@@ -1,19 +0,0 @@
|
|
| 1 |
-
#!/bin/bash
|
| 2 |
-
set -e
|
| 3 |
-
|
| 4 |
-
# Start FastAPI backend on port 8000 (internal only)
|
| 5 |
-
echo "Starting FastAPI backend on port 8000..."
|
| 6 |
-
uvicorn app.api:app --host 127.0.0.1 --port 8000 &
|
| 7 |
-
BACKEND_PID=$!
|
| 8 |
-
|
| 9 |
-
echo "Waiting for backend to initialize..."
|
| 10 |
-
sleep 5
|
| 11 |
-
echo "Backend started (PID: $BACKEND_PID)"
|
| 12 |
-
|
| 13 |
-
# Start Streamlit on port 10000 (Render's expected port)
|
| 14 |
-
echo "Starting Streamlit on port 10000..."
|
| 15 |
-
exec streamlit run streamlit_app.py \
|
| 16 |
-
--server.port=10000 \
|
| 17 |
-
--server.address=0.0.0.0 \
|
| 18 |
-
--server.headless=true \
|
| 19 |
-
--browser.gatherUsageStats=false
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
startup.sh
CHANGED
|
@@ -16,7 +16,7 @@ if ! kill -0 $BACKEND_PID 2>/dev/null; then
|
|
| 16 |
fi
|
| 17 |
|
| 18 |
echo "Backend started successfully (PID: $BACKEND_PID)"
|
| 19 |
-
echo "Starting Streamlit frontend on port
|
| 20 |
|
| 21 |
-
# Start Streamlit frontend
|
| 22 |
-
streamlit run streamlit_app.py --server.port
|
|
|
|
| 16 |
fi
|
| 17 |
|
| 18 |
echo "Backend started successfully (PID: $BACKEND_PID)"
|
| 19 |
+
echo "Starting Streamlit frontend on port 7860..."
|
| 20 |
|
| 21 |
+
# Start Streamlit frontend on port 7860 (Hugging Face Spaces default)
|
| 22 |
+
streamlit run streamlit_app.py --server.port 7860 --server.address 0.0.0.0 --server.headless true
|
supervisord.conf
DELETED
|
@@ -1,29 +0,0 @@
|
|
| 1 |
-
[supervisord]
|
| 2 |
-
nodaemon=true
|
| 3 |
-
user=root
|
| 4 |
-
logfile=/dev/stdout
|
| 5 |
-
logfile_maxbytes=0
|
| 6 |
-
loglevel=info
|
| 7 |
-
|
| 8 |
-
[program:fastapi]
|
| 9 |
-
command=uvicorn app.api:app --host 0.0.0.0 --port 8000 --workers 1
|
| 10 |
-
directory=/app
|
| 11 |
-
autostart=true
|
| 12 |
-
autorestart=true
|
| 13 |
-
stdout_logfile=/dev/stdout
|
| 14 |
-
stdout_logfile_maxbytes=0
|
| 15 |
-
stderr_logfile=/dev/stderr
|
| 16 |
-
stderr_logfile_maxbytes=0
|
| 17 |
-
priority=1
|
| 18 |
-
|
| 19 |
-
[program:streamlit]
|
| 20 |
-
command=streamlit run streamlit_app.py --server.port=10000 --server.address=0.0.0.0 --server.headless=true --browser.gatherUsageStats=false
|
| 21 |
-
directory=/app
|
| 22 |
-
autostart=true
|
| 23 |
-
autorestart=true
|
| 24 |
-
stdout_logfile=/dev/stdout
|
| 25 |
-
stdout_logfile_maxbytes=0
|
| 26 |
-
stderr_logfile=/dev/stderr
|
| 27 |
-
stderr_logfile_maxbytes=0
|
| 28 |
-
priority=2
|
| 29 |
-
startsecs=10
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|