refactor(docker): simplify Dockerfile and remove custom browser component

- Simplified Dockerfile by removing system dependencies, Playwright installation, and unnecessary Python packages
- Removed custom browser_use_component.py (now using custom_components directory)
- Updated docker-compose to build from Dockerfile and mount custom_components
- Retained only essential dependencies: browser-use and langchain-openai
This commit is contained in:
nafer committed 2026-02-26 15:57:24 +03:00
1 parent 1f7d15a151
commit 0b91ee5481
5 files changed
+87 -304

No files matched your search

+3 -44
View File
@@ -1,48 +1,7 @@
# Используем официальный образ Langflow как базу
FROM langflowai/langflow:1.7.3 FROM langflowai/langflow:1.7.3
# Работаем от root RUN pip install --no-cache-dir browser-use langchain-openai
USER root
WORKDIR /app
# Устанавливаем системные зависимости для Playwright и browser-use EXPOSE 7860
RUN apt-get update && apt-get install -y \
wget \
gnupg \
libglib2.0-0 \
libnss3 \
libnspr4 \
libdbus-1-3 \
libatk1.0-0 \
libatk-bridge2.0-0 \
libcups2 \
libdrm2 \
libxkbcommon0 \
libxcomposite1 \
libxdamage1 \
libxfixes3 \
libxrandr2 \
libgbm1 \
libasound2 \
libpango-1.0-0 \
libcairo2 \
&& rm -rf /var/lib/apt/lists/*
# Устанавливаем Python зависимости CMD ["python", "-m", "langflow", "run", "--host", "0.0.0.0", "--port", "7860"]
RUN pip install --no-cache-dir \
browser-use \
langchain-community \
playwright \
httpx \
langchain-openai \
openai \
python-dotenv
# Устанавливаем Playwright браузеры
RUN playwright install chromium --with-deps
# Переменные окружения для browserless
ENV BROWSERLESS_API_URL=http://browserless.home
# По умолчанию запускаем Langflow
CMD ["langflow", "run"]
-258
View File
@@ -1,258 +0,0 @@
"""
Browser Use Custom Component для Langflow
Интеграция с browserless + OpenRouter
Основано на документации из Context7
"""
import os
from typing import Optional, Dict, Any, List
from langflow.custom import Component
from langflow.inputs import SecretStrInput, StrInput, DictInput
from langflow.template import Output
class BrowserUseComponent(Component):
"""
Browser Use компонент с интеграцией browserless + OpenRouter
Подключение к browserless через CDP URL.
Использует OpenRouter API для LLM.
"""
display_name = "Browser Use"
description = "browser-use с browserless + OpenRouter"
icon = "Globe"
inputs = [
SecretStrInput(
name="browserless_url",
display_name="Browserless URL",
value=os.getenv("BROWSERLESS_API_URL", "http://browserless.home"),
required=True,
helper_text="CDP URL browserless сервера",
),
StrInput(
name="task",
display_name="Задача",
required=True,
placeholder="Например: найди информацию о...",
),
StrInput(
name="model",
display_name="OpenRouter Модель",
value="arcee-ai/trinity-large-preview:free",
advanced=True,
helper_text="Модель: anthropic/claude-3-opus, openai/gpt-4o, google/gemini-pro и др.",
),
SecretStrInput(
name="openrouter_api_key",
display_name="OpenRouter API Key",
value=os.getenv("OPENROUTER_API_KEY", ""),
required=True,
),
]
outputs = [
Output(name="result", display_name="Результат", method="run_browser"),
]
def run_browser(self) -> str:
"""
Запускает browser-use агент с browserless + OpenRouter
"""
try:
from browser_use import Agent, Browser
from langchain_openai import ChatOpenAI
# URL browserless
browserless_url = self.browserless_url
# Формируем WebSocket URL для browserless
cdp_url = browserless_url.replace("http://", "ws://").replace("https://", "wss://")
cdp_url = f"{cdp_url}/playwright"
# Конфигурация браузера с CDP подключением
browser = Browser(
cdp_url=cdp_url,
headless=True,
)
# Инициализация LLM через OpenRouter
api_key = self.openrouter_api_key or os.getenv("OPENROUTER_API_KEY")
llm = ChatOpenAI(
model=self.model,
api_key=api_key,
base_url="https://openrouter.ai/api/v1",
default_headers={
"HTTP-Referer": "http://langflow.home",
"X-Title": "Langflow",
},
)
# Создание агента
agent = Agent(
task=self.task,
llm=llm,
browser=browser,
)
# Запуск агента
result = agent.run()
return str(result)
except ImportError as e:
return f"Ошибка импорта: {e}. Убедитесь, что browser-use установлен."
except Exception as e:
return f"Ошибка выполнения: {e}"
class BrowserUsePlaywrightComponent(Component):
"""
Альтернативный компонент - Playwright напрямую с browserless
"""
display_name = "Browser Use (Playwright)"
description = "Playwright напрямую с browserless"
icon = "Globe"
inputs = [
SecretStrInput(
name="browserless_url",
display_name="Browserless URL",
value=os.getenv("BROWSERLESS_API_URL", "http://browserless.home"),
required=True,
),
StrInput(
name="url",
display_name="URL",
required=True,
placeholder="https://example.com",
),
StrInput(
name="action",
display_name="Действие",
value="navigate",
advanced=True,
options=["navigate", "click", "fill", "screenshot", "get_content"],
),
StrInput(
name="selector",
display_name="CSS Selector",
advanced=True,
),
StrInput(
name="fill_text",
display_name="Текст для заполнения",
advanced=True,
),
]
outputs = [
Output(name="result", display_name="Результат", method="run_playwright"),
]
async def run_playwright(self) -> Dict[str, Any]:
"""Запускает Playwright с browserless"""
from playwright.async_api import async_playwright
browserless_url = self.browserless_url
ws_endpoint = browserless_url.replace("http://", "ws://").replace("https://", "wss://")
ws_endpoint = f"{ws_endpoint}/playwright?launch=%s" % str({"headless": True})
async with async_playwright() as p:
try:
browser = await p.chromium.connect_over_cdp(ws_endpoint)
page = await browser.new_page()
try:
if self.action == "navigate":
await page.goto(self.url)
content = await page.content()
return {"status": "success", "content": content[:5000]}
elif self.action == "click":
await page.click(self.selector or "body")
return {"status": "success", "action": "clicked"}
elif self.action == "fill":
await page.fill(self.selector or "body", self.fill_text or "")
return {"status": "success", "action": "filled"}
elif self.action == "screenshot":
await page.goto(self.url)
screenshot_bytes = await page.screenshot()
import base64
return {"status": "success", "screenshot": base64.b64encode(screenshot_bytes).decode()}
elif self.action == "get_content":
await page.goto(self.url)
content = await page.content()
return {"status": "success", "content": content}
finally:
await page.close()
await browser.close()
except Exception as e:
return {"status": "error", "message": str(e)}
class SimpleBrowserAgentComponent(Component):
"""
Простой browser-use агент с OpenRouter (локальный браузер)
"""
display_name = "Simple Browser Agent + OpenRouter"
description = "browser-use агент с OpenRouter (локальный браузер)"
icon = "Globe"
inputs = [
StrInput(
name="task",
display_name="Задача",
required=True,
),
StrInput(
name="model",
display_name="Модель",
value="arcee-ai/trinity-large-preview:free",
advanced=True,
),
SecretStrInput(
name="openrouter_api_key",
display_name="OpenRouter API Key",
value=os.getenv("OPENROUTER_API_KEY", ""),
required=True,
),
]
outputs = [
Output(name="result", display_name="Результат", method="run_agent"),
]
def run_agent(self) -> str:
try:
from browser_use import Agent, Browser
from langchain_openai import ChatOpenAI
# Локальный браузер
browser = Browser(headless=True)
api_key = self.openrouter_api_key or os.getenv("OPENROUTER_API_KEY")
llm = ChatOpenAI(
model=self.model,
api_key=api_key,
base_url="https://openrouter.ai/api/v1",
default_headers={
"HTTP-Referer": "http://langflow.home",
"X-Title": "Langflow",
},
)
agent = Agent(task=self.task, llm=llm, browser=browser)
result = agent.run()
return str(result)
except Exception as e:
return f"Ошибка: {e}"
+3
View File
@@ -0,0 +1,3 @@
from .browser_use_component import BrowserUseComponent
__all__ = ["BrowserUseComponent"]
@@ -0,0 +1,75 @@
"""
Browser Use Custom Component для Langflow
"""
import os
from typing import Dict, Any
from lfx.custom import Component
from lfx.io import SecretStrInput, StrInput
from lfx.template import Output
class BrowserUseComponent(Component):
"""Browser Use компонент с browserless + OpenRouter"""
display_name = "Browser Use"
description = "browser-use с browserless + OpenRouter"
icon = "Globe"
inputs = [
SecretStrInput(
name="browserless_url",
display_name="Browserless URL",
value=os.getenv("BROWSERLESS_API_URL", "http://browserless.home"),
required=True,
),
StrInput(
name="task",
display_name="Задача",
required=True,
placeholder="Например: найди информацию о...",
),
StrInput(
name="model",
display_name="OpenRouter Модель",
value="arcee-ai/trinity-large-preview:free",
advanced=True,
),
]
outputs = [
Output(name="result", display_name="Результат", method="run_browser"),
]
def run_browser(self) -> str:
"""Запускает browser-use агент"""
try:
from browser_use import Agent, Browser
from langchain_openai import ChatOpenAI
browserless_url = self.browserless_url or "http://browserless.home"
cdp_url = browserless_url.replace("http://", "ws://").replace("https://", "wss://")
cdp_url = f"{cdp_url}/playwright"
browser = Browser(cdp_url=cdp_url, headless=True)
api_key = os.getenv("OPENROUTER_API_KEY", "")
llm = ChatOpenAI(
model=self.model,
api_key=api_key,
base_url="https://openrouter.ai/api/v1",
default_headers={
"HTTP-Referer": "http://langflow.home",
"X-Title": "Langflow",
},
)
agent = Agent(task=self.task, llm=llm, browser=browser)
result = agent.run()
return str(result)
except ImportError as e:
return f"Ошибка импорта: {e}. Установите browser-use"
except Exception as e:
return f"Ошибка: {e}"
+6 -2
View File
@@ -2,21 +2,25 @@ version: '3.8'
services: services:
langflow: langflow:
image: langflowai/langflow:1.7.3 build:
context: .
dockerfile: Dockerfile
restart: unless-stopped restart: unless-stopped
ports: ports:
- "7860:7860" - "7860:7860"
networks: networks:
- dokploy-network - dokploy-network
volumes:
- ./custom_components:/app/custom_components
environment: environment:
LANGFLOW_SECRET_KEY: ${LANGFLOW_SECRET_KEY:-changeme} LANGFLOW_SECRET_KEY: ${LANGFLOW_SECRET_KEY:-changeme}
LANGFLOW_HOST: 0.0.0.0 LANGFLOW_HOST: 0.0.0.0
LANGFLOW_PORT: 7860 LANGFLOW_PORT: 7860
LANGFLOW_COMPONENTS_PATH: /app/custom_components
OPENROUTER_API_KEY: ${OPENROUTER_API_KEY} OPENROUTER_API_KEY: ${OPENROUTER_API_KEY}
OPENROUTER_BASE_URL: https://openrouter.ai/api/v1 OPENROUTER_BASE_URL: https://openrouter.ai/api/v1
BROWSERLESS_API_URL: http://browserless.home BROWSERLESS_API_URL: http://browserless.home
BROWSER_HEADLESS: "true" BROWSER_HEADLESS: "true"
command: ["python", "-m", "langflow", "run", "--host", "0.0.0.0", "--port", "7860"]
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:7860/"] test: ["CMD", "curl", "-f", "http://localhost:7860/"]
interval: 30s interval: 30s