From 16b8f1a4511beb11fbd999433fa46be5e1f7644f Mon Sep 17 00:00:00 2001 From: martin legrand Date: Sun, 25 May 2025 21:19:18 +0200 Subject: [PATCH 01/31] deploy : current attempt at backend dockerization --- .env.example | 4 +- .gitignore | 1 + Dockerfile.backend | 89 +++++++++++++++++++------- README.md | 4 ++ api.py | 9 +++ docker-compose.yml | 21 +++++- frontend/agentic-seek-front/src/App.js | 12 ++-- requirements.txt | 1 + sources/browser.py | 14 +++- start_services.sh | 50 ++++++++++++++- 10 files changed, 170 insertions(+), 35 deletions(-) diff --git a/.env.example b/.env.example index 069f23c..0e98844 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,6 @@ SEARXNG_BASE_URL="http://127.0.0.1:8080" OPENAI_API_KEY='xxxxx' DEEPSEEK_API_KEY='xxxxx' -OPENROUTER_API_KEY='xxxxx' \ No newline at end of file +OPENROUTER_API_KEY='xxxxx' +BACKEND_PORT=8000 +WORK_DIR="/tmp/" \ No newline at end of file diff --git a/.gitignore b/.gitignore index 5369222..43242b9 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ agentic_seek_env/* .env */.env dsk/ +chrome136/ ### react ### .DS_* diff --git a/Dockerfile.backend b/Dockerfile.backend index 1cb8149..9bae45f 100644 --- a/Dockerfile.backend +++ b/Dockerfile.backend @@ -1,38 +1,57 @@ FROM ubuntu:22.04 -# Warning: doesn't work yet, backend is run on host machine for now WORKDIR /app -RUN apt-get update -qq -y && \ -apt-get install -y \ - gcc \ - g++ \ - gfortran \ - libportaudio2 \ - portaudio19-dev \ - ffmpeg \ - libavcodec-dev \ - libavformat-dev \ - libavutil-dev \ - gnupg2 \ - wget \ - unzip \ - python3 \ - python3-pip \ - libasound2 \ - libatk-bridge2.0-0 \ - libgtk-4-1 \ - libnss3 \ - xdg-utils \ - wget && \ +# Install essential packages and Chrome dependencies +RUN apt-get update && apt-get install -y \ + wget \ + unzip \ + curl \ + gnupg \ + python3-dev \ + python3-pip \ + python3-wheel \ + build-essential \ + # Chrome dependencies - comprehensive list + fonts-liberation \ + libasound2 \ + libatk-bridge2.0-0 \ + libdrm2 \ + libxcomposite1 \ + libxdamage1 \ + libxrandr2 \ + libgbm1 \ + libxss1 \ + libnss3 \ + 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 COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt # Copy application code COPY api.py . +COPY chrome_bundle/ ./chrome_bundle/ COPY sources/ ./sources/ COPY prompts/ ./prompts/ COPY crx/ crx/ @@ -40,6 +59,28 @@ COPY llm_router/ llm_router/ COPY .env . 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 8000 diff --git a/README.md b/README.md index f18ccd0..31851f3 100644 --- a/README.md +++ b/README.md @@ -557,3 +557,7 @@ We’re looking for developers to improve AgenticSeek! Check out open issues or > [antoineVIVIES](https://github.com/antoineVIVIES) | Taipei Time > [steveh8758](https://github.com/steveh8758) | Taipei Time + +## Special Thanks: + + > [tcsenpai](https://github.com/tcsenpai) For dockerization of backend diff --git a/api.py b/api.py index fa82896..3689c04 100755 --- a/api.py +++ b/api.py @@ -22,6 +22,10 @@ from sources.utility import pretty_print from sources.logger import Logger from sources.schemas import QueryRequest, QueryResponse +from dotenv import load_dotenv + +load_dotenv() + from celery import Celery @@ -247,4 +251,9 @@ async def process_query(request: QueryRequest): interaction.save_session() 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) \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 2f78cb9..f2a0d6c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -31,7 +31,7 @@ services: volumes: - ./searxng:/etc/searxng:rw environment: - - SEARXNG_BASE_URL=http://localhost:8080/ + - SEARXNG_BASE_URL=${SEARXNG_BASE_URL:-http://localhost:8080/} - SEARXNG_SECRET_KEY=$(openssl rand -hex 32) - UWSGI_WORKERS=4 - UWSGI_THREADS=4 @@ -62,13 +62,28 @@ services: environment: - NODE_ENV=development - CHOKIDAR_USEPOLLING=true - - BACKEND_URL=http://backend:8000 + - REACT_APP_BACKEND_URL=http://0.0.0.0:${BACKEND_PORT:-8000} networks: - 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. # Therefore backend is run on host machine. - # Open to pull requests to fix this. #backend: # container_name: backend diff --git a/frontend/agentic-seek-front/src/App.js b/frontend/agentic-seek-front/src/App.js index c1e6ba8..a9e6407 100644 --- a/frontend/agentic-seek-front/src/App.js +++ b/frontend/agentic-seek-front/src/App.js @@ -4,6 +4,8 @@ import axios from 'axios'; import './App.css'; import { colors } from './colors'; +const BACKEND_URL = process.env.REACT_APP_BACKEND_URL || 'http://0.0.0.0:8000'; + function App() { const [query, setQuery] = useState(''); const [messages, setMessages] = useState([]); @@ -27,7 +29,7 @@ function App() { const checkHealth = async () => { try { - await axios.get('http://127.0.0.1:8000/health'); + await axios.get(`${BACKEND_URL}/health`); setIsOnline(true); console.log('System is online'); } catch { @@ -39,7 +41,7 @@ function App() { const fetchScreenshot = async () => { try { 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' }); console.log('Screenshot fetched successfully'); @@ -90,7 +92,7 @@ function App() { const fetchLatestAnswer = async () => { 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; updateData(data); @@ -141,7 +143,7 @@ function App() { setIsLoading(false); setError(null); try { - const res = await axios.get('http://127.0.0.1:8000/stop'); + const res = await axios.get(`${BACKEND_URL}/stop`); setStatus("Requesting stop..."); } catch (err) { console.error('Error stopping the agent:', err); @@ -162,7 +164,7 @@ function App() { try { console.log('Sending query:', query); 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, tts_enabled: false }); diff --git a/requirements.txt b/requirements.txt index a63646c..eba75e1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -41,6 +41,7 @@ fake_useragent>=2.1.0 selenium_stealth>=1.0.6 undetected-chromedriver>=3.5.5 sentencepiece>=0.2.0 +python-dotenv>=1.0.0 tqdm>4 openai sniffio diff --git a/sources/browser.py b/sources/browser.py index 3604e9b..f3ebad4 100644 --- a/sources/browser.py +++ b/sources/browser.py @@ -42,7 +42,14 @@ def get_chrome_path() -> str: paths = ["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", "/Applications/Google Chrome Beta.app/Contents/MacOS/Google Chrome Beta"] 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: 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. """ 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: try: + print("ChromeDriver not found, attempting to install automatically...") chromedriver_path = chromedriver_autoinstaller.install() except Exception as e: raise FileNotFoundError( diff --git a/start_services.sh b/start_services.sh index 995f6ff..32759e8 100755 --- a/start_services.sh +++ b/start_services.sh @@ -1,5 +1,7 @@ #!/bin/bash +source .env + command_exists() { command -v "$1" &> /dev/null } @@ -60,12 +62,58 @@ if [ ! -f "docker-compose.yml" ]; then exit 1 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)..." sleep 4 docker stop $(docker ps -a -q) 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 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." From 6ec9647d19c0c54b2165e2961700cbfbfcfde127 Mon Sep 17 00:00:00 2001 From: martin legrand Date: Sun, 25 May 2025 21:56:29 +0200 Subject: [PATCH 02/31] comment out bundle approach --- Dockerfile.backend | 3 ++- start_services.sh | 39 ++++++++++++++++++++------------------- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/Dockerfile.backend b/Dockerfile.backend index 9bae45f..0e9b2e9 100644 --- a/Dockerfile.backend +++ b/Dockerfile.backend @@ -51,7 +51,8 @@ RUN pip install --no-cache-dir -r requirements.txt # Copy application code COPY api.py . -COPY chrome_bundle/ ./chrome_bundle/ +# Chrome bundle approach, commented out opting for direct download +#COPY chrome_bundle/ ./chrome_bundle/ COPY sources/ ./sources/ COPY prompts/ ./prompts/ COPY crx/ crx/ diff --git a/start_services.sh b/start_services.sh index 32759e8..ef95319 100755 --- a/start_services.sh +++ b/start_services.sh @@ -62,26 +62,27 @@ if [ ! -f "docker-compose.yml" ]; then exit 1 fi +# bundle based approach, commented out in favor of direct download for now # 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 +#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/Fosowl/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)..." From 500605d5da16f4f6d4f60c3f66e581b5fd7a5cdb Mon Sep 17 00:00:00 2001 From: martin legrand Date: Sun, 25 May 2025 21:57:56 +0200 Subject: [PATCH 03/31] remove commented service --- docker-compose.yml | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index f2a0d6c..df34535 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -82,35 +82,6 @@ services: - WORK_DIR=${WORK_DIR} network_mode: "host" - # NOTE: backend service is not working yet due to issue with chromedriver on docker. - # Therefore backend is run on host machine. - - #backend: - # container_name: backend - # build: - # context: ./ - # dockerfile: Dockerfile.backend - # stdin_open: true - # tty: true - # shm_size: 8g - # ports: - # - "8000:8000" - # volumes: - # - ./:/app - # environment: - # - NODE_ENV=development - # - REDIS_URL=redis://redis:6379/0 - # - SEARXNG_URL=http://searxng:8080 - # - OLLAMA_URL=http://localhost:11434 - # - LM_STUDIO_URL=http://localhost:1234 - # extra_hosts: - # - "host.docker.internal:host-gateway" - # depends_on: - # - redis - # - searxng - # networks: - # - agentic-seek-net - volumes: redis-data: chrome_profiles: From 50f9e11a350173164961122754fc2ecd198cf7a3 Mon Sep 17 00:00:00 2001 From: martin legrand Date: Sun, 25 May 2025 22:34:13 +0200 Subject: [PATCH 04/31] feat : optional run backend on host for start_services.sh --- docker-compose.yml | 4 ++++ start_services.sh | 56 +++++++++++++++++++++++++--------------------- 2 files changed, 34 insertions(+), 26 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index df34535..824d869 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,6 +3,7 @@ version: '3' services: redis: container_name: redis + profiles: ["core", "full"] image: docker.io/valkey/valkey:8-alpine command: valkey-server --save 30 1 --loglevel warning restart: unless-stopped @@ -24,6 +25,7 @@ services: searxng: container_name: searxng + profiles: ["core", "full"] image: docker.io/searxng/searxng:latest restart: unless-stopped ports: @@ -51,6 +53,7 @@ services: frontend: container_name: frontend + profiles: ["core", "full"] build: context: ./frontend dockerfile: Dockerfile.frontend @@ -68,6 +71,7 @@ services: backend: container_name: backend + profiles: ["backend", "full"] build: context: . dockerfile: Dockerfile.backend diff --git a/start_services.sh b/start_services.sh index ef95319..a972ce2 100755 --- a/start_services.sh +++ b/start_services.sh @@ -90,34 +90,38 @@ sleep 4 docker stop $(docker ps -a -q) 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 +if [ "$1" = "full" ]; then + # First start backend and wait for it to be healthy + echo "Full docker deployement. Starting backend service..." + if ! $COMPOSE_CMD up -d backend; then + echo "Error: Failed to start backend container." + exit 1 fi - if [ $i -eq 30 ]; then - echo "Error: backend failed to start properly after 30 seconds" - $COMPOSE_CMD logs backend + # 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 + if ! $COMPOSE_CMD --profile full up; then + 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." + exit 1 + fi +else + if ! $COMPOSE_CMD --profile core up; then + 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." exit 1 fi - sleep 1 -done - -# start remaining services for searxng, redis, frontend services - -if ! $COMPOSE_CMD up; then - 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." - exit 1 fi sleep 10 \ No newline at end of file From 58f46d43519c86d12feed3ce7ccacbb2801feca2 Mon Sep 17 00:00:00 2001 From: martin legrand Date: Tue, 27 May 2025 18:19:20 +0200 Subject: [PATCH 05/31] update start_servicees.sh --- README.md | 2 +- start_services.sh | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 31851f3..eee06aa 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Disclaimer: This demo, including all the files that appear (e.g: CV_candidates.z Make sure you have chrome driver, docker and python3.10 installed. -We highly advice you use exactly python3.10 for the setup. Dependencies error might happen otherwise. +We highly advise you use exactly python3.10 for the setup. Dependencies error might happen otherwise. For issues related to chrome driver, see the **Chromedriver** section. diff --git a/start_services.sh b/start_services.sh index a972ce2..07fcbb0 100755 --- a/start_services.sh +++ b/start_services.sh @@ -6,6 +6,12 @@ command_exists() { command -v "$1" &> /dev/null } +if [ "$1" = "full" ]; then + echo "Starting full deployment with backend and all services..." +else + echo "Starting core deployment with frontend and search services only..." +fi + # # Check if Docker is installed é running # From f3da9f2965ee62815d1e281b98332decc8181a95 Mon Sep 17 00:00:00 2001 From: martin legrand Date: Tue, 27 May 2025 23:25:33 +0200 Subject: [PATCH 06/31] gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 0e82296..f9a09cc 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,8 @@ *.egg-info cookies.json test_agent.py +searxng/uwsgi.ini.new +searxng/settings.yml.new config.ini .voices/ experimental/ From 58656ab43c05c3ba6931710f69c044dd7ea44d5f Mon Sep 17 00:00:00 2001 From: martin legrand Date: Wed, 28 May 2025 18:41:47 +0200 Subject: [PATCH 07/31] fix typo in readme --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index eee06aa..a728211 100644 --- a/README.md +++ b/README.md @@ -62,9 +62,9 @@ source agentic_seek_env/bin/activate Ensure Python, Docker and docker compose, and Google chrome are installed. -We recommand Python 3.10.0. +We recommend Python 3.10.0. -**Automatic Installation (Recommanded):** +**Automatic Installation (recommended):** For Linux/Macos: ```sh @@ -138,7 +138,7 @@ See below for a list of local supported provider. **Update the config.ini** -Change the config.ini file to set the provider_name to a supported provider and provider_model to a LLM supported by your provider. We recommand reasoning model such as *Qwen* or *Deepseek*. +Change the config.ini file to set the provider_name to a supported provider and provider_model to a LLM supported by your provider. We recommend reasoning model such as *Qwen* or *Deepseek*. See the **FAQ** at the end of the README for required hardware. @@ -157,7 +157,7 @@ work_dir = /Users/mlg/Documents/workspace # The workspace for AgenticSeek. jarvis_personality = False # Whenever to use a more "Jarvis" like personality (experimental) languages = en zh # The list of languages, Text to speech will default to the first language on the list [BROWSER] -headless_browser = True # Whenever to use headless browser, recommanded only if you use web interface. +headless_browser = True # Whenever to use headless browser, recommended only if you use web interface. stealth_mode = True # Use undetected selenium to reduce browser detection ``` @@ -212,7 +212,7 @@ Example: export `TOGETHER_API_KEY="xxxxx"` *We advice against using gpt-4o or other closedAI models*, performance are poor for web browsing and task planning. -Please also note that coding/bash might fail with gemini, it seem to ignore our prompt for format to respect, which are optimized for deepseek r1. +Please also note that coding/bash might fail with gemini, it seems to ignore our prompt for format to respect, which are optimized for deepseek r1. Next step: [Start services and run AgenticSeek](#Start-services-and-Run) @@ -539,7 +539,7 @@ Yes with Ollama, lm-studio or server providers, all speech to text, LLM and text **Q: Why should I use AgenticSeek when I have Manus?** This started as Side-Project we did out of interest about AI agents. What’s special about it is that we want to use local model and avoid APIs. -We draw inspiration from Jarvis and Friday (Iron man movies) to make it "cool" but for functionnality we take more inspiration from Manus, because that's what people want in the first place: a local manus alternative. +We draw inspiration from Jarvis and Friday (Iron man movies) to make it "cool" but for functionality we take more inspiration from Manus, because that's what people want in the first place: a local manus alternative. Unlike Manus, AgenticSeek prioritizes independence from external systems, giving you more control, privacy and avoid api cost. ## Contribute From a3ad635728163668cb73fdb62e608d3f5984bc04 Mon Sep 17 00:00:00 2001 From: martin legrand Date: Sun, 25 May 2025 21:19:18 +0200 Subject: [PATCH 08/31] deploy : current attempt at backend dockerization --- .env.example | 4 +- .gitignore | 1 + Dockerfile.backend | 89 +++++++++++++++++++------- README.md | 4 ++ api.py | 9 +++ docker-compose.yml | 21 +++++- frontend/agentic-seek-front/src/App.js | 12 ++-- requirements.txt | 1 + sources/browser.py | 14 +++- start_services.sh | 50 ++++++++++++++- 10 files changed, 170 insertions(+), 35 deletions(-) diff --git a/.env.example b/.env.example index 069f23c..0e98844 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,6 @@ SEARXNG_BASE_URL="http://127.0.0.1:8080" OPENAI_API_KEY='xxxxx' DEEPSEEK_API_KEY='xxxxx' -OPENROUTER_API_KEY='xxxxx' \ No newline at end of file +OPENROUTER_API_KEY='xxxxx' +BACKEND_PORT=8000 +WORK_DIR="/tmp/" \ No newline at end of file diff --git a/.gitignore b/.gitignore index 0e82296..f8801e4 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ agentic_seek_env/* .env */.env dsk/ +chrome136/ ### react ### .DS_* diff --git a/Dockerfile.backend b/Dockerfile.backend index 1cb8149..9bae45f 100644 --- a/Dockerfile.backend +++ b/Dockerfile.backend @@ -1,38 +1,57 @@ FROM ubuntu:22.04 -# Warning: doesn't work yet, backend is run on host machine for now WORKDIR /app -RUN apt-get update -qq -y && \ -apt-get install -y \ - gcc \ - g++ \ - gfortran \ - libportaudio2 \ - portaudio19-dev \ - ffmpeg \ - libavcodec-dev \ - libavformat-dev \ - libavutil-dev \ - gnupg2 \ - wget \ - unzip \ - python3 \ - python3-pip \ - libasound2 \ - libatk-bridge2.0-0 \ - libgtk-4-1 \ - libnss3 \ - xdg-utils \ - wget && \ +# Install essential packages and Chrome dependencies +RUN apt-get update && apt-get install -y \ + wget \ + unzip \ + curl \ + gnupg \ + python3-dev \ + python3-pip \ + python3-wheel \ + build-essential \ + # Chrome dependencies - comprehensive list + fonts-liberation \ + libasound2 \ + libatk-bridge2.0-0 \ + libdrm2 \ + libxcomposite1 \ + libxdamage1 \ + libxrandr2 \ + libgbm1 \ + libxss1 \ + libnss3 \ + 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 COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt # Copy application code COPY api.py . +COPY chrome_bundle/ ./chrome_bundle/ COPY sources/ ./sources/ COPY prompts/ ./prompts/ COPY crx/ crx/ @@ -40,6 +59,28 @@ COPY llm_router/ llm_router/ COPY .env . 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 8000 diff --git a/README.md b/README.md index 34612c5..ecf2486 100644 --- a/README.md +++ b/README.md @@ -559,3 +559,7 @@ We’re looking for developers to improve AgenticSeek! Check out open issues or > [antoineVIVIES](https://github.com/antoineVIVIES) | Taipei Time > [steveh8758](https://github.com/steveh8758) | Taipei Time + +## Special Thanks: + + > [tcsenpai](https://github.com/tcsenpai) For dockerization of backend diff --git a/api.py b/api.py index fa82896..3689c04 100755 --- a/api.py +++ b/api.py @@ -22,6 +22,10 @@ from sources.utility import pretty_print from sources.logger import Logger from sources.schemas import QueryRequest, QueryResponse +from dotenv import load_dotenv + +load_dotenv() + from celery import Celery @@ -247,4 +251,9 @@ async def process_query(request: QueryRequest): interaction.save_session() 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) \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 2f78cb9..f2a0d6c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -31,7 +31,7 @@ services: volumes: - ./searxng:/etc/searxng:rw environment: - - SEARXNG_BASE_URL=http://localhost:8080/ + - SEARXNG_BASE_URL=${SEARXNG_BASE_URL:-http://localhost:8080/} - SEARXNG_SECRET_KEY=$(openssl rand -hex 32) - UWSGI_WORKERS=4 - UWSGI_THREADS=4 @@ -62,13 +62,28 @@ services: environment: - NODE_ENV=development - CHOKIDAR_USEPOLLING=true - - BACKEND_URL=http://backend:8000 + - REACT_APP_BACKEND_URL=http://0.0.0.0:${BACKEND_PORT:-8000} networks: - 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. # Therefore backend is run on host machine. - # Open to pull requests to fix this. #backend: # container_name: backend diff --git a/frontend/agentic-seek-front/src/App.js b/frontend/agentic-seek-front/src/App.js index c1e6ba8..a9e6407 100644 --- a/frontend/agentic-seek-front/src/App.js +++ b/frontend/agentic-seek-front/src/App.js @@ -4,6 +4,8 @@ import axios from 'axios'; import './App.css'; import { colors } from './colors'; +const BACKEND_URL = process.env.REACT_APP_BACKEND_URL || 'http://0.0.0.0:8000'; + function App() { const [query, setQuery] = useState(''); const [messages, setMessages] = useState([]); @@ -27,7 +29,7 @@ function App() { const checkHealth = async () => { try { - await axios.get('http://127.0.0.1:8000/health'); + await axios.get(`${BACKEND_URL}/health`); setIsOnline(true); console.log('System is online'); } catch { @@ -39,7 +41,7 @@ function App() { const fetchScreenshot = async () => { try { 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' }); console.log('Screenshot fetched successfully'); @@ -90,7 +92,7 @@ function App() { const fetchLatestAnswer = async () => { 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; updateData(data); @@ -141,7 +143,7 @@ function App() { setIsLoading(false); setError(null); try { - const res = await axios.get('http://127.0.0.1:8000/stop'); + const res = await axios.get(`${BACKEND_URL}/stop`); setStatus("Requesting stop..."); } catch (err) { console.error('Error stopping the agent:', err); @@ -162,7 +164,7 @@ function App() { try { console.log('Sending query:', query); 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, tts_enabled: false }); diff --git a/requirements.txt b/requirements.txt index a63646c..eba75e1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -41,6 +41,7 @@ fake_useragent>=2.1.0 selenium_stealth>=1.0.6 undetected-chromedriver>=3.5.5 sentencepiece>=0.2.0 +python-dotenv>=1.0.0 tqdm>4 openai sniffio diff --git a/sources/browser.py b/sources/browser.py index 3604e9b..f3ebad4 100644 --- a/sources/browser.py +++ b/sources/browser.py @@ -42,7 +42,14 @@ def get_chrome_path() -> str: paths = ["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", "/Applications/Google Chrome Beta.app/Contents/MacOS/Google Chrome Beta"] 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: 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. """ 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: try: + print("ChromeDriver not found, attempting to install automatically...") chromedriver_path = chromedriver_autoinstaller.install() except Exception as e: raise FileNotFoundError( diff --git a/start_services.sh b/start_services.sh index 995f6ff..32759e8 100755 --- a/start_services.sh +++ b/start_services.sh @@ -1,5 +1,7 @@ #!/bin/bash +source .env + command_exists() { command -v "$1" &> /dev/null } @@ -60,12 +62,58 @@ if [ ! -f "docker-compose.yml" ]; then exit 1 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)..." sleep 4 docker stop $(docker ps -a -q) 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 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." From 7d74a348c979d52feaa276d2556ddcc14d605387 Mon Sep 17 00:00:00 2001 From: martin legrand Date: Sun, 25 May 2025 21:56:29 +0200 Subject: [PATCH 09/31] comment out bundle approach --- Dockerfile.backend | 3 ++- start_services.sh | 39 ++++++++++++++++++++------------------- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/Dockerfile.backend b/Dockerfile.backend index 9bae45f..0e9b2e9 100644 --- a/Dockerfile.backend +++ b/Dockerfile.backend @@ -51,7 +51,8 @@ RUN pip install --no-cache-dir -r requirements.txt # Copy application code COPY api.py . -COPY chrome_bundle/ ./chrome_bundle/ +# Chrome bundle approach, commented out opting for direct download +#COPY chrome_bundle/ ./chrome_bundle/ COPY sources/ ./sources/ COPY prompts/ ./prompts/ COPY crx/ crx/ diff --git a/start_services.sh b/start_services.sh index 32759e8..ef95319 100755 --- a/start_services.sh +++ b/start_services.sh @@ -62,26 +62,27 @@ if [ ! -f "docker-compose.yml" ]; then exit 1 fi +# bundle based approach, commented out in favor of direct download for now # 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 +#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/Fosowl/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)..." From 819a3fb98da7209b6140bbe38e69189153e1937b Mon Sep 17 00:00:00 2001 From: martin legrand Date: Sun, 25 May 2025 21:57:56 +0200 Subject: [PATCH 10/31] remove commented service --- docker-compose.yml | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index f2a0d6c..df34535 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -82,35 +82,6 @@ services: - WORK_DIR=${WORK_DIR} network_mode: "host" - # NOTE: backend service is not working yet due to issue with chromedriver on docker. - # Therefore backend is run on host machine. - - #backend: - # container_name: backend - # build: - # context: ./ - # dockerfile: Dockerfile.backend - # stdin_open: true - # tty: true - # shm_size: 8g - # ports: - # - "8000:8000" - # volumes: - # - ./:/app - # environment: - # - NODE_ENV=development - # - REDIS_URL=redis://redis:6379/0 - # - SEARXNG_URL=http://searxng:8080 - # - OLLAMA_URL=http://localhost:11434 - # - LM_STUDIO_URL=http://localhost:1234 - # extra_hosts: - # - "host.docker.internal:host-gateway" - # depends_on: - # - redis - # - searxng - # networks: - # - agentic-seek-net - volumes: redis-data: chrome_profiles: From abae98cf77859e39ef0d8c0ee546efd9e37fb9f4 Mon Sep 17 00:00:00 2001 From: martin legrand Date: Sun, 25 May 2025 22:34:13 +0200 Subject: [PATCH 11/31] feat : optional run backend on host for start_services.sh --- docker-compose.yml | 4 ++++ start_services.sh | 56 +++++++++++++++++++++++++--------------------- 2 files changed, 34 insertions(+), 26 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index df34535..824d869 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,6 +3,7 @@ version: '3' services: redis: container_name: redis + profiles: ["core", "full"] image: docker.io/valkey/valkey:8-alpine command: valkey-server --save 30 1 --loglevel warning restart: unless-stopped @@ -24,6 +25,7 @@ services: searxng: container_name: searxng + profiles: ["core", "full"] image: docker.io/searxng/searxng:latest restart: unless-stopped ports: @@ -51,6 +53,7 @@ services: frontend: container_name: frontend + profiles: ["core", "full"] build: context: ./frontend dockerfile: Dockerfile.frontend @@ -68,6 +71,7 @@ services: backend: container_name: backend + profiles: ["backend", "full"] build: context: . dockerfile: Dockerfile.backend diff --git a/start_services.sh b/start_services.sh index ef95319..a972ce2 100755 --- a/start_services.sh +++ b/start_services.sh @@ -90,34 +90,38 @@ sleep 4 docker stop $(docker ps -a -q) 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 +if [ "$1" = "full" ]; then + # First start backend and wait for it to be healthy + echo "Full docker deployement. Starting backend service..." + if ! $COMPOSE_CMD up -d backend; then + echo "Error: Failed to start backend container." + exit 1 fi - if [ $i -eq 30 ]; then - echo "Error: backend failed to start properly after 30 seconds" - $COMPOSE_CMD logs backend + # 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 + if ! $COMPOSE_CMD --profile full up; then + 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." + exit 1 + fi +else + if ! $COMPOSE_CMD --profile core up; then + 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." exit 1 fi - sleep 1 -done - -# start remaining services for searxng, redis, frontend services - -if ! $COMPOSE_CMD up; then - 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." - exit 1 fi sleep 10 \ No newline at end of file From ec1f7d31fbc357eb54b66076428a7d9e9a302325 Mon Sep 17 00:00:00 2001 From: martin legrand Date: Tue, 27 May 2025 18:19:20 +0200 Subject: [PATCH 12/31] update start_servicees.sh --- README.md | 2 +- start_services.sh | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ecf2486..cae9e18 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ Disclaimer: This demo, including all the files that appear (e.g: CV_candidates.z Make sure you have chrome driver, docker and python3.10 installed. -We highly advice you use exactly python3.10 for the setup. Dependencies error might happen otherwise. +We highly advise you use exactly python3.10 for the setup. Dependencies error might happen otherwise. For issues related to chrome driver, see the **Chromedriver** section. diff --git a/start_services.sh b/start_services.sh index a972ce2..07fcbb0 100755 --- a/start_services.sh +++ b/start_services.sh @@ -6,6 +6,12 @@ command_exists() { command -v "$1" &> /dev/null } +if [ "$1" = "full" ]; then + echo "Starting full deployment with backend and all services..." +else + echo "Starting core deployment with frontend and search services only..." +fi + # # Check if Docker is installed é running # From 95aeaf74fa0c7505ae4353bd20076f056d0f0f94 Mon Sep 17 00:00:00 2001 From: martin legrand Date: Thu, 29 May 2025 15:34:23 +0200 Subject: [PATCH 13/31] docker: latest backend dockerization attempt but crash --- Dockerfile.backend | 27 +++++++++++++++++---------- docker-compose.yml | 2 +- sources/browser.py | 15 +++++++++++++-- start_services.sh | 3 +++ 4 files changed, 34 insertions(+), 13 deletions(-) diff --git a/Dockerfile.backend b/Dockerfile.backend index 0e9b2e9..befe60f 100644 --- a/Dockerfile.backend +++ b/Dockerfile.backend @@ -1,4 +1,5 @@ -FROM ubuntu:22.04 +FROM --platform=linux/amd64 ubuntu:22.04 +ARG DEBIAN_FRONTEND=noninteractive WORKDIR /app @@ -12,13 +13,15 @@ RUN apt-get update && apt-get install -y \ python3-pip \ python3-wheel \ build-essential \ - # Chrome dependencies - comprehensive list fonts-liberation \ + libasound-dev \ libasound2 \ + portaudio19-dev \ libatk-bridge2.0-0 \ libdrm2 \ libxcomposite1 \ libxdamage1 \ + libfontconfig1 \ libxrandr2 \ libgbm1 \ libxss1 \ @@ -61,22 +64,26 @@ COPY .env . 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 && \ +RUN wget -O chrome-headless-shell-linux64.zip https://storage.googleapis.com/chrome-for-testing-public/137.0.7151.55/linux64/chrome-headless-shell-linux64.zip && \ + wget -O chromedriver-linux64.zip https://storage.googleapis.com/chrome-for-testing-public/137.0.7151.55/linux64/chromedriver-linux64.zip && \ + unzip chrome-headless-shell-linux64.zip && \ unzip chromedriver-linux64.zip && \ mkdir -p /opt/google && \ ls -la && \ - mv chrome-linux64 /opt/google/chrome && \ + mv chrome-headless-shell-linux64 /opt/google/chrome && \ mv chromedriver-linux64/chromedriver /usr/local/bin/chromedriver && \ - chmod +x /opt/google/chrome/chrome && \ + chmod +x /opt/google/chrome/chrome-headless-shell && \ 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 +# Debug ChromeDriver +RUN echo "=== ChromeDriver Debug ===" && \ + /usr/local/bin/chromedriver --version && \ + echo "Chrome binary:" && \ + /opt/google/chrome/chrome --version && \ + echo "Testing ChromeDriver startup:" && \ + timeout 5 /usr/local/bin/chromedriver --port=9999 || echo "ChromeDriver failed to start" ENV CHROME_BIN=/opt/google/chrome/chrome ENV CHROMEDRIVER_PATH=/usr/local/bin/chromedriver diff --git a/docker-compose.yml b/docker-compose.yml index 824d869..3360e8e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -34,7 +34,7 @@ services: - ./searxng:/etc/searxng:rw environment: - SEARXNG_BASE_URL=${SEARXNG_BASE_URL:-http://localhost:8080/} - - SEARXNG_SECRET_KEY=$(openssl rand -hex 32) + - SEARXNG_SECRET_KEY=${SEARXNG_SECRET_KEY} - UWSGI_WORKERS=4 - UWSGI_THREADS=4 cap_add: diff --git a/sources/browser.py b/sources/browser.py index f3ebad4..496cfdb 100644 --- a/sources/browser.py +++ b/sources/browser.py @@ -46,8 +46,9 @@ def get_chrome_path() -> str: "/usr/bin/chromium-browser", "/usr/bin/chromium", "/opt/chrome/chrome", - "opt/google/chrome/chrome", "/usr/local/bin/chrome", + "/opt/google/chrome/chrome-headless-shell", + "/opt/google/chrome/chrome", #"/app/chrome_bundle/chrome136/chrome-linux64" ] @@ -84,6 +85,7 @@ def install_chromedriver() -> str: # 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" + print("path:", chromedriver_path) if not chromedriver_path: try: print("ChromeDriver not found, attempting to install automatically...") @@ -132,7 +134,8 @@ def create_driver(headless=False, stealth_mode=True, crx_path="./crx/nopecha.crx chrome_options.binary_location = chrome_path if headless: - chrome_options.add_argument("--headless") + #chrome_options.add_argument("--headless") + chrome_options.add_argument("--headless=new") chrome_options.add_argument("--disable-gpu") chrome_options.add_argument("--disable-webgl") user_data_dir = tempfile.mkdtemp() @@ -142,6 +145,14 @@ def create_driver(headless=False, stealth_mode=True, crx_path="./crx/nopecha.crx chrome_options.add_argument(f"--accept-lang={lang}-{lang.upper()},{lang};q=0.9") chrome_options.add_argument("--timezone=Europe/Paris") chrome_options.add_argument("--no-sandbox") + chrome_options.add_argument('--disable-dev-shm-usage') + chrome_options.add_argument('--remote-debugging-port=9222') + chrome_options.add_argument('--disable-extensions') + chrome_options.add_argument('--disable-background-timer-throttling') + chrome_options.add_argument('--disable-backgrounding-occluded-windows') + chrome_options.add_argument('--disable-renderer-backgrounding') + chrome_options.add_argument('--disable-features=TranslateUI') + chrome_options.add_argument('--disable-ipc-flooding-protection') chrome_options.add_argument("--disable-dev-shm-usage") chrome_options.add_argument("--mute-audio") chrome_options.add_argument("--disable-notifications") diff --git a/start_services.sh b/start_services.sh index 07fcbb0..d9cc98c 100755 --- a/start_services.sh +++ b/start_services.sh @@ -96,6 +96,9 @@ sleep 4 docker stop $(docker ps -a -q) echo "All containers stopped" +# export searxng secret key +export SEARXNG_SECRET_KEY=$(openssl rand -hex 32) + if [ "$1" = "full" ]; then # First start backend and wait for it to be healthy echo "Full docker deployement. Starting backend service..." From 1c4a550c6f30a3020235403b0b3b7f6549c1334b Mon Sep 17 00:00:00 2001 From: martin legrand Date: Thu, 29 May 2025 15:35:00 +0200 Subject: [PATCH 14/31] docker: latest backend dockerization attempt but crash --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a728211..4fc0927 100644 --- a/README.md +++ b/README.md @@ -210,7 +210,7 @@ Example: export `TOGETHER_API_KEY="xxxxx"` | togetherAI | No | Use together AI API (non-private) | | google | No | Use google gemini API (non-private) | -*We advice against using gpt-4o or other closedAI models*, performance are poor for web browsing and task planning. +*We advise against using gpt-4o or other closedAI models*, performance are poor for web browsing and task planning. Please also note that coding/bash might fail with gemini, it seems to ignore our prompt for format to respect, which are optimized for deepseek r1. @@ -245,7 +245,7 @@ start ./start_services.cmd # Window python3 cli.py ``` -We advice you set `headless_browser` to False in the config.ini for CLI mode. +We advise you set `headless_browser` to False in the config.ini for CLI mode. **Options 2:** Run with the Web interface. From b96e83dbbe58c3af5ac8bbb6bc62d87ea96e5b71 Mon Sep 17 00:00:00 2001 From: martin legrand Date: Thu, 29 May 2025 21:33:48 +0200 Subject: [PATCH 15/31] feat : latest docker attempt + fix attempt for #249 --- .env.example | 1 + Dockerfile.backend | 46 +++++++++++++++-------------- sources/agents/browser_agent.py | 21 ++++++++----- sources/browser.py | 7 +++-- tests/test_browser_agent_parsing.py | 2 +- 5 files changed, 44 insertions(+), 33 deletions(-) diff --git a/.env.example b/.env.example index 0e98844..3b38eb2 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,5 @@ SEARXNG_BASE_URL="http://127.0.0.1:8080" +TOKENIZERS_PARALLELISM="false" OPENAI_API_KEY='xxxxx' DEEPSEEK_API_KEY='xxxxx' OPENROUTER_API_KEY='xxxxx' diff --git a/Dockerfile.backend b/Dockerfile.backend index befe60f..228618e 100644 --- a/Dockerfile.backend +++ b/Dockerfile.backend @@ -60,33 +60,35 @@ COPY sources/ ./sources/ COPY prompts/ ./prompts/ COPY crx/ crx/ COPY llm_router/ llm_router/ -COPY .env . -COPY config.ini . +RUN ls +COPY .env.example .env # Install Chrome and ChromeDriver from chrome-for-testing -RUN wget -O chrome-headless-shell-linux64.zip https://storage.googleapis.com/chrome-for-testing-public/137.0.7151.55/linux64/chrome-headless-shell-linux64.zip && \ - wget -O chromedriver-linux64.zip https://storage.googleapis.com/chrome-for-testing-public/137.0.7151.55/linux64/chromedriver-linux64.zip && \ - unzip chrome-headless-shell-linux64.zip && \ - unzip chromedriver-linux64.zip && \ - mkdir -p /opt/google && \ - ls -la && \ - mv chrome-headless-shell-linux64 /opt/google/chrome && \ - mv chromedriver-linux64/chromedriver /usr/local/bin/chromedriver && \ - chmod +x /opt/google/chrome/chrome-headless-shell && \ - chmod +x /usr/local/bin/chromedriver +#RUN wget -O chrome-headless-shell-linux64.zip https://storage.googleapis.com/chrome-for-testing-public/137.0.7151.55/linux64/chrome-headless-shell-linux64.zip && \ +# wget -O chromedriver-linux64.zip https://storage.googleapis.com/chrome-for-testing-public/137.0.7151.55/linux64/chromedriver-linux64.zip && \ +# unzip chrome-headless-shell-linux64.zip && \ +# unzip chromedriver-linux64.zip && \ +# mkdir -p /opt/google && \ +# ls -la && \ +# mv chrome-headless-shell-linux64 /opt/google/chrome && \ +# mv chromedriver-linux64/chromedriver /usr/local/bin/chromedriver && \ +# chmod +x /opt/google/chrome/chrome-headless-shell && \ +# chmod +x /usr/local/bin/chromedriver -RUN ln -s /opt/google/chrome/chrome /usr/local/bin/chrome +RUN wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | apt-key add - && \ + echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list && \ + apt-get update && \ + apt-get install -y google-chrome-stable && \ + rm -rf /var/lib/apt/lists/* -# Debug ChromeDriver -RUN echo "=== ChromeDriver Debug ===" && \ - /usr/local/bin/chromedriver --version && \ - echo "Chrome binary:" && \ - /opt/google/chrome/chrome --version && \ - echo "Testing ChromeDriver startup:" && \ - timeout 5 /usr/local/bin/chromedriver --port=9999 || echo "ChromeDriver failed to start" +# Install matching ChromeDriver +RUN CHROME_VERSION=$(google-chrome --version | grep -oP '\d+\.\d+\.\d+') && \ + wget -O chromedriver.zip "https://chromedriver.storage.googleapis.com/LATEST_RELEASE_${CHROME_VERSION%%.*}/chromedriver_linux64.zip" && \ + unzip chromedriver.zip && \ + mv chromedriver /usr/local/bin/ && \ + chmod +x /usr/local/bin/chromedriver && \ + rm chromedriver.zip -ENV CHROME_BIN=/opt/google/chrome/chrome -ENV CHROMEDRIVER_PATH=/usr/local/bin/chromedriver ENV DISPLAY=:99 # Expose port diff --git a/sources/agents/browser_agent.py b/sources/agents/browser_agent.py index 3817fb3..3f5de5d 100644 --- a/sources/agents/browser_agent.py +++ b/sources/agents/browser_agent.py @@ -41,7 +41,7 @@ class BrowserAgent(Agent): self.memory = Memory(self.load_prompt(prompt_path), recover_last_session=False, # session recovery in handled by the interaction class memory_compression=False, - model_provider=provider.get_model_name()) + model_provider=provider.get_model_name() if provider else None) def get_today_date(self) -> str: """Get the date""" @@ -77,14 +77,14 @@ class BrowserAgent(Agent): def get_unvisited_links(self) -> List[str]: return "\n".join([f"[{i}] {link}" for i, link in enumerate(self.navigable_links) if link not in self.search_history]) - def make_newsearch_prompt(self, user_prompt: str, search_result: dict) -> str: + def make_newsearch_prompt(self, prompt: str, search_result: dict) -> str: search_choice = self.stringify_search_results(search_result) self.logger.info(f"Search results: {search_choice}") return f""" Based on the search result: {search_choice} Your goal is to find accurate and complete information to satisfy the user’s request. - User request: {user_prompt} + User request: {prompt} To proceed, choose a relevant link from the search results. Announce your choice by saying: "I will navigate to " Do not explain your choice. """ @@ -235,13 +235,17 @@ class BrowserAgent(Agent): return links def select_link(self, links: List[str]) -> str | None: + """ + Select the first unvisited link that is not the current page. + Preference is given to links not in search_history. + """ for lk in links: - if lk == self.current_page: - self.logger.info(f"Already visited {lk}. Skipping.") + if lk == self.current_page or lk in self.search_history: + self.logger.info(f"Skipping already visited or current link: {lk}") continue self.logger.info(f"Selected link: {lk}") return lk - self.logger.warning("No link selected.") + self.logger.warning("No suitable link selected.") return None def get_page_text(self, limit_to_model_ctx = False) -> str: @@ -396,7 +400,10 @@ class BrowserAgent(Agent): if (link == None and len(extracted_form) < 3) or Action.GO_BACK.value in answer or link in self.search_history: pretty_print(f"Going back to results. Still {len(unvisited)}", color="status") self.status_message = "Going back to search results..." - prompt = self.make_newsearch_prompt(user_prompt, unvisited) + request_prompt = user_prompt + if link is None: + request_prompt += f"\nYou previously choosen:\n{self.last_answer} but the website is unavailable. Consider other options." + prompt = self.make_newsearch_prompt(request_prompt, unvisited) self.search_history.append(link) self.current_page = link continue diff --git a/sources/browser.py b/sources/browser.py index 496cfdb..ea7e088 100644 --- a/sources/browser.py +++ b/sources/browser.py @@ -136,18 +136,21 @@ def create_driver(headless=False, stealth_mode=True, crx_path="./crx/nopecha.crx if headless: #chrome_options.add_argument("--headless") chrome_options.add_argument("--headless=new") + chrome_options.add_argument("--disable-dev-shm-usage") chrome_options.add_argument("--disable-gpu") chrome_options.add_argument("--disable-webgl") + chrome_options.add_argument("--remote-debugging-port=9222") user_data_dir = tempfile.mkdtemp() user_agent = get_random_user_agent() width, height = (1920, 1080) chrome_options.add_argument(f"--user-data-dir={user_data_dir}") chrome_options.add_argument(f"--accept-lang={lang}-{lang.upper()},{lang};q=0.9") + chrome_options.add_argument("--disable-extensions") + chrome_options.add_argument("--disable-background-timer-throttling") chrome_options.add_argument("--timezone=Europe/Paris") chrome_options.add_argument("--no-sandbox") chrome_options.add_argument('--disable-dev-shm-usage') chrome_options.add_argument('--remote-debugging-port=9222') - chrome_options.add_argument('--disable-extensions') chrome_options.add_argument('--disable-background-timer-throttling') chrome_options.add_argument('--disable-backgrounding-occluded-windows') chrome_options.add_argument('--disable-renderer-backgrounding') @@ -721,8 +724,6 @@ if __name__ == "__main__": input("press enter to continue") print("AntiCaptcha / Form Test") - browser.go_to("https://www.google.com/recaptcha/api2/demo") - time.sleep(50) browser.go_to("https://bot.sannysoft.com") time.sleep(5) #txt = browser.get_text() diff --git a/tests/test_browser_agent_parsing.py b/tests/test_browser_agent_parsing.py index aac95bc..40d0eec 100644 --- a/tests/test_browser_agent_parsing.py +++ b/tests/test_browser_agent_parsing.py @@ -23,7 +23,7 @@ class TestBrowserAgentParsing(unittest.TestCase): "https://thriveonai.com/15-ai-startups-in-japan-to-take-note-of", "www.google.com", "https://test.org/about?page=1", - "https://weatherstack.com/documentation", + "https://weatherstack.com/documentation" ] result = self.agent.extract_links(test_text) self.assertEqual(result, expected) From 54cc2a03ec755f8a9c787bdbb26f3bfb7dcfc731 Mon Sep 17 00:00:00 2001 From: martin legrand Date: Sat, 31 May 2025 17:20:40 +0200 Subject: [PATCH 16/31] feat : updating with latest docker backend build thx to #265 --- .env.example | 8 ++- Dockerfile.backend | 143 +++++++++++++++++++++++++---------------- api.py | 2 +- docker-compose.yml | 13 +++- sources/browser.py | 2 +- sources/tools/tools.py | 2 +- 6 files changed, 104 insertions(+), 66 deletions(-) diff --git a/.env.example b/.env.example index 3b38eb2..a476049 100644 --- a/.env.example +++ b/.env.example @@ -1,7 +1,9 @@ SEARXNG_BASE_URL="http://127.0.0.1:8080" -TOKENIZERS_PARALLELISM="false" +REDIS_BASE_URL="redis://redis:6379/0" +WORK_DIR_HOST="/Users/mlg/Documents/workspace_for_ai" OPENAI_API_KEY='xxxxx' DEEPSEEK_API_KEY='xxxxx' OPENROUTER_API_KEY='xxxxx' -BACKEND_PORT=8000 -WORK_DIR="/tmp/" \ No newline at end of file +TOGETHER_API_KEY='xxxx' +GOOGLE_API_KEY='xxxxx' +ANTHROPIC_API_KEY='xxxxx' \ No newline at end of file diff --git a/Dockerfile.backend b/Dockerfile.backend index 228618e..f5f51d2 100644 --- a/Dockerfile.backend +++ b/Dockerfile.backend @@ -1,67 +1,100 @@ -FROM --platform=linux/amd64 ubuntu:22.04 -ARG DEBIAN_FRONTEND=noninteractive + +FROM --platform=linux/amd64 python:3.11-slim +ENV DEBIAN_FRONTEND=noninteractive WORKDIR /app # Install essential packages and Chrome dependencies -RUN apt-get update && apt-get install -y \ +RUN apt-get update -y && apt-get install -y \ wget \ + gnupg2 \ + ca-certificates \ unzip \ - curl \ - gnupg \ - python3-dev \ - python3-pip \ - python3-wheel \ - build-essential \ + xvfb \ + libxss1 \ + libappindicator1 \ fonts-liberation \ - libasound-dev \ - libasound2 \ - portaudio19-dev \ + libnss3 \ + libatk1.0-0 \ libatk-bridge2.0-0 \ + libcups2 \ libdrm2 \ libxcomposite1 \ libxdamage1 \ - libfontconfig1 \ libxrandr2 \ - libgbm1 \ - libxss1 \ - libnss3 \ - 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 \ + xdg-utils \ + dbus \ && rm -rf /var/lib/apt/lists/* -RUN pip3 install --upgrade pip setuptools wheel && \ -pip3 install selenium +RUN apt-get update -y && \ + apt-get install -y \ + gcc \ + g++ \ + gfortran \ + libportaudio2 \ + portaudio19-dev \ + ffmpeg \ + libavcodec-dev \ + libavformat-dev \ + libavutil-dev \ + gnupg2 \ + wget \ + unzip \ + python3 \ + python3-pip \ + libasound2 \ + libatk-bridge2.0-0 \ + libgtk-4-1 \ + libnss3 \ + xdg-utils \ + wget \ + && rm -rf /var/lib/apt/lists/* + + +RUN apt-get update -y && \ +apt-get install -y \ + alsa-utils \ +&& rm -rf /var/lib/apt/lists/* + +ENV CHROME_TESTING_VERSION=134.0.6998.88 +ENV DISPLAY=:99 + +RUN set -eux; \ + wget -qO /tmp/chrome.zip \ + "https://storage.googleapis.com/chrome-for-testing-public/${CHROME_TESTING_VERSION}/linux64/chrome-linux64.zip"; \ + unzip -q /tmp/chrome.zip -d /opt; \ + rm /tmp/chrome.zip; \ + ln -s /opt/chrome-linux64/chrome /usr/local/bin/google-chrome; \ + ln -s /opt/chrome-linux64/chrome /usr/local/bin/chrome; \ + mkdir -p /opt/chrome; \ + ln -s /opt/chrome-linux64/chrome /opt/chrome/chrome; \ + google-chrome --version + +RUN set -eux; \ + wget -qO /tmp/chromedriver.zip \ + "https://storage.googleapis.com/chrome-for-testing-public/${CHROME_TESTING_VERSION}/linux64/chromedriver-linux64.zip"; \ + unzip -q /tmp/chromedriver.zip -d /tmp; \ + mv /tmp/chromedriver-linux64/chromedriver /usr/local/bin; \ + rm /tmp/chromedriver.zip; \ + chmod +x /usr/local/bin/chromedriver; \ + chromedriver --version + +RUN chmod +x /opt/chrome/chrome + +RUN pip3 install --upgrade pip setuptools wheel -# Install dependencies COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt +RUN mkdir -p /opt/workspace + # Copy application code COPY api.py . -# Chrome bundle approach, commented out opting for direct download -#COPY chrome_bundle/ ./chrome_bundle/ COPY sources/ ./sources/ COPY prompts/ ./prompts/ COPY crx/ crx/ COPY llm_router/ llm_router/ -RUN ls -COPY .env.example .env +COPY config.ini . # Install Chrome and ChromeDriver from chrome-for-testing #RUN wget -O chrome-headless-shell-linux64.zip https://storage.googleapis.com/chrome-for-testing-public/137.0.7151.55/linux64/chrome-headless-shell-linux64.zip && \ @@ -75,24 +108,20 @@ COPY .env.example .env # chmod +x /opt/google/chrome/chrome-headless-shell && \ # chmod +x /usr/local/bin/chromedriver -RUN wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | apt-key add - && \ - echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list && \ - apt-get update && \ - apt-get install -y google-chrome-stable && \ - rm -rf /var/lib/apt/lists/* +#RUN wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | apt-key add - && \ +# echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list && \ +# apt-get update && \ +# apt-get install -y google-chrome-stable && \ +# rm -rf /var/lib/apt/lists/* +# +## Install matching ChromeDriver +#RUN CHROME_VERSION=$(google-chrome --version | grep -oP '\d+\.\d+\.\d+') && \ +# wget -O chromedriver.zip "https://chromedriver.storage.googleapis.com/LATEST_RELEASE_${CHROME_VERSION%%.*}/chromedriver_linux64.zip" && \ +# unzip chromedriver.zip && \ +# mv chromedriver /usr/local/bin/ && \ +# chmod +x /usr/local/bin/chromedriver && \ +# rm chromedriver.zip -# Install matching ChromeDriver -RUN CHROME_VERSION=$(google-chrome --version | grep -oP '\d+\.\d+\.\d+') && \ - wget -O chromedriver.zip "https://chromedriver.storage.googleapis.com/LATEST_RELEASE_${CHROME_VERSION%%.*}/chromedriver_linux64.zip" && \ - unzip chromedriver.zip && \ - mv chromedriver /usr/local/bin/ && \ - chmod +x /usr/local/bin/chromedriver && \ - rm chromedriver.zip - -ENV DISPLAY=:99 - -# Expose port EXPOSE 8000 - # Run the application CMD ["python3", "api.py"] \ No newline at end of file diff --git a/api.py b/api.py index 3689c04..9e70a4a 100755 --- a/api.py +++ b/api.py @@ -38,7 +38,7 @@ config.read('config.ini') api.add_middleware( CORSMiddleware, - allow_origins=["http://localhost", "http://localhost:3000"], + allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], diff --git a/docker-compose.yml b/docker-compose.yml index 3360e8e..55d98a1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -79,11 +79,18 @@ services: - ${BACKEND_PORT:-8000}:${BACKEND_PORT:-8000} volumes: - ./:/app - - ${WORK_DIR}:${WORK_DIR} + - ${WORK_DIR_HOST:-.}:/opt/workspace command: python3 api.py environment: - - SEARXNG_URL=http://localhost:8080 - - WORK_DIR=${WORK_DIR} + - SEARXNG_URL=${SEARXNG_BASE_URL:-http://searxng:8080} + - REDIS_URL=${REDIS_BASE_URL:-redis://redis:6379/0} + - WORK_DIR_HOST=${WORK_DIR_HOST:-.} + - OPENAI_API_KEY=${OPENAI_API_KEY} + - DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY} + - OPENROUTER_API_KEY=${OPENROUTER_API_KEY} + - TOGETHER_API_KEY=${TOGETHER_API_KEY} + - GOOGLE_API_KEY=${GOOGLE_API_KEY} + - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} network_mode: "host" volumes: diff --git a/sources/browser.py b/sources/browser.py index ea7e088..4f05f0d 100644 --- a/sources/browser.py +++ b/sources/browser.py @@ -143,7 +143,7 @@ def create_driver(headless=False, stealth_mode=True, crx_path="./crx/nopecha.crx user_data_dir = tempfile.mkdtemp() user_agent = get_random_user_agent() width, height = (1920, 1080) - chrome_options.add_argument(f"--user-data-dir={user_data_dir}") + #chrome_options.add_argument(f"--user-data-dir={user_data_dir}") chrome_options.add_argument(f"--accept-lang={lang}-{lang.upper()},{lang};q=0.9") chrome_options.add_argument("--disable-extensions") chrome_options.add_argument("--disable-background-timer-throttling") diff --git a/sources/tools/tools.py b/sources/tools/tools.py index 555f30c..25b9fac 100644 --- a/sources/tools/tools.py +++ b/sources/tools/tools.py @@ -73,7 +73,7 @@ class Tools(): default_path = os.path.dirname(os.getcwd()) if self.config_exists(): self.config.read('./config.ini') - config_path = self.config['MAIN']['work_dir'] + config_path = self.config['MAIN']['work_dir'] or os.getenv('WORK_DIR') dir_path = default_path if not self.check_config_dir_validity() else config_path else: dir_path = default_path From fc74d4361a6278dee17fc2ab4222a92d6de1096a Mon Sep 17 00:00:00 2001 From: martin legrand Date: Sat, 31 May 2025 19:31:25 +0200 Subject: [PATCH 17/31] latest attempt of dockerization --- .dockerignore | 5 ++--- Dockerfile.backend | 36 +++++++++--------------------------- sources/browser.py | 22 +++++++++------------- 3 files changed, 20 insertions(+), 43 deletions(-) diff --git a/.dockerignore b/.dockerignore index 14aab39..222b03b 100644 --- a/.dockerignore +++ b/.dockerignore @@ -3,10 +3,9 @@ __pycache__/ *.py[cod] # Virtual environments -venv/ -.venv/ +agentic_seek_env/ +.agentic_seek_env/ -# Environment variables (secrets) .env # Git metadata diff --git a/Dockerfile.backend b/Dockerfile.backend index f5f51d2..821744c 100644 --- a/Dockerfile.backend +++ b/Dockerfile.backend @@ -2,7 +2,8 @@ FROM --platform=linux/amd64 python:3.11-slim ENV DEBIAN_FRONTEND=noninteractive -WORKDIR /app +RUN groupadd -r chrome && useradd -r -g chrome -G audio,video chrome + # Install essential packages and Chrome dependencies RUN apt-get update -y && apt-get install -y \ @@ -59,6 +60,8 @@ apt-get install -y \ ENV CHROME_TESTING_VERSION=134.0.6998.88 ENV DISPLAY=:99 +WORKDIR /app + RUN set -eux; \ wget -qO /tmp/chrome.zip \ "https://storage.googleapis.com/chrome-for-testing-public/${CHROME_TESTING_VERSION}/linux64/chrome-linux64.zip"; \ @@ -87,6 +90,7 @@ COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt RUN mkdir -p /opt/workspace +RUN mkdir -p /tmp && chmod 1777 /tmp # Copy application code COPY api.py . @@ -96,32 +100,10 @@ COPY crx/ crx/ COPY llm_router/ llm_router/ COPY config.ini . -# Install Chrome and ChromeDriver from chrome-for-testing -#RUN wget -O chrome-headless-shell-linux64.zip https://storage.googleapis.com/chrome-for-testing-public/137.0.7151.55/linux64/chrome-headless-shell-linux64.zip && \ -# wget -O chromedriver-linux64.zip https://storage.googleapis.com/chrome-for-testing-public/137.0.7151.55/linux64/chromedriver-linux64.zip && \ -# unzip chrome-headless-shell-linux64.zip && \ -# unzip chromedriver-linux64.zip && \ -# mkdir -p /opt/google && \ -# ls -la && \ -# mv chrome-headless-shell-linux64 /opt/google/chrome && \ -# mv chromedriver-linux64/chromedriver /usr/local/bin/chromedriver && \ -# chmod +x /opt/google/chrome/chrome-headless-shell && \ -# chmod +x /usr/local/bin/chromedriver - -#RUN wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | apt-key add - && \ -# echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list && \ -# apt-get update && \ -# apt-get install -y google-chrome-stable && \ -# rm -rf /var/lib/apt/lists/* -# -## Install matching ChromeDriver -#RUN CHROME_VERSION=$(google-chrome --version | grep -oP '\d+\.\d+\.\d+') && \ -# wget -O chromedriver.zip "https://chromedriver.storage.googleapis.com/LATEST_RELEASE_${CHROME_VERSION%%.*}/chromedriver_linux64.zip" && \ -# unzip chromedriver.zip && \ -# mv chromedriver /usr/local/bin/ && \ -# chmod +x /usr/local/bin/chromedriver && \ -# rm chromedriver.zip - EXPOSE 8000 +# Switch to non-root user +USER chrome +RUN chown -R chrome:chrome /app +RUN chown -R chrome:chrome /tmp # Run the application CMD ["python3", "api.py"] \ No newline at end of file diff --git a/sources/browser.py b/sources/browser.py index 4f05f0d..64fd2a7 100644 --- a/sources/browser.py +++ b/sources/browser.py @@ -19,6 +19,7 @@ import time import random import os import shutil +import uuid import tempfile import markdownify import sys @@ -43,12 +44,11 @@ def get_chrome_path() -> str: "/Applications/Google Chrome Beta.app/Contents/MacOS/Google Chrome Beta"] else: # Linux paths = ["/usr/bin/google-chrome", + "/opt/chrome/chrome", "/usr/bin/chromium-browser", "/usr/bin/chromium", - "/opt/chrome/chrome", "/usr/local/bin/chrome", "/opt/google/chrome/chrome-headless-shell", - "/opt/google/chrome/chrome", #"/app/chrome_bundle/chrome136/chrome-linux64" ] @@ -81,11 +81,6 @@ def install_chromedriver() -> str: Install the ChromeDriver if not already installed. Return the path. """ 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" - print("path:", chromedriver_path) if not chromedriver_path: try: print("ChromeDriver not found, attempting to install automatically...") @@ -136,27 +131,28 @@ def create_driver(headless=False, stealth_mode=True, crx_path="./crx/nopecha.crx if headless: #chrome_options.add_argument("--headless") chrome_options.add_argument("--headless=new") - chrome_options.add_argument("--disable-dev-shm-usage") chrome_options.add_argument("--disable-gpu") chrome_options.add_argument("--disable-webgl") - chrome_options.add_argument("--remote-debugging-port=9222") user_data_dir = tempfile.mkdtemp() user_agent = get_random_user_agent() width, height = (1920, 1080) - #chrome_options.add_argument(f"--user-data-dir={user_data_dir}") + user_data_dir = tempfile.mkdtemp(prefix="chrome_profile_") + import os + print(f"Running as UID: {os.getuid()}") # Will show 0 if root + chrome_options.add_argument("--no-sandbox") + chrome_options.add_argument('--disable-dev-shm-usage') + profile_dir = f"/tmp/chrome_profile_{uuid.uuid4().hex[:8]}" + chrome_options.add_argument(f'--user-data-dir={profile_dir}') chrome_options.add_argument(f"--accept-lang={lang}-{lang.upper()},{lang};q=0.9") chrome_options.add_argument("--disable-extensions") chrome_options.add_argument("--disable-background-timer-throttling") chrome_options.add_argument("--timezone=Europe/Paris") - chrome_options.add_argument("--no-sandbox") - chrome_options.add_argument('--disable-dev-shm-usage') chrome_options.add_argument('--remote-debugging-port=9222') chrome_options.add_argument('--disable-background-timer-throttling') chrome_options.add_argument('--disable-backgrounding-occluded-windows') chrome_options.add_argument('--disable-renderer-backgrounding') chrome_options.add_argument('--disable-features=TranslateUI') chrome_options.add_argument('--disable-ipc-flooding-protection') - chrome_options.add_argument("--disable-dev-shm-usage") chrome_options.add_argument("--mute-audio") chrome_options.add_argument("--disable-notifications") chrome_options.add_argument("--autoplay-policy=user-gesture-required") From a3b0bb22aae7f92a1d7753fb6994ae3d22fad28d Mon Sep 17 00:00:00 2001 From: martin legrand Date: Sat, 31 May 2025 19:44:58 +0200 Subject: [PATCH 18/31] latest attempt of dockerization --- Dockerfile.backend | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Dockerfile.backend b/Dockerfile.backend index 821744c..1526dbe 100644 --- a/Dockerfile.backend +++ b/Dockerfile.backend @@ -2,8 +2,8 @@ FROM --platform=linux/amd64 python:3.11-slim ENV DEBIAN_FRONTEND=noninteractive -RUN groupadd -r chrome && useradd -r -g chrome -G audio,video chrome - +#RUN groupadd -r chrome && useradd -r -g chrome -G audio,video chrome +#USER chrome # Install essential packages and Chrome dependencies RUN apt-get update -y && apt-get install -y \ @@ -101,9 +101,8 @@ COPY llm_router/ llm_router/ COPY config.ini . EXPOSE 8000 -# Switch to non-root user -USER chrome -RUN chown -R chrome:chrome /app -RUN chown -R chrome:chrome /tmp + +#RUN chown -R chrome:chrome /app +#RUN chown -R chrome:chrome /tmp # Run the application CMD ["python3", "api.py"] \ No newline at end of file From be1bfc5cf2805eaec560ec9e4cbddea6634b50bd Mon Sep 17 00:00:00 2001 From: martin legrand Date: Sat, 31 May 2025 22:01:42 +0200 Subject: [PATCH 19/31] docker deploy of backend now working --- Dockerfile.backend | 5 ----- docker-compose.yml | 2 +- requirements.txt | 1 + sources/tools/tools.py | 31 +++++++++++++------------------ 4 files changed, 15 insertions(+), 24 deletions(-) diff --git a/Dockerfile.backend b/Dockerfile.backend index 1526dbe..f6dec0f 100644 --- a/Dockerfile.backend +++ b/Dockerfile.backend @@ -2,9 +2,6 @@ FROM --platform=linux/amd64 python:3.11-slim ENV DEBIAN_FRONTEND=noninteractive -#RUN groupadd -r chrome && useradd -r -g chrome -G audio,video chrome -#USER chrome - # Install essential packages and Chrome dependencies RUN apt-get update -y && apt-get install -y \ wget \ @@ -102,7 +99,5 @@ COPY config.ini . EXPOSE 8000 -#RUN chown -R chrome:chrome /app -#RUN chown -R chrome:chrome /tmp # Run the application CMD ["python3", "api.py"] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 55d98a1..5c8f408 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -84,7 +84,7 @@ services: environment: - SEARXNG_URL=${SEARXNG_BASE_URL:-http://searxng:8080} - REDIS_URL=${REDIS_BASE_URL:-redis://redis:6379/0} - - WORK_DIR_HOST=${WORK_DIR_HOST:-.} + - WORK_DIR=/opt/workspace - OPENAI_API_KEY=${OPENAI_API_KEY} - DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY} - OPENROUTER_API_KEY=${OPENROUTER_API_KEY} diff --git a/requirements.txt b/requirements.txt index eba75e1..cbc657d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -42,6 +42,7 @@ selenium_stealth>=1.0.6 undetected-chromedriver>=3.5.5 sentencepiece>=0.2.0 python-dotenv>=1.0.0 +together>=1.5.0 tqdm>4 openai sniffio diff --git a/sources/tools/tools.py b/sources/tools/tools.py index 25b9fac..cb63869 100644 --- a/sources/tools/tools.py +++ b/sources/tools/tools.py @@ -49,20 +49,16 @@ class Tools(): def set_allow_language_exec_bash(value: bool) -> None: self.allow_language_exec_bash = value - - def check_config_dir_validity(self): - """Check if the config directory is valid.""" - path = self.config['MAIN']['work_dir'] - if path == "": - print("WARNING: Work directory not set in config.ini") - return False - if path.lower() == "none": - print("WARNING: Work directory set to none in config.ini") - return False - if not os.path.exists(path): - print(f"WARNING: Work directory {path} does not exist") - return False - return True + + def safe_get_work_dir_path(self): + path = None + path = os.getenv('WORK_DIR', path) + if path is None or path == "": + path = self.config['MAIN']['work_dir'] if 'MAIN' in self.config and 'work_dir' in self.config['MAIN'] else None + if path is None or path == "": + print("No work directory specified, using default.") + path = self.create_work_dir() + return path def config_exists(self): """Check if the config file exists.""" @@ -73,11 +69,10 @@ class Tools(): default_path = os.path.dirname(os.getcwd()) if self.config_exists(): self.config.read('./config.ini') - config_path = self.config['MAIN']['work_dir'] or os.getenv('WORK_DIR') - dir_path = default_path if not self.check_config_dir_validity() else config_path + workdir_path = self.safe_get_work_dir_path() else: - dir_path = default_path - return dir_path + workdir_path = default_path + return workdir_path @abstractmethod def execute(self, blocks:[str], safety:bool) -> str: From 9f0fdd547ee2d18e31b0462f1453dd27d3be80ae Mon Sep 17 00:00:00 2001 From: martin legrand Date: Sun, 1 Jun 2025 16:40:53 +0200 Subject: [PATCH 20/31] refactor: remove unsused sentiment analysis --- sources/browser.py | 2 -- sources/language.py | 44 +++----------------------------------------- 2 files changed, 3 insertions(+), 43 deletions(-) diff --git a/sources/browser.py b/sources/browser.py index 64fd2a7..639eaec 100644 --- a/sources/browser.py +++ b/sources/browser.py @@ -137,8 +137,6 @@ def create_driver(headless=False, stealth_mode=True, crx_path="./crx/nopecha.crx user_agent = get_random_user_agent() width, height = (1920, 1080) user_data_dir = tempfile.mkdtemp(prefix="chrome_profile_") - import os - print(f"Running as UID: {os.getuid()}") # Will show 0 if root chrome_options.add_argument("--no-sandbox") chrome_options.add_argument('--disable-dev-shm-usage') profile_dir = f"/tmp/chrome_profile_{uuid.uuid4().hex[:8]}" diff --git a/sources/language.py b/sources/language.py index b62c087..a665bda 100644 --- a/sources/language.py +++ b/sources/language.py @@ -16,7 +16,6 @@ class LanguageUtility: args: supported_language: list of languages for translation, determine which Helsinki-NLP model to load """ - self.sid = None self.translators_tokenizer = None self.translators_model = None self.logger = Logger("language.log") @@ -25,11 +24,6 @@ class LanguageUtility: def load_model(self) -> None: animate_thinking("Loading language utility...", color="status") - try: - nltk.data.find('vader_lexicon') - except LookupError: - nltk.download('vader_lexicon') - self.sid = SentimentIntensityAnalyzer() self.translators_tokenizer = {lang: MarianTokenizer.from_pretrained(f"Helsinki-NLP/opus-mt-{lang}-en") for lang in self.supported_language if lang != "en"} self.translators_model = {lang: MarianMTModel.from_pretrained(f"Helsinki-NLP/opus-mt-{lang}-en") for lang in self.supported_language if lang != "en"} @@ -65,49 +59,17 @@ class LanguageUtility: translation = model.generate(**inputs) return tokenizer.decode(translation[0], skip_special_tokens=True) - def detect_emotion(self, text: str) -> str: - """ - Detect the dominant emotion in the given text - Args: - text: string to analyze - Returns: string of the dominant emotion - """ - try: - scores = self.sid.polarity_scores(text) - emotions = { - 'Happy': max(scores['pos'], 0), - 'Angry': 0, - 'Sad': max(scores['neg'], 0), - 'Fear': 0, - 'Surprise': 0 - } - if scores['compound'] < -0.5: - emotions['Angry'] = abs(scores['compound']) * 0.5 - emotions['Fear'] = abs(scores['compound']) * 0.5 - elif scores['compound'] > 0.5: - emotions['Happy'] = scores['compound'] - emotions['Surprise'] = scores['compound'] * 0.5 - dominant_emotion = max(emotions, key=emotions.get) - if emotions[dominant_emotion] == 0: - return 'Neutral' - self.logger.info(f"Emotion: {dominant_emotion} for text: {text}") - return dominant_emotion - except Exception as e: - raise e - def analyze(self, text): """ Combined analysis of language and emotion Args: text: string to analyze - Returns: dictionary with language and emotion results + Returns: dictionary with language related information """ try: language = self.detect_language(text) - emotions = self.detect_emotion(text) return { - "language": language, - "emotions": emotions + "language": language } except Exception as e: raise e @@ -125,4 +87,4 @@ if __name__ == "__main__": pretty_print(f"Language: {detector.detect_language(text)}", color="status") result = detector.analyze(text) trans = detector.translate(text, result['language']) - pretty_print(f"Translation: {trans} - from: {result['language']} - Emotion: {result['emotions']}") \ No newline at end of file + pretty_print(f"Translation: {trans} - from: {result['language']}") \ No newline at end of file From d3f20819ff4ed98368a4eafe3d4a8b894d9a34b9 Mon Sep 17 00:00:00 2001 From: martin legrand Date: Sun, 1 Jun 2025 16:44:07 +0200 Subject: [PATCH 21/31] feat : working mount of work directory on docker --- .env.example | 7 ++-- docker-compose.yml | 9 +++-- frontend/agentic-seek-front/src/App.js | 2 +- start_services.cmd | 24 +++++++++---- start_services.sh | 47 +++++++++++--------------- 5 files changed, 51 insertions(+), 38 deletions(-) diff --git a/.env.example b/.env.example index a476049..7cf366d 100644 --- a/.env.example +++ b/.env.example @@ -1,9 +1,12 @@ SEARXNG_BASE_URL="http://127.0.0.1:8080" REDIS_BASE_URL="redis://redis:6379/0" -WORK_DIR_HOST="/Users/mlg/Documents/workspace_for_ai" +WORK_DIR="/Users/username/Documents/workspace_with_my_files" +OLLAMA_PORT="11434" +LM_STUDIO_PORT="1234" +CUSTOM_ADDITIONAL_LLM_PORT="11435" OPENAI_API_KEY='xxxxx' DEEPSEEK_API_KEY='xxxxx' OPENROUTER_API_KEY='xxxxx' -TOGETHER_API_KEY='xxxx' +TOGETHER_API_KEY='xxxxx' GOOGLE_API_KEY='xxxxx' ANTHROPIC_API_KEY='xxxxx' \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 5c8f408..ddaec26 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -76,10 +76,13 @@ services: context: . dockerfile: Dockerfile.backend ports: - - ${BACKEND_PORT:-8000}:${BACKEND_PORT:-8000} + - ${BACKEND_PORT:-7777}:${BACKEND_PORT:-7777} + - ${OLLAMA_PORT:-11434}:${OLLAMA_PORT:-11434} + - ${LM_STUDIO_PORT:-1234}:${LM_STUDIO_PORT:-1234} + - ${CUSTOM_ADDITIONAL_LLM_PORT:-8000}:${CUSTOM_ADDITIONAL_LLM_PORT:-8000} volumes: - ./:/app - - ${WORK_DIR_HOST:-.}:/opt/workspace + - ${WORK_DIR:-.}:/opt/workspace command: python3 api.py environment: - SEARXNG_URL=${SEARXNG_BASE_URL:-http://searxng:8080} @@ -91,6 +94,8 @@ services: - TOGETHER_API_KEY=${TOGETHER_API_KEY} - GOOGLE_API_KEY=${GOOGLE_API_KEY} - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} + - HUGGINGFACE_API_KEY=${HUGGINGFACE_API_KEY} + - DSK_DEEPSEEK_API_KEY=${DSK_DEEPSEEK_API_KEY} network_mode: "host" volumes: diff --git a/frontend/agentic-seek-front/src/App.js b/frontend/agentic-seek-front/src/App.js index a9e6407..ed64d08 100644 --- a/frontend/agentic-seek-front/src/App.js +++ b/frontend/agentic-seek-front/src/App.js @@ -4,7 +4,7 @@ import axios from 'axios'; import './App.css'; import { colors } from './colors'; -const BACKEND_URL = process.env.REACT_APP_BACKEND_URL || 'http://0.0.0.0:8000'; +const BACKEND_URL = process.env.BACKEND_PORT || 'http://0.0.0.0:8000'; function App() { const [query, setQuery] = useState(''); diff --git a/start_services.cmd b/start_services.cmd index 94e8649..b069390 100644 --- a/start_services.cmd +++ b/start_services.cmd @@ -1,10 +1,22 @@ @echo off -docker-compose up -if %ERRORLEVEL% neq 0 ( - echo Error: Failed to start containers. Check Docker logs with 'docker compose logs'. - echo Possible fixes: Ensure Docker Desktop is running or check if port 8080 is free. - exit /b 1 +if "%1"=="full" ( + echo Starting full deployment... +) else ( + echo Starting partial deployment... (backend run on host), use "full" to run all services in containers ) -timeout /t 10 /nobreak >nul \ No newline at end of file +REM Stop all containers +echo Stopping containers... +docker stop $(docker ps -aq) >nul 2>&1 + +REM Generate secret key +for /f %%i in ('powershell -command "[System.Web.Security.Membership]::GeneratePassword(64,0)"') do set SEARXNG_SECRET_KEY=%%i + +if "%1"=="full" ( + docker compose up -d backend + timeout /t 5 /nobreak >nul + docker compose --profile full up +) else ( + docker compose --profile core up +) \ No newline at end of file diff --git a/start_services.sh b/start_services.sh index d9cc98c..f3b632a 100755 --- a/start_services.sh +++ b/start_services.sh @@ -5,17 +5,32 @@ source .env command_exists() { command -v "$1" &> /dev/null } +if [ -z "$WORK_DIR" ]; then + echo "Error: WORK_DIR environment variable is not set. Please set it in your .env file." + exit 1 +fi + +if [[ "$OSTYPE" == "darwin"* ]]; then + dir_size_bytes=$(du -s -b "$WORK_DIR" 2>/dev/null | awk '{print $1}') +else + dir_size_bytes=$(du -s --bytes "$WORK_DIR" 2>/dev/null | awk '{print $1}') +fi + +max_size_bytes=$((2 * 1024 * 1024 * 1024)) + +echo "Mounting $WORK_DIR ($dir_size_bytes bytes) to docker." + +if [ "$dir_size_bytes" -gt "$max_size_bytes" ]; then + echo "Error: WORK_DIR ($WORK_DIR) contains more than 2GB of data ($(du -sh "$WORK_DIR" 2>/dev/null | awk '{print $1}'))." + exit 1 +fi if [ "$1" = "full" ]; then echo "Starting full deployment with backend and all services..." else - echo "Starting core deployment with frontend and search services only..." + echo "Starting core deployment with frontend and search services only... use ./start_services.sh full to start backend as well" fi -# -# Check if Docker is installed é running -# - if ! command_exists docker; then echo "Error: Docker is not installed. Please install Docker first." echo "On Ubuntu: sudo apt install docker.io" @@ -68,28 +83,6 @@ if [ ! -f "docker-compose.yml" ]; then exit 1 fi -# bundle based approach, commented out in favor of direct download for now -# 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/Fosowl/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)..." sleep 4 From 444e7bce2245f278f20688b8697cb4600828dad6 Mon Sep 17 00:00:00 2001 From: martin legrand Date: Sun, 1 Jun 2025 16:47:05 +0200 Subject: [PATCH 22/31] refactor : remove ntlk import --- sources/language.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/sources/language.py b/sources/language.py index a665bda..17e4c97 100644 --- a/sources/language.py +++ b/sources/language.py @@ -1,8 +1,6 @@ from typing import List, Tuple, Type, Dict import re import langid -import nltk -from nltk.sentiment.vader import SentimentIntensityAnalyzer from transformers import MarianMTModel, MarianTokenizer from sources.utility import pretty_print, animate_thinking From c81c0ffde6259bab632ab3c44c970306866fef26 Mon Sep 17 00:00:00 2001 From: martin legrand Date: Sun, 1 Jun 2025 16:58:16 +0200 Subject: [PATCH 23/31] requirement correction --- requirements.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index cbc657d..d3846c9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -17,7 +17,6 @@ playsound>=1.3.0 soundfile>=0.13.1 transformers>=4.46.3 torch>=2.4.1 -python-dotenv>=1.0.0 ollama>=0.4.7 scipy>=1.9.3 soundfile>=0.13.1 @@ -41,7 +40,6 @@ fake_useragent>=2.1.0 selenium_stealth>=1.0.6 undetected-chromedriver>=3.5.5 sentencepiece>=0.2.0 -python-dotenv>=1.0.0 together>=1.5.0 tqdm>4 openai From 2f8d2d4954ba0c5bc3fba857b36d36f732a731c2 Mon Sep 17 00:00:00 2001 From: martin legrand Date: Sun, 1 Jun 2025 21:53:39 +0200 Subject: [PATCH 24/31] config.ini --- config.ini | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/config.ini b/config.ini index 19cb1e4..4e91517 100644 --- a/config.ini +++ b/config.ini @@ -1,14 +1,13 @@ [MAIN] is_local = True provider_name = ollama -provider_model = deepseek-r1:14b +provider_model = deepseek-r1:1.5b provider_server_address = 127.0.0.1:11434 -agent_name = Name_of_your_AI +agent_name = Jarvis recover_last_session = False save_session = False speak = False listen = False -work_dir = /Users/mlg/Documents/workspace_for_agenticseek jarvis_personality = False languages = en [BROWSER] From da6056e94cc35b4e90379b3c6dccabd5fb18a927 Mon Sep 17 00:00:00 2001 From: martin legrand Date: Mon, 2 Jun 2025 21:52:24 +0200 Subject: [PATCH 25/31] feat: fallback when openssl unavailable --- start_services.sh | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/start_services.sh b/start_services.sh index f3b632a..79451ec 100755 --- a/start_services.sh +++ b/start_services.sh @@ -89,8 +89,18 @@ sleep 4 docker stop $(docker ps -a -q) echo "All containers stopped" -# export searxng secret key -export SEARXNG_SECRET_KEY=$(openssl rand -hex 32) +# export searxng secret key (cross-platform) +if command -v openssl &> /dev/null; then + export SEARXNG_SECRET_KEY=$(openssl rand -hex 32) +else + # Fallback: use Python if openssl is not available + if command -v python3 &> /dev/null; then + export SEARXNG_SECRET_KEY=$(python3 -c "import secrets; print(secrets.token_hex(32))") + else + echo "Error: Neither openssl nor python is available to generate a secret key." + exit 1 + fi +fi if [ "$1" = "full" ]; then # First start backend and wait for it to be healthy From e0fa4e6356830c2e19d4d27555870e1f38024bb1 Mon Sep 17 00:00:00 2001 From: martin legrand Date: Mon, 2 Jun 2025 22:25:22 +0200 Subject: [PATCH 26/31] readme upd --- README.md | 171 ++++++++++++++++++++------------------------- start_services.cmd | 13 ++++ 2 files changed, 87 insertions(+), 97 deletions(-) diff --git a/README.md b/README.md index dc99a5a..bd1fdc0 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ * 📋 Plans & Executes Complex Tasks - From trip planning to complex projects — it can split big tasks into steps and get things done using multiple AI agents. -* 🎙️ Voice-Enabled - Clean, fast, futuristic voice and speech to text allowing you to talk to it like it's your personal AI from a sci-fi movie +* 🎙️ Voice-Enabled - Clean, fast, futuristic voice and speech to text allowing you to talk to it like it's your personal AI from a sci-fi movie. (In progress) ### **Demo** @@ -32,19 +32,17 @@ https://github.com/user-attachments/assets/b8ca60e9-7b3b-4533-840e-08f9ac426316 Disclaimer: This demo, including all the files that appear (e.g: CV_candidates.zip), are entirely fictional. We are not a corporation, we seek open-source contributors not candidates. -> 🛠⚠️️ **Active Work in Progress** – Please note that Code/Bash is not dockerized yet but will be soon (see docker_deployement branch) - Do not deploy over network or production. +> 🛠⚠️️ **Active Work in Progress** -> 🙏 This project started as a side-project with zero roadmap and zero funding. It's grown way beyond what I expected by ending in GitHub Trending. Contributions, feedback, and patience are deeply appreciated. +> 🙏 This project started as a side-project and has zero roadmap and zero funding. It's grown way beyond what I expected by ending in GitHub Trending. Contributions, feedback, and patience are deeply appreciated. -## Installation +## Prerequisites Make sure you have chrome driver, docker and python3.10 installed. -We highly advise you use exactly python3.10 for the setup. Dependencies error might happen otherwise. - For issues related to chrome driver, see the **Chromedriver** section. -### 1️⃣ **Clone the repository and setup** +### **Clone the repository and setup** ```sh git clone https://github.com/Fosowl/agenticSeek.git @@ -52,73 +50,56 @@ cd agenticSeek mv .env.example .env ``` -### 2️ **Create a virtual env** +### Change the .env file content + +**API Key are totally optional for user who choose to run LLM locally. Which is the primary purpose of this project. Leave empty if you have sufficient hardware** ```sh -python3 -m venv agentic_seek_env -source agentic_seek_env/bin/activate -# On Windows: agentic_seek_env\Scripts\activate +SEARXNG_BASE_URL="http://127.0.0.1:8080" +REDIS_BASE_URL="redis://redis:6379/0" +WORK_DIR="/Users/mlg/Documents/workspace_for_ai" +OLLAMA_PORT="11434" +LM_STUDIO_PORT="1234" +CUSTOM_ADDITIONAL_LLM_PORT="11435" +OPENAI_API_KEY='optional' +DEEPSEEK_API_KEY='optional' +OPENROUTER_API_KEY='optional' +TOGETHER_API_KEY='optional' +GOOGLE_API_KEY='optional' +ANTHROPIC_API_KEY='optional' ``` -### 3️⃣ **Install package** +The following environment variables configure your application's connections and API keys. -Ensure Python, Docker and docker compose, and Google chrome are installed. +Update the `.env` file with your own values as needed: -We recommend Python 3.10.0. +- **SEARXNG_BASE_URL**: Leave unchanged +- **REDIS_BASE_URL**: Leave unchanged +- **WORK_DIR**: Path to your working directory on your local machine. AgenticSeek will be able to read and interact with these files. +- **OLLAMA_PORT**: Port number for the Ollama service. +- **LM_STUDIO_PORT**: Port number for the LM Studio service. +- **CUSTOM_ADDITIONAL_LLM_PORT**: Port for any additional custom LLM service. +All API key environment variables below are **optional**. You only need to provide them if you plan to use external APIs instead of running LLMs locally. -**Automatic Installation (recommended):** +### **Start Docker** -For Linux/Macos: +Make sure Docker is installed and running on your system. You can start Docker using the following commands: + +- **On Linux/macOS:** + Open a terminal and run: + ```sh + sudo systemctl start docker + ``` + Or launch Docker Desktop from your applications menu if installed. + +- **On Windows:** + Start Docker Desktop from the Start menu. + +You can verify Docker is running by executing: ```sh -./install.sh +docker info ``` - -For windows: - -```sh -./install.bat -``` - -**Manually:** - -**Note: For any OS, ensure the ChromeDriver you install matches your installed Chrome version. Run `google-chrome --version`. See known issues if you have chrome >135** - -- *Linux*: - -Update Package List: `sudo apt update` - -Install Dependencies: `sudo apt install -y alsa-utils portaudio19-dev python3-pyaudio libgtk-3-dev libnotify-dev libgconf-2-4 libnss3 libxss1` - -Install ChromeDriver matching your Chrome browser version: -`sudo apt install -y chromium-chromedriver` - -Install requirements: `pip3 install -r requirements.txt` - -- *Macos*: - -Update brew : `brew update` - -Install chromedriver : `brew install --cask chromedriver` - -Install portaudio: `brew install portaudio` - -Upgrade pip : `python3 -m pip install --upgrade pip` - -Upgrade wheel : : `pip3 install --upgrade setuptools wheel` - -Install requirements: `pip3 install -r requirements.txt` - -- *Windows*: - -Install pyreadline3 `pip install pyreadline3` - -Install portaudio manually (e.g., via vcpkg or prebuilt binaries) and then run: `pip install pyaudio` - -Download and install chromedriver manually from: https://sites.google.com/chromium.org/driver/getting-started - -Place chromedriver in a directory included in your PATH. - -Install requirements: `pip3 install -r requirements.txt` +If you see information about your Docker installation, it is running correctly. --- @@ -153,13 +134,12 @@ provider_server_address = 127.0.0.1:11434 agent_name = Jarvis # name of your AI recover_last_session = True # whenever to recover the previous session save_session = True # whenever to remember the current session -speak = True # text to speech -listen = False # Speech to text, only for CLI -work_dir = /Users/mlg/Documents/workspace # The workspace for AgenticSeek. +speak = False # text to speech +listen = False # Speech to text, only for CLI, experimental jarvis_personality = False # Whenever to use a more "Jarvis" like personality (experimental) languages = en zh # The list of languages, Text to speech will default to the first language on the list [BROWSER] -headless_browser = True # Whenever to use headless browser, recommended only if you use web interface. +headless_browser = True # leave unchanged unless using CLI on host. stealth_mode = True # Use undetected selenium to reduce browser detection ``` @@ -187,6 +167,8 @@ Next step: [Start services and run AgenticSeek](#Start-services-and-Run) ## Setup to run with an API +**Running with an API is optional, see above to run locally.** + Set the desired provider in the `config.ini`. See below for a list of API providers. ```sh @@ -212,9 +194,7 @@ Example: export `TOGETHER_API_KEY="xxxxx"` | togetherAI | No | Use together AI API (non-private) | | google | No | Use google gemini API (non-private) | -*We advise against using gpt-4o or other closedAI models*, performance are poor for web browsing and task planning. - -Please also note that coding/bash might fail with gemini, it seems to ignore our prompt for format to respect, which are optimized for deepseek r1. +Please note that coding/bash might fail with gemini, it seems to ignore our prompt for format to respect, which are optimized for deepseek r1. Model such are gpt-4o seem to perform poorly with our prompt as well. Next step: [Start services and run AgenticSeek](#Start-services-and-Run) @@ -226,44 +206,42 @@ Next step: [Start services and run AgenticSeek](#Start-services-and-Run) ## Start services and Run -Activate your python env if needed. -```sh -source agentic_seek_env/bin/activate -``` - Start required services. This will start all services from the docker-compose.yml, including: - searxng - redis (required by searxng) - frontend + - backend (if using `full`) + +```sh +sudo ./start_services.sh full # MacOS +start ./start_services.cmd full # Window +``` + +Go to `http://localhost:3000/` and you should see the web interface. + +**Optional:** Run with the CLI interface: + +To run with CLI interface you would have to install package on host: + +```sh +./install.sh +./install.bat # windows +``` + +Start services: ```sh sudo ./start_services.sh # MacOS start ./start_services.cmd # Window ``` -**Options 1:** Run with the CLI interface. - -```sh -python3 cli.py -``` - -We advise you set `headless_browser` to False in the config.ini for CLI mode. - -**Options 2:** Run with the Web interface. - -Start the backend. - -```sh -python3 api.py -``` - -Go to `http://localhost:3000/` and you should see the web interface. +Then run : `python3 cli.py` --- ## Usage -Make sure the services are up and running with `./start_services.sh` and run the AgenticSeek with `python3 cli.py` for CLI mode or `python3 api.py` then go to `localhost:3000` for web interface. +Make sure the services are up and running with `./start_services.sh full` and go to `localhost:3000` for web interface. You can also use speech to text by setting `listen = True` in the config. Only for CLI mode. @@ -359,6 +337,8 @@ Next step: [Start services and run AgenticSeek](#Start-services-and-Run) ## Speech to Text +Warning: speech to text only work in CLI mode at the moment. + Please note that currently speech to text only work in english. The speech-to-text functionality is disabled by default. To enable it, set the listen option to True in the config.ini file: @@ -398,7 +378,6 @@ recover_last_session = False save_session = False speak = False listen = False -work_dir = /Users/mlg/Documents/ai_folder jarvis_personality = False languages = en zh [BROWSER] @@ -426,8 +405,6 @@ stealth_mode = False - listen -> listen to voice input (True) or not (False). -- work_dir -> Folder the AI will have access to. eg: /Users/user/Documents/. - - jarvis_personality -> Uses a JARVIS-like personality (True) or not (False). This simply change the prompt file. - languages -> The list of supported language, needed for the llm router to work properly, avoid putting too many or too similar languages. diff --git a/start_services.cmd b/start_services.cmd index b069390..ce278a8 100644 --- a/start_services.cmd +++ b/start_services.cmd @@ -6,6 +6,19 @@ if "%1"=="full" ( echo Starting partial deployment... (backend run on host), use "full" to run all services in containers ) +where openssl >nul 2>&1 +if %ERRORLEVEL% == 0 ( + for /f %%i in ('openssl rand -hex 32') do set SEARXNG_SECRET_KEY=%%i +) else ( + where python3 >nul 2>&1 + if %ERRORLEVEL% == 0 ( + for /f %%i in ('python3 -c "import secrets; print(secrets.token_hex(32))"') do set SEARXNG_SECRET_KEY=%%i + ) else ( + echo Error: Neither openssl nor python is available to generate a secret key. + exit /b 1 + ) +) + REM Stop all containers echo Stopping containers... docker stop $(docker ps -aq) >nul 2>&1 From e952ac3e6187f5a5bf7b95026dcbaa130004c711 Mon Sep 17 00:00:00 2001 From: martin legrand Date: Mon, 2 Jun 2025 22:31:43 +0200 Subject: [PATCH 27/31] readme upd --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bd1fdc0..392b79b 100644 --- a/README.md +++ b/README.md @@ -52,8 +52,6 @@ mv .env.example .env ### Change the .env file content -**API Key are totally optional for user who choose to run LLM locally. Which is the primary purpose of this project. Leave empty if you have sufficient hardware** - ```sh SEARXNG_BASE_URL="http://127.0.0.1:8080" REDIS_BASE_URL="redis://redis:6379/0" @@ -69,6 +67,8 @@ GOOGLE_API_KEY='optional' ANTHROPIC_API_KEY='optional' ``` +**API Key are totally optional for user who choose to run LLM locally. Which is the primary purpose of this project. Leave empty if you have sufficient hardware** + The following environment variables configure your application's connections and API keys. Update the `.env` file with your own values as needed: @@ -79,6 +79,7 @@ Update the `.env` file with your own values as needed: - **OLLAMA_PORT**: Port number for the Ollama service. - **LM_STUDIO_PORT**: Port number for the LM Studio service. - **CUSTOM_ADDITIONAL_LLM_PORT**: Port for any additional custom LLM service. + All API key environment variables below are **optional**. You only need to provide them if you plan to use external APIs instead of running LLMs locally. ### **Start Docker** @@ -217,6 +218,8 @@ sudo ./start_services.sh full # MacOS start ./start_services.cmd full # Window ``` +**Warning:** This step will download and load all Docker images, which may take up to 30 minutes. After starting the services, please wait until the backend service is fully running (you should see backend: in the log) before sending any messages. The backend services may take longer to start than others. + Go to `http://localhost:3000/` and you should see the web interface. **Optional:** Run with the CLI interface: From 81760bfd9cdca55b5fe9730d4a4564121b2f49c9 Mon Sep 17 00:00:00 2001 From: martin legrand Date: Mon, 2 Jun 2025 22:33:27 +0200 Subject: [PATCH 28/31] upd reamdem --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 392b79b..7ccd9ee 100644 --- a/README.md +++ b/README.md @@ -542,4 +542,5 @@ We’re looking for developers to improve AgenticSeek! Check out open issues or ## Special Thanks: - > [tcsenpai](https://github.com/tcsenpai) For dockerization of backend + > [tcsenpai](https://github.com/tcsenpai) and [plitc](https://github.com/plitc) For helping with backend dockerization + From a58b1cf9f87a07e3f1216d0fed5b382c55ede784 Mon Sep 17 00:00:00 2001 From: martin legrand Date: Tue, 3 Jun 2025 02:19:50 +0200 Subject: [PATCH 29/31] fix : conditional stt & tts activation --- sources/speech_to_text.py | 44 +++++++++++++++++++++++++++++++++------ sources/text_to_speech.py | 16 +++++++++----- 2 files changed, 49 insertions(+), 11 deletions(-) diff --git a/sources/speech_to_text.py b/sources/speech_to_text.py index a888326..9d6917b 100644 --- a/sources/speech_to_text.py +++ b/sources/speech_to_text.py @@ -3,11 +3,18 @@ from typing import List, Tuple, Type, Dict import queue import threading import numpy as np -import torch import time -from transformers import AutoModelForSpeechSeq2Seq, AutoProcessor, pipeline -import librosa -import pyaudio + +IMPORT_FOUND = True + +try: + import torch + import librosa + import pyaudio + from transformers import AutoModelForSpeechSeq2Seq, AutoProcessor, pipeline +except ImportError: + print(Fore.RED + "Speech To Text disabled." + Fore.RESET) + IMPORT_FOUND = False audio_queue = queue.Queue() done = False @@ -23,13 +30,18 @@ class AudioRecorder: self.chunk = chunk self.record_seconds = record_seconds self.verbose = verbose - self.audio = pyaudio.PyAudio() - self.thread = threading.Thread(target=self._record, daemon=True) + self.thread = None + self.audio = None + if IMPORT_FOUND: + self.audio = pyaudio.PyAudio() + self.thread = threading.Thread(target=self._record, daemon=True) def _record(self) -> None: """ Record audio from the microphone and add it to the audio queue. """ + if not IMPORT_FOUND: + return stream = self.audio.open(format=self.format, channels=self.channels, rate=self.rate, input=True, frames_per_buffer=self.chunk) if self.verbose: @@ -58,10 +70,14 @@ class AudioRecorder: def start(self) -> None: """Start the recording thread.""" + if not IMPORT_FOUND: + return self.thread.start() def join(self) -> None: """Wait for the recording thread to finish.""" + if not IMPORT_FOUND: + return self.thread.join() class Transcript: @@ -69,6 +85,9 @@ class Transcript: Transcript is a class that transcribes audio from the audio queue and adds it to the transcript. """ def __init__(self): + if not IMPORT_FOUND: + print(Fore.RED + "Transcript: Speech to Text is disabled." + Fore.RESET) + return self.last_read = None device = self.get_device() torch_dtype = torch.float16 if device == "cuda" else torch.float32 @@ -91,6 +110,8 @@ class Transcript: ) def get_device(self) -> str: + if not IMPORT_FOUND: + return "cpu" if torch.backends.mps.is_available(): return "mps" if torch.cuda.is_available(): @@ -108,6 +129,8 @@ class Transcript: def transcript_job(self, audio_data: np.ndarray, sample_rate: int = 16000) -> str: """Transcribe the audio data.""" + if not IMPORT_FOUND: + return "" if audio_data.dtype != np.float32: audio_data = audio_data.astype(np.float32) / np.iinfo(audio_data.dtype).max if len(audio_data.shape) > 1: @@ -122,6 +145,9 @@ class AudioTranscriber: AudioTranscriber is a class that transcribes audio from the audio queue and adds it to the transcript. """ def __init__(self, ai_name: str, verbose: bool = False): + if not IMPORT_FOUND: + print(Fore.RED + "AudioTranscriber: Speech to Text is disabled." + Fore.RESET) + return self.verbose = verbose self.ai_name = ai_name self.transcriptor = Transcript() @@ -152,6 +178,8 @@ class AudioTranscriber: """ Transcribe the audio data using AI stt model. """ + if not IMPORT_FOUND: + return global done if self.verbose: print(Fore.BLUE + "AudioTranscriber: Started processing..." + Fore.RESET) @@ -185,9 +213,13 @@ class AudioTranscriber: def start(self): """Start the transcription thread.""" + if not IMPORT_FOUND: + return self.thread.start() def join(self): + if not IMPORT_FOUND: + return """Wait for the transcription thread to finish.""" self.thread.join() diff --git a/sources/text_to_speech.py b/sources/text_to_speech.py index b57d782..310bfee 100644 --- a/sources/text_to_speech.py +++ b/sources/text_to_speech.py @@ -5,9 +5,14 @@ import subprocess from sys import modules from typing import List, Tuple, Type, Dict -from kokoro import KPipeline -from IPython.display import display, Audio -import soundfile as sf +IMPORT_FOUND = True +try: + from kokoro import KPipeline + from IPython.display import display, Audio + import soundfile as sf +except ImportError: + print("Speech synthesis disabled. Please install the kokoro package.") + IMPORT_FOUND = False if __name__ == "__main__": from utility import pretty_print, animate_thinking @@ -33,7 +38,7 @@ class Speech(): } self.pipeline = None self.language = language - if enable: + if enable and IMPORT_FOUND: self.pipeline = KPipeline(lang_code=self.lang_map[language]) self.voice = self.voice_map[language][voice_idx] self.speed = 1.2 @@ -57,7 +62,7 @@ class Speech(): sentence (str): The text to convert to speech. Will be pre-processed. voice_idx (int, optional): Index of the voice to use from the voice map. """ - if not self.pipeline: + if not self.pipeline or not IMPORT_FOUND: return if voice_idx >= len(self.voice_map[self.language]): pretty_print("Invalid voice number, using default voice", color="error") @@ -159,6 +164,7 @@ class Speech(): if __name__ == "__main__": # TODO add info message for cn2an, jieba chinese related import + IMPORT_FOUND = False sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) speech = Speech() tosay_en = """ From 517b4a79e022bb021f233817146930af4d7320c6 Mon Sep 17 00:00:00 2001 From: martin legrand Date: Tue, 3 Jun 2025 22:35:50 +0200 Subject: [PATCH 30/31] upd config.ini --- config.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.ini b/config.ini index 4e91517..21bce48 100644 --- a/config.ini +++ b/config.ini @@ -1,7 +1,7 @@ [MAIN] is_local = True provider_name = ollama -provider_model = deepseek-r1:1.5b +provider_model = deepseek-r1:14b provider_server_address = 127.0.0.1:11434 agent_name = Jarvis recover_last_session = False From 42bb65e8f6895a244c5e8ea596a3db7170221d90 Mon Sep 17 00:00:00 2001 From: martin legrand Date: Tue, 3 Jun 2025 22:38:53 +0200 Subject: [PATCH 31/31] upd config.ini --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7ccd9ee..5072316 100644 --- a/README.md +++ b/README.md @@ -144,9 +144,14 @@ headless_browser = True # leave unchanged unless using CLI on host. stealth_mode = True # Use undetected selenium to reduce browser detection ``` -Warning: Do *NOT* set provider_name to `openai` if using LM-studio for running LLMs. Set it to `lm-studio`. +**Warning**: -Note: Some provider (eg: lm-studio) require you to have `http://` in front of the IP. For example `http://127.0.0.1:1234` +- The `config.ini` file format does not support comments. +Do not copy and paste the example configuration directly, as comments will cause errors. Instead, manually modify the `config.ini` file with your desired settings, excluding any comments. + +- Do *NOT* set provider_name to `openai` if using LM-studio for running LLMs. Set it to `lm-studio`. + +- Some provider (eg: lm-studio) require you to have `http://` in front of the IP. For example `http://127.0.0.1:1234` **List of local providers**