Spaces:
No application file
No application file
Upload 4 files
Browse files
Dockerfile
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Hugging Face Spaces - ResearchOS MVP Deployment
|
| 2 |
+
# Compatible with HF Spaces Docker SDK
|
| 3 |
+
|
| 4 |
+
FROM python:3.11-slim
|
| 5 |
+
|
| 6 |
+
WORKDIR /app
|
| 7 |
+
|
| 8 |
+
# Install system dependencies
|
| 9 |
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
| 10 |
+
nodejs npm curl \
|
| 11 |
+
gcc libpq-dev \
|
| 12 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 13 |
+
|
| 14 |
+
# Install Python dependencies for all services
|
| 15 |
+
COPY services/api-gateway/requirements.txt /tmp/req-gateway.txt
|
| 16 |
+
COPY services/project-service/requirements.txt /tmp/req-project.txt
|
| 17 |
+
COPY services/analysis-service/requirements.txt /tmp/req-analysis.txt
|
| 18 |
+
COPY services/auth-service/requirements.txt /tmp/req-auth.txt
|
| 19 |
+
COPY services/manuscript-service/requirements.txt /tmp/req-manuscript.txt
|
| 20 |
+
COPY services/verification-service/requirements.txt /tmp/req-verification.txt
|
| 21 |
+
COPY services/agent-service/requirements.txt /tmp/req-agent.txt
|
| 22 |
+
|
| 23 |
+
RUN pip install --no-cache-dir \
|
| 24 |
+
-r /tmp/req-gateway.txt \
|
| 25 |
+
-r /tmp/req-project.txt \
|
| 26 |
+
-r /tmp/req-analysis.txt \
|
| 27 |
+
-r /tmp/req-auth.txt \
|
| 28 |
+
-r /tmp/req-manuscript.txt \
|
| 29 |
+
-r /tmp/req-verification.txt \
|
| 30 |
+
-r /tmp/req-agent.txt \
|
| 31 |
+
gradio==4.0.0
|
| 32 |
+
|
| 33 |
+
# Copy all source code
|
| 34 |
+
COPY services/ /app/services/
|
| 35 |
+
COPY agents/ /app/agents/
|
| 36 |
+
COPY packages/ /app/packages/
|
| 37 |
+
COPY apps/web/ /app/apps/web/
|
| 38 |
+
COPY docs/ /app/docs/
|
| 39 |
+
COPY scripts/ /app/scripts/
|
| 40 |
+
|
| 41 |
+
# Build Next.js frontend
|
| 42 |
+
RUN cd /app/apps/web && npm install && npm run build
|
| 43 |
+
|
| 44 |
+
# Copy HF-specific files
|
| 45 |
+
COPY infrastructure/huggingface/start.sh /app/start.sh
|
| 46 |
+
COPY infrastructure/huggingface/app.py /app/app.py
|
| 47 |
+
RUN chmod +x /app/start.sh
|
| 48 |
+
|
| 49 |
+
# Environment setup for HF Spaces
|
| 50 |
+
ENV PYTHONPATH=/app
|
| 51 |
+
ENV NODE_ENV=production
|
| 52 |
+
ENV DATABASE_URL=sqlite:///app/researchos.db
|
| 53 |
+
ENV JWT_SECRET=hf-spaces-secret-change-me
|
| 54 |
+
ENV API_GATEWAY_URL=http://localhost:8000
|
| 55 |
+
ENV WEBSOCKET_URL=ws://localhost:8003
|
| 56 |
+
|
| 57 |
+
# HF Spaces exposes 7860
|
| 58 |
+
EXPOSE 7860
|
| 59 |
+
ENV PORT=7860
|
| 60 |
+
|
| 61 |
+
# Use start.sh for Docker SDK, app.py for Gradio SDK fallback
|
| 62 |
+
CMD ["/app/start.sh"]
|
README.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: ResearchOS
|
| 3 |
+
colorFrom: blue
|
| 4 |
+
colorTo: indigo
|
| 5 |
+
sdk: docker
|
| 6 |
+
app_port: 7860
|
| 7 |
+
---
|
| 8 |
+
|
| 9 |
+
# ResearchOS on Hugging Face Spaces
|
| 10 |
+
|
| 11 |
+
AI-Powered Research Operating System MVP deployed on Hugging Face Spaces.
|
| 12 |
+
|
| 13 |
+
## What's Included
|
| 14 |
+
|
| 15 |
+
- **Frontend**: Next.js 14 app with project dashboard, manuscript editor, literature search, analysis upload, and peer review
|
| 16 |
+
- **API Gateway**: FastAPI router with JWT authentication
|
| 17 |
+
- **Auth Service**: User registration/login with bcrypt + JWT
|
| 18 |
+
- **Project Service**: Project CRUD with PostgreSQL/SQLite
|
| 19 |
+
- **Manuscript Service**: Document storage with versioning
|
| 20 |
+
- **Analysis Service**: Statistical engine with schema detection and APA output
|
| 21 |
+
- **Agent Service**: Literature search, writing generation, peer review simulation
|
| 22 |
+
- **Verification Service**: Cryptographic receipts + 3-probe verification
|
| 23 |
+
- **Collaboration Service**: WebSocket + Yjs real-time editing
|
| 24 |
+
|
| 25 |
+
## Environment Variables
|
| 26 |
+
|
| 27 |
+
Set these in your Space Settings:
|
| 28 |
+
|
| 29 |
+
| Variable | Required | Description |
|
| 30 |
+
|----------|----------|-------------|
|
| 31 |
+
| `JWT_SECRET` | Yes | Secret key for JWT tokens |
|
| 32 |
+
| `OPENAI_API_KEY` | No | For AI generation (falls back to HF API) |
|
| 33 |
+
| `HUGGINGFACE_API_TOKEN` | No | For HF Inference API fallback |
|
| 34 |
+
|
| 35 |
+
## Architecture on HF Spaces
|
| 36 |
+
|
| 37 |
+
Since HF Spaces is ephemeral:
|
| 38 |
+
- Uses **SQLite** instead of PostgreSQL (data resets on restart)
|
| 39 |
+
- File uploads stored in container (ephemeral)
|
| 40 |
+
- All services run in single container (simplified for MVP)
|
| 41 |
+
|
| 42 |
+
## Usage
|
| 43 |
+
|
| 44 |
+
1. Open the Space URL
|
| 45 |
+
2. Register a new account
|
| 46 |
+
3. Create a research project
|
| 47 |
+
4. Use Literature tab to search papers
|
| 48 |
+
5. Upload data in Analysis tab
|
| 49 |
+
6. Write manuscript in Writing tab
|
| 50 |
+
7. Run peer review simulation
|
| 51 |
+
|
| 52 |
+
## Limitations
|
| 53 |
+
|
| 54 |
+
- No persistent database (use external DB for production)
|
| 55 |
+
- Docker sandbox limited (analysis runs in-process)
|
| 56 |
+
- WebSockets may need polling fallback behind HF proxy
|
| 57 |
+
- File storage is ephemeral
|
| 58 |
+
|
| 59 |
+
## GitHub
|
| 60 |
+
|
| 61 |
+
Full source: [your-repo/researchos](https://github.com/your-repo/researchos)
|
app.py
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Hugging Face Spaces Entry Point for ResearchOS
|
| 3 |
+
This serves as the main entry point when using Gradio SDK fallback,
|
| 4 |
+
or as a health-check wrapper when using Docker SDK.
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
import gradio as gr
|
| 8 |
+
import os
|
| 9 |
+
import subprocess
|
| 10 |
+
import threading
|
| 11 |
+
import time
|
| 12 |
+
|
| 13 |
+
# Start all backend services in background thread
|
| 14 |
+
def start_services():
|
| 15 |
+
print("[HF Spaces] Starting ResearchOS services...")
|
| 16 |
+
|
| 17 |
+
# Set SQLite fallback for HF Spaces
|
| 18 |
+
os.environ.setdefault('DATABASE_URL', 'sqlite:///app/researchos.db')
|
| 19 |
+
os.environ.setdefault('JWT_SECRET', os.getenv('JWT_SECRET', 'hf-spaces-secret'))
|
| 20 |
+
|
| 21 |
+
services = [
|
| 22 |
+
("auth", "python services/auth-service/src/main.py"),
|
| 23 |
+
("project", "python services/project-service/src/main.py"),
|
| 24 |
+
("manuscript", "python services/manuscript-service/src/main.py"),
|
| 25 |
+
("analysis", "python services/analysis-service/src/main.py"),
|
| 26 |
+
("agent", "python services/agent-service/src/main.py"),
|
| 27 |
+
("verification", "python services/verification-service/src/main.py"),
|
| 28 |
+
]
|
| 29 |
+
|
| 30 |
+
for name, cmd in services:
|
| 31 |
+
try:
|
| 32 |
+
subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
| 33 |
+
print(f"[HF Spaces] Started {name} service")
|
| 34 |
+
time.sleep(1)
|
| 35 |
+
except Exception as e:
|
| 36 |
+
print(f"[HF Spaces] Failed to start {name}: {e}")
|
| 37 |
+
|
| 38 |
+
# Start API Gateway
|
| 39 |
+
time.sleep(2)
|
| 40 |
+
try:
|
| 41 |
+
subprocess.Popen("python services/api-gateway/src/main.py", shell=True)
|
| 42 |
+
print("[HF Spaces] Started API Gateway")
|
| 43 |
+
except Exception as e:
|
| 44 |
+
print(f"[HF Spaces] Failed to start API Gateway: {e}")
|
| 45 |
+
|
| 46 |
+
# Start Next.js frontend
|
| 47 |
+
time.sleep(2)
|
| 48 |
+
try:
|
| 49 |
+
subprocess.Popen("cd apps/web && PORT=7860 node server.js", shell=True)
|
| 50 |
+
print("[HF Spaces] Started Web Frontend on port 7860")
|
| 51 |
+
except Exception as e:
|
| 52 |
+
print(f"[HF Spaces] Failed to start frontend: {e}")
|
| 53 |
+
|
| 54 |
+
# Start services in background
|
| 55 |
+
threading.Thread(target=start_services, daemon=True).start()
|
| 56 |
+
|
| 57 |
+
# Gradio interface as fallback/wrapper
|
| 58 |
+
def health_check():
|
| 59 |
+
import urllib.request
|
| 60 |
+
try:
|
| 61 |
+
req = urllib.request.Request('http://localhost:8000/health', method='GET')
|
| 62 |
+
with urllib.request.urlopen(req, timeout=5) as resp:
|
| 63 |
+
return resp.read().decode()
|
| 64 |
+
except Exception as e:
|
| 65 |
+
return f"Services starting... ({str(e)})"
|
| 66 |
+
|
| 67 |
+
with gr.Blocks(title="ResearchOS") as demo:
|
| 68 |
+
gr.Markdown("# ResearchOS - AI Research Platform")
|
| 69 |
+
gr.Markdown("The full Next.js application is running in the background.")
|
| 70 |
+
|
| 71 |
+
with gr.Row():
|
| 72 |
+
with gr.Column():
|
| 73 |
+
gr.Markdown("### System Status")
|
| 74 |
+
status_btn = gr.Button("Check Health")
|
| 75 |
+
status_output = gr.Textbox(label="Status", value="Starting...")
|
| 76 |
+
status_btn.click(health_check, outputs=status_output)
|
| 77 |
+
|
| 78 |
+
with gr.Column():
|
| 79 |
+
gr.Markdown("### Quick Links")
|
| 80 |
+
gr.Markdown("- [Open Full App](/)")
|
| 81 |
+
gr.Markdown("- API Gateway: `http://localhost:8000`")
|
| 82 |
+
|
| 83 |
+
gr.Markdown("---")
|
| 84 |
+
gr.Markdown("If the full app doesn't load, wait 30 seconds for services to boot, then refresh.")
|
| 85 |
+
|
| 86 |
+
# Launch Gradio (this is required for HF Spaces Gradio SDK)
|
| 87 |
+
# But if using Docker SDK, this file is ignored and start.sh is used instead
|
| 88 |
+
demo.launch(server_name="0.0.0.0", server_port=7860, share=False)
|
start.sh
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
set -e
|
| 3 |
+
|
| 4 |
+
echo "=========================================="
|
| 5 |
+
echo " ResearchOS MVP - Hugging Face Spaces"
|
| 6 |
+
echo "=========================================="
|
| 7 |
+
|
| 8 |
+
# Initialize SQLite database
|
| 9 |
+
echo "[1/9] Initializing SQLite database..."
|
| 10 |
+
python3 << 'PYEOF'
|
| 11 |
+
import os
|
| 12 |
+
from sqlalchemy import create_engine
|
| 13 |
+
|
| 14 |
+
# Import all model bases
|
| 15 |
+
import sys
|
| 16 |
+
sys.path.insert(0, '/app')
|
| 17 |
+
|
| 18 |
+
# Create engine
|
| 19 |
+
engine = create_engine('sqlite:///app/researchos.db', echo=False)
|
| 20 |
+
|
| 21 |
+
# Create tables by importing main modules
|
| 22 |
+
from services.auth_service.src.main import Base as AuthBase
|
| 23 |
+
from services.project_service.src.main import Base as ProjectBase
|
| 24 |
+
from services.manuscript_service.src.main import Base as ManuscriptBase
|
| 25 |
+
from services.verification_service.src.main import Base as VerificationBase
|
| 26 |
+
|
| 27 |
+
AuthBase.metadata.create_all(engine)
|
| 28 |
+
ProjectBase.metadata.create_all(engine)
|
| 29 |
+
ManuscriptBase.metadata.create_all(engine)
|
| 30 |
+
VerificationBase.metadata.create_all(engine)
|
| 31 |
+
|
| 32 |
+
print("Database initialized successfully")
|
| 33 |
+
PYEOF
|
| 34 |
+
|
| 35 |
+
# Function to start a service
|
| 36 |
+
start_service() {
|
| 37 |
+
local name=$1
|
| 38 |
+
local port=$2
|
| 39 |
+
local cmd=$3
|
| 40 |
+
echo "[START] $name on port $port..."
|
| 41 |
+
eval "$cmd > /tmp/$name.log 2>&1 &"
|
| 42 |
+
echo $! > /tmp/$name.pid
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
# Start all backend services
|
| 46 |
+
start_service "auth-service" "8005" "python3 services/auth-service/src/main.py"
|
| 47 |
+
start_service "project-service" "8002" "python3 services/project-service/src/main.py"
|
| 48 |
+
start_service "manuscript-service" "8007" "python3 services/manuscript-service/src/main.py"
|
| 49 |
+
start_service "analysis-service" "8001" "python3 services/analysis-service/src/main.py"
|
| 50 |
+
start_service "agent-service" "8004" "python3 services/agent-service/src/main.py"
|
| 51 |
+
start_service "verification-service" "8006" "python3 services/verification-service/src/main.py"
|
| 52 |
+
|
| 53 |
+
# Wait for services to be ready
|
| 54 |
+
echo "[2/9] Waiting for services to boot..."
|
| 55 |
+
sleep 5
|
| 56 |
+
|
| 57 |
+
# Start API Gateway
|
| 58 |
+
start_service "api-gateway" "8000" "python3 services/api-gateway/src/main.py"
|
| 59 |
+
|
| 60 |
+
sleep 3
|
| 61 |
+
|
| 62 |
+
# Start Next.js frontend on port 7860 (HF Spaces requirement)
|
| 63 |
+
echo "[3/9] Starting Next.js frontend on port 7860..."
|
| 64 |
+
cd /app/apps/web && PORT=7860 node server.js > /tmp/web.log 2>&1 &
|
| 65 |
+
echo $! > /tmp/web.pid
|
| 66 |
+
|
| 67 |
+
echo ""
|
| 68 |
+
echo "=========================================="
|
| 69 |
+
echo " ResearchOS is starting up!"
|
| 70 |
+
echo "=========================================="
|
| 71 |
+
echo ""
|
| 72 |
+
echo "Services:"
|
| 73 |
+
echo " - Auth: http://localhost:8005"
|
| 74 |
+
echo " - Projects: http://localhost:8002"
|
| 75 |
+
echo " - Manuscripts: http://localhost:8007"
|
| 76 |
+
echo " - Analysis: http://localhost:8001"
|
| 77 |
+
echo " - Agents: http://localhost:8004"
|
| 78 |
+
echo " - Verification:http://localhost:8006"
|
| 79 |
+
echo " - API Gateway: http://localhost:8000"
|
| 80 |
+
echo " - Web App: http://localhost:7860"
|
| 81 |
+
echo ""
|
| 82 |
+
echo "Logs available in /tmp/*.log"
|
| 83 |
+
echo ""
|
| 84 |
+
|
| 85 |
+
# Health check loop
|
| 86 |
+
for i in {1..30}; do
|
| 87 |
+
if curl -s http://localhost:8000/health > /dev/null 2>&1; then
|
| 88 |
+
echo "[✓] API Gateway is ready!"
|
| 89 |
+
break
|
| 90 |
+
fi
|
| 91 |
+
echo "[...] Waiting for API Gateway ($i/30)..."
|
| 92 |
+
sleep 2
|
| 93 |
+
done
|
| 94 |
+
|
| 95 |
+
echo ""
|
| 96 |
+
echo "=========================================="
|
| 97 |
+
echo " ResearchOS is LIVE!"
|
| 98 |
+
echo "=========================================="
|
| 99 |
+
|
| 100 |
+
# Keep container alive and stream logs
|
| 101 |
+
tail -f /tmp/web.log /tmp/api-gateway.log 2>/dev/null || wait
|