| 1 | # This file should ensure the existence of records required to run the application in every environment (production, |
| 2 | # development, test). The code here should be idempotent so that it can be executed at any point in every environment. |
| 3 | # The data can then be loaded with the bin/rails db:seed command (or created alongside the database with db:setup). |
| 4 | |
| 5 | require "digest" |
| 6 | require "open3" |
| 7 | require "fileutils" |
| 8 | require "tmpdir" |
| 9 | |
| 10 | # --------------------------------------------------------------------------- |
| 11 | # Demo model library — seeds a handful of Hugging Face-style model repositories |
| 12 | # so the /models discovery page and model pages work out of the box. |
| 13 | # --------------------------------------------------------------------------- |
| 14 | |
| 15 | # A Git LFS pointer file: the tiny text stub that stands in for a large weight |
| 16 | # file. The UI resolves the real `size` and shows an "LFS" badge. |
| 17 | def lfs_pointer(size_bytes, seed) |
| 18 | oid = Digest::SHA256.hexdigest("#{seed}-#{size_bytes}") |
| 19 | "version https://git-lfs.github.com/spec/v1\noid sha256:#{oid}\nsize #{size_bytes}\n" |
| 20 | end |
| 21 | |
| 22 | GB = 1024 * 1024 * 1024 |
| 23 | MB = 1024 * 1024 |
| 24 | |
| 25 | # Pushes README + files into the model's bare repo (idempotent: skips if the |
| 26 | # default branch already has commits). |
| 27 | def seed_model_files(repo, card:, files:) |
| 28 | path = repo.disk_path |
| 29 | GitRepositoryService.create_bare_repo(repo.user.username, repo.name) unless repo.initialized? |
| 30 | return if GitRepositoryService.branch_exists?(path, repo.default_branch) |
| 31 | |
| 32 | Dir.mktmpdir do |dir| |
| 33 | system("git", "-C", dir, "init", "-b", repo.default_branch, exception: true) |
| 34 | system("git", "-C", dir, "config", "user.email", "sigitsi@localhost", exception: true) |
| 35 | system("git", "-C", dir, "config", "user.name", "siGit", exception: true) |
| 36 | # The seed writes Git LFS *pointer* text directly — we do not want the local |
| 37 | # git-lfs filter (if installed) to try to clean/upload them as real objects. |
| 38 | # Neutralise the LFS filters so the pointer bytes are committed verbatim. |
| 39 | %w[clean smudge].each { |f| system("git", "-C", dir, "config", "filter.lfs.#{f}", "cat", exception: true) } |
| 40 | system("git", "-C", dir, "config", "filter.lfs.process", "", exception: true) |
| 41 | system("git", "-C", dir, "config", "filter.lfs.required", "false", exception: true) |
| 42 | |
| 43 | File.write(File.join(dir, "README.md"), card) |
| 44 | File.write(File.join(dir, ".gitattributes"), |
| 45 | "*.gguf filter=lfs diff=lfs merge=lfs -text\n*.safetensors filter=lfs diff=lfs merge=lfs -text\n") |
| 46 | files.each do |f| |
| 47 | full = File.join(dir, f[:path]) |
| 48 | FileUtils.mkdir_p(File.dirname(full)) |
| 49 | File.write(full, f[:content]) |
| 50 | end |
| 51 | |
| 52 | system("git", "-C", dir, "add", ".", exception: true) |
| 53 | system("git", "-C", dir, "commit", "-m", "Upload model", exception: true) |
| 54 | system("git", "-C", dir, "remote", "add", "origin", path, exception: true) |
| 55 | system("git", "-C", dir, "push", "origin", repo.default_branch, exception: true) |
| 56 | end |
| 57 | end |
| 58 | |
| 59 | def seed_model(username:, email:, smbcloud_id:, name:, description:, card:, files:, downloads:, likes:, updated_at: Time.current) |
| 60 | user = User.find_or_create_by!(smbcloud_id: smbcloud_id) do |u| |
| 61 | u.username = username |
| 62 | u.email = email |
| 63 | end |
| 64 | |
| 65 | repo = user.repositories.find_or_initialize_by(name: name) |
| 66 | repo.assign_attributes( |
| 67 | kind: "model", |
| 68 | description: description, |
| 69 | default_branch: "main", |
| 70 | disk_path: GitRepositoryService.repo_path(username, name), |
| 71 | downloads_count: downloads, |
| 72 | stars_count: likes, |
| 73 | updated_at: updated_at |
| 74 | ) |
| 75 | repo.save! |
| 76 | |
| 77 | seed_model_files(repo, card: card, files: files) |
| 78 | repo |
| 79 | rescue => e |
| 80 | warn " ! Skipped #{username}/#{name}: #{e.message}" |
| 81 | nil |
| 82 | end |
| 83 | |
| 84 | # ── bartowski/Qwen2.5-3B-Instruct-GGUF (the showcase model) ── |
| 85 | qwen_card = <<~MD |
| 86 | --- |
| 87 | license: apache-2.0 |
| 88 | base_model: Qwen/Qwen2.5-3B-Instruct |
| 89 | pipeline_tag: text-generation |
| 90 | library_name: gguf |
| 91 | language: |
| 92 | - en |
| 93 | tags: |
| 94 | - text-generation |
| 95 | - gguf |
| 96 | - quantized |
| 97 | - qwen2.5 |
| 98 | --- |
| 99 | |
| 100 | # Qwen2.5-3B-Instruct-GGUF |
| 101 | |
| 102 | GGUF quantizations of [Qwen/Qwen2.5-3B-Instruct](https://sigit.si/qwen/Qwen2.5-3B-Instruct), |
| 103 | produced with `llama.cpp`. Pick a quant that fits your hardware — higher bits |
| 104 | mean better quality, lower bits mean a smaller file and faster inference. |
| 105 | |
| 106 | ## Quant table |
| 107 | |
| 108 | | File | Quant | Size | Notes | |
| 109 | | ---- | ----- | ---- | ----- | |
| 110 | | `Qwen2.5-3B-Instruct-Q8_0.gguf` | Q8_0 | 3.3 GB | Near-lossless, recommended for quality | |
| 111 | | `Qwen2.5-3B-Instruct-Q5_K_M.gguf` | Q5_K_M | 2.2 GB | Balanced quality / size | |
| 112 | | `Qwen2.5-3B-Instruct-Q4_K_M.gguf` | Q4_K_M | 1.9 GB | Good default for most setups | |
| 113 | | `Qwen2.5-3B-Instruct-Q3_K_M.gguf` | Q3_K_M | 1.6 GB | Smallest, some quality loss | |
| 114 | |
| 115 | ## Run it |
| 116 | |
| 117 | ```bash |
| 118 | llama-cli -hf bartowski/Qwen2.5-3B-Instruct-GGUF -p "Hello!" |
| 119 | ``` |
| 120 | |
| 121 | ## Prompt format |
| 122 | |
| 123 | ``` |
| 124 | <|im_start|>system |
| 125 | You are a helpful assistant.<|im_end|> |
| 126 | <|im_start|>user |
| 127 | {prompt}<|im_end|> |
| 128 | <|im_start|>assistant |
| 129 | ``` |
| 130 | MD |
| 131 | |
| 132 | qwen_files = [ |
| 133 | { path: "Qwen2.5-3B-Instruct-Q8_0.gguf", content: lfs_pointer((3.3 * GB).to_i, "q8") }, |
| 134 | { path: "Qwen2.5-3B-Instruct-Q5_K_M.gguf", content: lfs_pointer((2.2 * GB).to_i, "q5") }, |
| 135 | { path: "Qwen2.5-3B-Instruct-Q4_K_M.gguf", content: lfs_pointer((1.9 * GB).to_i, "q4") }, |
| 136 | { path: "Qwen2.5-3B-Instruct-Q3_K_M.gguf", content: lfs_pointer((1.6 * GB).to_i, "q3") }, |
| 137 | { path: "config.json", content: %({\n "model_type": "qwen2",\n "quantized_by": "bartowski"\n}\n) } |
| 138 | ] |
| 139 | |
| 140 | seed_model( |
| 141 | username: "bartowski", email: "bartowski@example.com", smbcloud_id: 900_001, |
| 142 | name: "Qwen2.5-3B-Instruct-GGUF", |
| 143 | description: "GGUF quants of Qwen2.5-3B-Instruct for llama.cpp.", |
| 144 | card: qwen_card, files: qwen_files, |
| 145 | downloads: 1_284_530, likes: 412, updated_at: 2.weeks.ago |
| 146 | ) |
| 147 | |
| 148 | # ── meta-llama/Llama-3.2-1B-Instruct (safetensors / transformers) ── |
| 149 | llama_card = <<~MD |
| 150 | --- |
| 151 | license: llama3.2 |
| 152 | base_model: meta-llama/Llama-3.2-1B |
| 153 | pipeline_tag: text-generation |
| 154 | library_name: transformers |
| 155 | language: |
| 156 | - en |
| 157 | tags: |
| 158 | - text-generation |
| 159 | - llama |
| 160 | - instruct |
| 161 | --- |
| 162 | |
| 163 | # Llama-3.2-1B-Instruct |
| 164 | |
| 165 | A compact 1B instruction-tuned model. Load it with 🤗 Transformers: |
| 166 | |
| 167 | ```python |
| 168 | from transformers import AutoModelForCausalLM, AutoTokenizer |
| 169 | |
| 170 | model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-3.2-1B-Instruct") |
| 171 | tok = AutoTokenizer.from_pretrained("meta-llama/Llama-3.2-1B-Instruct") |
| 172 | ``` |
| 173 | MD |
| 174 | |
| 175 | llama_files = [ |
| 176 | { path: "model.safetensors", content: lfs_pointer((2.5 * GB).to_i, "llama-st") }, |
| 177 | { path: "config.json", content: %({\n "model_type": "llama",\n "hidden_size": 2048\n}\n) }, |
| 178 | { path: "tokenizer.json", content: lfs_pointer((9 * MB).to_i, "llama-tok") }, |
| 179 | { path: "generation_config.json", content: %({\n "temperature": 0.6,\n "top_p": 0.9\n}\n) } |
| 180 | ] |
| 181 | |
| 182 | seed_model( |
| 183 | username: "meta-llama", email: "meta-llama@example.com", smbcloud_id: 900_002, |
| 184 | name: "Llama-3.2-1B-Instruct", |
| 185 | description: "Lightweight 1B instruction-tuned text model.", |
| 186 | card: llama_card, files: llama_files, |
| 187 | downloads: 3_902_117, likes: 1_287, updated_at: 5.days.ago |
| 188 | ) |
| 189 | |
| 190 | # ── sentence-transformers/all-MiniLM-L6-v2 (embeddings) ── |
| 191 | minilm_card = <<~MD |
| 192 | --- |
| 193 | license: apache-2.0 |
| 194 | pipeline_tag: sentence-similarity |
| 195 | library_name: sentence-transformers |
| 196 | tags: |
| 197 | - sentence-similarity |
| 198 | - feature-extraction |
| 199 | - embeddings |
| 200 | --- |
| 201 | |
| 202 | # all-MiniLM-L6-v2 |
| 203 | |
| 204 | Maps sentences and paragraphs to a 384-dimensional dense vector space for |
| 205 | semantic search, clustering, and retrieval. |
| 206 | |
| 207 | ```python |
| 208 | from sentence_transformers import SentenceTransformer |
| 209 | model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2") |
| 210 | emb = model.encode(["A sentence to embed."]) |
| 211 | ``` |
| 212 | MD |
| 213 | |
| 214 | minilm_files = [ |
| 215 | { path: "model.safetensors", content: lfs_pointer((90 * MB).to_i, "minilm-st") }, |
| 216 | { path: "config.json", content: %({\n "model_type": "bert",\n "hidden_size": 384\n}\n) }, |
| 217 | { path: "tokenizer.json", content: lfs_pointer((700 * 1024).to_i, "minilm-tok") } |
| 218 | ] |
| 219 | |
| 220 | seed_model( |
| 221 | username: "sentence-transformers", email: "st@example.com", smbcloud_id: 900_003, |
| 222 | name: "all-MiniLM-L6-v2", |
| 223 | description: "384-dim sentence embeddings for semantic search.", |
| 224 | card: minilm_card, files: minilm_files, |
| 225 | downloads: 8_450_990, likes: 2_034, updated_at: 1.month.ago |
| 226 | ) |
| 227 | |
| 228 | # ── A model published by the demo @sigit profile, so its Models tab has content ── |
| 229 | # Attaches to the existing "sigit" user rather than creating one. On-brand: a |
| 230 | # small code-completion model the platform ships itself. |
| 231 | if (sigit = User.find_by(username: "sigit")) |
| 232 | sigit_card = <<~MD |
| 233 | --- |
| 234 | license: apache-2.0 |
| 235 | base_model: Qwen/Qwen2.5-Coder-1.5B |
| 236 | pipeline_tag: text-generation |
| 237 | library_name: gguf |
| 238 | language: |
| 239 | - en |
| 240 | tags: |
| 241 | - text-generation |
| 242 | - code |
| 243 | - code-completion |
| 244 | - gguf |
| 245 | --- |
| 246 | |
| 247 | # SiGit-Coder-1.5B-GGUF |
| 248 | |
| 249 | A small, fast code-completion model that powers inline suggestions in the |
| 250 | siGit Code & Deploy editor. GGUF quantizations run locally with `llama.cpp`, |
| 251 | so completions stay on your machine. |
| 252 | |
| 253 | ## Quant table |
| 254 | |
| 255 | | File | Quant | Size | Notes | |
| 256 | | ---- | ----- | ---- | ----- | |
| 257 | | `SiGit-Coder-1.5B-Q8_0.gguf` | Q8_0 | 1.6 GB | Best quality | |
| 258 | | `SiGit-Coder-1.5B-Q5_K_M.gguf` | Q5_K_M | 1.1 GB | Balanced | |
| 259 | | `SiGit-Coder-1.5B-Q4_K_M.gguf` | Q4_K_M | 1.0 GB | Recommended default | |
| 260 | |
| 261 | ## Run it |
| 262 | |
| 263 | ```bash |
| 264 | llama-cli -hf sigit/SiGit-Coder-1.5B-GGUF -p "def fib(n):" |
| 265 | ``` |
| 266 | MD |
| 267 | |
| 268 | sigit_files = [ |
| 269 | { path: "SiGit-Coder-1.5B-Q8_0.gguf", content: lfs_pointer((1.6 * GB).to_i, "sigit-q8") }, |
| 270 | { path: "SiGit-Coder-1.5B-Q5_K_M.gguf", content: lfs_pointer((1.1 * GB).to_i, "sigit-q5") }, |
| 271 | { path: "SiGit-Coder-1.5B-Q4_K_M.gguf", content: lfs_pointer((1.0 * GB).to_i, "sigit-q4") }, |
| 272 | { path: "config.json", content: %({\n "model_type": "qwen2",\n "quantized_by": "sigit"\n}\n) } |
| 273 | ] |
| 274 | |
| 275 | repo = sigit.repositories.find_or_initialize_by(name: "SiGit-Coder-1.5B-GGUF") |
| 276 | repo.assign_attributes( |
| 277 | kind: "model", |
| 278 | description: "Local code-completion model behind the siGit editor's inline suggestions.", |
| 279 | default_branch: "main", |
| 280 | disk_path: GitRepositoryService.repo_path(sigit.username, "SiGit-Coder-1.5B-GGUF"), |
| 281 | downloads_count: 47_213, stars_count: 96, updated_at: 4.days.ago |
| 282 | ) |
| 283 | repo.save! |
| 284 | seed_model_files(repo, card: sigit_card, files: sigit_files) |
| 285 | end |
| 286 | |
| 287 | puts "Seeded #{Repository.models.count} model repositories." |