winebox 0.1.2__tar.gz → 0.1.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. {winebox-0.1.2 → winebox-0.1.3}/PKG-INFO +34 -1
  2. {winebox-0.1.2 → winebox-0.1.3}/README.md +32 -0
  3. {winebox-0.1.2 → winebox-0.1.3}/docs/index.md +9 -5
  4. winebox-0.1.3/docs/screenshots/cellar.png +0 -0
  5. winebox-0.1.3/docs/screenshots/checkin.png +0 -0
  6. winebox-0.1.3/docs/screenshots/dashboard.png +0 -0
  7. winebox-0.1.3/docs/screenshots/login.png +0 -0
  8. {winebox-0.1.2 → winebox-0.1.3}/docs/user-guide.md +10 -4
  9. {winebox-0.1.2 → winebox-0.1.3}/pyproject.toml +2 -1
  10. {winebox-0.1.2 → winebox-0.1.3}/tasks.py +97 -0
  11. {winebox-0.1.2 → winebox-0.1.3}/uv.lock +134 -1
  12. {winebox-0.1.2 → winebox-0.1.3}/winebox/__init__.py +1 -1
  13. {winebox-0.1.2 → winebox-0.1.3}/winebox/config.py +4 -0
  14. {winebox-0.1.2 → winebox-0.1.3}/winebox/routers/wines.py +146 -10
  15. {winebox-0.1.2 → winebox-0.1.3}/winebox/services/ocr.py +37 -0
  16. winebox-0.1.3/winebox/services/vision.py +251 -0
  17. {winebox-0.1.2 → winebox-0.1.3}/winebox/static/css/style.css +344 -0
  18. winebox-0.1.3/winebox/static/favicon.svg +22 -0
  19. {winebox-0.1.2 → winebox-0.1.3}/winebox/static/index.html +75 -1
  20. {winebox-0.1.2 → winebox-0.1.3}/winebox/static/js/app.js +299 -5
  21. {winebox-0.1.2 → winebox-0.1.3}/.github/workflows/ci.yml +0 -0
  22. {winebox-0.1.2 → winebox-0.1.3}/.github/workflows/publish.yml +0 -0
  23. {winebox-0.1.2 → winebox-0.1.3}/.gitignore +0 -0
  24. {winebox-0.1.2 → winebox-0.1.3}/.python-version +0 -0
  25. {winebox-0.1.2 → winebox-0.1.3}/LICENSE +0 -0
  26. {winebox-0.1.2 → winebox-0.1.3}/docs/api-reference.md +0 -0
  27. {winebox-0.1.2 → winebox-0.1.3}/docs/conf.py +0 -0
  28. {winebox-0.1.2 → winebox-0.1.3}/tests/__init__.py +0 -0
  29. {winebox-0.1.2 → winebox-0.1.3}/tests/conftest.py +0 -0
  30. {winebox-0.1.2 → winebox-0.1.3}/tests/test_ocr.py +0 -0
  31. {winebox-0.1.2 → winebox-0.1.3}/tests/test_search.py +0 -0
  32. {winebox-0.1.2 → winebox-0.1.3}/tests/test_transactions.py +0 -0
  33. {winebox-0.1.2 → winebox-0.1.3}/tests/test_wines.py +0 -0
  34. {winebox-0.1.2 → winebox-0.1.3}/winebox/cli/__init__.py +0 -0
  35. {winebox-0.1.2 → winebox-0.1.3}/winebox/cli/server.py +0 -0
  36. {winebox-0.1.2 → winebox-0.1.3}/winebox/cli/user_admin.py +0 -0
  37. {winebox-0.1.2 → winebox-0.1.3}/winebox/database.py +0 -0
  38. {winebox-0.1.2 → winebox-0.1.3}/winebox/main.py +0 -0
  39. {winebox-0.1.2 → winebox-0.1.3}/winebox/models/__init__.py +0 -0
  40. {winebox-0.1.2 → winebox-0.1.3}/winebox/models/inventory.py +0 -0
  41. {winebox-0.1.2 → winebox-0.1.3}/winebox/models/transaction.py +0 -0
  42. {winebox-0.1.2 → winebox-0.1.3}/winebox/models/user.py +0 -0
  43. {winebox-0.1.2 → winebox-0.1.3}/winebox/models/wine.py +0 -0
  44. {winebox-0.1.2 → winebox-0.1.3}/winebox/routers/__init__.py +0 -0
  45. {winebox-0.1.2 → winebox-0.1.3}/winebox/routers/auth.py +0 -0
  46. {winebox-0.1.2 → winebox-0.1.3}/winebox/routers/cellar.py +0 -0
  47. {winebox-0.1.2 → winebox-0.1.3}/winebox/routers/search.py +0 -0
  48. {winebox-0.1.2 → winebox-0.1.3}/winebox/routers/transactions.py +0 -0
  49. {winebox-0.1.2 → winebox-0.1.3}/winebox/schemas/__init__.py +0 -0
  50. {winebox-0.1.2 → winebox-0.1.3}/winebox/schemas/transaction.py +0 -0
  51. {winebox-0.1.2 → winebox-0.1.3}/winebox/schemas/wine.py +0 -0
  52. {winebox-0.1.2 → winebox-0.1.3}/winebox/services/__init__.py +0 -0
  53. {winebox-0.1.2 → winebox-0.1.3}/winebox/services/auth.py +0 -0
  54. {winebox-0.1.2 → winebox-0.1.3}/winebox/services/image_storage.py +0 -0
  55. {winebox-0.1.2 → winebox-0.1.3}/winebox/services/wine_parser.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: winebox
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: Wine Cellar Management Application with OCR label scanning
5
5
  Project-URL: Homepage, https://github.com/jdrumgoole/winebox
6
6
  Project-URL: Repository, https://github.com/jdrumgoole/winebox
@@ -22,6 +22,7 @@ Classifier: Topic :: Home Automation
22
22
  Requires-Python: >=3.11
23
23
  Requires-Dist: aiofiles>=23.0.0
24
24
  Requires-Dist: aiosqlite>=0.19.0
25
+ Requires-Dist: anthropic>=0.40.0
25
26
  Requires-Dist: bcrypt<4.1.0,>=4.0.0
26
27
  Requires-Dist: fastapi>=0.109.0
27
28
  Requires-Dist: jinja2>=3.1.0
@@ -173,6 +174,38 @@ Images are served via the API at `/api/images/{filename}`.
173
174
 
174
175
  **Note:** The `data/` directory is excluded from git (see `.gitignore`). Make sure to back up this directory to preserve your wine collection data.
175
176
 
177
+ ## Label Scanning
178
+
179
+ WineBox uses AI-powered label scanning to extract wine information from photos.
180
+
181
+ ### Claude Vision (Recommended)
182
+
183
+ For best results, configure Claude Vision by setting your Anthropic API key:
184
+
185
+ ```bash
186
+ export ANTHROPIC_API_KEY=your-api-key
187
+ # or
188
+ export WINEBOX_ANTHROPIC_API_KEY=your-api-key
189
+ ```
190
+
191
+ Claude Vision provides intelligent label analysis that:
192
+ - Handles decorative and artistic fonts
193
+ - Understands wine-specific terminology
194
+ - Extracts structured data (winery, vintage, grape variety, region, etc.)
195
+ - Works with curved or angled text
196
+
197
+ ### Tesseract OCR (Fallback)
198
+
199
+ If no Anthropic API key is configured, WineBox falls back to Tesseract OCR. This requires Tesseract to be installed on your system:
200
+
201
+ ```bash
202
+ # macOS
203
+ brew install tesseract
204
+
205
+ # Ubuntu/Debian
206
+ sudo apt-get install tesseract-ocr
207
+ ```
208
+
176
209
  ## Authentication
177
210
 
178
211
  WineBox requires authentication for all API endpoints (except `/health`).
@@ -127,6 +127,38 @@ Images are served via the API at `/api/images/{filename}`.
127
127
 
128
128
  **Note:** The `data/` directory is excluded from git (see `.gitignore`). Make sure to back up this directory to preserve your wine collection data.
129
129
 
130
+ ## Label Scanning
131
+
132
+ WineBox uses AI-powered label scanning to extract wine information from photos.
133
+
134
+ ### Claude Vision (Recommended)
135
+
136
+ For best results, configure Claude Vision by setting your Anthropic API key:
137
+
138
+ ```bash
139
+ export ANTHROPIC_API_KEY=your-api-key
140
+ # or
141
+ export WINEBOX_ANTHROPIC_API_KEY=your-api-key
142
+ ```
143
+
144
+ Claude Vision provides intelligent label analysis that:
145
+ - Handles decorative and artistic fonts
146
+ - Understands wine-specific terminology
147
+ - Extracts structured data (winery, vintage, grape variety, region, etc.)
148
+ - Works with curved or angled text
149
+
150
+ ### Tesseract OCR (Fallback)
151
+
152
+ If no Anthropic API key is configured, WineBox falls back to Tesseract OCR. This requires Tesseract to be installed on your system:
153
+
154
+ ```bash
155
+ # macOS
156
+ brew install tesseract
157
+
158
+ # Ubuntu/Debian
159
+ sudo apt-get install tesseract-ocr
160
+ ```
161
+
130
162
  ## Authentication
131
163
 
132
164
  WineBox requires authentication for all API endpoints (except `/health`).
@@ -6,7 +6,7 @@ Welcome to WineBox, a wine cellar management application with OCR label scanning
6
6
 
7
7
  WineBox helps you manage your wine collection by:
8
8
 
9
- - **Scanning wine labels** using OCR to automatically extract wine details
9
+ - **Scanning wine labels** using Claude Vision AI (with Tesseract OCR fallback) to automatically extract wine details
10
10
  - **Tracking inventory** with check-in and check-out functionality
11
11
  - **Searching your cellar** by vintage, grape variety, region, and more
12
12
  - **Maintaining history** of all bottle movements
@@ -23,10 +23,14 @@ cd winebox
23
23
  # Install dependencies
24
24
  uv sync --all-extras
25
25
 
26
- # Install Tesseract OCR (macOS)
26
+ # Set up Claude Vision (recommended for better label scanning)
27
+ # Add your Anthropic API key to .env file:
28
+ echo "WINEBOX_ANTHROPIC_API_KEY=your-api-key-here" > .env
29
+
30
+ # Install Tesseract OCR as fallback (macOS)
27
31
  brew install tesseract
28
32
 
29
- # Install Tesseract OCR (Ubuntu/Debian)
33
+ # Install Tesseract OCR as fallback (Ubuntu/Debian)
30
34
  sudo apt-get install tesseract-ocr
31
35
  ```
32
36
 
@@ -70,8 +74,8 @@ api-reference
70
74
  ### Check-In Process
71
75
 
72
76
  1. Upload front label image (required) and back label (optional)
73
- 2. OCR automatically extracts text from the labels
74
- 3. Wine parser identifies: vintage, winery, grape variety, region, country
77
+ 2. Claude Vision AI (or Tesseract OCR fallback) automatically analyzes the labels
78
+ 3. Form fields are instantly populated with: wine name, vintage, winery, grape variety, region, country, alcohol %
75
79
  4. Review and edit auto-detected values
76
80
  5. Specify quantity of bottles
77
81
  6. Wine is added to your cellar with a CHECK_IN transaction
Binary file
@@ -27,11 +27,15 @@ The check-in process adds bottles to your cellar inventory.
27
27
  2. **Upload the front label image** (required):
28
28
  - Click the file input or drag and drop an image
29
29
  - Supported formats: JPG, PNG, GIF, WebP
30
+ - Form fields are automatically populated as soon as the image is uploaded
30
31
  3. **Upload the back label image** (optional):
31
32
  - Back labels often contain additional details
33
+ - Scanning updates with information from both labels
32
34
  4. **Review auto-detected values**:
33
- - The OCR system will attempt to extract wine details
34
- - Edit any incorrect values
35
+ - Claude Vision AI (or Tesseract OCR fallback) extracts wine details
36
+ - A toast notification shows which scanning engine was used
37
+ - Edit any incorrect values as needed
38
+ - View raw label text in the collapsible "Raw Label Text" section
35
39
  5. **Set the quantity**:
36
40
  - Enter the number of bottles you're adding
37
41
  6. **Add notes** (optional):
@@ -150,13 +154,15 @@ Shows the last 10 transactions with quick details.
150
154
 
151
155
  ### Taking Good Label Photos
152
156
 
153
- For best OCR results:
157
+ For best scanning results with Claude Vision:
154
158
 
155
159
  1. **Good lighting**: Natural light or well-lit room
156
160
  2. **Flat surface**: Lay the bottle on its side or hold label flat
157
161
  3. **Focus**: Ensure text is sharp and readable
158
162
  4. **Full label**: Capture the entire label in frame
159
- 5. **High resolution**: Higher resolution improves OCR accuracy
163
+ 5. **High resolution**: Higher resolution improves accuracy
164
+
165
+ Claude Vision provides intelligent label analysis that understands wine label context. If the Anthropic API key is not configured, the app falls back to Tesseract OCR.
160
166
 
161
167
  ### Organizing Your Cellar
162
168
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "winebox"
3
- version = "0.1.2"
3
+ version = "0.1.3"
4
4
  description = "Wine Cellar Management Application with OCR label scanning"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -36,6 +36,7 @@ dependencies = [
36
36
  "passlib>=1.7.4",
37
37
  "bcrypt>=4.0.0,<4.1.0",
38
38
  "python-jose[cryptography]>=3.3.0",
39
+ "anthropic>=0.40.0",
39
40
  ]
40
41
 
41
42
  [project.urls]
@@ -203,6 +203,103 @@ def purge(ctx: Context, include_images: bool = False, force: bool = False) -> No
203
203
  print("\nNote: Run 'invoke start' to restart the server.")
204
204
 
205
205
 
206
+ @task(name="purge-wines")
207
+ def purge_wines(ctx: Context, include_images: bool = True, force: bool = False) -> None:
208
+ """Purge all wine data from the database without affecting users.
209
+
210
+ This deletes all wines, transactions, and inventory records but keeps
211
+ user accounts intact.
212
+
213
+ Args:
214
+ ctx: Invoke context
215
+ include_images: Also delete all uploaded wine label images (default: True)
216
+ force: Skip confirmation prompt
217
+ """
218
+ import shutil
219
+
220
+ db_path = Path("data/winebox.db")
221
+ images_path = Path("data/images")
222
+
223
+ if not db_path.exists():
224
+ print("Database does not exist. Nothing to purge.")
225
+ return
226
+
227
+ # Count records to be deleted
228
+ count_script = """
229
+ import asyncio
230
+ from sqlalchemy import text
231
+ from winebox.database import async_session_maker
232
+
233
+ async def count_records():
234
+ async with async_session_maker() as session:
235
+ wines = (await session.execute(text('SELECT COUNT(*) FROM wines'))).scalar()
236
+ transactions = (await session.execute(text('SELECT COUNT(*) FROM transactions'))).scalar()
237
+ inventory = (await session.execute(text('SELECT COUNT(*) FROM cellar_inventory'))).scalar()
238
+ return wines, transactions, inventory
239
+
240
+ wines, transactions, inventory = asyncio.run(count_records())
241
+ print(f'{wines},{transactions},{inventory}')
242
+ """
243
+ result = ctx.run(f'uv run python -c "{count_script}"', hide=True, warn=True)
244
+
245
+ if result.ok:
246
+ counts = result.stdout.strip().split(',')
247
+ wine_count, transaction_count, inventory_count = int(counts[0]), int(counts[1]), int(counts[2])
248
+ else:
249
+ wine_count, transaction_count, inventory_count = 0, 0, 0
250
+
251
+ # Check images
252
+ image_count = 0
253
+ if include_images and images_path.exists():
254
+ image_count = len(list(images_path.glob("*")))
255
+
256
+ if wine_count == 0 and transaction_count == 0 and inventory_count == 0 and image_count == 0:
257
+ print("No wine data to purge.")
258
+ return
259
+
260
+ # Show what will be deleted
261
+ print("The following wine data will be deleted:")
262
+ print(f" - Wines: {wine_count} records")
263
+ print(f" - Transactions: {transaction_count} records")
264
+ print(f" - Inventory: {inventory_count} records")
265
+ if include_images:
266
+ print(f" - Images: {image_count} files")
267
+ print("\nUser accounts will NOT be affected.")
268
+
269
+ # Confirm unless --force is used
270
+ if not force:
271
+ response = input("\nAre you sure you want to purge wine data? [y/N]: ").strip().lower()
272
+ if response not in ("y", "yes"):
273
+ print("Purge cancelled.")
274
+ return
275
+
276
+ # Delete wine data from database
277
+ delete_script = """
278
+ import asyncio
279
+ from sqlalchemy import text
280
+ from winebox.database import async_session_maker
281
+
282
+ async def delete_wine_data():
283
+ async with async_session_maker() as session:
284
+ await session.execute(text('DELETE FROM transactions'))
285
+ await session.execute(text('DELETE FROM cellar_inventory'))
286
+ await session.execute(text('DELETE FROM wines'))
287
+ await session.commit()
288
+ print('Wine data deleted from database.')
289
+
290
+ asyncio.run(delete_wine_data())
291
+ """
292
+ ctx.run(f'uv run python -c "{delete_script}"')
293
+
294
+ # Delete images if requested
295
+ if include_images and images_path.exists() and image_count > 0:
296
+ shutil.rmtree(images_path)
297
+ images_path.mkdir(parents=True)
298
+ print(f"Deleted {image_count} images and recreated: {images_path}")
299
+
300
+ print("\nWine data purge complete. User accounts preserved.")
301
+
302
+
206
303
  @task(name="docs-build")
207
304
  def docs_build(ctx: Context) -> None:
208
305
  """Build the Sphinx documentation."""
@@ -51,6 +51,25 @@ wheels = [
51
51
  { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" },
52
52
  ]
53
53
 
54
+ [[package]]
55
+ name = "anthropic"
56
+ version = "0.77.1"
57
+ source = { registry = "https://pypi.org/simple" }
58
+ dependencies = [
59
+ { name = "anyio" },
60
+ { name = "distro" },
61
+ { name = "docstring-parser" },
62
+ { name = "httpx" },
63
+ { name = "jiter" },
64
+ { name = "pydantic" },
65
+ { name = "sniffio" },
66
+ { name = "typing-extensions" },
67
+ ]
68
+ sdist = { url = "https://files.pythonhosted.org/packages/88/61/50aef0587acd9dd8bf1b8b7fd7fbb25ba4c6ec5387a6ffc195a697951fcc/anthropic-0.77.1.tar.gz", hash = "sha256:a19d78ff6fff9e05d211e3a936051cd5b9462f0eac043d2d45b2372f455d11cd", size = 504691, upload-time = "2026-02-03T17:44:22.667Z" }
69
+ wheels = [
70
+ { url = "https://files.pythonhosted.org/packages/2b/54/e83babf9833547c5548b4e25230ef3d62492e45925b0d104a43e501918a0/anthropic-0.77.1-py3-none-any.whl", hash = "sha256:76fd6f2ab36033a5294d58182a5f712dab9573c3a54413a275ecdf29e727c1e0", size = 397856, upload-time = "2026-02-03T17:44:20.962Z" },
71
+ ]
72
+
54
73
  [[package]]
55
74
  name = "anyio"
56
75
  version = "4.12.1"
@@ -324,6 +343,24 @@ wheels = [
324
343
  { url = "https://files.pythonhosted.org/packages/79/f4/9ceb90cfd6a3847069b0b0b353fd3075dc69b49defc70182d8af0c4ca390/cryptography-46.0.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:be8c01a7d5a55f9a47d1888162b76c8f49d62b234d88f0ff91a9fbebe32ffbc3", size = 3406043, upload-time = "2026-01-28T00:24:32.236Z" },
325
344
  ]
326
345
 
346
+ [[package]]
347
+ name = "distro"
348
+ version = "1.9.0"
349
+ source = { registry = "https://pypi.org/simple" }
350
+ sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722, upload-time = "2023-12-24T09:54:32.31Z" }
351
+ wheels = [
352
+ { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" },
353
+ ]
354
+
355
+ [[package]]
356
+ name = "docstring-parser"
357
+ version = "0.17.0"
358
+ source = { registry = "https://pypi.org/simple" }
359
+ sdist = { url = "https://files.pythonhosted.org/packages/b2/9d/c3b43da9515bd270df0f80548d9944e389870713cc1fe2b8fb35fe2bcefd/docstring_parser-0.17.0.tar.gz", hash = "sha256:583de4a309722b3315439bb31d64ba3eebada841f2e2cee23b99df001434c912", size = 27442, upload-time = "2025-07-21T07:35:01.868Z" }
360
+ wheels = [
361
+ { url = "https://files.pythonhosted.org/packages/55/e2/2537ebcff11c1ee1ff17d8d0b6f4db75873e3b0fb32c2d4a2ee31ecb310a/docstring_parser-0.17.0-py3-none-any.whl", hash = "sha256:cf2569abd23dce8099b300f9b4fa8191e9582dda731fd533daf54c4551658708", size = 36896, upload-time = "2025-07-21T07:35:00.684Z" },
362
+ ]
363
+
327
364
  [[package]]
328
365
  name = "docutils"
329
366
  version = "0.22.4"
@@ -533,6 +570,91 @@ wheels = [
533
570
  { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" },
534
571
  ]
535
572
 
573
+ [[package]]
574
+ name = "jiter"
575
+ version = "0.13.0"
576
+ source = { registry = "https://pypi.org/simple" }
577
+ sdist = { url = "https://files.pythonhosted.org/packages/0d/5e/4ec91646aee381d01cdb9974e30882c9cd3b8c5d1079d6b5ff4af522439a/jiter-0.13.0.tar.gz", hash = "sha256:f2839f9c2c7e2dffc1bc5929a510e14ce0a946be9365fd1219e7ef342dae14f4", size = 164847, upload-time = "2026-02-02T12:37:56.441Z" }
578
+ wheels = [
579
+ { url = "https://files.pythonhosted.org/packages/71/29/499f8c9eaa8a16751b1c0e45e6f5f1761d180da873d417996cc7bddc8eef/jiter-0.13.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ea026e70a9a28ebbdddcbcf0f1323128a8db66898a06eaad3a4e62d2f554d096", size = 311157, upload-time = "2026-02-02T12:35:37.758Z" },
580
+ { url = "https://files.pythonhosted.org/packages/50/f6/566364c777d2ab450b92100bea11333c64c38d32caf8dc378b48e5b20c46/jiter-0.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:66aa3e663840152d18cc8ff1e4faad3dd181373491b9cfdc6004b92198d67911", size = 319729, upload-time = "2026-02-02T12:35:39.246Z" },
581
+ { url = "https://files.pythonhosted.org/packages/73/dd/560f13ec5e4f116d8ad2658781646cca91b617ae3b8758d4a5076b278f70/jiter-0.13.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3524798e70655ff19aec58c7d05adb1f074fecff62da857ea9be2b908b6d701", size = 354766, upload-time = "2026-02-02T12:35:40.662Z" },
582
+ { url = "https://files.pythonhosted.org/packages/7c/0d/061faffcfe94608cbc28a0d42a77a74222bdf5055ccdbe5fd2292b94f510/jiter-0.13.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ec7e287d7fbd02cb6e22f9a00dd9c9cd504c40a61f2c61e7e1f9690a82726b4c", size = 362587, upload-time = "2026-02-02T12:35:42.025Z" },
583
+ { url = "https://files.pythonhosted.org/packages/92/c9/c66a7864982fd38a9773ec6e932e0398d1262677b8c60faecd02ffb67bf3/jiter-0.13.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:47455245307e4debf2ce6c6e65a717550a0244231240dcf3b8f7d64e4c2f22f4", size = 487537, upload-time = "2026-02-02T12:35:43.459Z" },
584
+ { url = "https://files.pythonhosted.org/packages/6c/86/84eb4352cd3668f16d1a88929b5888a3fe0418ea8c1dfc2ad4e7bf6e069a/jiter-0.13.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ee9da221dca6e0429c2704c1b3655fe7b025204a71d4d9b73390c759d776d165", size = 373717, upload-time = "2026-02-02T12:35:44.928Z" },
585
+ { url = "https://files.pythonhosted.org/packages/6e/09/9fe4c159358176f82d4390407a03f506a8659ed13ca3ac93a843402acecf/jiter-0.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24ab43126d5e05f3d53a36a8e11eb2f23304c6c1117844aaaf9a0aa5e40b5018", size = 362683, upload-time = "2026-02-02T12:35:46.636Z" },
586
+ { url = "https://files.pythonhosted.org/packages/c9/5e/85f3ab9caca0c1d0897937d378b4a515cae9e119730563572361ea0c48ae/jiter-0.13.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9da38b4fedde4fb528c740c2564628fbab737166a0e73d6d46cb4bb5463ff411", size = 392345, upload-time = "2026-02-02T12:35:48.088Z" },
587
+ { url = "https://files.pythonhosted.org/packages/12/4c/05b8629ad546191939e6f0c2f17e29f542a398f4a52fb987bc70b6d1eb8b/jiter-0.13.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0b34c519e17658ed88d5047999a93547f8889f3c1824120c26ad6be5f27b6cf5", size = 517775, upload-time = "2026-02-02T12:35:49.482Z" },
588
+ { url = "https://files.pythonhosted.org/packages/4d/88/367ea2eb6bc582c7052e4baf5ddf57ebe5ab924a88e0e09830dfb585c02d/jiter-0.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d2a6394e6af690d462310a86b53c47ad75ac8c21dc79f120714ea449979cb1d3", size = 551325, upload-time = "2026-02-02T12:35:51.104Z" },
589
+ { url = "https://files.pythonhosted.org/packages/f3/12/fa377ffb94a2f28c41afaed093e0d70cfe512035d5ecb0cad0ae4792d35e/jiter-0.13.0-cp311-cp311-win32.whl", hash = "sha256:0f0c065695f616a27c920a56ad0d4fc46415ef8b806bf8fc1cacf25002bd24e1", size = 204709, upload-time = "2026-02-02T12:35:52.467Z" },
590
+ { url = "https://files.pythonhosted.org/packages/cb/16/8e8203ce92f844dfcd3d9d6a5a7322c77077248dbb12da52d23193a839cd/jiter-0.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:0733312953b909688ae3c2d58d043aa040f9f1a6a75693defed7bc2cc4bf2654", size = 204560, upload-time = "2026-02-02T12:35:53.925Z" },
591
+ { url = "https://files.pythonhosted.org/packages/44/26/97cc40663deb17b9e13c3a5cf29251788c271b18ee4d262c8f94798b8336/jiter-0.13.0-cp311-cp311-win_arm64.whl", hash = "sha256:5d9b34ad56761b3bf0fbe8f7e55468704107608512350962d3317ffd7a4382d5", size = 189608, upload-time = "2026-02-02T12:35:55.304Z" },
592
+ { url = "https://files.pythonhosted.org/packages/2e/30/7687e4f87086829955013ca12a9233523349767f69653ebc27036313def9/jiter-0.13.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0a2bd69fc1d902e89925fc34d1da51b2128019423d7b339a45d9e99c894e0663", size = 307958, upload-time = "2026-02-02T12:35:57.165Z" },
593
+ { url = "https://files.pythonhosted.org/packages/c3/27/e57f9a783246ed95481e6749cc5002a8a767a73177a83c63ea71f0528b90/jiter-0.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f917a04240ef31898182f76a332f508f2cc4b57d2b4d7ad2dbfebbfe167eb505", size = 318597, upload-time = "2026-02-02T12:35:58.591Z" },
594
+ { url = "https://files.pythonhosted.org/packages/cf/52/e5719a60ac5d4d7c5995461a94ad5ef962a37c8bf5b088390e6fad59b2ff/jiter-0.13.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1e2b199f446d3e82246b4fd9236d7cb502dc2222b18698ba0d986d2fecc6152", size = 348821, upload-time = "2026-02-02T12:36:00.093Z" },
595
+ { url = "https://files.pythonhosted.org/packages/61/db/c1efc32b8ba4c740ab3fc2d037d8753f67685f475e26b9d6536a4322bcdd/jiter-0.13.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:04670992b576fa65bd056dbac0c39fe8bd67681c380cb2b48efa885711d9d726", size = 364163, upload-time = "2026-02-02T12:36:01.937Z" },
596
+ { url = "https://files.pythonhosted.org/packages/55/8a/fb75556236047c8806995671a18e4a0ad646ed255276f51a20f32dceaeec/jiter-0.13.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5a1aff1fbdb803a376d4d22a8f63f8e7ccbce0b4890c26cc7af9e501ab339ef0", size = 483709, upload-time = "2026-02-02T12:36:03.41Z" },
597
+ { url = "https://files.pythonhosted.org/packages/7e/16/43512e6ee863875693a8e6f6d532e19d650779d6ba9a81593ae40a9088ff/jiter-0.13.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b3fb8c2053acaef8580809ac1d1f7481a0a0bdc012fd7f5d8b18fb696a5a089", size = 370480, upload-time = "2026-02-02T12:36:04.791Z" },
598
+ { url = "https://files.pythonhosted.org/packages/f8/4c/09b93e30e984a187bc8aaa3510e1ec8dcbdcd71ca05d2f56aac0492453aa/jiter-0.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bdaba7d87e66f26a2c45d8cbadcbfc4bf7884182317907baf39cfe9775bb4d93", size = 360735, upload-time = "2026-02-02T12:36:06.994Z" },
599
+ { url = "https://files.pythonhosted.org/packages/1a/1b/46c5e349019874ec5dfa508c14c37e29864ea108d376ae26d90bee238cd7/jiter-0.13.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7b88d649135aca526da172e48083da915ec086b54e8e73a425ba50999468cc08", size = 391814, upload-time = "2026-02-02T12:36:08.368Z" },
600
+ { url = "https://files.pythonhosted.org/packages/15/9e/26184760e85baee7162ad37b7912797d2077718476bf91517641c92b3639/jiter-0.13.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e404ea551d35438013c64b4f357b0474c7abf9f781c06d44fcaf7a14c69ff9e2", size = 513990, upload-time = "2026-02-02T12:36:09.993Z" },
601
+ { url = "https://files.pythonhosted.org/packages/e9/34/2c9355247d6debad57a0a15e76ab1566ab799388042743656e566b3b7de1/jiter-0.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1f4748aad1b4a93c8bdd70f604d0f748cdc0e8744c5547798acfa52f10e79228", size = 548021, upload-time = "2026-02-02T12:36:11.376Z" },
602
+ { url = "https://files.pythonhosted.org/packages/ac/4a/9f2c23255d04a834398b9c2e0e665382116911dc4d06b795710503cdad25/jiter-0.13.0-cp312-cp312-win32.whl", hash = "sha256:0bf670e3b1445fc4d31612199f1744f67f889ee1bbae703c4b54dc097e5dd394", size = 203024, upload-time = "2026-02-02T12:36:12.682Z" },
603
+ { url = "https://files.pythonhosted.org/packages/09/ee/f0ae675a957ae5a8f160be3e87acea6b11dc7b89f6b7ab057e77b2d2b13a/jiter-0.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:15db60e121e11fe186c0b15236bd5d18381b9ddacdcf4e659feb96fc6c969c92", size = 205424, upload-time = "2026-02-02T12:36:13.93Z" },
604
+ { url = "https://files.pythonhosted.org/packages/1b/02/ae611edf913d3cbf02c97cdb90374af2082c48d7190d74c1111dde08bcdd/jiter-0.13.0-cp312-cp312-win_arm64.whl", hash = "sha256:41f92313d17989102f3cb5dd533a02787cdb99454d494344b0361355da52fcb9", size = 186818, upload-time = "2026-02-02T12:36:15.308Z" },
605
+ { url = "https://files.pythonhosted.org/packages/91/9c/7ee5a6ff4b9991e1a45263bfc46731634c4a2bde27dfda6c8251df2d958c/jiter-0.13.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1f8a55b848cbabf97d861495cd65f1e5c590246fabca8b48e1747c4dfc8f85bf", size = 306897, upload-time = "2026-02-02T12:36:16.748Z" },
606
+ { url = "https://files.pythonhosted.org/packages/7c/02/be5b870d1d2be5dd6a91bdfb90f248fbb7dcbd21338f092c6b89817c3dbf/jiter-0.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f556aa591c00f2c45eb1b89f68f52441a016034d18b65da60e2d2875bbbf344a", size = 317507, upload-time = "2026-02-02T12:36:18.351Z" },
607
+ { url = "https://files.pythonhosted.org/packages/da/92/b25d2ec333615f5f284f3a4024f7ce68cfa0604c322c6808b2344c7f5d2b/jiter-0.13.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7e1d61da332ec412350463891923f960c3073cf1aae93b538f0bb4c8cd46efb", size = 350560, upload-time = "2026-02-02T12:36:19.746Z" },
608
+ { url = "https://files.pythonhosted.org/packages/be/ec/74dcb99fef0aca9fbe56b303bf79f6bd839010cb18ad41000bf6cc71eec0/jiter-0.13.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3097d665a27bc96fd9bbf7f86178037db139f319f785e4757ce7ccbf390db6c2", size = 363232, upload-time = "2026-02-02T12:36:21.243Z" },
609
+ { url = "https://files.pythonhosted.org/packages/1b/37/f17375e0bb2f6a812d4dd92d7616e41917f740f3e71343627da9db2824ce/jiter-0.13.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d01ecc3a8cbdb6f25a37bd500510550b64ddf9f7d64a107d92f3ccb25035d0f", size = 483727, upload-time = "2026-02-02T12:36:22.688Z" },
610
+ { url = "https://files.pythonhosted.org/packages/77/d2/a71160a5ae1a1e66c1395b37ef77da67513b0adba73b993a27fbe47eb048/jiter-0.13.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ed9bbc30f5d60a3bdf63ae76beb3f9db280d7f195dfcfa61af792d6ce912d159", size = 370799, upload-time = "2026-02-02T12:36:24.106Z" },
611
+ { url = "https://files.pythonhosted.org/packages/01/99/ed5e478ff0eb4e8aa5fd998f9d69603c9fd3f32de3bd16c2b1194f68361c/jiter-0.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98fbafb6e88256f4454de33c1f40203d09fc33ed19162a68b3b257b29ca7f663", size = 359120, upload-time = "2026-02-02T12:36:25.519Z" },
612
+ { url = "https://files.pythonhosted.org/packages/16/be/7ffd08203277a813f732ba897352797fa9493faf8dc7995b31f3d9cb9488/jiter-0.13.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5467696f6b827f1116556cb0db620440380434591e93ecee7fd14d1a491b6daa", size = 390664, upload-time = "2026-02-02T12:36:26.866Z" },
613
+ { url = "https://files.pythonhosted.org/packages/d1/84/e0787856196d6d346264d6dcccb01f741e5f0bd014c1d9a2ebe149caf4f3/jiter-0.13.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:2d08c9475d48b92892583df9da592a0e2ac49bcd41fae1fec4f39ba6cf107820", size = 513543, upload-time = "2026-02-02T12:36:28.217Z" },
614
+ { url = "https://files.pythonhosted.org/packages/65/50/ecbd258181c4313cf79bca6c88fb63207d04d5bf5e4f65174114d072aa55/jiter-0.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:aed40e099404721d7fcaf5b89bd3b4568a4666358bcac7b6b15c09fb6252ab68", size = 547262, upload-time = "2026-02-02T12:36:29.678Z" },
615
+ { url = "https://files.pythonhosted.org/packages/27/da/68f38d12e7111d2016cd198161b36e1f042bd115c169255bcb7ec823a3bf/jiter-0.13.0-cp313-cp313-win32.whl", hash = "sha256:36ebfbcffafb146d0e6ffb3e74d51e03d9c35ce7c625c8066cdbfc7b953bdc72", size = 200630, upload-time = "2026-02-02T12:36:31.808Z" },
616
+ { url = "https://files.pythonhosted.org/packages/25/65/3bd1a972c9a08ecd22eb3b08a95d1941ebe6938aea620c246cf426ae09c2/jiter-0.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:8d76029f077379374cf0dbc78dbe45b38dec4a2eb78b08b5194ce836b2517afc", size = 202602, upload-time = "2026-02-02T12:36:33.679Z" },
617
+ { url = "https://files.pythonhosted.org/packages/15/fe/13bd3678a311aa67686bb303654792c48206a112068f8b0b21426eb6851e/jiter-0.13.0-cp313-cp313-win_arm64.whl", hash = "sha256:bb7613e1a427cfcb6ea4544f9ac566b93d5bf67e0d48c787eca673ff9c9dff2b", size = 185939, upload-time = "2026-02-02T12:36:35.065Z" },
618
+ { url = "https://files.pythonhosted.org/packages/49/19/a929ec002ad3228bc97ca01dbb14f7632fffdc84a95ec92ceaf4145688ae/jiter-0.13.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fa476ab5dd49f3bf3a168e05f89358c75a17608dbabb080ef65f96b27c19ab10", size = 316616, upload-time = "2026-02-02T12:36:36.579Z" },
619
+ { url = "https://files.pythonhosted.org/packages/52/56/d19a9a194afa37c1728831e5fb81b7722c3de18a3109e8f282bfc23e587a/jiter-0.13.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ade8cb6ff5632a62b7dbd4757d8c5573f7a2e9ae285d6b5b841707d8363205ef", size = 346850, upload-time = "2026-02-02T12:36:38.058Z" },
620
+ { url = "https://files.pythonhosted.org/packages/36/4a/94e831c6bf287754a8a019cb966ed39ff8be6ab78cadecf08df3bb02d505/jiter-0.13.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9950290340acc1adaded363edd94baebcee7dabdfa8bee4790794cd5cfad2af6", size = 358551, upload-time = "2026-02-02T12:36:39.417Z" },
621
+ { url = "https://files.pythonhosted.org/packages/a2/ec/a4c72c822695fa80e55d2b4142b73f0012035d9fcf90eccc56bc060db37c/jiter-0.13.0-cp313-cp313t-win_amd64.whl", hash = "sha256:2b4972c6df33731aac0742b64fd0d18e0a69bc7d6e03108ce7d40c85fd9e3e6d", size = 201950, upload-time = "2026-02-02T12:36:40.791Z" },
622
+ { url = "https://files.pythonhosted.org/packages/b6/00/393553ec27b824fbc29047e9c7cd4a3951d7fbe4a76743f17e44034fa4e4/jiter-0.13.0-cp313-cp313t-win_arm64.whl", hash = "sha256:701a1e77d1e593c1b435315ff625fd071f0998c5f02792038a5ca98899261b7d", size = 185852, upload-time = "2026-02-02T12:36:42.077Z" },
623
+ { url = "https://files.pythonhosted.org/packages/6e/f5/f1997e987211f6f9bd71b8083047b316208b4aca0b529bb5f8c96c89ef3e/jiter-0.13.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:cc5223ab19fe25e2f0bf2643204ad7318896fe3729bf12fde41b77bfc4fafff0", size = 308804, upload-time = "2026-02-02T12:36:43.496Z" },
624
+ { url = "https://files.pythonhosted.org/packages/cd/8f/5482a7677731fd44881f0204981ce2d7175db271f82cba2085dd2212e095/jiter-0.13.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9776ebe51713acf438fd9b4405fcd86893ae5d03487546dae7f34993217f8a91", size = 318787, upload-time = "2026-02-02T12:36:45.071Z" },
625
+ { url = "https://files.pythonhosted.org/packages/f3/b9/7257ac59778f1cd025b26a23c5520a36a424f7f1b068f2442a5b499b7464/jiter-0.13.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:879e768938e7b49b5e90b7e3fecc0dbec01b8cb89595861fb39a8967c5220d09", size = 353880, upload-time = "2026-02-02T12:36:47.365Z" },
626
+ { url = "https://files.pythonhosted.org/packages/c3/87/719eec4a3f0841dad99e3d3604ee4cba36af4419a76f3cb0b8e2e691ad67/jiter-0.13.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:682161a67adea11e3aae9038c06c8b4a9a71023228767477d683f69903ebc607", size = 366702, upload-time = "2026-02-02T12:36:48.871Z" },
627
+ { url = "https://files.pythonhosted.org/packages/d2/65/415f0a75cf6921e43365a1bc227c565cb949caca8b7532776e430cbaa530/jiter-0.13.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a13b68cd1cd8cc9de8f244ebae18ccb3e4067ad205220ef324c39181e23bbf66", size = 486319, upload-time = "2026-02-02T12:36:53.006Z" },
628
+ { url = "https://files.pythonhosted.org/packages/54/a2/9e12b48e82c6bbc6081fd81abf915e1443add1b13d8fc586e1d90bb02bb8/jiter-0.13.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87ce0f14c6c08892b610686ae8be350bf368467b6acd5085a5b65441e2bf36d2", size = 372289, upload-time = "2026-02-02T12:36:54.593Z" },
629
+ { url = "https://files.pythonhosted.org/packages/4e/c1/e4693f107a1789a239c759a432e9afc592366f04e901470c2af89cfd28e1/jiter-0.13.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c365005b05505a90d1c47856420980d0237adf82f70c4aff7aebd3c1cc143ad", size = 360165, upload-time = "2026-02-02T12:36:56.112Z" },
630
+ { url = "https://files.pythonhosted.org/packages/17/08/91b9ea976c1c758240614bd88442681a87672eebc3d9a6dde476874e706b/jiter-0.13.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1317fdffd16f5873e46ce27d0e0f7f4f90f0cdf1d86bf6abeaea9f63ca2c401d", size = 389634, upload-time = "2026-02-02T12:36:57.495Z" },
631
+ { url = "https://files.pythonhosted.org/packages/18/23/58325ef99390d6d40427ed6005bf1ad54f2577866594bcf13ce55675f87d/jiter-0.13.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:c05b450d37ba0c9e21c77fef1f205f56bcee2330bddca68d344baebfc55ae0df", size = 514933, upload-time = "2026-02-02T12:36:58.909Z" },
632
+ { url = "https://files.pythonhosted.org/packages/5b/25/69f1120c7c395fd276c3996bb8adefa9c6b84c12bb7111e5c6ccdcd8526d/jiter-0.13.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:775e10de3849d0631a97c603f996f518159272db00fdda0a780f81752255ee9d", size = 548842, upload-time = "2026-02-02T12:37:00.433Z" },
633
+ { url = "https://files.pythonhosted.org/packages/18/05/981c9669d86850c5fbb0d9e62bba144787f9fba84546ba43d624ee27ef29/jiter-0.13.0-cp314-cp314-win32.whl", hash = "sha256:632bf7c1d28421c00dd8bbb8a3bac5663e1f57d5cd5ed962bce3c73bf62608e6", size = 202108, upload-time = "2026-02-02T12:37:01.718Z" },
634
+ { url = "https://files.pythonhosted.org/packages/8d/96/cdcf54dd0b0341db7d25413229888a346c7130bd20820530905fdb65727b/jiter-0.13.0-cp314-cp314-win_amd64.whl", hash = "sha256:f22ef501c3f87ede88f23f9b11e608581c14f04db59b6a801f354397ae13739f", size = 204027, upload-time = "2026-02-02T12:37:03.075Z" },
635
+ { url = "https://files.pythonhosted.org/packages/fb/f9/724bcaaab7a3cd727031fe4f6995cb86c4bd344909177c186699c8dec51a/jiter-0.13.0-cp314-cp314-win_arm64.whl", hash = "sha256:07b75fe09a4ee8e0c606200622e571e44943f47254f95e2436c8bdcaceb36d7d", size = 187199, upload-time = "2026-02-02T12:37:04.414Z" },
636
+ { url = "https://files.pythonhosted.org/packages/62/92/1661d8b9fd6a3d7a2d89831db26fe3c1509a287d83ad7838831c7b7a5c7e/jiter-0.13.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:964538479359059a35fb400e769295d4b315ae61e4105396d355a12f7fef09f0", size = 318423, upload-time = "2026-02-02T12:37:05.806Z" },
637
+ { url = "https://files.pythonhosted.org/packages/4f/3b/f77d342a54d4ebcd128e520fc58ec2f5b30a423b0fd26acdfc0c6fef8e26/jiter-0.13.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e104da1db1c0991b3eaed391ccd650ae8d947eab1480c733e5a3fb28d4313e40", size = 351438, upload-time = "2026-02-02T12:37:07.189Z" },
638
+ { url = "https://files.pythonhosted.org/packages/76/b3/ba9a69f0e4209bd3331470c723c2f5509e6f0482e416b612431a5061ed71/jiter-0.13.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0e3a5f0cde8ff433b8e88e41aa40131455420fb3649a3c7abdda6145f8cb7202", size = 364774, upload-time = "2026-02-02T12:37:08.579Z" },
639
+ { url = "https://files.pythonhosted.org/packages/b3/16/6cdb31fa342932602458dbb631bfbd47f601e03d2e4950740e0b2100b570/jiter-0.13.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:57aab48f40be1db920a582b30b116fe2435d184f77f0e4226f546794cedd9cf0", size = 487238, upload-time = "2026-02-02T12:37:10.066Z" },
640
+ { url = "https://files.pythonhosted.org/packages/ed/b1/956cc7abaca8d95c13aa8d6c9b3f3797241c246cd6e792934cc4c8b250d2/jiter-0.13.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7772115877c53f62beeb8fd853cab692dbc04374ef623b30f997959a4c0e7e95", size = 372892, upload-time = "2026-02-02T12:37:11.656Z" },
641
+ { url = "https://files.pythonhosted.org/packages/26/c4/97ecde8b1e74f67b8598c57c6fccf6df86ea7861ed29da84629cdbba76c4/jiter-0.13.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1211427574b17b633cfceba5040de8081e5abf114f7a7602f73d2e16f9fdaa59", size = 360309, upload-time = "2026-02-02T12:37:13.244Z" },
642
+ { url = "https://files.pythonhosted.org/packages/4b/d7/eabe3cf46715854ccc80be2cd78dd4c36aedeb30751dbf85a1d08c14373c/jiter-0.13.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7beae3a3d3b5212d3a55d2961db3c292e02e302feb43fce6a3f7a31b90ea6dfe", size = 389607, upload-time = "2026-02-02T12:37:14.881Z" },
643
+ { url = "https://files.pythonhosted.org/packages/df/2d/03963fc0804e6109b82decfb9974eb92df3797fe7222428cae12f8ccaa0c/jiter-0.13.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:e5562a0f0e90a6223b704163ea28e831bd3a9faa3512a711f031611e6b06c939", size = 514986, upload-time = "2026-02-02T12:37:16.326Z" },
644
+ { url = "https://files.pythonhosted.org/packages/f6/6c/8c83b45eb3eb1c1e18d841fe30b4b5bc5619d781267ca9bc03e005d8fd0a/jiter-0.13.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:6c26a424569a59140fb51160a56df13f438a2b0967365e987889186d5fc2f6f9", size = 548756, upload-time = "2026-02-02T12:37:17.736Z" },
645
+ { url = "https://files.pythonhosted.org/packages/47/66/eea81dfff765ed66c68fd2ed8c96245109e13c896c2a5015c7839c92367e/jiter-0.13.0-cp314-cp314t-win32.whl", hash = "sha256:24dc96eca9f84da4131cdf87a95e6ce36765c3b156fc9ae33280873b1c32d5f6", size = 201196, upload-time = "2026-02-02T12:37:19.101Z" },
646
+ { url = "https://files.pythonhosted.org/packages/ff/32/4ac9c7a76402f8f00d00842a7f6b83b284d0cf7c1e9d4227bc95aa6d17fa/jiter-0.13.0-cp314-cp314t-win_amd64.whl", hash = "sha256:0a8d76c7524087272c8ae913f5d9d608bd839154b62c4322ef65723d2e5bb0b8", size = 204215, upload-time = "2026-02-02T12:37:20.495Z" },
647
+ { url = "https://files.pythonhosted.org/packages/f9/8e/7def204fea9f9be8b3c21a6f2dd6c020cf56c7d5ff753e0e23ed7f9ea57e/jiter-0.13.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2c26cf47e2cad140fa23b6d58d435a7c0161f5c514284802f25e87fddfe11024", size = 187152, upload-time = "2026-02-02T12:37:22.124Z" },
648
+ { url = "https://files.pythonhosted.org/packages/79/b3/3c29819a27178d0e461a8571fb63c6ae38be6dc36b78b3ec2876bbd6a910/jiter-0.13.0-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b1cbfa133241d0e6bdab48dcdc2604e8ba81512f6bbd68ec3e8e1357dd3c316c", size = 307016, upload-time = "2026-02-02T12:37:42.755Z" },
649
+ { url = "https://files.pythonhosted.org/packages/eb/ae/60993e4b07b1ac5ebe46da7aa99fdbb802eb986c38d26e3883ac0125c4e0/jiter-0.13.0-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:db367d8be9fad6e8ebbac4a7578b7af562e506211036cba2c06c3b998603c3d2", size = 305024, upload-time = "2026-02-02T12:37:44.774Z" },
650
+ { url = "https://files.pythonhosted.org/packages/77/fa/2227e590e9cf98803db2811f172b2d6460a21539ab73006f251c66f44b14/jiter-0.13.0-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45f6f8efb2f3b0603092401dc2df79fa89ccbc027aaba4174d2d4133ed661434", size = 339337, upload-time = "2026-02-02T12:37:46.668Z" },
651
+ { url = "https://files.pythonhosted.org/packages/2d/92/015173281f7eb96c0ef580c997da8ef50870d4f7f4c9e03c845a1d62ae04/jiter-0.13.0-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:597245258e6ad085d064780abfb23a284d418d3e61c57362d9449c6c7317ee2d", size = 346395, upload-time = "2026-02-02T12:37:48.09Z" },
652
+ { url = "https://files.pythonhosted.org/packages/80/60/e50fa45dd7e2eae049f0ce964663849e897300433921198aef94b6ffa23a/jiter-0.13.0-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:3d744a6061afba08dd7ae375dcde870cffb14429b7477e10f67e9e6d68772a0a", size = 305169, upload-time = "2026-02-02T12:37:50.376Z" },
653
+ { url = "https://files.pythonhosted.org/packages/d2/73/a009f41c5eed71c49bec53036c4b33555afcdee70682a18c6f66e396c039/jiter-0.13.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:ff732bd0a0e778f43d5009840f20b935e79087b4dc65bd36f1cd0f9b04b8ff7f", size = 303808, upload-time = "2026-02-02T12:37:52.092Z" },
654
+ { url = "https://files.pythonhosted.org/packages/c4/10/528b439290763bff3d939268085d03382471b442f212dca4ff5f12802d43/jiter-0.13.0-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab44b178f7981fcaea7e0a5df20e773c663d06ffda0198f1a524e91b2fde7e59", size = 337384, upload-time = "2026-02-02T12:37:53.582Z" },
655
+ { url = "https://files.pythonhosted.org/packages/67/8a/a342b2f0251f3dac4ca17618265d93bf244a2a4d089126e81e4c1056ac50/jiter-0.13.0-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bb00b6d26db67a05fe3e12c76edc75f32077fb51deed13822dc648fa373bc19", size = 343768, upload-time = "2026-02-02T12:37:55.055Z" },
656
+ ]
657
+
536
658
  [[package]]
537
659
  name = "markdown-it-py"
538
660
  version = "4.0.0"
@@ -1104,6 +1226,15 @@ wheels = [
1104
1226
  { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" },
1105
1227
  ]
1106
1228
 
1229
+ [[package]]
1230
+ name = "sniffio"
1231
+ version = "1.3.1"
1232
+ source = { registry = "https://pypi.org/simple" }
1233
+ sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" }
1234
+ wheels = [
1235
+ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" },
1236
+ ]
1237
+
1107
1238
  [[package]]
1108
1239
  name = "snowballstemmer"
1109
1240
  version = "3.0.1"
@@ -1531,11 +1662,12 @@ wheels = [
1531
1662
 
1532
1663
  [[package]]
1533
1664
  name = "winebox"
1534
- version = "0.1.0"
1665
+ version = "0.1.3"
1535
1666
  source = { editable = "." }
1536
1667
  dependencies = [
1537
1668
  { name = "aiofiles" },
1538
1669
  { name = "aiosqlite" },
1670
+ { name = "anthropic" },
1539
1671
  { name = "bcrypt" },
1540
1672
  { name = "fastapi" },
1541
1673
  { name = "jinja2" },
@@ -1566,6 +1698,7 @@ dev = [
1566
1698
  requires-dist = [
1567
1699
  { name = "aiofiles", specifier = ">=23.0.0" },
1568
1700
  { name = "aiosqlite", specifier = ">=0.19.0" },
1701
+ { name = "anthropic", specifier = ">=0.40.0" },
1569
1702
  { name = "bcrypt", specifier = ">=4.0.0,<4.1.0" },
1570
1703
  { name = "fastapi", specifier = ">=0.109.0" },
1571
1704
  { name = "greenlet", marker = "extra == 'dev'", specifier = ">=3.0.0" },
@@ -1,3 +1,3 @@
1
1
  """WineBox - Wine Cellar Management Application."""
2
2
 
3
- __version__ = "0.1.0"
3
+ __version__ = "0.1.3"
@@ -35,6 +35,10 @@ class Settings(BaseSettings):
35
35
  # OCR
36
36
  tesseract_cmd: str | None = None # Use system default if None
37
37
 
38
+ # Claude Vision (for wine label scanning)
39
+ anthropic_api_key: str | None = None # Set WINEBOX_ANTHROPIC_API_KEY or ANTHROPIC_API_KEY
40
+ use_claude_vision: bool = True # Fall back to Tesseract if False or no API key
41
+
38
42
  # Authentication
39
43
  secret_key: str = generate_secret_key() # Override with WINEBOX_SECRET_KEY env var
40
44
  auth_enabled: bool = True # Set to False to disable authentication