Patryk Studzinski commited on
Commit
9a9ec03
·
1 Parent(s): b525236

adding-github-files-to-spaces

Browse files
.gitignore ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.pyo
5
+ *.pyd
6
+
7
+ # Virtual environment
8
+ venv/
9
+ env/
10
+
11
+ # Model files and large data
12
+ /app/pretrain_model/
13
+ *.bin
14
+ *.safetensors
15
+ *.gguf
16
+
17
+ # Secrets
18
+ my_hf_token.txt
19
+ /run/secrets/
20
+
21
+ # Logs and debug files
22
+ *.log
23
+ *.out
24
+ *.err
25
+
26
+ # IDE and editor settings
27
+ .vscode/
28
+ .idea/
29
+ *.swp
30
+ *.swo
31
+
32
+ # Docker
33
+ *.env
34
+ *.dockerignore
35
+ docker-compose.override.yml
36
+
37
+ # Python package files
38
+ *.egg
39
+ *.egg-info/
40
+ dist/
41
+ build/
42
+ *.wheel
43
+
44
+ # Cache files
45
+ *.cache
46
+ *.mypy_cache/
47
+ *.pytest_cache/
48
+ *.ipynb_checkpoints/
49
+
50
+ # System files
51
+ .DS_Store
52
+ Thumbs.db
Dockerfile ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ FROM python:3.9-slim
3
+
4
+ # Set the working directory
5
+ WORKDIR /app
6
+
7
+ # Define where the model will be stored in the image
8
+ ENV MODEL_DIR=/app/pretrain_model
9
+ ENV HF_HUB_DISABLE_SYMLINKS_WARNING=1
10
+
11
+ # Copy the requirements file
12
+ COPY requirements.txt .
13
+
14
+ # Install dependencies
15
+ RUN pip install --no-cache-dir -r requirements.txt
16
+
17
+ # Copy the download script into the image
18
+ COPY download_model.py /app/download_model.py
19
+
20
+ # Download the model using the script and the secret
21
+ RUN --mount=type=secret,id=huggingface_token \
22
+ echo "--- Docker RUN: Starting model download script /app/download_model.py..." && \
23
+ python /app/download_model.py && \
24
+ echo "--- Docker RUN: Model download script finished." && \
25
+ rm /app/download_model.py # Optional: clean up the script after use
26
+
27
+ # Copy the rest of your application code AFTER model download
28
+ COPY . .
29
+
30
+ # Expose the port the app runs on
31
+ EXPOSE 8000
32
+
33
+ # Run the application
34
+ CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
PROJECT_CONTEXT.md ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # GPT4All Service - Project Context
2
+
3
+ ## Project Overview
4
+ This is a **Polish Car Description Enhancement Service** built as a FastAPI microservice that uses a Hugging Face Large Language Model to generate enhanced marketing descriptions for cars in Polish language.
5
+
6
+ ## Core Functionality
7
+ The service takes basic car information (make, model, year, mileage, features, condition) and generates compelling, marketing-friendly descriptions in Polish using the `speakleash/Bielik-1.5B-v3.0-Instruct` model - a Polish language model from the Bielik series.
8
+
9
+ ## Project Structure
10
+
11
+ ```
12
+ gpt4all-service/
13
+ ├── app/
14
+ │ ├── main.py # FastAPI application with endpoints
15
+ │ ├── models/
16
+ │ │ └── huggingface_service.py # Core LLM service wrapper
17
+ │ └── schemas/
18
+ │ └── schemas.py # Pydantic data models
19
+ ├── Dockerfile # Multi-stage Docker build
20
+ ├── download_model.py # Model download script for Docker
21
+ ├── requirements.txt # Python dependencies
22
+ ├── start_container.ps1 # PowerShell startup script
23
+ ├── start_container.sh # Bash startup script
24
+ └── README.md # Comprehensive documentation
25
+ ```
26
+
27
+ ## Technical Architecture
28
+
29
+ ### 1. FastAPI Application (`app/main.py`)
30
+ - **Framework**: FastAPI with CORS middleware
31
+ - **Main Endpoint**: `POST /enhance-description` - takes car data, returns enhanced description
32
+ - **Health Check**: `GET /health` - service status and model initialization check
33
+ - **CORS**: Configured for frontend on `http://localhost:5173` (likely React/Vue dev server)
34
+
35
+ ### 2. LLM Service (`app/models/huggingface_service.py`)
36
+ - **Purpose**: Wrapper around Hugging Face Transformers pipeline
37
+ - **Model**: `speakleash/Bielik-1.5B-v3.0-Instruct` (Polish language model)
38
+ - **Features**:
39
+ - Async initialization and text generation
40
+ - Support for both GPU (CUDA) and CPU inference
41
+ - Chat template support for conversation-style prompts
42
+ - Configurable generation parameters (temperature, top_p, max_tokens)
43
+ - Smart response parsing to extract only the assistant's response
44
+
45
+ ### 3. Data Models (`app/schemas/schemas.py`)
46
+ - **CarData**: Input model with make, model, year, mileage, features[], condition
47
+ - **EnhancedDescriptionResponse**: Output model with generated description
48
+
49
+ ### 4. Containerization
50
+ - **Docker**: Self-contained image with pre-downloaded model (~3.2GB)
51
+ - **Security**: Uses Docker BuildKit secrets for Hugging Face token handling
52
+ - **Model Storage**: Downloaded to `/app/pretrain_model` during build
53
+ - **Runtime**: Python 3.9-slim base image
54
+
55
+ ## Key Technical Details
56
+
57
+ ### Model Configuration
58
+ - **Model Path**: `/app/pretrain_model` (in container) or configurable for local dev
59
+ - **Device**: Currently set to CPU in main.py, but service supports GPU
60
+ - **Generation Params**: 150 max tokens, temperature 0.75, top_p 0.9
61
+
62
+ ### Prompt Engineering
63
+ The service uses a carefully crafted Polish system prompt:
64
+ - Instructs the model to create marketing descriptions in Polish
65
+ - Limits output to 500 characters maximum
66
+ - Tells the model to ignore off-topic content
67
+ - Uses chat template format with system/user roles
68
+
69
+ ### Dependencies
70
+ - **fastapi**: Web framework
71
+ - **uvicorn[standard]**: ASGI server
72
+ - **transformers[torch]**: Hugging Face transformers with PyTorch
73
+ - **accelerate**: Hugging Face optimization library
74
+
75
+ ## Current State & Issues
76
+
77
+ ### Git Status
78
+ - Modified `app/main.py` (likely recent changes)
79
+ - Deleted `app/models/gpt4all.py` (indicates migration from GPT4All to Hugging Face)
80
+
81
+ ### Linter Issues in `huggingface_service.py`
82
+ 1. Import issues: `pipeline` and `AutoTokenizer` imports need specific paths
83
+ 2. Type annotations: `device: str = None` should be `Optional[str] = None`
84
+ 3. Method parameters: Similar optional parameter typing issues
85
+
86
+ ## Usage Scenarios
87
+ 1. **Car Dealership Websites**: Auto-generate compelling descriptions from basic car specs
88
+ 2. **Marketplace Applications**: Enhance user-provided car listings
89
+ 3. **Inventory Management**: Bulk description generation for car databases
90
+
91
+ ## Deployment Options
92
+ 1. **Local Development**: Direct Python/uvicorn execution
93
+ 2. **Docker Container**: Self-contained deployment with pre-downloaded model
94
+ 3. **Production**: Containerized deployment with proper authentication
95
+
96
+ ## Authentication Requirements
97
+ - Hugging Face Hub token required for model download (gated model)
98
+ - Token stored in `my_hf_token.txt` during Docker build
99
+ - Securely handled via Docker BuildKit secrets
100
+
101
+ ## Performance Considerations
102
+ - Model size: ~3.2GB (significant memory footprint)
103
+ - CPU inference: Slower but more accessible
104
+ - GPU inference: Faster but requires CUDA setup
105
+ - Async design: Non-blocking text generation
106
+
107
+ This service represents a specialized AI application for the Polish automotive market, focusing on generating marketing content using state-of-the-art Polish language models.
README.md CHANGED
@@ -1,12 +1,295 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
- title: Bielik App Service
3
- emoji: 🏃
4
- colorFrom: yellow
5
- colorTo: yellow
6
- sdk: docker
7
- pinned: false
8
- license: mit
9
- short_description: This is a description enhancer service running with bielik
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  ---
11
 
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## Contents
2
+
3
+ 1. [Features](#features)
4
+ 2. [Prerequisites](#prerequisites)
5
+ 3. [Project Structure](#project-structure)
6
+ 4. [Installation (Local Development)](#installation-local-development)
7
+ 5. [Usage (Local Development)](#usage-local-development)
8
+ 6. [Docker Usage](#docker-usage)
9
+ 7. [Quick Start with PowerShell (`start_container.ps1`)](#quick-start-with-powershell-start_containerps1)
10
+ 8. [API Endpoints](#api-endpoints)
11
+ - [Health Check](#health-check)
12
+ - [Enhance Description](#enhance-description)
13
+ 9. [Core Service (`app/models/huggingface_service.py`)](#core-service-appmodelshuggingface_servicepy)
14
+ 10. [Configuration](#configuration)
15
+ 11. [Schemas (`app/schemas/schemas.py`)](#schemas-appschemasschemaspy)
16
+ - [CarData](#cardata)
17
+ - [EnhancedDescriptionResponse](#enhanceddescriptionresponse)
18
+ 12. [Contributing](#contributing)
19
+ 13. [License](#license)
20
+
21
  ---
22
+
23
+ # LLM Car Description Enhancer (Polish)
24
+
25
+ This repository contains a FastAPI application that utilizes a Hugging Face Transformers Large Language Model (specifically, `speakleash/Bielik-1.5B-v3.0-Instruct` or a similar model from the Bielik series) to generate enhanced marketing descriptions for cars, primarily in Polish.
26
+
27
+ The application is designed to be run locally for development or containerized using Docker for deployment. The LLM is baked into the Docker image for self-contained and efficient execution, which may require Hugging Face Hub authentication during the build process if the model is gated.
28
+
29
+ ## Features
30
+
31
+ - Generate enhanced marketing descriptions for cars in Polish.
32
+ - Utilizes the `speakleash/Bielik-1.5B-v3.0-Instruct` model via the Hugging Face `transformers` library.
33
+ - Health check endpoint.
34
+ - Docker support for easy deployment, with the model included in the image.
35
+ - Includes a `start_container.sh` script for convenient container startup.
36
+
37
+ ## Prerequisites
38
+
39
+ - Python 3.9 or higher
40
+ - `pip` (Python package installer)
41
+ - Docker (for containerized deployment, Docker BuildKit enabled recommended for secrets)
42
+ - Git (for cloning the repository)
43
+ - A Hugging Face Hub account and an access token (with `read` permissions) if the chosen model is gated (see Docker Usage section).
44
+ - For using `start_container.sh`: A bash-compatible shell (like those on Linux, macOS, or Git Bash on Windows).
45
+
46
+ ## Project Structure
47
+
48
+ A typical layout for this project would be:
49
+
50
+ ```text
51
+ .
52
+ ├── app/
53
+ │ ├── __init__.py
54
+ │ ├── main.py # FastAPI application, endpoints
55
+ │ ├── models/
56
+ │ │ ├── __init__.py
57
+ │ │ └── huggingface_service.py # Service for interacting with the LLM
58
+ │ └── schemas/
59
+ │ ├── __init__.py
60
+ │ └── schemas.py # Pydantic schemas for request/response
61
+ ├── .gitignore
62
+ ├── Dockerfile
63
+ ├── download_model.py # Script to download model during Docker build
64
+ ├── my_hf_token.txt # (Should be created locally) For storing HF token
65
+ ├── requirements.txt
66
+ ├── start_container.sh # Helper script to run the Docker container
67
+ └── README.md
68
+
69
+ ```
70
+
71
+ ## Installation (Local Development)
72
+
73
+ 1. **Clone the repository:**
74
+ ```bash
75
+ git clone [https://github.com/studzin-sky/llm-description-enhancer.git](https://github.com/studzin-sky/llm-description-enhancer.git)
76
+ cd llm-description-enhancer
77
+ ```
78
+
79
+ 2. **Create and activate a virtual environment:**
80
+ (Recommended to keep dependencies isolated)
81
+ ```bash
82
+ python -m venv venv
83
+ ```
84
+ * On macOS/Linux:
85
+ ```bash
86
+ source venv/bin/activate
87
+ ```
88
+ * On Windows (PowerShell):
89
+ ```bash
90
+ .\venv\Scripts\Activate.ps1
91
+ ```
92
+ * On Windows (Command Prompt):
93
+ ```bash
94
+ venv\Scripts\activate.bat
95
+ ```
96
+
97
+ 3. **Install the required dependencies:**
98
+ Ensure your `requirements.txt` includes `fastapi`, `uvicorn[standard]`, `transformers[torch]`, `torch`, `accelerate`, and `huggingface_hub`.
99
+ ```bash
100
+ pip install -r requirements.txt
101
+ ```
102
+ *Note: The first time you run the application locally (or if the model cache is empty), the Hugging Face model (~3.2GB) will be downloaded. This might take some time. **If the model (`speakleash/Bielik-1.5B-v3.0-Instruct` or the one configured) is gated or requires authentication, you may need to log in using `huggingface-cli login` in your terminal before running the application locally.** After logging in, your token will be cached by the `huggingface_hub` library.*
103
+
104
+ ## Usage (Local Development)
105
+
106
+ 1. **Start the FastAPI server:**
107
+ From the project root directory:
108
+ ```bash
109
+ uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
110
+ ```
111
+ * `--reload` enables auto-reloading for development.
112
+ * `--host 0.0.0.0` makes the server accessible on your network.
113
+
114
+ 2. **Access the application:**
115
+ * Health Check: [http://127.0.0.1:8000/health](http://127.0.0.1:8000/health)
116
+ * API Documentation (Swagger UI): [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)
117
+ * Enhance Description: `POST` requests to [http://127.0.0.1:8000/enhance-description](http://127.0.0.1:8000/enhance-description)
118
+
119
+ ## Docker Usage
120
+
121
+ The included `Dockerfile` builds an image with the application and the pre-downloaded Hugging Face model, making it self-contained. Downloading gated models during the build process requires a Hugging Face Hub token.
122
+
123
+ 1. **Prepare Hugging Face Hub Token (for Gated Models):**
124
+ The `speakleash/Bielik-1.5B-v3.0-Instruct` model may require authentication to download.
125
+ * **Get a Token:**
126
+ 1. Go to your Hugging Face account settings: [https://huggingface.co/settings/tokens](https://huggingface.co/settings/tokens)
127
+ 2. Create a new token (e.g., named "docker-bielik-access") with `read` permissions.
128
+ 3. Copy the generated token (it will start with `hf_`).
129
+ * **Create Token File:**
130
+ 1. In your project's root directory (next to your `Dockerfile`), create a file named `my_hf_token.txt`.
131
+ 2. Paste **only the token string** (e.g., `hf_YourActualTokenValueHere`) into this file. Do not add any other text or variable names.
132
+
133
+ 2. **Build the Docker image:**
134
+ From the project root directory, run:
135
+ ```bash
136
+ DOCKER_BUILDKIT=1 docker build --secret id=huggingface_token,src=my_hf_token.txt -t llm-description-enhancer .
137
+ ```
138
+ * `DOCKER_BUILDKIT=1`: Enables BuildKit, which is required for using `--secret`.
139
+ * `--secret id=huggingface_token,src=my_hf_token.txt`: Securely provides the content of `my_hf_token.txt` to the build process. The `id=huggingface_token` must match the ID used in the `RUN --mount` directive in your `Dockerfile`.
140
+ * *(This step will take a while, especially the first time, as it downloads the LLM using your token).*
141
+
142
+ 3. **Run the Docker container using the Helper Script (`start_container.sh`):**
143
+ A helper script `start_container.sh` is included in the repository to simplify starting the Docker container. This script typically handles stopping/removing any pre-existing container with the same configured name and then starts a new one.
144
+
145
+ * **Ensure the script is executable:**
146
+ After cloning the repository, or if the execute permission isn't set, you might need to make the script executable (on Linux, macOS, or Git Bash on Windows):
147
+ ```bash
148
+ chmod +x start_container.sh
149
+ ```
150
+
151
+ * **Run the script:**
152
+ From the project root directory:
153
+ ```bash
154
+ ./start_container.sh
155
+ ```
156
+
157
+ * **Expected Outcome (depends on your script's content):**
158
+ The script will likely:
159
+ * Output messages indicating it's managing the container.
160
+ * Start the container (possibly in detached mode).
161
+ * Inform you that the service is available at `http://127.0.0.1:8000`.
162
+ * Provide commands to view logs or stop the container if it's running in detached mode (e.g., `docker logs <container_name> -f` and `docker stop <container_name>`).
163
+
164
+ *(Alternatively, you can run the container manually: `docker run --rm -p 8000:8000 llm-description-enhancer`)*
165
+
166
+ 4. **Test the containerized application:**
167
+ Once the container is running (via the script or manually), send requests to `http://127.0.0.1:8000` as described in the API Endpoints section.
168
+
169
+ ## Quick Start with PowerShell (`start_container.ps1`)
170
+
171
+ For Windows users, you can automate the Docker build and run process using the provided PowerShell script. This script will:
172
+ - Build the Docker image using your Hugging Face token (from `my_hf_token.txt`)
173
+ - Stop and remove any existing container named `bielik_app_instance`
174
+ - Start a new container and map port 8000
175
+
176
+ **Steps:**
177
+
178
+ 1. Ensure your Hugging Face token is saved in `my_hf_token.txt` in the project root (see above for details).
179
+ 2. Open PowerShell in the project directory.
180
+ 3. (Optional, but recommended) Temporarily allow running unsigned scripts for this session:
181
+ ```powershell
182
+ Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process
183
+ ```
184
+ 4. Run the script:
185
+ ```powershell
186
+ .\start_container.ps1
187
+ ```
188
+
189
+ The script will build the image and start the container. Your FastAPI service will be available at [http://127.0.0.1:8000](http://127.0.0.1:8000).
190
+
191
+ You can view logs with:
192
+ ```powershell
193
+ docker logs bielik_app_instance -f
194
+ ```
195
+ To stop the container:
196
+ ```powershell
197
+ docker stop bielik_app_instance
198
+ ```
199
+
200
+ If you encounter a security error about script signing, see the [Microsoft documentation on execution policies](https://go.microsoft.com/fwlink/?LinkID=135170).
201
+
202
  ---
203
 
204
+ ## API Endpoints
205
+
206
+ ### Health Check
207
+
208
+ - **Endpoint:** `/health`
209
+ - **Method:** `GET`
210
+ - **Description:** Returns the status of the application and model initialization.
211
+ - **Example Response:**
212
+ ```json
213
+ {
214
+ "status": "ok",
215
+ "model_initialized": true,
216
+ "model_path": "/app/pretrain_model"
217
+ }
218
+ ```
219
+
220
+ ### Enhance Description
221
+
222
+ - **Endpoint:** `/enhance-description`
223
+ - **Method:** `POST`
224
+ - **Description:** Generates an enhanced marketing description for a car in Polish.
225
+ - **Request Body (`application/json`):**
226
+ ```json
227
+ {
228
+ "make": "Volkswagen",
229
+ "model": "Golf",
230
+ "year": 2022,
231
+ "mileage": 15000,
232
+ "features": ["Klimatyzacja automatyczna", "System nawigacji", "Czujniki parkowania"],
233
+ "condition": "Bardzo dobry"
234
+ }
235
+ ```
236
+ - **Response (`application/json`):**
237
+ ```json
238
+ {
239
+ "description": "Wygenerowany przez AI opis samochodu..."
240
+ }
241
+ ```
242
+ - **Example cURL request (for Git Bash / bash-like shells):**
243
+ ```bash
244
+ curl -X POST "http://127.0.0.1:8000/enhance-description" \
245
+ -H "Content-Type: application/json" \
246
+ -d '{
247
+ "make": "Toyota",
248
+ "model": "Corolla",
249
+ "year": 2021,
250
+ "mileage": 25000,
251
+ "features": ["Kamera cofania", "Apple CarPlay", "Android Auto", "System bezkluczykowy"],
252
+ "condition": "Bardzo dobry"
253
+ }'
254
+ ```
255
+
256
+ ## Core Service (`app/models/huggingface_service.py`)
257
+
258
+ The `HuggingFaceTextGenerationService` class handles the interaction with the Large Language Model.
259
+
260
+ - **Key Methods:**
261
+ - `async initialize()`: Loads the pre-trained model and tokenizer from the path specified during service instantiation (e.g., `/app/pretrain_model` in Docker, or from Hugging Face cache locally).
262
+ - `async generate_text(chat_template_messages: list, max_new_tokens: int, ...)`: Generates text based on a structured chat prompt, applying appropriate chat templates and parsing the model's output to return only the assistant's response.
263
+
264
+ ## Configuration
265
+
266
+ - **Model Used:** `speakleash/Bielik-1.5B-v3.0-Instruct`. This is baked into `/app/pretrain_model` in the Docker image. For local development, it's downloaded to the Hugging Face cache.
267
+ - **Language:** The primary focus is on generating descriptions in **Polish**.
268
+ - **Prompt Engineering:** The system and user prompts in `app/main.py` are crafted to guide the model towards generating concise and relevant marketing descriptions.
269
+
270
+ ## Schemas (`app/schemas/schemas.py`)
271
+
272
+ Pydantic models are used for request and response validation.
273
+
274
+ ### `CarData`
275
+
276
+ - **Fields:**
277
+ - `make`: `str`
278
+ - `model`: `str`
279
+ - `year`: `int`
280
+ - `mileage`: `int`
281
+ - `features`: `list[str]`
282
+ - `condition`: `str`
283
+
284
+ ### `EnhancedDescriptionResponse`
285
+
286
+ - **Fields:**
287
+ - `description`: `str`
288
+
289
+ ## Contributing
290
+
291
+ Contributions are welcome! Please open an issue or submit a pull request for any changes.
292
+
293
+ ## License
294
+
295
+ This project is licensed under the MIT License.
answer.md ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Great choice! Creating a separate service for GPT4All is a clean and scalable approach. Let’s break this down step by step, starting from setting up the project structure to deploying the service.
2
+
3
+ ---
4
+
5
+ ### **1. Project Structure**
6
+ Here’s a suggested folder structure for your GPT4All service:
7
+
8
+ ```
9
+ gpt4all-service/
10
+ ├── app/
11
+ │ ├── __init__.py
12
+ │ ├── main.py # FastAPI/Flask app entry point
13
+ │ ├── models/ # GPT4All model loading and inference logic
14
+ │ │ └── gpt4all.py
15
+ │ └── schemas/ # Pydantic models for request/response validation
16
+ │ └── schemas.py
17
+ ├── tests/ # Unit and integration tests
18
+ │ └── test_api.py
19
+ ├── requirements.txt # Python dependencies
20
+ ├── Dockerfile # For containerization
21
+ ├── README.md # Project documentation
22
+ └── .env # Environment variables (optional)
23
+ ```
24
+
25
+ ---
26
+
27
+ ### **2. Setting Up the Project**
28
+ 1. **Create the Project Folder**:
29
+ ```bash
30
+ mkdir gpt4all-service
31
+ cd gpt4all-service
32
+ ```
33
+
34
+ 2. **Initialize a Virtual Environment**:
35
+ ```bash
36
+ python -m venv venv
37
+ source venv/bin/activate # On Windows: venv\Scripts\activate
38
+ ```
39
+
40
+ 3. **Install Dependencies**:
41
+ Create a `requirements.txt` file:
42
+ ```plaintext
43
+ fastapi
44
+ uvicorn
45
+ gpt4all
46
+ pydantic
47
+ python-dotenv
48
+ ```
49
+
50
+ Install the dependencies:
51
+ ```bash
52
+ pip install -r requirements.txt
53
+ ```
54
+
55
+ ---
56
+
57
+ ### **3. Build the GPT4All Service**
58
+ #### **Step 1: Create the Model Loading Logic**
59
+ - Create `app/models/gpt4all.py`:
60
+ ```python
61
+ from gpt4all import GPT4All
62
+
63
+ class GPT4AllService:
64
+ def __init__(self, model_path: str):
65
+ self.model = GPT4All(model_path)
66
+
67
+ def generate_description(self, prompt: str) -> str:
68
+ response = self.model.generate(prompt, max_tokens=300)
69
+ return response
70
+ ```
71
+
72
+ #### **Step 2: Define Request/Response Schemas**
73
+ - Create `app/schemas/schemas.py`:
74
+ ```python
75
+ from pydantic import BaseModel
76
+
77
+ class CarData(BaseModel):
78
+ make: str
79
+ model: str
80
+ year: int
81
+ mileage: int
82
+ features: list[str]
83
+ condition: str
84
+
85
+ class EnhancedDescriptionResponse(BaseModel):
86
+ description: str
87
+ ```
88
+
89
+ #### **Step 3: Create the FastAPI App**
90
+ - Create `app/main.py`:
91
+ ```python
92
+ from fastapi import FastAPI, HTTPException
93
+ from app.models.gpt4all import GPT4AllService
94
+ from app.schemas.schemas import CarData, EnhancedDescriptionResponse
95
+
96
+ app = FastAPI()
97
+
98
+ # Initialize GPT4All service
99
+ gpt4all_service = GPT4AllService("ggml-model-gpt4all-falcon-q4_0.bin")
100
+
101
+ @app.post("/enhance-description", response_model=EnhancedDescriptionResponse)
102
+ async def enhance_description(car_data: CarData):
103
+ try:
104
+ # Create a prompt from car data
105
+ prompt = f"""
106
+ Enhance this car description for an auction portal:
107
+ - Make: {car_data.make}
108
+ - Model: {car_data.model}
109
+ - Year: {car_data.year}
110
+ - Mileage: {car_data.mileage}
111
+ - Features: {', '.join(car_data.features)}
112
+ - Condition: {car_data.condition}
113
+ """
114
+ # Generate description
115
+ description = gpt4all_service.generate_description(prompt)
116
+ return {"description": description}
117
+ except Exception as e:
118
+ raise HTTPException(status_code=500, detail=str(e))
119
+ ```
120
+
121
+ ---
122
+
123
+ ### **4. Run the Service**
124
+ 1. **Start the Service**:
125
+ ```bash
126
+ uvicorn app.main:app --reload --port 8000
127
+ ```
128
+
129
+ 2. **Test the API**:
130
+ Use `curl` or Postman to send a POST request:
131
+ ```bash
132
+ curl -X POST "http://localhost:8000/enhance-description" \
133
+ -H "Content-Type: application/json" \
134
+ -d '{
135
+ "make": "Toyota",
136
+ "model": "Camry",
137
+ "year": 2020,
138
+ "mileage": 45000,
139
+ "features": ["sunroof", "leather seats", "lane assist"],
140
+ "condition": "excellent"
141
+ }'
142
+ ```
143
+
144
+ **Expected Response**:
145
+ ```json
146
+ {
147
+ "description": "This 2020 Toyota Camry is a well-maintained vehicle with only 45,000 miles on the odometer. It comes equipped with a sunroof, luxurious leather seats, and advanced lane assist technology. Perfect for families or commuters, this car is in excellent condition and ready to hit the road. Don’t miss out on this fantastic deal!"
148
+ }
149
+ ```
150
+
151
+ ---
152
+
153
+ ### **5. Add Logging and Error Handling**
154
+ - Add logging to track requests and errors:
155
+ ```python
156
+ import logging
157
+
158
+ logging.basicConfig(level=logging.INFO)
159
+ logger = logging.getLogger(__name__)
160
+
161
+ @app.post("/enhance-description", response_model=EnhancedDescriptionResponse)
162
+ async def enhance_description(car_data: CarData):
163
+ try:
164
+ logger.info(f"Received request for car: {car_data.make} {car_data.model}")
165
+ prompt = f"Enhance this car description: {car_data}"
166
+ description = gpt4all_service.generate_description(prompt)
167
+ return {"description": description}
168
+ except Exception as e:
169
+ logger.error(f"Error generating description: {e}")
170
+ raise HTTPException(status_code=500, detail=str(e))
171
+ ```
172
+
173
+ ---
174
+
175
+ ### **6. Containerize the Service (Optional)**
176
+ Create a `Dockerfile` to containerize the service:
177
+ ```dockerfile
178
+ # Use an official Python runtime as a parent image
179
+ FROM python:3.9-slim
180
+
181
+ # Set the working directory
182
+ WORKDIR /app
183
+
184
+ # Copy the requirements file
185
+ COPY requirements.txt .
186
+
187
+ # Install dependencies
188
+ RUN pip install --no-cache-dir -r requirements.txt
189
+
190
+ # Copy the application code
191
+ COPY . .
192
+
193
+ # Expose the port the app runs on
194
+ EXPOSE 8000
195
+
196
+ # Run the application
197
+ CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
198
+ ```
199
+
200
+ Build and run the Docker container:
201
+ ```bash
202
+ docker build -t gpt4all-service .
203
+ docker run -p 8000:8000 gpt4all-service
204
+ ```
205
+
206
+ ---
207
+
208
+ ### **7. Next Steps**
209
+ - Add unit tests in the `tests/` folder.
210
+ - Add environment variables for configuration (e.g., model path, port).
211
+ - Integrate with your Flask backend by calling this service via HTTP.
212
+
213
+ Let me know if you need help with any specific part (e.g., testing, deployment, or advanced features)!
app/main.py ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, HTTPException
2
+ from app.models.huggingface_service import HuggingFaceTextGenerationService
3
+ from fastapi.middleware.cors import CORSMiddleware
4
+ from app.schemas.schemas import CarData, EnhancedDescriptionResponse
5
+
6
+ app = FastAPI()
7
+
8
+ app.add_middleware(
9
+ CORSMiddleware,
10
+ allow_origins=["http://localhost:5173"],
11
+ allow_credentials=True,
12
+ allow_methods=["*"],
13
+ allow_headers=["*"],
14
+ )
15
+
16
+ MODEL_PATH_IN_CONTAINER = "/app/pretrain_model"
17
+ hf_service = HuggingFaceTextGenerationService(
18
+ model_name_or_path=MODEL_PATH_IN_CONTAINER,
19
+ device="cpu"
20
+ )
21
+
22
+
23
+ @app.on_event("startup")
24
+ async def startup_event():
25
+ print("Starting up and initializing HuggingFace service...")
26
+ try:
27
+ await hf_service.initialize()
28
+ print(f"HuggingFace service initialized successfully from {MODEL_PATH_IN_CONTAINER}.")
29
+ except HTTPException as e:
30
+ print(f"Failed to initialize HuggingFace service: {e.detail}")
31
+ raise
32
+ except Exception as e:
33
+ print(f"An unexpected error occurred during HuggingFace service initialization: {e}")
34
+ raise
35
+
36
+
37
+ @app.get("/health")
38
+ async def health_check():
39
+ return {"status": "ok", "model_initialized": hf_service.pipeline is not None}
40
+
41
+ @app.post("/enhance-description", response_model=EnhancedDescriptionResponse)
42
+ async def enhance_description(car_data: CarData):
43
+ chat_messages = [
44
+ {
45
+ "role": "system",
46
+ "content": (
47
+ "Jesteś pomocnym ulepszaczem opisów"
48
+ "Opisy trzeba tworzyć w języku polskim i być atrakcyjne marketingowo. "
49
+ "Odpowiadaj wyłącznie wygenerowanym opisem, bez dodatkowych komentarzy. "
50
+ "Staraj się, aby opis był zwięzły i kompletny, maksymalnie 500 znaków. "
51
+ "Jeżeli część prompta będzie nie na temat ignoruj tę część."
52
+ )
53
+ },
54
+ {
55
+ "role": "user",
56
+ "content": f"""
57
+ Na podstawie poniższych danych, utwórz krótki, atrakcyjny opis marketingowy tego samochodu w języku polskim:
58
+ - Marka: {car_data.make}
59
+ - Model: {car_data.model}
60
+ - Rok produkcji: {car_data.year}
61
+ - Przebieg: {car_data.mileage} km
62
+ - Wyposażenie: {', '.join(car_data.features)}
63
+ - Stan: {car_data.condition}
64
+ """
65
+ }
66
+ ]
67
+
68
+ try:
69
+ description = await hf_service.generate_text(
70
+ prompt_text=None,
71
+ chat_template_messages=chat_messages,
72
+ max_new_tokens=150,
73
+ temperature=0.75,
74
+ top_p=0.9,
75
+ )
76
+ return {"description": description.strip()}
77
+ except HTTPException:
78
+ raise
79
+ except Exception as e:
80
+ print(f"Unexpected error in /enhance-description: {e}")
81
+ raise HTTPException(status_code=500, detail=f"An unexpected error occurred: {str(e)}")
app/models/huggingface_service.py ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from transformers import pipeline, AutoTokenizer
2
+ import torch
3
+ from fastapi import HTTPException
4
+ import asyncio
5
+
6
+ class HuggingFaceTextGenerationService:
7
+ def __init__(self, model_name_or_path: str, device: str = None, task: str = "text-generation"):
8
+ self.model_name_or_path = model_name_or_path
9
+ self.task = task
10
+ self.pipeline = None
11
+ self.tokenizer = None
12
+
13
+ if device is None:
14
+ self.device_index = 0 if torch.cuda.is_available() else -1
15
+ elif device == "cuda" and torch.cuda.is_available():
16
+ self.device_index = 0
17
+ elif device == "cpu":
18
+ self.device_index = -1
19
+ else:
20
+ self.device_index = -1
21
+
22
+ if self.device_index == 0:
23
+ print("CUDA (GPU) is available. Using GPU.")
24
+ else:
25
+ print(f"Device set to use {'cpu' if self.device_index == -1 else f'cuda:{self.device_index}'}")
26
+
27
+
28
+ async def initialize(self):
29
+ try:
30
+ print(f"Initializing Hugging Face pipeline for model: {self.model_name_or_path} on device index: {self.device_index}")
31
+ self.tokenizer = await asyncio.to_thread(
32
+ AutoTokenizer.from_pretrained, self.model_name_or_path, trust_remote_code=True
33
+ )
34
+ self.pipeline = await asyncio.to_thread(
35
+ pipeline,
36
+ self.task,
37
+ model=self.model_name_or_path,
38
+ tokenizer=self.tokenizer,
39
+ device=self.device_index,
40
+ torch_dtype=torch.bfloat16 if self.device_index != -1 and torch.cuda.is_available() and torch.cuda.is_bf16_supported() else torch.float32,
41
+ trust_remote_code=True,
42
+ )
43
+ print(f"Pipeline for model {self.model_name_or_path} initialized successfully.")
44
+ except Exception as e:
45
+ print(f"Error initializing HuggingFace pipeline: {e}")
46
+ raise HTTPException(status_code=503, detail=f"LLM (HuggingFace) model could not be loaded: {str(e)}")
47
+
48
+ async def generate_text(self, prompt_text: str = None, chat_template_messages: list = None, max_new_tokens: int = 250, temperature: float = 0.7, top_p: float = 0.9, do_sample: bool = True, **kwargs) -> str:
49
+ if not self.pipeline or not self.tokenizer:
50
+ raise Exception("Pipeline is not initialized. Call initialize() first.")
51
+
52
+ formatted_prompt_input = ""
53
+ if chat_template_messages:
54
+ try:
55
+ formatted_prompt_input = self.tokenizer.apply_chat_template(
56
+ chat_template_messages,
57
+ tokenize=False,
58
+ add_generation_prompt=True
59
+ )
60
+ except Exception as e:
61
+ print(f"Could not apply chat template, falling back to raw prompt if available. Error: {e}")
62
+ if prompt_text:
63
+ formatted_prompt_input = prompt_text
64
+ else:
65
+ raise ValueError("Cannot generate text without a valid prompt or chat_template_messages.")
66
+ elif prompt_text:
67
+ formatted_prompt_input = prompt_text
68
+ else:
69
+ raise ValueError("Either prompt_text or chat_template_messages must be provided.")
70
+
71
+ try:
72
+ generated_outputs = await asyncio.to_thread(
73
+ self.pipeline,
74
+ formatted_prompt_input,
75
+ max_new_tokens=max_new_tokens,
76
+ do_sample=do_sample,
77
+ temperature=temperature,
78
+ top_p=top_p,
79
+ eos_token_id=self.tokenizer.eos_token_id,
80
+ pad_token_id=self.tokenizer.eos_token_id if self.tokenizer.pad_token_id is None else self.tokenizer.pad_token_id, # Common setting
81
+ **kwargs
82
+ )
83
+
84
+ if generated_outputs and isinstance(generated_outputs, list) and "generated_text" in generated_outputs[0]:
85
+ full_generated_sequence = generated_outputs[0]["generated_text"]
86
+
87
+ assistant_response = ""
88
+ if full_generated_sequence.startswith(formatted_prompt_input):
89
+ assistant_response = full_generated_sequence[len(formatted_prompt_input):]
90
+ else:
91
+ assistant_marker = "<|im_start|>assistant\n"
92
+ last_marker_pos = full_generated_sequence.rfind(assistant_marker)
93
+ if last_marker_pos != -1:
94
+ assistant_response = full_generated_sequence[last_marker_pos + len(assistant_marker):]
95
+ print("Warning: Used fallback parsing for assistant response.")
96
+ else:
97
+ print("Error: Could not isolate assistant response from the full generated sequence.")
98
+ assistant_response = full_generated_sequence
99
+
100
+ if assistant_response.endswith("<|im_end|>"):
101
+ assistant_response = assistant_response[:-len("<|im_end|>")]
102
+
103
+ return assistant_response.strip()
104
+ else:
105
+ print(f"Unexpected output format from pipeline: {generated_outputs}")
106
+ return "Error: Could not parse generated text from pipeline output."
107
+
108
+ except Exception as e:
109
+ print(f"Error during text generation with {self.model_name_or_path}: {e}")
110
+ raise HTTPException(status_code=500, detail=f"Error generating text: {str(e)}")
111
+
app/schemas/schemas.py ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic import BaseModel
2
+
3
+ class CarData(BaseModel):
4
+ make: str
5
+ model: str
6
+ year: int
7
+ mileage: int
8
+ features: list[str]
9
+ condition: str
10
+
11
+ class EnhancedDescriptionResponse(BaseModel):
12
+ description: str
download_model.py ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # This script is intended to be run in a Docker container with the Hugging Face token mounted as a secret.
2
+ from huggingface_hub import snapshot_download
3
+ from huggingface_hub.errors import HfHubHTTPError
4
+ import os
5
+ import sys
6
+ import traceback
7
+
8
+ def main():
9
+ token_path = '/run/secrets/huggingface_token'
10
+ model_dir_path = os.environ.get('MODEL_DIR')
11
+ repo_id_to_download = 'speakleash/Bielik-1.5B-v3.0-Instruct'
12
+
13
+ print(f'--- Python SCRIPT DEBUG: Target model directory: {model_dir_path}')
14
+ if not model_dir_path:
15
+ print('--- Python SCRIPT CRITICAL ERROR: MODEL_DIR environment variable not set!')
16
+ sys.exit(1)
17
+
18
+ token_value = None
19
+ try:
20
+ with open(token_path, 'r') as f:
21
+ token_value = f.read().strip()
22
+ print(f'--- Python SCRIPT DEBUG: Token file {token_path} read successfully.')
23
+ if token_value:
24
+ masked_token = f"{token_value[:4]}****{token_value[-4:] if len(token_value) > 4 else '(token too short)'}"
25
+ print(f'--- Python SCRIPT DEBUG: Token content (masked): {masked_token}')
26
+ if not token_value.startswith('hf_'):
27
+ print('--- Python SCRIPT WARNING: Token does not appear to start with hf_! Check token file content.')
28
+ else:
29
+ print('--- Python SCRIPT CRITICAL ERROR: Token file was empty or only whitespace!')
30
+ sys.exit(1)
31
+ except FileNotFoundError:
32
+ print(f'--- Python SCRIPT CRITICAL ERROR: Token secret file {token_path} not found! Ensure --mount is correct.')
33
+ sys.exit(1)
34
+ except Exception as e:
35
+ print(f'--- Python SCRIPT CRITICAL ERROR: Could not read token from {token_path}: {e}')
36
+ traceback.print_exc()
37
+ sys.exit(1)
38
+
39
+ try:
40
+ print(f'--- Python SCRIPT INFO: Calling snapshot_download for {repo_id_to_download}...')
41
+ snapshot_download(
42
+ repo_id=repo_id_to_download,
43
+ local_dir=model_dir_path,
44
+ token=token_value,
45
+ local_dir_use_symlinks=False,
46
+ resume_download=True
47
+ # Removed ignore_patterns for now to ensure no interference
48
+ )
49
+ print(f'--- Python SCRIPT INFO: snapshot_download completed for {repo_id_to_download}.')
50
+ except HfHubHTTPError as http_e:
51
+ print(f'--- Python SCRIPT ERROR: HfHubHTTPError during snapshot_download: {http_e}')
52
+ if http_e.response is not None:
53
+ print(f'--- Python SCRIPT ERROR: Response status: {http_e.response.status_code}')
54
+ print(f'--- Python SCRIPT ERROR: Response headers: {http_e.response.headers}')
55
+ try:
56
+ response_content = http_e.response.content.decode()
57
+ except UnicodeDecodeError:
58
+ response_content = str(http_e.response.content)
59
+ print(f'--- Python SCRIPT ERROR: Response content: {response_content}')
60
+ if http_e.request_id:
61
+ print(f'--- Python SCRIPT ERROR: Request ID: {http_e.request_id}')
62
+ sys.exit(1)
63
+ except Exception as e:
64
+ print(f'--- Python SCRIPT ERROR: Other Exception during snapshot_download: {e}')
65
+ traceback.print_exc()
66
+ sys.exit(1)
67
+
68
+ if __name__ == "__main__":
69
+ main()
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ fastapi
2
+ uvicorn[standard]
3
+ transformers[torch]
4
+ accelerate
start_container.ps1 ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # PowerShell script to build and run the Docker container for your FastAPI service
2
+
3
+ # Set variables
4
+ $imageName = "bielik-fastapi-service"
5
+ $containerName = "bielik_app_instance"
6
+ $tokenFile = "my_hf_token.txt"
7
+
8
+ Write-Host "Building Docker image..."
9
+ docker build --secret id=huggingface_token,src=$tokenFile -t $imageName .
10
+
11
+ Write-Host "Stopping and removing any existing container named $containerName..."
12
+ docker stop $containerName | Out-Null 2>&1
13
+
14
+ docker rm $containerName | Out-Null 2>&1
15
+
16
+ Write-Host "Running new container..."
17
+ docker run -d --name $containerName -p 8000:8000 $imageName
18
+
19
+ Write-Host ""
20
+ Write-Host "$containerName should be starting up."
21
+ Write-Host "You can view logs with: docker logs $containerName -f"
22
+ Write-Host "To stop the container, run: docker stop $containerName"
23
+ Write-Host "The service will be available at http://127.0.0.1:8000"
start_container.sh ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ IMAGE_NAME="bielik-fastapi-service"
4
+ CONTAINER_NAME="bielik_app_instance"
5
+ TOKEN_FILE="my_hf_token.txt"
6
+
7
+ # Build the Docker image with Hugging Face token as a secret
8
+ echo "Building Docker image..."
9
+ DOCKER_BUILDKIT=1 docker build --secret id=huggingface_token,src=$TOKEN_FILE -t $IMAGE_NAME .
10
+
11
+ echo "Attempting to stop and remove existing container named $CONTAINER_NAME (if any)..."
12
+ docker stop $CONTAINER_NAME > /dev/null 2>&1 || true # Stop if running, ignore error if not
13
+ docker rm $CONTAINER_NAME > /dev/null 2>&1 || true # Remove if exists, ignore error if not
14
+
15
+ echo "Starting new $IMAGE_NAME container as $CONTAINER_NAME..."
16
+ docker run -d --name $CONTAINER_NAME -p 8000:8000 $IMAGE_NAME
17
+ # -d : Runs the container in detached mode (in the background)
18
+ # --name : Assigns a specific name to your running container instance
19
+ # -p 8000:8000 : Maps port 8000 on your host to port 8000 in the container
20
+
21
+ echo ""
22
+ echo "$CONTAINER_NAME should be starting up."
23
+ echo "You can view logs with: docker logs $CONTAINER_NAME -f"
24
+ echo "To stop the container, run: docker stop $CONTAINER_NAME"
25
+ echo "The service will be available at http://127.0.0.1:8000"