mishrabp commited on
Commit
1c1c554
·
verified ·
1 Parent(s): aa73888

Upload folder using huggingface_hub

Browse files
Files changed (9) hide show
  1. .gitignore +208 -0
  2. Dockerfile +37 -0
  3. LICENSE +21 -0
  4. README.md +146 -4
  5. deploy.yml +43 -0
  6. deploy_microk8s.sh +31 -0
  7. testapp/README.md +11 -0
  8. testapp/client.py +61 -0
  9. testapp/requirements.txt +1 -0
.gitignore ADDED
@@ -0,0 +1,208 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[codz]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ *.tar
28
+ MANIFEST
29
+
30
+ # PyInstaller
31
+ # Usually these files are written by a python script from a template
32
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
33
+ *.manifest
34
+ *.spec
35
+
36
+ # Installer logs
37
+ pip-log.txt
38
+ pip-delete-this-directory.txt
39
+
40
+ # Unit test / coverage reports
41
+ htmlcov/
42
+ .tox/
43
+ .nox/
44
+ .coverage
45
+ .coverage.*
46
+ .cache
47
+ nosetests.xml
48
+ coverage.xml
49
+ *.cover
50
+ *.py.cover
51
+ .hypothesis/
52
+ .pytest_cache/
53
+ cover/
54
+
55
+ # Translations
56
+ *.mo
57
+ *.pot
58
+
59
+ # Django stuff:
60
+ *.log
61
+ local_settings.py
62
+ db.sqlite3
63
+ db.sqlite3-journal
64
+
65
+ # Flask stuff:
66
+ instance/
67
+ .webassets-cache
68
+
69
+ # Scrapy stuff:
70
+ .scrapy
71
+
72
+ # Sphinx documentation
73
+ docs/_build/
74
+
75
+ # PyBuilder
76
+ .pybuilder/
77
+ target/
78
+
79
+ # Jupyter Notebook
80
+ .ipynb_checkpoints
81
+
82
+ # IPython
83
+ profile_default/
84
+ ipython_config.py
85
+
86
+ # pyenv
87
+ # For a library or package, you might want to ignore these files since the code is
88
+ # intended to run in multiple environments; otherwise, check them in:
89
+ # .python-version
90
+
91
+ # pipenv
92
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
93
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
94
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
95
+ # install all needed dependencies.
96
+ #Pipfile.lock
97
+
98
+ # UV
99
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
100
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
101
+ # commonly ignored for libraries.
102
+ #uv.lock
103
+
104
+ # poetry
105
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
106
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
107
+ # commonly ignored for libraries.
108
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
109
+ #poetry.lock
110
+ #poetry.toml
111
+
112
+ # pdm
113
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
114
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
115
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
116
+ #pdm.lock
117
+ #pdm.toml
118
+ .pdm-python
119
+ .pdm-build/
120
+
121
+ # pixi
122
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
123
+ #pixi.lock
124
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
125
+ # in the .venv directory. It is recommended not to include this directory in version control.
126
+ .pixi
127
+
128
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
129
+ __pypackages__/
130
+
131
+ # Celery stuff
132
+ celerybeat-schedule
133
+ celerybeat.pid
134
+
135
+ # SageMath parsed files
136
+ *.sage.py
137
+
138
+ # Environments
139
+ .env
140
+ .envrc
141
+ .venv
142
+ env/
143
+ venv/
144
+ ENV/
145
+ env.bak/
146
+ venv.bak/
147
+
148
+ # Spyder project settings
149
+ .spyderproject
150
+ .spyproject
151
+
152
+ # Rope project settings
153
+ .ropeproject
154
+
155
+ # mkdocs documentation
156
+ /site
157
+
158
+ # mypy
159
+ .mypy_cache/
160
+ .dmypy.json
161
+ dmypy.json
162
+
163
+ # Pyre type checker
164
+ .pyre/
165
+
166
+ # pytype static type analyzer
167
+ .pytype/
168
+
169
+ # Cython debug symbols
170
+ cython_debug/
171
+
172
+ # PyCharm
173
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
174
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
175
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
176
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
177
+ #.idea/
178
+
179
+ # Abstra
180
+ # Abstra is an AI-powered process automation framework.
181
+ # Ignore directories containing user credentials, local state, and settings.
182
+ # Learn more at https://abstra.io/docs
183
+ .abstra/
184
+
185
+ # Visual Studio Code
186
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
187
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
188
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
189
+ # you could uncomment the following to ignore the entire vscode folder
190
+ # .vscode/
191
+
192
+ # Ruff stuff:
193
+ .ruff_cache/
194
+
195
+ # PyPI configuration file
196
+ .pypirc
197
+
198
+ # Cursor
199
+ # Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
200
+ # exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
201
+ # refer to https://docs.cursor.com/context/ignore-files
202
+ .cursorignore
203
+ .cursorindexingignore
204
+
205
+ # Marimo
206
+ marimo/_static/
207
+ marimo/_lsp/
208
+ __marimo__/
Dockerfile ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM ollama/ollama:latest
2
+
3
+ # Set environment variables for Hugging Face Spaces
4
+ # Spaces expect the service to listen on port 7860
5
+ ENV OLLAMA_HOST=0.0.0.0:7860
6
+ ENV OLLAMA_ORIGINS="*"
7
+
8
+ # Hugging Face Spaces typically run as user 1000.
9
+ # We create a user and set up the home directory and model path.
10
+ ENV HOME=/home/user
11
+ ENV OLLAMA_MODELS=$HOME/.ollama/models
12
+
13
+ # The base image may already have a user with UID 1000 (often named 'ollama').
14
+ # We setup the home directory expected by HF Spaces and ensure permissions.
15
+ RUN mkdir -p $HOME/.ollama/models && \
16
+ chown -R 1000:1000 $HOME
17
+
18
+ # Switch to UID 1000 (whether it's 'user' or 'ollama')
19
+ USER 1000
20
+
21
+ # Pre-pull the model during the build process
22
+ # Llama 3.2 3B is small enough to fit in the image layer for deployment stability
23
+ RUN /bin/ollama serve & \
24
+ pid=$! && \
25
+ sleep 5 && \
26
+ echo "Pulling llama3.2:3b model..." && \
27
+ /bin/ollama pull llama3.2:3b && \
28
+ kill $pid
29
+
30
+ # Expose the port expected by HF Spaces
31
+ EXPOSE 7860
32
+
33
+ # Start Ollama
34
+ ENTRYPOINT ["/bin/ollama"]
35
+ CMD ["serve"]
36
+
37
+
LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2026 bm80177
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
README.md CHANGED
@@ -1,10 +1,152 @@
1
  ---
2
  title: Ollama
3
- emoji: 🔥
4
- colorFrom: indigo
5
- colorTo: indigo
6
  sdk: docker
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
  title: Ollama
3
+ emoji:
4
+ colorFrom: pink
5
+ colorTo: blue
6
  sdk: docker
7
  pinned: false
8
+ license: mit
9
+ short_description: Ollama (llama3.2:3b) on Hugging Face Spaces (Docker)
10
  ---
11
 
12
+
13
+ # 🦙 Ollama (llama3.2:3b) on Hugging Face Spaces (Docker)
14
+
15
+ This Space runs **[Ollama](https://ollama.com/)** with the **`llama3.2:3b`** model using a **Docker-based Hugging Face Space**.
16
+
17
+ The container starts Ollama, pulls the model at runtime, and exposes the Ollama HTTP API so you can interact with the model programmatically.
18
+
19
+ ---
20
+
21
+ ## 🚀 Hugging Face Space Configuration
22
+
23
+ When creating the Space:
24
+
25
+ - **SDK**: `Docker`
26
+ - **Template**: `Blank`
27
+ - **Hardware**: `Free CPU` (sufficient for 3B models)
28
+ - **Visibility**: Public or Private (your choice)
29
+
30
+ No additional configuration files are required beyond this repository.
31
+
32
+ ---
33
+
34
+ ## 🧱 How It Works
35
+
36
+ - Ollama runs inside a Docker container
37
+ - The model `llama3.2:3b` is pulled on startup
38
+ - Ollama listens on port **11434**
39
+ - Hugging Face automatically maps the port and exposes the Space URL
40
+
41
+ ---
42
+
43
+ ## 📡 API Usage
44
+
45
+ Once the Space is running, you can interact with Ollama via HTTP.
46
+
47
+ ### Check version
48
+ ```bash
49
+ curl https://<your-space>.hf.space/api/version
50
+ ```
51
+
52
+ ### Generate text
53
+ ```bash
54
+ curl https://<your-space>.hf.space/api/generate \
55
+ -H "Content-Type: application/json" \
56
+ -d '{
57
+ "model": "llama3.2:3b",
58
+ "prompt": "Explain Kubernetes like I am five"
59
+ }'
60
+ ```
61
+
62
+ ---
63
+
64
+ ## 🔄 Automatic Deployment (GitHub → Hugging Face)
65
+
66
+ You can deploy automatically using **GitHub Actions**.
67
+
68
+ ### Required Secrets (GitHub Repository)
69
+
70
+ Go to **Settings → Secrets and variables → Actions**, then add:
71
+
72
+ | Secret Name | Description |
73
+ |------------|------------|
74
+ | `HF_USERNAME` | Your Hugging Face username |
75
+ | `HF_TOKEN` | Hugging Face **Write** access token |
76
+ | `SPACE_NAME` | Name of the Hugging Face Space |
77
+
78
+ The workflow logs in to:
79
+ ```
80
+ registry.hf.space
81
+ ```
82
+ and pushes the Docker image, triggering a redeploy of the Space.
83
+
84
+ ---
85
+
86
+ ## 🧪 Local Development (Optional)
87
+
88
+ You can run the same container locally for testing.
89
+
90
+ ### Build the image
91
+ ```bash
92
+ docker build -t ollama-local:latest .
93
+ ```
94
+
95
+ If you hit DNS/network issues:
96
+ ```bash
97
+ docker build --network=host -t ollama-local:latest .
98
+ ```
99
+
100
+ ### Run locally
101
+ ```bash
102
+ docker run -p 11434:11434 ollama-local:latest
103
+ ```
104
+
105
+ Test:
106
+ ```bash
107
+ curl http://localhost:11434/api/version
108
+ ```
109
+
110
+ ---
111
+
112
+ ## ☸️ Local Kubernetes Deployment (Optional)
113
+
114
+ This project can also be deployed to a local Kubernetes cluster (Docker Desktop, Minikube, MicroK8s).
115
+
116
+ ### Build the image
117
+ ```bash
118
+ docker build -t ollama-local:latest .
119
+ ```
120
+
121
+ ### Deploy
122
+ ```bash
123
+ kubectl apply -f local.yml
124
+ ```
125
+
126
+ ### Access the service
127
+ - **Docker Desktop**:
128
+ `http://localhost:30786`
129
+ - **Minikube**:
130
+ ```bash
131
+ echo "http://$(minikube ip):30786"
132
+ ```
133
+
134
+ Verify:
135
+ ```bash
136
+ curl http://localhost:30786/api/version
137
+ ```
138
+
139
+ ---
140
+
141
+ ## ⚠️ Notes & Limitations
142
+
143
+ - Free CPU Spaces are **slow** for inference (expected for LLMs)
144
+ - Model downloads happen at container startup
145
+ - Hugging Face Spaces may restart containers periodically
146
+
147
+ ---
148
+
149
+ ## 📚 References
150
+
151
+ - Ollama: https://ollama.com/
152
+ - Hugging Face Spaces (Docker): https://huggingface.co/docs/hub/spaces-sdks-docker
deploy.yml ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ apiVersion: v1
2
+ kind: Service
3
+ metadata:
4
+ name: ollama-service
5
+ spec:
6
+ selector:
7
+ app: ollama
8
+ ports:
9
+ - protocol: TCP
10
+ port: 7860
11
+ targetPort: 7860
12
+ nodePort: 30786
13
+ type: NodePort
14
+
15
+ ---
16
+ apiVersion: apps/v1
17
+ kind: Deployment
18
+ metadata:
19
+ name: ollama-deployment
20
+ spec:
21
+ replicas: 1
22
+ selector:
23
+ matchLabels:
24
+ app: ollama
25
+ template:
26
+ metadata:
27
+ labels:
28
+ app: ollama
29
+ spec:
30
+ containers:
31
+ - name: ollama
32
+ image: docker.io/library/ollama-local:latest
33
+ # Never forces K8s to use the local image or fail immediately (no network pull)
34
+ imagePullPolicy: Never
35
+ ports:
36
+ - containerPort: 7860
37
+ resources:
38
+ requests:
39
+ memory: "4Gi"
40
+ cpu: "2"
41
+ limits:
42
+ memory: "8Gi"
43
+ cpu: "4"
deploy_microk8s.sh ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ # Define image name
5
+ IMG_NAME="docker.io/library/ollama-local:latest"
6
+
7
+ echo "1. Building image: $IMG_NAME ..."
8
+ docker build --network=host -t $IMG_NAME .
9
+
10
+ echo "2. Saving image to ollama-local.tar ..."
11
+ docker save $IMG_NAME > ollama-local.tar
12
+
13
+ echo "3. Importing into Microk8s (k8s.io namespace)..."
14
+ # Using 'images import' explicitly
15
+ microk8s ctr --namespace k8s.io images import ollama-local.tar
16
+
17
+ echo "---------------------------------------------------"
18
+ echo "VERIFICATION: Checking if image exists in Microk8s:"
19
+ microk8s ctr --namespace k8s.io images list | grep "ollama-local" || echo "❌ Image NOT found in Microk8s registry!"
20
+ echo "---------------------------------------------------"
21
+
22
+ echo "4. Redeploying..."
23
+ kubectl apply -f deploy.yml
24
+ # Retrieve the pod name to delete it
25
+ POD_NAME=$(kubectl get pod -l app=ollama -o jsonpath="{.items[0].metadata.name}")
26
+ if [ -n "$POD_NAME" ]; then
27
+ echo "Deleting old pod: $POD_NAME"
28
+ kubectl delete pod $POD_NAME
29
+ fi
30
+
31
+ echo "Done! Watch the pods with: kubectl get pods -w"
testapp/README.md ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Setup
2
+ # Best practice on Ubuntu/WSL: use a virtual environment
3
+ python3 -m venv venv
4
+ source venv/bin/activate
5
+ pip install -r requirements.txt
6
+
7
+ # Run with default prompt
8
+ python3 client.py
9
+
10
+ # Run with custom prompt (Quote your strings in Zsh!)
11
+ python3 client.py "Write a haiku about Kubernetes"
testapp/client.py ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ import requests
3
+ import json
4
+ import sys
5
+ import time
6
+
7
+ # Configuration
8
+ # If running outside k8s (e.g. from your WSL terminal), use localhost and the NodePort
9
+ # If running inside k8s, you would use http://ollama-service:7860
10
+ OLLAMA_URL = "http://localhost:30786/api/generate"
11
+ MODEL = "llama3.2:3b"
12
+
13
+ def query_ollama(prompt):
14
+ print(f"🔵 Querying {MODEL} at {OLLAMA_URL}...")
15
+ print(f"📝 Prompt: {prompt}")
16
+ print("-" * 50)
17
+
18
+ payload = {
19
+ "model": MODEL,
20
+ "prompt": prompt,
21
+ "stream": True # Enable streaming for real-time output
22
+ }
23
+
24
+ try:
25
+ response = requests.post(OLLAMA_URL, json=payload, stream=True)
26
+ response.raise_for_status()
27
+
28
+ full_response = ""
29
+ start_time = time.time()
30
+
31
+ for line in response.iter_lines():
32
+ if line:
33
+ decoded_line = line.decode('utf-8')
34
+ data = json.loads(decoded_line)
35
+
36
+ if "response" in data:
37
+ chunk = data["response"]
38
+ print(chunk, end='', flush=True)
39
+ full_response += chunk
40
+
41
+ if data.get("done", False):
42
+ print() # Newline at end
43
+ total_duration = data.get("total_duration", 0) / 1e9 # Convert ns to s
44
+ print("-" * 50)
45
+ print(f"✅ Done in {total_duration:.2f}s")
46
+
47
+ except requests.exceptions.ConnectionError:
48
+ print(f"\n❌ Could not connect to Ollama at {OLLAMA_URL}")
49
+ print(" Ensure the Kubernetes service is running and port 30786 is accessible.")
50
+ sys.exit(1)
51
+ except Exception as e:
52
+ print(f"\n❌ Error: {e}")
53
+ sys.exit(1)
54
+
55
+ if __name__ == "__main__":
56
+ if len(sys.argv) > 1:
57
+ prompt = " ".join(sys.argv[1:])
58
+ else:
59
+ prompt = "Why is the sky blue? Keep it brief."
60
+
61
+ query_ollama(prompt)
testapp/requirements.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ requests