Universities commited on
Commit
a68985d
·
verified ·
1 Parent(s): d4f773b

Upload 4 files

Browse files
Files changed (4) hide show
  1. Dockerfile +62 -0
  2. README.md +61 -0
  3. app.py +88 -0
  4. start.sh +101 -0
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