From 53e71bd96af1fe05faec7c0b029bf98a761b8998 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0lker=20SI=C4=9EIRCI?= Date: Thu, 2 Jan 2025 00:47:45 +0300 Subject: [PATCH] ready for docker dev deployment --- .dockerignore | 4 +++- docker-compose.yml | 28 +++++++++++++++++++++++++- docker/Dockerfile | 2 +- docker/entrypoint.sh | 2 ++ src/podflix/db/init_db.py | 42 +++++++++++++++++++++++++++++---------- src/podflix/gui/audio.py | 40 ++++++++++++++++++++++++++----------- 6 files changed, 93 insertions(+), 25 deletions(-) diff --git a/.dockerignore b/.dockerignore index 9779c31..d77ea85 100644 --- a/.dockerignore +++ b/.dockerignore @@ -18,6 +18,8 @@ htmlcov/ .venv venv +deployment docs +notebooks tests -deployment +*.sqlite diff --git a/docker-compose.yml b/docker-compose.yml index 4265d77..f1f93af 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -84,7 +84,7 @@ services: networks: - t2_proxy - podflix-network - command: ["tail", "-f", "/dev/null"] # NOTE: For testing the container + # command: ["tail", "-f", "/dev/null"] # NOTE: For testing the container restart: "no" develop: watch: @@ -99,6 +99,19 @@ services: # Rebuild the image on changes to the `pyproject.toml` - action: rebuild path: ./pyproject.toml + env_file: + - .env + environment: + - LIBRARY_BASE_PATH=/app + - CHAINLIT_APP_ROOT=/app/configs/chainlit + labels: + - "traefik.enable=true" + ## HTTP Routers + - "traefik.http.routers.podflix-rtr.entrypoints=https" + - "traefik.http.routers.podflix-rtr.rule=Host(`podflix.$DOMAIN_NAME`)" + ## HTTP Services + - "traefik.http.routers.podflix-rtr.service=podflix-svc" + - "traefik.http.services.podflix-svc.loadbalancer.server.port=5000" podflix-prod: image: podflix-prod:latest @@ -112,6 +125,19 @@ services: - podflix-network command: ["tail", "-f", "/dev/null"] # NOTE: For testing the container restart: "no" + env_file: + - .env + environment: + - LIBRARY_BASE_PATH=/app + - CHAINLIT_APP_ROOT=/app/configs/chainlit + labels: + - "traefik.enable=true" + ## HTTP Routers + - "traefik.http.routers.podflix-rtr.entrypoints=https" + - "traefik.http.routers.podflix-rtr.rule=Host(`podflix.$DOMAIN_NAME`)" + ## HTTP Services + - "traefik.http.routers.podflix-rtr.service=podflix-svc" + - "traefik.http.services.podflix-svc.loadbalancer.server.port=5000" ############ LANGFUSE ############# langfuse-db: diff --git a/docker/Dockerfile b/docker/Dockerfile index 61b03ea..1bc7ab3 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -54,7 +54,7 @@ RUN \ RUN chmod +x /app/docker/entrypoint.sh ENTRYPOINT ["/app/docker/entrypoint.sh"] - +CMD ["uv", "run", "chainlit", "run", "src/podflix/gui/audio.py", "--host", "0.0.0.0", "--port", "5000", "--headless"] # # Stage: build diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index eb36946..c4004ed 100644 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -1,4 +1,6 @@ #!/bin/sh +uv run src/podflix/db/init_db.py + # Start the main application exec "$@" diff --git a/src/podflix/db/init_db.py b/src/podflix/db/init_db.py index f2cf7ca..5537fde 100644 --- a/src/podflix/db/init_db.py +++ b/src/podflix/db/init_db.py @@ -1,5 +1,6 @@ """Initialize the database schema using SQL statements from init_db.sql file.""" +import sqlite3 from pathlib import Path import sqlalchemy as sa @@ -26,24 +27,45 @@ def read_sql_file(file_path: str | Path) -> list[str]: return [x.strip() for x in f.read().split(";") if x.strip()] +def table_exists(conn) -> bool: + """Check if any tables exist in the database. + + Args: + conn: SQLAlchemy connection object + + Returns: + bool: True if any tables exist, False otherwise + """ + try: + # Query to check for existing tables in the public schema + query = """ + SELECT COUNT(*) + FROM users + """ + result = conn.execute(sa.text(query)).scalar() + return result > 0 + except Exception as e: + logger.error(f"Error checking for tables: {e}") + return False + + def initialize_db(): """Initialize the database using SQL statements from init_db.sql file. - Examples: - >>> initialize_db() # Creates/updates database schema - - The function reads SQL statements from the init_db.sql file in the same - directory and executes them sequentially using a database connection. + The function only initializes the database if no tables exist. """ - logger.info("Initializing the database...") + engine = sa.create_engine(DBInterfaceFactory.create().sync_connection()) - raw_sql_statements = read_sql_file(Path(__file__).parent / "init_db.sql") + with engine.connect() as conn: + if table_exists(conn) is True: + logger.info("Database already initialized, skipping...") + return - with sa.create_engine( - DBInterfaceFactory.create().sync_connection() - ).connect() as conn: + logger.info("Initializing the database...") + raw_sql_statements = read_sql_file(Path(__file__).parent / "init_db.sql") for stmt in raw_sql_statements: conn.execute(sa.text(stmt)) + conn.commit() if __name__ == "__main__": diff --git a/src/podflix/gui/audio.py b/src/podflix/gui/audio.py index 5ca209e..0aa87a8 100644 --- a/src/podflix/gui/audio.py +++ b/src/podflix/gui/audio.py @@ -1,4 +1,4 @@ -import webbrowser +import webbrowser # noqa: F401 from dataclasses import dataclass # noqa: F401 from pathlib import Path from uuid import uuid4 @@ -75,12 +75,17 @@ def auth_callback(username: str, password: str): return None -@cl.action_callback("Detailed Traces") -async def on_action(action: cl.Action): - webbrowser.open(action.value, new=0) +# @cl.action_callback("Detailed Traces") +# async def on_action(action: cl.Action): +# # FIXME: Doesn't work inside the docker container +# webbrowser.open(action.value, new=0) - # Optionally remove the action button from the chatbot user interface - # await action.remove() +# # await cl.Message( +# # content=f"Here's your link: [Open Trace]({action.value})", author="System" +# # ).send() + +# # Optionally remove the action button +# # await action.remove() @cl.on_chat_start @@ -201,15 +206,26 @@ async def on_message(msg: cl.Message): logger.debug(f"Langfuse Run ID: {run_id}") - actions = [ - cl.Action( + lf_traces_url = get_lf_traces_url(langchain_run_id=run_id) + + # actions = [ + # cl.Action( + # name="Detailed Traces", + # value=lf_traces_url, + # description="Detailed Logs in Langfuse", + # ) + # ] + + # assistant_message.actions.extend(actions) + + elements = [ + cl.Text( name="Detailed Traces", - value=get_lf_traces_url(langchain_run_id=run_id), - description="Detailed Logs in Langfuse", + content=f"[Detailed Logs]({lf_traces_url})", + display="inline", ) ] - - assistant_message.actions.extend(actions) + assistant_message.elements.extend(elements) await assistant_message.update() message_history.add_ai_message(assistant_message.content)