From 9b5487eba4efe0c1cc44805431d89661f50dfd3a Mon Sep 17 00:00:00 2001 From: er-jaydeep-gohel <94613631+er-jaydeep-gohel@users.noreply.github.com> Date: Fri, 17 Apr 2026 21:30:06 +0530 Subject: [PATCH] feat: containerize application with Docker and add docker-compose support for Streamlit deployment --- .dockerignore | 45 +++++++++++++++++++++++++++++++++++++++++++ Dockerfile | 47 +++++++++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 28 +++++++++++++++++++++++++++ requirements.txt | Bin 3624 -> 1814 bytes 4 files changed, 120 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 docker-compose.yml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..14dc652 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,45 @@ +# Git +.git +.gitignore +.github + +# Python artifacts +__pycache__/ +*.py[cod] +*.pyo +*.pyd +.Python +*.egg-info/ +dist/ +build/ +*.egg + +# Virtual environments +venv/ +.venv/ +env/ +.env/ + +# IDE / editors +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS files +.DS_Store +Thumbs.db + +# Logs & temp +*.log +*.tmp + +# Test / CI +.pytest_cache/ +htmlcov/ +.coverage + +# Docs & media (optional, remove if app needs them at runtime) +README.md +media/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..7f6d1b4 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,47 @@ +# Use official Python slim image for smaller size +FROM python:3.10-slim + +# Set environment variables +ENV PYTHONDONTWRITEBYTECODE=1 \ + PYTHONUNBUFFERED=1 \ + PIP_NO_CACHE_DIR=1 + +# Set working directory +WORKDIR /app + +# Install system dependencies +RUN apt-get update && apt-get install -y --no-install-recommends \ + build-essential \ + curl \ + git \ + && rm -rf /var/lib/apt/lists/* + +# Copy requirements first for better Docker layer caching +COPY requirements.txt . + +# Install Python dependencies +# Note: PyQt6 is excluded since we're running headless (Streamlit web UI only) +# Note: en_core_web_sm is already included in requirements.txt as a wheel download +RUN pip install --upgrade pip && \ + grep -v "^PyQt6" requirements.txt > requirements_web.txt && \ + pip install -r requirements_web.txt + +# Download additional NLTK data required by the app +RUN python -c "import nltk; nltk.download('punkt'); nltk.download('wordnet'); nltk.download('averaged_perceptron_tagger'); nltk.download('punkt_tab')" + +# Copy the application source code +COPY . . + +# Expose Streamlit's default port +EXPOSE 8501 + +# Health check +HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \ + CMD curl -f http://localhost:8501/_stcore/health || exit 1 + +# Run the Streamlit app +CMD ["streamlit", "run", "main.py", \ + "--server.port=8501", \ + "--server.address=0.0.0.0", \ + "--server.headless=true", \ + "--browser.gatherUsageStats=false"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..70bde62 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,28 @@ +version: "3.9" + +services: + ai-text-humanizer: + build: + context: . + dockerfile: Dockerfile + image: ai-text-humanizer-app:latest + container_name: ai-text-humanizer + ports: + - "8501:8501" + environment: + - PYTHONUNBUFFERED=1 + restart: unless-stopped + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8501/_stcore/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + volumes: + # Optional: mount local code for development (comment out for production) + # - .:/app + # Persist NLTK data to avoid re-downloading on container restart + - nltk_data:/root/nltk_data + +volumes: + nltk_data: diff --git a/requirements.txt b/requirements.txt index b52a5672ec58f4f0aa1443b307e8d5bbc9e35b77..eff4e302d442701ad43ae94d271410f1234e5249 100644 GIT binary patch literal 1814 zcmZuy%Z}tW47@kc|FA&LcKg+@01YIk06`X*Ag7!LvPIjPmL;zwqsQ}WIpmY_3n|jQ zSuBvFXo)Nqi{*d*`ditgOt{^S`7tl{JLQ~DDv{38I#ayeiu^3`lmbrGF)#VpTI247 zXJvkUp7FKJD?W6p8!35j5#qEZhmx{>SO_WdA}{$Cg=BhzKp|OczBZ~5DP_)wNm=v3 z73#c^4Ayk_+wFq-7hJS{(X&dUH7#ST3MuTZ4{A~zY4Q`UdDl~yjCUL=^CLp*MAH)m zDw2Ece4y6{wXbpd^wXy?r8)k1I1DC@OPhCoI?(%UeMFK&oK?4GlhAECWJs8niV$ ziE6+5#iW-tjZ6~WcISCyCV^y5AjDk#N#9tYTTP8+O0T}K=Id{dJA|iKZ<+S3)@x8`( zW37K6ce!oY94L;YH@H`P4?g*J>3OB9tGrlM2=W9g$n4ImRxTMHH8TnQe~pO7rPNul zteRLM1(p{;U)EtFmjp}sjQpNXx7!HS}CNEXf0eVMX?hrv96{r`tieLk92+~q6 z_An#j3{NM5K`rys-p)tfaU>YY!V-s3!CT-n3?~}EM@m`32w|qo&xE4qZNhPy6bOXv z3NE%5u5ppKVl(tb1HVh=77w?RRKR zbtd7-Q#WZe4x+hWs{lKVNT6rfcb725=LRN!C&z{?Ojhy}NPgNDNE%2!@Gz>)u5ofo zdmgc;2=CykEU38n3*E z2#t-WUst_)_0jEr{~4E6>B_h)%dULT=c=5=b5Xu8-|2m;&n6IEnU#mq==*Eg>ia(M z7sB7@NqndEUB5OAOM~O;M81}?_pIIa#@gLi>$c0v@VGJ+lWBR>zD{g5vSU=T9RyoY z#Ih1%Q4T^Ak*%DSLCoMX&C~V<%q@To&zj4HZ*Cuq>m37!(mM_N`M%r^3 zd%cSor-~8Fx4q5V-XhEnQgIthA488xAklFshN|E>Ztb7)R==MF6bA2Pqsj8)swT+^lMc&TC*Ghklg`tklwYHJ(HY|+w7Z$(G ztWl26Lfeb~fo#O*RXd%@RvsELX!Y()zRAUp;zG`;g=^_GP;HL%*QK62v6`sThk73L zW+LV1S|uv_;#zM;dOy|MsWNq?cXL^|(dSO@=X%C^I}H3pzpn#(tJR@mnF}`+eyqK7 z*}CoXM~$Kt+GbS|J(jap=HiXoRKnYOt{vpO5d#RSh-w?5 z4#F;kxfjy&2zH(HIeaM^c1uBbe^M@Soevmtg3_gL#s^25Bli| z?2Od4<{gZ6uNcmkr7~rGb1t05o>Qoa2)TJ2LJ8L_%u=tdG~8<~v%>`Y((6@Ebt(h@ zf0bX#$MX9z0#q=nLQ14eG8Qmzfc zjx)?jO>I~mran`P>f4J4-l?ACKu$eFQJ%e>)Y$6h>Fw<%>~mT;d+sW_&+0Q{d~ZQn zVzN3^kJWc?){~HX3$uqAxsgBE5)Fvj!=S*q08M;!1=zx76gk_*}3ev?S7 z*D8lIPt%bX)b7$T6H!cXZ~iv<_Xm@Wy^_B~>|Yd2e&)zCwRz4X#vy z`DXuEdHM~_J!y#88T9VQo&on(=Z_nwdl8%!G4;iizG0gCe