Загрузить файлы в «/»
This commit is contained in:
1 parent
19d5a837b2
commit
76bb9dd19c
3 files changed
+270
-8
No files matched your search
+2
-1
@@ -31,7 +31,8 @@ RUN pip install --no-cache-dir \
|
||||
playwright \
|
||||
httpx \
|
||||
langchain-openai \
|
||||
openai
|
||||
openai \
|
||||
python-dotenv
|
||||
|
||||
# Устанавливаем Playwright браузеры
|
||||
RUN playwright install chromium --with-deps
|
||||
|
||||
@@ -0,0 +1,258 @@
|
||||
"""
|
||||
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}"
|
||||
+10
-7
@@ -5,16 +5,22 @@ services:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
image: langflow:${VERSION:-latest}
|
||||
container_name: langflow
|
||||
restart: unless-stopped
|
||||
expose:
|
||||
- "7860"
|
||||
environment:
|
||||
# Langflow настройки
|
||||
LANGFLOW_DATABASE_URL: sqlite:///./langflow.db
|
||||
LANGFLOW_SECRET_KEY: ${LANGFLOW_SECRET_KEY:-your-secret-key-change-in-production}
|
||||
LANGFLOW_AUTO_LOGY: "false"
|
||||
LANGFLOW_AUTO_LOGIN: "false"
|
||||
LANGFLOW_LOG_LEVEL: INFO
|
||||
LANGFLOW_URL: ${LANGFLOW_URL:-http://langflow.home}
|
||||
|
||||
# OpenAI API Key для browser-use агентов
|
||||
OPENAI_API_KEY: ${OPENAI_API_KEY:-}
|
||||
# OpenRouter API для LLM
|
||||
OPENROUTER_API_KEY: ${OPENROUTER_API_KEY:-}
|
||||
OPENROUTER_BASE_URL: https://openrouter.ai/api/v1
|
||||
|
||||
# Настройки для browser-use
|
||||
BROWSERLESS_API_URL: http://browserless.home
|
||||
@@ -24,15 +30,12 @@ services:
|
||||
# Прокси для доступа к browserless
|
||||
HTTP_PROXY: ${HTTP_PROXY:-}
|
||||
HTTPS_PROXY: ${HTTPS_PROXY:-}
|
||||
NO_PROXY: ${NO_PROXY:-localhost,127.0.0.1}
|
||||
NO_PROXY: ${NO_PROXY:-localhost,127.0.0.1,browserless.home}
|
||||
|
||||
volumes:
|
||||
#persistent volume for SQLite database and files
|
||||
- langflow_data:/app/langflow
|
||||
- langflow_cache:/root/.cache
|
||||
|
||||
networks:
|
||||
- langflow_network
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:7860/health"]
|
||||
interval: 30s
|
||||
|
||||
Reference in new issue
Block a user