Merge branch 'main' into tui-improvements
This commit is contained in:
commit
cec0516639
5 changed files with 45 additions and 21 deletions
|
|
@ -37,6 +37,9 @@ AWS_SECRET_ACCESS_KEY=
|
||||||
# OPTIONAL url for openrag link to langflow in the UI
|
# OPTIONAL url for openrag link to langflow in the UI
|
||||||
LANGFLOW_PUBLIC_URL=
|
LANGFLOW_PUBLIC_URL=
|
||||||
|
|
||||||
|
# OPTIONAL: Override host for docling service (for special networking setups)
|
||||||
|
# HOST_DOCKER_INTERNAL=host.containers.internal
|
||||||
|
|
||||||
# Langflow auth
|
# Langflow auth
|
||||||
LANGFLOW_AUTO_LOGIN=False
|
LANGFLOW_AUTO_LOGIN=False
|
||||||
LANGFLOW_SUPERUSER=
|
LANGFLOW_SUPERUSER=
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ services:
|
||||||
volumes:
|
volumes:
|
||||||
- ./documents:/app/documents:Z
|
- ./documents:/app/documents:Z
|
||||||
- ./keys:/app/keys:Z
|
- ./keys:/app/keys:Z
|
||||||
- ./flows:/app/flows:Z
|
- ./flows:/app/flows:U,z
|
||||||
|
|
||||||
openrag-frontend:
|
openrag-frontend:
|
||||||
image: phact/openrag-frontend:${OPENRAG_VERSION:-latest}
|
image: phact/openrag-frontend:${OPENRAG_VERSION:-latest}
|
||||||
|
|
@ -92,7 +92,7 @@ services:
|
||||||
|
|
||||||
langflow:
|
langflow:
|
||||||
volumes:
|
volumes:
|
||||||
- ./flows:/app/flows:Z
|
- ./flows:/app/flows:U,z
|
||||||
image: phact/openrag-langflow:${LANGFLOW_VERSION:-latest}
|
image: phact/openrag-langflow:${LANGFLOW_VERSION:-latest}
|
||||||
# build:
|
# build:
|
||||||
# context: .
|
# context: .
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ services:
|
||||||
volumes:
|
volumes:
|
||||||
- ./documents:/app/documents:Z
|
- ./documents:/app/documents:Z
|
||||||
- ./keys:/app/keys:Z
|
- ./keys:/app/keys:Z
|
||||||
- ./flows:/app/flows:z
|
- ./flows:/app/flows:U,z
|
||||||
gpus: all
|
gpus: all
|
||||||
|
|
||||||
openrag-frontend:
|
openrag-frontend:
|
||||||
|
|
@ -92,7 +92,7 @@ services:
|
||||||
|
|
||||||
langflow:
|
langflow:
|
||||||
volumes:
|
volumes:
|
||||||
- ./flows:/app/flows:z
|
- ./flows:/app/flows:U,z
|
||||||
image: phact/openrag-langflow:${LANGFLOW_VERSION:-latest}
|
image: phact/openrag-langflow:${LANGFLOW_VERSION:-latest}
|
||||||
# build:
|
# build:
|
||||||
# context: .
|
# context: .
|
||||||
|
|
|
||||||
|
|
@ -41,23 +41,36 @@ def determine_docling_host() -> str:
|
||||||
"""Determine the host address used for docling health checks."""
|
"""Determine the host address used for docling health checks."""
|
||||||
container_type = detect_container_environment()
|
container_type = detect_container_environment()
|
||||||
if container_type:
|
if container_type:
|
||||||
|
# Try HOST_DOCKER_INTERNAL env var first
|
||||||
container_host = get_container_host()
|
container_host = get_container_host()
|
||||||
if container_host:
|
if container_host:
|
||||||
logger.info("Using container-aware host '%s'", container_host)
|
logger.info("Using container-aware host '%s'", container_host)
|
||||||
return container_host
|
return container_host
|
||||||
|
|
||||||
|
# Try special hostnames (Docker Desktop and rootless podman)
|
||||||
|
import socket
|
||||||
|
for hostname in ["host.docker.internal", "host.containers.internal"]:
|
||||||
|
try:
|
||||||
|
socket.getaddrinfo(hostname, None)
|
||||||
|
logger.info("Using %s for container-to-host communication", hostname)
|
||||||
|
return hostname
|
||||||
|
except socket.gaierror:
|
||||||
|
logger.debug("%s not available", hostname)
|
||||||
|
|
||||||
|
# Try gateway IP detection (Docker on Linux)
|
||||||
gateway_ip = _get_gateway_ip_from_route()
|
gateway_ip = _get_gateway_ip_from_route()
|
||||||
if gateway_ip:
|
if gateway_ip:
|
||||||
logger.info("Detected host gateway IP: %s", gateway_ip)
|
logger.info("Detected host gateway IP: %s", gateway_ip)
|
||||||
return gateway_ip
|
return gateway_ip
|
||||||
|
|
||||||
# Either we're not inside a container or gateway detection failed.
|
# Fallback to bridge IP
|
||||||
fallback_ip = guess_host_ip_for_containers(logger=logger)
|
fallback_ip = guess_host_ip_for_containers(logger=logger)
|
||||||
if container_type:
|
|
||||||
logger.info("Falling back to container bridge host %s", fallback_ip)
|
logger.info("Falling back to container bridge host %s", fallback_ip)
|
||||||
else:
|
return fallback_ip
|
||||||
logger.info("Running outside a container; using host %s", fallback_ip)
|
|
||||||
return fallback_ip
|
# Running outside a container
|
||||||
|
logger.info("Running outside a container; using localhost")
|
||||||
|
return "localhost"
|
||||||
|
|
||||||
|
|
||||||
# Detect the host IP once at startup
|
# Detect the host IP once at startup
|
||||||
|
|
@ -70,10 +83,11 @@ async def health(request: Request) -> JSONResponse:
|
||||||
Proxy health check to docling-serve.
|
Proxy health check to docling-serve.
|
||||||
This allows the frontend to check docling status via same-origin request.
|
This allows the frontend to check docling status via same-origin request.
|
||||||
"""
|
"""
|
||||||
|
health_url = f"{DOCLING_SERVICE_URL}/health"
|
||||||
try:
|
try:
|
||||||
async with httpx.AsyncClient() as client:
|
async with httpx.AsyncClient() as client:
|
||||||
response = await client.get(
|
response = await client.get(
|
||||||
f"{DOCLING_SERVICE_URL}/health",
|
health_url,
|
||||||
timeout=2.0
|
timeout=2.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -83,6 +97,7 @@ async def health(request: Request) -> JSONResponse:
|
||||||
"host": HOST_IP
|
"host": HOST_IP
|
||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
|
logger.warning("Docling health check failed", url=health_url, status_code=response.status_code)
|
||||||
return JSONResponse({
|
return JSONResponse({
|
||||||
"status": "unhealthy",
|
"status": "unhealthy",
|
||||||
"message": f"Health check failed with status: {response.status_code}",
|
"message": f"Health check failed with status: {response.status_code}",
|
||||||
|
|
@ -90,13 +105,14 @@ async def health(request: Request) -> JSONResponse:
|
||||||
}, status_code=503)
|
}, status_code=503)
|
||||||
|
|
||||||
except httpx.TimeoutException:
|
except httpx.TimeoutException:
|
||||||
|
logger.warning("Docling health check timeout", url=health_url)
|
||||||
return JSONResponse({
|
return JSONResponse({
|
||||||
"status": "unhealthy",
|
"status": "unhealthy",
|
||||||
"message": "Connection timeout",
|
"message": "Connection timeout",
|
||||||
"host": HOST_IP
|
"host": HOST_IP
|
||||||
}, status_code=503)
|
}, status_code=503)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error("Docling health check failed", error=str(e))
|
logger.error("Docling health check failed", url=health_url, error=str(e))
|
||||||
return JSONResponse({
|
return JSONResponse({
|
||||||
"status": "unhealthy",
|
"status": "unhealthy",
|
||||||
"message": str(e),
|
"message": str(e),
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ import threading
|
||||||
import time
|
import time
|
||||||
from typing import Optional, Tuple, Dict, Any, List, AsyncIterator
|
from typing import Optional, Tuple, Dict, Any, List, AsyncIterator
|
||||||
from utils.logging_config import get_logger
|
from utils.logging_config import get_logger
|
||||||
from utils.container_utils import guess_host_ip_for_containers
|
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
|
|
@ -32,7 +31,8 @@ class DoclingManager:
|
||||||
|
|
||||||
self._process: Optional[subprocess.Popen] = None
|
self._process: Optional[subprocess.Popen] = None
|
||||||
self._port = 5001
|
self._port = 5001
|
||||||
self._host = guess_host_ip_for_containers(logger=logger) # Get appropriate host IP based on runtime
|
# Bind to all interfaces by default (can be overridden with DOCLING_BIND_HOST env var)
|
||||||
|
self._host = os.getenv('DOCLING_BIND_HOST', '0.0.0.0')
|
||||||
self._running = False
|
self._running = False
|
||||||
self._external_process = False
|
self._external_process = False
|
||||||
|
|
||||||
|
|
@ -150,16 +150,20 @@ class DoclingManager:
|
||||||
else:
|
else:
|
||||||
pid = self._load_pid()
|
pid = self._load_pid()
|
||||||
|
|
||||||
|
# Use localhost for display URLs when bound to 0.0.0.0
|
||||||
|
display_host = "localhost" if self._host == "0.0.0.0" else self._host
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"status": "running",
|
"status": "running",
|
||||||
"port": self._port,
|
"port": self._port,
|
||||||
"host": self._host,
|
"host": self._host,
|
||||||
"endpoint": f"http://{self._host}:{self._port}",
|
"endpoint": f"http://{display_host}:{self._port}",
|
||||||
"docs_url": f"http://{self._host}:{self._port}/docs",
|
"docs_url": f"http://{display_host}:{self._port}/docs",
|
||||||
"ui_url": f"http://{self._host}:{self._port}/ui",
|
"ui_url": f"http://{display_host}:{self._port}/ui",
|
||||||
"pid": pid
|
"pid": pid
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
|
display_host = "localhost" if self._host == "0.0.0.0" else self._host
|
||||||
return {
|
return {
|
||||||
"status": "stopped",
|
"status": "stopped",
|
||||||
"port": self._port,
|
"port": self._port,
|
||||||
|
|
@ -176,10 +180,9 @@ class DoclingManager:
|
||||||
return False, "Docling serve is already running"
|
return False, "Docling serve is already running"
|
||||||
|
|
||||||
self._port = port
|
self._port = port
|
||||||
# Use provided host or the bridge IP we detected in __init__
|
# Use provided host or keep default from __init__
|
||||||
if host is not None:
|
if host is not None:
|
||||||
self._host = host
|
self._host = host
|
||||||
# else: keep self._host as already set in __init__
|
|
||||||
|
|
||||||
# Check if port is already in use before trying to start
|
# Check if port is already in use before trying to start
|
||||||
import socket
|
import socket
|
||||||
|
|
@ -293,7 +296,8 @@ class DoclingManager:
|
||||||
self._running = False
|
self._running = False
|
||||||
return False, f"Docling serve process exited immediately (code: {return_code})"
|
return False, f"Docling serve process exited immediately (code: {return_code})"
|
||||||
|
|
||||||
return True, f"Docling serve starting on http://{host}:{port}"
|
display_host = "localhost" if self._host == "0.0.0.0" else self._host
|
||||||
|
return True, f"Docling serve starting on http://{display_host}:{port}"
|
||||||
|
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
return False, "docling-serve not available. Please install: uv add docling-serve"
|
return False, "docling-serve not available. Please install: uv add docling-serve"
|
||||||
|
|
@ -454,7 +458,8 @@ class DoclingManager:
|
||||||
async def follow_logs(self) -> AsyncIterator[str]:
|
async def follow_logs(self) -> AsyncIterator[str]:
|
||||||
"""Follow logs from the docling-serve process in real-time."""
|
"""Follow logs from the docling-serve process in real-time."""
|
||||||
# First yield status message and any existing logs
|
# First yield status message and any existing logs
|
||||||
status_msg = f"Docling serve is running on http://{self._host}:{self._port}"
|
display_host = "localhost" if self._host == "0.0.0.0" else self._host
|
||||||
|
status_msg = f"Docling serve is running on http://{display_host}:{self._port}"
|
||||||
|
|
||||||
with self._log_lock:
|
with self._log_lock:
|
||||||
if self._log_buffer:
|
if self._log_buffer:
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue