deploy : current attempt at backend dockerization

This commit is contained in:
martin legrand
2025-05-29 10:51:08 +08:00
committed by Antoine Vivies
parent c1a1e9409d
commit a3ad635728
10 changed files with 170 additions and 35 deletions
+2
View File
@@ -2,3 +2,5 @@ SEARXNG_BASE_URL="http://127.0.0.1:8080"
OPENAI_API_KEY='xxxxx' OPENAI_API_KEY='xxxxx'
DEEPSEEK_API_KEY='xxxxx' DEEPSEEK_API_KEY='xxxxx'
OPENROUTER_API_KEY='xxxxx' OPENROUTER_API_KEY='xxxxx'
BACKEND_PORT=8000
WORK_DIR="/tmp/"
+1
View File
@@ -19,6 +19,7 @@ agentic_seek_env/*
.env .env
*/.env */.env
dsk/ dsk/
chrome136/
### react ### ### react ###
.DS_* .DS_*
+65 -24
View File
@@ -1,38 +1,57 @@
FROM ubuntu:22.04 FROM ubuntu:22.04
# Warning: doesn't work yet, backend is run on host machine for now
WORKDIR /app WORKDIR /app
RUN apt-get update -qq -y && \ # Install essential packages and Chrome dependencies
apt-get install -y \ RUN apt-get update && apt-get install -y \
gcc \ wget \
g++ \ unzip \
gfortran \ curl \
libportaudio2 \ gnupg \
portaudio19-dev \ python3-dev \
ffmpeg \ python3-pip \
libavcodec-dev \ python3-wheel \
libavformat-dev \ build-essential \
libavutil-dev \ # Chrome dependencies - comprehensive list
gnupg2 \ fonts-liberation \
wget \ libasound2 \
unzip \ libatk-bridge2.0-0 \
python3 \ libdrm2 \
python3-pip \ libxcomposite1 \
libasound2 \ libxdamage1 \
libatk-bridge2.0-0 \ libxrandr2 \
libgtk-4-1 \ libgbm1 \
libnss3 \ libxss1 \
xdg-utils \ libnss3 \
wget && \ libnspr4 \
libxshmfence1 \
libgconf-2-4 \
libxfixes3 \
libxinerama1 \
libgtk-3-0 \
libgdk-pixbuf2.0-0 \
libatspi2.0-0 \
libdrm2 \
libxkbcommon0 \
libepoxy0 \
libgtk-3-0 \
libharfbuzz0b \
libegl1-mesa \
libgles2-mesa \
# Virtual display for headless operation
xvfb \
&& rm -rf /var/lib/apt/lists/*
RUN pip3 install --upgrade pip setuptools wheel && \
pip3 install selenium
RUN chmod +x /opt/chrome/chrome
# Install dependencies # Install dependencies
COPY requirements.txt . COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt RUN pip install --no-cache-dir -r requirements.txt
# Copy application code # Copy application code
COPY api.py . COPY api.py .
COPY chrome_bundle/ ./chrome_bundle/
COPY sources/ ./sources/ COPY sources/ ./sources/
COPY prompts/ ./prompts/ COPY prompts/ ./prompts/
COPY crx/ crx/ COPY crx/ crx/
@@ -40,6 +59,28 @@ COPY llm_router/ llm_router/
COPY .env . COPY .env .
COPY config.ini . COPY config.ini .
# Install Chrome and ChromeDriver from chrome-for-testing
RUN wget -O chrome-linux64.zip https://storage.googleapis.com/chrome-for-testing-public/136.0.7103.113/linux64/chrome-linux64.zip && \
wget -O chromedriver-linux64.zip https://storage.googleapis.com/chrome-for-testing-public/136.0.7103.113/linux64/chromedriver-linux64.zip && \
unzip chrome-linux64.zip && \
unzip chromedriver-linux64.zip && \
mkdir -p /opt/google && \
ls -la && \
mv chrome-linux64 /opt/google/chrome && \
mv chromedriver-linux64/chromedriver /usr/local/bin/chromedriver && \
chmod +x /opt/google/chrome/chrome && \
chmod +x /usr/local/bin/chromedriver
RUN ln -s /opt/google/chrome/chrome /usr/local/bin/chrome
# Verify Chrome and ChromeDriver installation
RUN google-chrome --version
RUN chromedriver --version > /dev/null 2>&1
ENV CHROME_BIN=/opt/google/chrome/chrome
ENV CHROMEDRIVER_PATH=/usr/local/bin/chromedriver
ENV DISPLAY=:99
# Expose port # Expose port
EXPOSE 8000 EXPOSE 8000
+4
View File
@@ -559,3 +559,7 @@ Were looking for developers to improve AgenticSeek! Check out open issues or
> [antoineVIVIES](https://github.com/antoineVIVIES) | Taipei Time > [antoineVIVIES](https://github.com/antoineVIVIES) | Taipei Time
> [steveh8758](https://github.com/steveh8758) | Taipei Time > [steveh8758](https://github.com/steveh8758) | Taipei Time
## Special Thanks:
> [tcsenpai](https://github.com/tcsenpai) For dockerization of backend
+9
View File
@@ -22,6 +22,10 @@ from sources.utility import pretty_print
from sources.logger import Logger from sources.logger import Logger
from sources.schemas import QueryRequest, QueryResponse from sources.schemas import QueryRequest, QueryResponse
from dotenv import load_dotenv
load_dotenv()
from celery import Celery from celery import Celery
@@ -247,4 +251,9 @@ async def process_query(request: QueryRequest):
interaction.save_session() interaction.save_session()
if __name__ == "__main__": if __name__ == "__main__":
envport = os.getenv("BACKEND_PORT")
if envport:
port = int(envport)
else:
port = 8000
uvicorn.run(api, host="0.0.0.0", port=8000) uvicorn.run(api, host="0.0.0.0", port=8000)
+18 -3
View File
@@ -31,7 +31,7 @@ services:
volumes: volumes:
- ./searxng:/etc/searxng:rw - ./searxng:/etc/searxng:rw
environment: environment:
- SEARXNG_BASE_URL=http://localhost:8080/ - SEARXNG_BASE_URL=${SEARXNG_BASE_URL:-http://localhost:8080/}
- SEARXNG_SECRET_KEY=$(openssl rand -hex 32) - SEARXNG_SECRET_KEY=$(openssl rand -hex 32)
- UWSGI_WORKERS=4 - UWSGI_WORKERS=4
- UWSGI_THREADS=4 - UWSGI_THREADS=4
@@ -62,13 +62,28 @@ services:
environment: environment:
- NODE_ENV=development - NODE_ENV=development
- CHOKIDAR_USEPOLLING=true - CHOKIDAR_USEPOLLING=true
- BACKEND_URL=http://backend:8000 - REACT_APP_BACKEND_URL=http://0.0.0.0:${BACKEND_PORT:-8000}
networks: networks:
- agentic-seek-net - agentic-seek-net
backend:
container_name: backend
build:
context: .
dockerfile: Dockerfile.backend
ports:
- ${BACKEND_PORT:-8000}:${BACKEND_PORT:-8000}
volumes:
- ./:/app
- ${WORK_DIR}:${WORK_DIR}
command: python3 api.py
environment:
- SEARXNG_URL=http://localhost:8080
- WORK_DIR=${WORK_DIR}
network_mode: "host"
# NOTE: backend service is not working yet due to issue with chromedriver on docker. # NOTE: backend service is not working yet due to issue with chromedriver on docker.
# Therefore backend is run on host machine. # Therefore backend is run on host machine.
# Open to pull requests to fix this.
#backend: #backend:
# container_name: backend # container_name: backend
+7 -5
View File
@@ -4,6 +4,8 @@ import axios from 'axios';
import './App.css'; import './App.css';
import { colors } from './colors'; import { colors } from './colors';
const BACKEND_URL = process.env.REACT_APP_BACKEND_URL || 'http://0.0.0.0:8000';
function App() { function App() {
const [query, setQuery] = useState(''); const [query, setQuery] = useState('');
const [messages, setMessages] = useState([]); const [messages, setMessages] = useState([]);
@@ -27,7 +29,7 @@ function App() {
const checkHealth = async () => { const checkHealth = async () => {
try { try {
await axios.get('http://127.0.0.1:8000/health'); await axios.get(`${BACKEND_URL}/health`);
setIsOnline(true); setIsOnline(true);
console.log('System is online'); console.log('System is online');
} catch { } catch {
@@ -39,7 +41,7 @@ function App() {
const fetchScreenshot = async () => { const fetchScreenshot = async () => {
try { try {
const timestamp = new Date().getTime(); const timestamp = new Date().getTime();
const res = await axios.get(`http://127.0.0.1:8000/screenshots/updated_screen.png?timestamp=${timestamp}`, { const res = await axios.get(`${BACKEND_URL}/screenshots/updated_screen.png?timestamp=${timestamp}`, {
responseType: 'blob' responseType: 'blob'
}); });
console.log('Screenshot fetched successfully'); console.log('Screenshot fetched successfully');
@@ -90,7 +92,7 @@ function App() {
const fetchLatestAnswer = async () => { const fetchLatestAnswer = async () => {
try { try {
const res = await axios.get('http://127.0.0.1:8000/latest_answer'); const res = await axios.get(`${BACKEND_URL}/latest_answer`);
const data = res.data; const data = res.data;
updateData(data); updateData(data);
@@ -141,7 +143,7 @@ function App() {
setIsLoading(false); setIsLoading(false);
setError(null); setError(null);
try { try {
const res = await axios.get('http://127.0.0.1:8000/stop'); const res = await axios.get(`${BACKEND_URL}/stop`);
setStatus("Requesting stop..."); setStatus("Requesting stop...");
} catch (err) { } catch (err) {
console.error('Error stopping the agent:', err); console.error('Error stopping the agent:', err);
@@ -162,7 +164,7 @@ function App() {
try { try {
console.log('Sending query:', query); console.log('Sending query:', query);
setQuery('waiting for response...'); setQuery('waiting for response...');
const res = await axios.post('http://127.0.0.1:8000/query', { const res = await axios.post(`${BACKEND_URL}/query`, {
query, query,
tts_enabled: false tts_enabled: false
}); });
+1
View File
@@ -41,6 +41,7 @@ fake_useragent>=2.1.0
selenium_stealth>=1.0.6 selenium_stealth>=1.0.6
undetected-chromedriver>=3.5.5 undetected-chromedriver>=3.5.5
sentencepiece>=0.2.0 sentencepiece>=0.2.0
python-dotenv>=1.0.0
tqdm>4 tqdm>4
openai openai
sniffio sniffio
+13 -1
View File
@@ -42,7 +42,14 @@ def get_chrome_path() -> str:
paths = ["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", paths = ["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
"/Applications/Google Chrome Beta.app/Contents/MacOS/Google Chrome Beta"] "/Applications/Google Chrome Beta.app/Contents/MacOS/Google Chrome Beta"]
else: # Linux else: # Linux
paths = ["/usr/bin/google-chrome", "/usr/bin/chromium-browser", "/usr/bin/chromium", "/opt/chrome/chrome", "/usr/local/bin/chrome"] paths = ["/usr/bin/google-chrome",
"/usr/bin/chromium-browser",
"/usr/bin/chromium",
"/opt/chrome/chrome",
"opt/google/chrome/chrome",
"/usr/local/bin/chrome",
#"/app/chrome_bundle/chrome136/chrome-linux64"
]
for path in paths: for path in paths:
if os.path.exists(path) and os.access(path, os.X_OK): if os.path.exists(path) and os.access(path, os.X_OK):
@@ -73,8 +80,13 @@ def install_chromedriver() -> str:
Install the ChromeDriver if not already installed. Return the path. Install the ChromeDriver if not already installed. Return the path.
""" """
chromedriver_path = shutil.which("chromedriver") chromedriver_path = shutil.which("chromedriver")
#if not chromedriver_path:
# if os.path.exists("/app/chrome_bundle/chrome136/chromedriver"):
# print("Using bundled ChromeDriver from /app/chrome_bundle/chrome136/chromedriver")
# chromedriver_path = "/app/chrome_bundle/chrome136/chromedriver"
if not chromedriver_path: if not chromedriver_path:
try: try:
print("ChromeDriver not found, attempting to install automatically...")
chromedriver_path = chromedriver_autoinstaller.install() chromedriver_path = chromedriver_autoinstaller.install()
except Exception as e: except Exception as e:
raise FileNotFoundError( raise FileNotFoundError(
+49 -1
View File
@@ -1,5 +1,7 @@
#!/bin/bash #!/bin/bash
source .env
command_exists() { command_exists() {
command -v "$1" &> /dev/null command -v "$1" &> /dev/null
} }
@@ -60,12 +62,58 @@ if [ ! -f "docker-compose.yml" ]; then
exit 1 exit 1
fi fi
# start docker compose for searxng, redis, frontend services # Download and extract Chrome bundle if not present
echo "Checking Chrome bundle..."
if [ ! -d "chrome_bundle/chrome136" ]; then
echo "Chrome bundle not found. Downloading..."
mkdir -p chrome_bundle
curl -L https://github.com/tcsenpai/agenticSeek/releases/download/utility/chrome136.zip -o /tmp/chrome136.zip
if [ $? -ne 0 ]; then
echo "Error: Failed to download Chrome bundle"
exit 1
fi
unzip -q /tmp/chrome136.zip -d chrome_bundle/
if [ $? -ne 0 ]; then
echo "Error: Failed to extract Chrome bundle"
exit 1
fi
rm /tmp/chrome136.zip
echo "Chrome bundle downloaded and extracted successfully"
else
echo "Chrome bundle already exists"
fi
# Stop all running containers to ensure a clean state
echo "Warning: stopping all docker containers (t-4 seconds)..." echo "Warning: stopping all docker containers (t-4 seconds)..."
sleep 4 sleep 4
docker stop $(docker ps -a -q) docker stop $(docker ps -a -q)
echo "All containers stopped" echo "All containers stopped"
# First start backend and wait for it to be healthy
echo "Starting backend service..."
if ! $COMPOSE_CMD up -d backend; then
echo "Error: Failed to start backend container."
exit 1
fi
# Wait for backend to be healthy (check if it's running and not restarting)
echo "Waiting for backend to be ready..."
for i in {1..30}; do
if [ "$(docker inspect -f '{{.State.Running}}' backend)" = "true" ] && \
[ "$(docker inspect -f '{{.State.Restarting}}' backend)" = "false" ]; then
echo "backend is ready!"
break
fi
if [ $i -eq 30 ]; then
echo "Error: backend failed to start properly after 30 seconds"
$COMPOSE_CMD logs backend
exit 1
fi
sleep 1
done
# start remaining services for searxng, redis, frontend services
if ! $COMPOSE_CMD up; then if ! $COMPOSE_CMD up; then
echo "Error: Failed to start containers. Check Docker logs with '$COMPOSE_CMD logs'." echo "Error: Failed to start containers. Check Docker logs with '$COMPOSE_CMD logs'."
echo "Possible fixes: Run with sudo or ensure port 8080 is free." echo "Possible fixes: Run with sudo or ensure port 8080 is free."