deploy : current attempt at backend dockerization
This commit is contained in:
+3
-1
@@ -1,4 +1,6 @@
|
|||||||
SEARXNG_BASE_URL="http://127.0.0.1:8080"
|
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/"
|
||||||
@@ -18,6 +18,7 @@ agentic_seek_env/*
|
|||||||
.env
|
.env
|
||||||
*/.env
|
*/.env
|
||||||
dsk/
|
dsk/
|
||||||
|
chrome136/
|
||||||
|
|
||||||
### react ###
|
### react ###
|
||||||
.DS_*
|
.DS_*
|
||||||
|
|||||||
+65
-24
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -557,3 +557,7 @@ We’re 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
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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."
|
||||||
|
|||||||
Reference in New Issue
Block a user