opencode-skills-collection 3.1.10 → 3.1.11

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 (66) hide show
  1. package/bundled-skills/.antigravity-install-manifest.json +8 -1
  2. package/bundled-skills/browser-testing-with-devtools/SKILL.md +334 -0
  3. package/bundled-skills/docs/integrations/jetski-cortex.md +3 -3
  4. package/bundled-skills/docs/integrations/jetski-gemini-loader/README.md +1 -1
  5. package/bundled-skills/docs/maintainers/repo-growth-seo.md +3 -3
  6. package/bundled-skills/docs/maintainers/skills-update-guide.md +1 -1
  7. package/bundled-skills/docs/sources/sources.md +4 -0
  8. package/bundled-skills/docs/users/bundles.md +1 -1
  9. package/bundled-skills/docs/users/claude-code-skills.md +1 -1
  10. package/bundled-skills/docs/users/gemini-cli-skills.md +1 -1
  11. package/bundled-skills/docs/users/getting-started.md +1 -1
  12. package/bundled-skills/docs/users/kiro-integration.md +1 -1
  13. package/bundled-skills/docs/users/usage.md +4 -4
  14. package/bundled-skills/docs/users/visual-guide.md +4 -4
  15. package/bundled-skills/drizzle-migration-conflict/SKILL.md +179 -0
  16. package/bundled-skills/drizzle-migration-conflict/references/ci-policy.md +87 -0
  17. package/bundled-skills/drizzle-migration-conflict/references/conflict-resolution.md +163 -0
  18. package/bundled-skills/drizzle-migration-conflict/references/report-template.md +69 -0
  19. package/bundled-skills/drizzle-migration-conflict/references/sources.md +51 -0
  20. package/bundled-skills/drizzle-migration-conflict/scripts/check_drizzle_migrations.py +721 -0
  21. package/bundled-skills/frontend-lighthouse/SKILL.md +348 -0
  22. package/bundled-skills/pre-release-review/SKILL.md +198 -0
  23. package/bundled-skills/pre-release-review/references/checklist.md +104 -0
  24. package/bundled-skills/pre-release-review/references/report-template.md +91 -0
  25. package/bundled-skills/re-create/SKILL.md +251 -0
  26. package/bundled-skills/weaviate/SKILL.md +132 -0
  27. package/bundled-skills/weaviate/references/ask.md +36 -0
  28. package/bundled-skills/weaviate/references/create_collection.md +152 -0
  29. package/bundled-skills/weaviate/references/environment_requirements.md +34 -0
  30. package/bundled-skills/weaviate/references/example_data.md +24 -0
  31. package/bundled-skills/weaviate/references/explore_collection.md +50 -0
  32. package/bundled-skills/weaviate/references/fetch_filter.md +88 -0
  33. package/bundled-skills/weaviate/references/get_collection.md +32 -0
  34. package/bundled-skills/weaviate/references/hybrid_search.md +47 -0
  35. package/bundled-skills/weaviate/references/import_data.md +160 -0
  36. package/bundled-skills/weaviate/references/keyword_search.md +38 -0
  37. package/bundled-skills/weaviate/references/list_collections.md +31 -0
  38. package/bundled-skills/weaviate/references/query_search.md +38 -0
  39. package/bundled-skills/weaviate/references/semantic_search.md +46 -0
  40. package/bundled-skills/weaviate/scripts/ask.py +106 -0
  41. package/bundled-skills/weaviate/scripts/create_collection.py +359 -0
  42. package/bundled-skills/weaviate/scripts/example_data.py +945 -0
  43. package/bundled-skills/weaviate/scripts/explore_collection.py +295 -0
  44. package/bundled-skills/weaviate/scripts/fetch_filter.py +261 -0
  45. package/bundled-skills/weaviate/scripts/get_collection.py +122 -0
  46. package/bundled-skills/weaviate/scripts/hybrid_search.py +157 -0
  47. package/bundled-skills/weaviate/scripts/import.py +701 -0
  48. package/bundled-skills/weaviate/scripts/keyword_search.py +142 -0
  49. package/bundled-skills/weaviate/scripts/list_collections.py +77 -0
  50. package/bundled-skills/weaviate/scripts/query_search.py +135 -0
  51. package/bundled-skills/weaviate/scripts/semantic_search.py +139 -0
  52. package/bundled-skills/weaviate/scripts/weaviate_conn.py +231 -0
  53. package/bundled-skills/weaviate-cookbooks/SKILL.md +67 -0
  54. package/bundled-skills/weaviate-cookbooks/references/advanced_rag.md +274 -0
  55. package/bundled-skills/weaviate-cookbooks/references/agentic_rag.md +360 -0
  56. package/bundled-skills/weaviate-cookbooks/references/async_client.md +428 -0
  57. package/bundled-skills/weaviate-cookbooks/references/basic_agent.md +270 -0
  58. package/bundled-skills/weaviate-cookbooks/references/basic_rag.md +219 -0
  59. package/bundled-skills/weaviate-cookbooks/references/data_explorer.md +336 -0
  60. package/bundled-skills/weaviate-cookbooks/references/environment_requirements.md +78 -0
  61. package/bundled-skills/weaviate-cookbooks/references/frontend_interface.md +104 -0
  62. package/bundled-skills/weaviate-cookbooks/references/pdf_multimodal_rag.md +635 -0
  63. package/bundled-skills/weaviate-cookbooks/references/project_setup.md +75 -0
  64. package/bundled-skills/weaviate-cookbooks/references/query_agent_chatbot.md +163 -0
  65. package/package.json +1 -1
  66. package/skills_index.json +156 -0
@@ -0,0 +1,945 @@
1
+ #!/usr/bin/env python3
2
+ # /// script
3
+ # dependencies = [
4
+ # "weaviate-client==4.19.2",
5
+ # "weaviate-agents==1.2.0",
6
+ # "typer==0.21.0",
7
+ # "datasets>=4.5.0",
8
+ # ]
9
+ # ///
10
+ """
11
+ Download an example dataset from the Hugging Face dataset hub.
12
+
13
+ Usage:
14
+ uv run example_data.py --domain "domain_name" --nrows "number_of_rows" --vectorizer "vectorizer_name"
15
+
16
+ Environment Variables:
17
+ WEAVIATE_URL: Weaviate Cloud cluster URL
18
+ WEAVIATE_API_KEY: API key for authentication
19
+ + Any provider API keys (OPENAI_API_KEY, COHERE_API_KEY, etc.) - auto-detected
20
+ """
21
+
22
+ import sys
23
+ import typer
24
+ import weaviate
25
+ from weaviate.client import WeaviateClient
26
+ import re
27
+ from weaviate.classes.config import Property, DataType, Configure
28
+ from datasets import load_dataset
29
+ from datetime import datetime, timezone
30
+
31
+ # Import shared connection utilities (local to this skill)
32
+ from weaviate_conn import get_client
33
+
34
+ app = typer.Typer()
35
+
36
+ # Vectorizer string to config mapping
37
+ VECTORIZER_MAP = {
38
+ "text2vec_weaviate": lambda: Configure.Vectors.text2vec_weaviate(),
39
+ "text2vec_openai": lambda: Configure.Vectors.text2vec_openai(),
40
+ "text2vec_cohere": lambda: Configure.Vectors.text2vec_cohere(),
41
+ "text2vec_huggingface": lambda: Configure.Vectors.text2vec_huggingface(),
42
+ "text2vec_google_gemini": lambda: Configure.Vectors.text2vec_google_gemini(),
43
+ "text2vec_jinaai": lambda: Configure.Vectors.text2vec_jinaai(),
44
+ "text2vec_voyageai": lambda: Configure.Vectors.text2vec_voyageai(),
45
+ "text2vec_model2vec": lambda: Configure.Vectors.text2vec_model2vec(),
46
+ "text2vec_transformers": lambda: Configure.Vectors.text2vec_transformers(),
47
+ "text2vec_ollama": lambda: Configure.Vectors.text2vec_ollama(),
48
+ "multi2vec_clip": lambda: Configure.Vectors.multi2vec_clip(),
49
+ "multi2vec_bind": lambda: Configure.Vectors.multi2vec_bind(),
50
+ "none": lambda: Configure.Vectors.self_provided(),
51
+ }
52
+
53
+
54
+ def _get_sentences(document: str) -> tuple[list[str], list[tuple[int, int]]]:
55
+ """
56
+ Split document into sentences based on sentence_boundaries.
57
+ Maintains original order and preserves boundaries in chunks.
58
+ Returns sentences and their character spans (start, end) in the original document.
59
+ """
60
+ sentence_boundaries: list[str] = [".", "?", "!"]
61
+ if not sentence_boundaries or not document:
62
+ return ([document], [(0, len(document))]) if document else ([], [])
63
+
64
+ escaped_boundaries = [re.escape(boundary) for boundary in sentence_boundaries]
65
+ pattern = r"(?<=" + "|".join(escaped_boundaries) + r")\s+"
66
+
67
+ sentences = []
68
+ spans = []
69
+ current_pos = 0
70
+
71
+ for match in re.finditer(pattern, document):
72
+ sentence_end = match.start()
73
+ sentence = document[current_pos:sentence_end].strip()
74
+
75
+ if sentence:
76
+ sentences.append(sentence)
77
+ spans.append((current_pos, sentence_end))
78
+
79
+ current_pos = match.end()
80
+
81
+ remaining = document[current_pos:].strip()
82
+ if remaining:
83
+ sentences.append(remaining)
84
+ spans.append((current_pos, len(document)))
85
+
86
+ filtered_sentences = []
87
+ filtered_spans = []
88
+ for sentence, span in zip(sentences, spans):
89
+ if sentence:
90
+ filtered_sentences.append(sentence)
91
+ filtered_spans.append(span)
92
+
93
+ return (
94
+ (filtered_sentences, filtered_spans)
95
+ if filtered_sentences
96
+ else ([document], [(0, len(document))])
97
+ )
98
+
99
+
100
+ def chunk_by_sentences(
101
+ document: str,
102
+ num_sentences: int,
103
+ overlap_sentences: int = 1,
104
+ ) -> tuple[list[str], list[tuple[int, int]]]:
105
+ """
106
+ Given a document (string), return the sentences as chunks and span annotations (start and end indices of chunks).
107
+ """
108
+
109
+ if overlap_sentences >= num_sentences:
110
+ print(
111
+ f"Warning: overlap_sentences ({overlap_sentences}) is greater than num_sentences ({num_sentences}). Setting overlap to {num_sentences - 1}"
112
+ )
113
+ overlap_sentences = num_sentences - 1
114
+
115
+ sentences = _get_sentences(document)
116
+
117
+ span_annotations = []
118
+ chunks = []
119
+
120
+ i = 0
121
+ while i < len(sentences[0]):
122
+ # Get chunk of num_sentences sentences
123
+ chunk_sentences = sentences[1][i : i + num_sentences]
124
+ if not chunk_sentences:
125
+ break
126
+
127
+ # Get start and end char positions
128
+ start_char = chunk_sentences[0][0]
129
+ end_char = chunk_sentences[-1][1]
130
+
131
+ # Add chunk and its span annotation
132
+ chunks.append(document[start_char:end_char])
133
+ span_annotations.append((start_char, end_char))
134
+
135
+ # Move forward but account for overlap
136
+ i += num_sentences - overlap_sentences
137
+
138
+ return chunks, span_annotations
139
+
140
+
141
+ def create_ai_arxiv_collection(
142
+ client: WeaviateClient, vectorizer: str = "text2vec_weaviate", nrows: int = 1000
143
+ ):
144
+ # check existence of collection
145
+ if client.collections.exists("AI_Arxiv"):
146
+ print(
147
+ f"Collection 'AI_Arxiv' already exists. Cannot create. Returning.",
148
+ file=sys.stderr,
149
+ )
150
+ return
151
+
152
+ print(f"Creating collection 'AI_Arxiv'...", file=sys.stderr)
153
+ collection = client.collections.create(
154
+ "AI_Arxiv",
155
+ description="AI and machine learning research papers from arXiv, chunked by sentences for semantic search.",
156
+ properties=[
157
+ Property(
158
+ name="paper_id",
159
+ data_type=DataType.TEXT,
160
+ index_searchable=False,
161
+ description="Unique arXiv paper identifier (e.g., '2301.07041')",
162
+ ),
163
+ Property(
164
+ name="title",
165
+ data_type=DataType.TEXT,
166
+ description="Title of the research paper",
167
+ ),
168
+ Property(
169
+ name="summary",
170
+ data_type=DataType.TEXT,
171
+ description="Abstract or summary of the research paper",
172
+ ),
173
+ Property(
174
+ name="source",
175
+ data_type=DataType.TEXT,
176
+ index_searchable=False,
177
+ description="URL or source link to the original arXiv paper",
178
+ ),
179
+ Property(
180
+ name="authors",
181
+ data_type=DataType.TEXT,
182
+ description="Comma-separated list of paper authors",
183
+ ),
184
+ Property(
185
+ name="categories",
186
+ data_type=DataType.TEXT,
187
+ description="arXiv subject categories (e.g., 'cs.LG', 'stat.ML')",
188
+ ),
189
+ Property(
190
+ name="comment",
191
+ data_type=DataType.TEXT,
192
+ description="Additional comments or notes from the authors",
193
+ ),
194
+ Property(
195
+ name="primary_category",
196
+ data_type=DataType.TEXT,
197
+ description="Primary arXiv subject category for the paper",
198
+ ),
199
+ Property(
200
+ name="published",
201
+ data_type=DataType.DATE,
202
+ index_range_filters=True,
203
+ description="Date the paper was first published on arXiv",
204
+ ),
205
+ Property(
206
+ name="updated",
207
+ data_type=DataType.DATE,
208
+ index_range_filters=True,
209
+ description="Date the paper was last updated on arXiv",
210
+ ),
211
+ Property(
212
+ name="chunk",
213
+ data_type=DataType.TEXT,
214
+ description="Text chunk from the paper body used for semantic search",
215
+ ),
216
+ Property(
217
+ name="chunk_start",
218
+ data_type=DataType.NUMBER,
219
+ index_range_filters=True,
220
+ description="Character offset where this chunk starts in the original document",
221
+ ),
222
+ Property(
223
+ name="chunk_end",
224
+ data_type=DataType.NUMBER,
225
+ index_range_filters=True,
226
+ description="Character offset where this chunk ends in the original document",
227
+ ),
228
+ ],
229
+ vector_config=VECTORIZER_MAP[vectorizer](),
230
+ inverted_index_config=Configure.inverted_index(index_null_state=True),
231
+ )
232
+
233
+ dataset = load_dataset("jamescalam/ai-arxiv2", split="train", keep_in_memory=True)
234
+ nrows = nrows or len(dataset)
235
+
236
+ with collection.batch.fixed_size(batch_size=100) as batch:
237
+ for i in range(min(nrows, len(dataset))):
238
+ item = dataset[i]
239
+
240
+ if i % int(min(nrows, len(dataset)) / 10) == 0:
241
+ print(
242
+ f"Importing {i}/{min(nrows, len(dataset))} objects... (AI_Arxiv)",
243
+ file=sys.stderr,
244
+ )
245
+
246
+ if item and isinstance(item, dict):
247
+ chunks, span_annotations = chunk_by_sentences(
248
+ document=item["content"], num_sentences=15, overlap_sentences=0
249
+ )
250
+ del item["content"]
251
+
252
+ item["paper_id"] = item["id"]
253
+ del item["id"]
254
+ del item["references"]
255
+ item["published"] = (
256
+ datetime.strptime("20231126", "%Y%m%d").replace(tzinfo=timezone.utc)
257
+ if item["published"]
258
+ else None
259
+ )
260
+ item["updated"] = (
261
+ datetime.strptime("20231126", "%Y%m%d").replace(tzinfo=timezone.utc)
262
+ if item["updated"]
263
+ else None
264
+ )
265
+ for chunk, span in zip(chunks, span_annotations):
266
+ item["chunk"] = chunk
267
+ item["chunk_start"] = span[0]
268
+ item["chunk_end"] = span[1]
269
+ batch.add_object(properties=item)
270
+
271
+ if batch.number_errors > 10:
272
+ print(
273
+ "Batch import stopped due to excessive errors. Returning.",
274
+ file=sys.stderr,
275
+ )
276
+ break
277
+
278
+ failed_objects = collection.batch.failed_objects
279
+ if failed_objects:
280
+ print(
281
+ f"Number of failed imports: {len(failed_objects)}",
282
+ file=sys.stderr,
283
+ )
284
+ print(f"First failed object: {failed_objects[0]}", file=sys.stderr)
285
+ return
286
+
287
+ print(
288
+ f"Created collection 'AI_Arxiv' with {len(collection)} objects.",
289
+ file=sys.stderr,
290
+ )
291
+
292
+
293
+ def create_income_tax_returns_collection(
294
+ client: WeaviateClient, vectorizer: str = "text2vec_weaviate", nrows: int = 1000
295
+ ):
296
+ # check existence of collection
297
+ if client.collections.exists("Income_Tax_Returns"):
298
+ print(
299
+ f"Collection 'Income_Tax_Returns' already exists. Cannot create. Returning.",
300
+ file=sys.stderr,
301
+ )
302
+ return
303
+
304
+ print(f"Creating collection 'Income_Tax_Returns'...", file=sys.stderr)
305
+ collection = client.collections.create(
306
+ "Income_Tax_Returns",
307
+ description="Indian income tax return filings with taxpayer details, financials, and filing metadata.",
308
+ properties=[
309
+ Property(
310
+ name="pan",
311
+ data_type=DataType.TEXT,
312
+ index_searchable=False,
313
+ description="Permanent Account Number (PAN) — unique tax identifier for the taxpayer",
314
+ ),
315
+ Property(
316
+ name="acknowledgement_number",
317
+ data_type=DataType.TEXT,
318
+ index_searchable=False,
319
+ description="Government-issued acknowledgement number for the filed return",
320
+ ),
321
+ Property(
322
+ name="name",
323
+ data_type=DataType.TEXT,
324
+ description="Full legal name of the taxpayer",
325
+ ),
326
+ Property(
327
+ name="address",
328
+ data_type=DataType.TEXT,
329
+ index_searchable=False,
330
+ description="Street address of the taxpayer",
331
+ ),
332
+ Property(
333
+ name="area",
334
+ data_type=DataType.TEXT,
335
+ description="Area or locality name within the city",
336
+ ),
337
+ Property(
338
+ name="city", data_type=DataType.TEXT, description="City of residence"
339
+ ),
340
+ Property(
341
+ name="state",
342
+ data_type=DataType.TEXT,
343
+ description="State or province of residence",
344
+ ),
345
+ Property(
346
+ name="pincode",
347
+ data_type=DataType.NUMBER,
348
+ index_range_filters=True,
349
+ description="Postal PIN code for the taxpayer's address",
350
+ ),
351
+ Property(
352
+ name="state_code",
353
+ data_type=DataType.TEXT,
354
+ description="Two-character state code",
355
+ ),
356
+ Property(
357
+ name="country_code",
358
+ data_type=DataType.TEXT,
359
+ description="ISO two-character country code (e.g., 'IN' for India)",
360
+ ),
361
+ Property(
362
+ name="entity",
363
+ data_type=DataType.TEXT,
364
+ description="Type of taxpayer entity (e.g., 'Individual', 'Company', 'HUF')",
365
+ ),
366
+ Property(
367
+ name="form",
368
+ data_type=DataType.TEXT,
369
+ description="Tax form type used for filing (e.g., 'ITR-1', 'ITR-2')",
370
+ ),
371
+ Property(
372
+ name="assessment_year_start",
373
+ data_type=DataType.DATE,
374
+ index_range_filters=True,
375
+ description="Start date of the tax assessment year",
376
+ ),
377
+ Property(
378
+ name="assessment_year_end",
379
+ data_type=DataType.DATE,
380
+ index_range_filters=True,
381
+ description="End date of the tax assessment year",
382
+ ),
383
+ Property(
384
+ name="filing_datetime",
385
+ data_type=DataType.DATE,
386
+ index_range_filters=True,
387
+ description="Date and time when the return was filed",
388
+ ),
389
+ Property(
390
+ name="late_filing",
391
+ data_type=DataType.BOOL,
392
+ description="Whether the return was filed after the due date",
393
+ ),
394
+ Property(
395
+ name="signatory",
396
+ data_type=DataType.TEXT,
397
+ description="Name of the authorized signatory on the return",
398
+ ),
399
+ Property(
400
+ name="loss",
401
+ data_type=DataType.NUMBER,
402
+ index_range_filters=True,
403
+ description="Total loss amount in Indian Rupees (INR)",
404
+ ),
405
+ Property(
406
+ name="income",
407
+ data_type=DataType.NUMBER,
408
+ index_range_filters=True,
409
+ description="Total taxable income in Indian Rupees (INR)",
410
+ ),
411
+ Property(
412
+ name="tax",
413
+ data_type=DataType.NUMBER,
414
+ index_range_filters=True,
415
+ description="Total tax payable in Indian Rupees (INR)",
416
+ ),
417
+ Property(
418
+ name="cess",
419
+ data_type=DataType.NUMBER,
420
+ index_range_filters=True,
421
+ description="Health and education cess amount in Indian Rupees (INR)",
422
+ ),
423
+ Property(
424
+ name="interest",
425
+ data_type=DataType.NUMBER,
426
+ index_range_filters=True,
427
+ description="Interest payable or receivable in Indian Rupees (INR)",
428
+ ),
429
+ Property(
430
+ name="total_payable",
431
+ data_type=DataType.NUMBER,
432
+ index_range_filters=True,
433
+ description="Total amount payable including tax, cess, and interest in Indian Rupees (INR)",
434
+ ),
435
+ ],
436
+ vector_config=VECTORIZER_MAP[vectorizer](),
437
+ inverted_index_config=Configure.inverted_index(index_null_state=True),
438
+ )
439
+
440
+ dataset = load_dataset(
441
+ "AgamiAI/Indian-Income-Tax-Returns", split="train", keep_in_memory=True
442
+ )
443
+ nrows = nrows or len(dataset)
444
+
445
+ with collection.batch.fixed_size(batch_size=100) as batch:
446
+ for i in range(min(nrows, len(dataset))):
447
+ item = dataset[i]
448
+
449
+ if i % int(min(nrows, len(dataset)) / 10) == 0:
450
+ print(
451
+ f"Importing {i}/{min(nrows, len(dataset))} objects... (Income_Tax_Returns)",
452
+ file=sys.stderr,
453
+ )
454
+
455
+ if item and isinstance(item, dict):
456
+ batch.add_object(
457
+ properties={
458
+ "pan": item["pan"],
459
+ "acknowledgement_number": item["acknowledgement_number"],
460
+ "name": item["name"],
461
+ "address": item["address"],
462
+ "area": item["area"],
463
+ "city": item["city"],
464
+ "state": item["state"],
465
+ "pincode": item["pincode"],
466
+ "state_code": item["state_code"],
467
+ "country_code": item["country_code"],
468
+ "entity": item["entity"],
469
+ "form": item["form"],
470
+ "assessment_year_start": datetime.strptime(
471
+ item["assessment_year"][:4], "%Y"
472
+ ).replace(tzinfo=timezone.utc),
473
+ "assessment_year_end": datetime.strptime(
474
+ item["assessment_year"][5:], "%y"
475
+ ).replace(tzinfo=timezone.utc),
476
+ "filing_datetime": datetime.strptime(
477
+ item["filing_time"], "%d-%b-%Y %H:%M:%S"
478
+ ).replace(tzinfo=timezone.utc),
479
+ "late_filing": item["late_filing"],
480
+ "signatory": item["signatory"],
481
+ "loss": (
482
+ item["financials"]["loss"]
483
+ if "loss" in item["financials"]
484
+ else None
485
+ ),
486
+ "income": (
487
+ item["financials"]["income"]
488
+ if "income" in item["financials"]
489
+ else None
490
+ ),
491
+ "tax": (
492
+ item["financials"]["tax"]
493
+ if "tax" in item["financials"]
494
+ else None
495
+ ),
496
+ "cess": (
497
+ item["financials"]["cess"]
498
+ if "cess" in item["financials"]
499
+ else None
500
+ ),
501
+ "interest": (
502
+ item["financials"]["interest"]
503
+ if "interest" in item["financials"]
504
+ else None
505
+ ),
506
+ "total_payable": (
507
+ item["financials"]["total_payable"]
508
+ if "total_payable" in item["financials"]
509
+ else None
510
+ ),
511
+ }
512
+ )
513
+
514
+ if batch.number_errors > 10:
515
+ print(
516
+ "Batch import stopped due to excessive errors. Returning.",
517
+ file=sys.stderr,
518
+ )
519
+ break
520
+
521
+ failed_objects = collection.batch.failed_objects
522
+ if failed_objects:
523
+ print(
524
+ f"Number of failed imports: {len(failed_objects)}",
525
+ file=sys.stderr,
526
+ )
527
+ print(f"First failed object: {failed_objects[0]}", file=sys.stderr)
528
+ return
529
+
530
+ print(
531
+ f"Created collection 'Income_Tax_Returns' with {len(collection)} objects.",
532
+ file=sys.stderr,
533
+ )
534
+
535
+
536
+ def create_product_catalog_collection(
537
+ client: WeaviateClient, vectorizer: str = "text2vec_weaviate", nrows: int = 1000
538
+ ):
539
+ # check existence of collection
540
+ if client.collections.exists("Product_Catalog"):
541
+ print(
542
+ f"Collection 'Product_Catalog' already exists. Cannot create. Returning.",
543
+ file=sys.stderr,
544
+ )
545
+ return
546
+
547
+ print(f"Creating collection 'Product_Catalog'...", file=sys.stderr)
548
+ collection = client.collections.create(
549
+ "Product_Catalog",
550
+ description="E-commerce product catalog with pricing, brand, weight, and three-level category hierarchy.",
551
+ properties=[
552
+ Property(
553
+ name="product_name",
554
+ data_type=DataType.TEXT,
555
+ description="Name or title of the product",
556
+ ),
557
+ Property(
558
+ name="size",
559
+ data_type=DataType.TEXT,
560
+ description="Size specification of the product (e.g., 'Small', '250g', '1L')",
561
+ ),
562
+ Property(
563
+ name="pack_type",
564
+ data_type=DataType.TEXT,
565
+ description="Type of packaging (e.g., 'Box', 'Bag', 'Bottle')",
566
+ ),
567
+ Property(
568
+ name="organic_status",
569
+ data_type=DataType.TEXT,
570
+ description="Organic certification status of the product (e.g., 'Organic', 'Conventional')",
571
+ ),
572
+ Property(
573
+ name="weight_kg",
574
+ data_type=DataType.NUMBER,
575
+ index_range_filters=True,
576
+ description="Product weight in kilograms",
577
+ ),
578
+ Property(
579
+ name="brand",
580
+ data_type=DataType.TEXT,
581
+ description="Brand name of the product",
582
+ ),
583
+ Property(
584
+ name="price_usd",
585
+ data_type=DataType.NUMBER,
586
+ index_range_filters=True,
587
+ description="Product price in US dollars (USD)",
588
+ ),
589
+ Property(
590
+ name="category",
591
+ data_type=DataType.TEXT,
592
+ description="Top-level product category (L1)",
593
+ ),
594
+ Property(
595
+ name="subcategory",
596
+ data_type=DataType.TEXT,
597
+ description="Second-level product subcategory (L2)",
598
+ ),
599
+ Property(
600
+ name="subsubcategory",
601
+ data_type=DataType.TEXT,
602
+ description="Third-level product subcategory (L3)",
603
+ ),
604
+ ],
605
+ vector_config=VECTORIZER_MAP[vectorizer](),
606
+ inverted_index_config=Configure.inverted_index(index_null_state=True),
607
+ )
608
+
609
+ dataset = load_dataset(
610
+ "pkghf/ecom-product-catalog", split="train", keep_in_memory=True
611
+ )
612
+ nrows = nrows or len(dataset)
613
+
614
+ with collection.batch.fixed_size(batch_size=100) as batch:
615
+ for i in range(min(nrows, len(dataset))):
616
+ item = dataset[i]
617
+
618
+ if i % int(min(nrows, len(dataset)) / 10) == 0:
619
+ print(
620
+ f"Importing {i}/{min(nrows, len(dataset))} objects... (Product_Catalog)",
621
+ file=sys.stderr,
622
+ )
623
+
624
+ if item and isinstance(item, dict):
625
+ batch.add_object(
626
+ properties={
627
+ "product_name": item["product_name"],
628
+ "size": item["size"],
629
+ "pack_type": item["pack_type"],
630
+ "organic_status": item["organic_status"],
631
+ "weight_kg": item["weight_kg"],
632
+ "brand": item["brand"],
633
+ "price_usd": item["price_usd"],
634
+ "category": item["L1"],
635
+ "subcategory": item["L2"],
636
+ "subsubcategory": item["L3"],
637
+ }
638
+ )
639
+
640
+ if batch.number_errors > 10:
641
+ print(
642
+ "Batch import stopped due to excessive errors. Returning.",
643
+ file=sys.stderr,
644
+ )
645
+ break
646
+
647
+ failed_objects = collection.batch.failed_objects
648
+ if failed_objects:
649
+ print(
650
+ f"Number of failed imports: {len(failed_objects)}",
651
+ file=sys.stderr,
652
+ )
653
+ print(f"First failed object: {failed_objects[0]}", file=sys.stderr)
654
+ return
655
+
656
+ print(
657
+ f"Created collection 'Product_Catalog' with {len(collection)} objects.",
658
+ file=sys.stderr,
659
+ )
660
+
661
+
662
+ def duration_to_days(duration_str: str) -> float | None:
663
+ """Convert a duration string like '4 weeks', '2-4 weeks', '14 days' to a number of days.
664
+
665
+ For ranges like '2-4 weeks', returns the average (3 weeks = 21 days).
666
+ """
667
+ unit_to_days = {
668
+ "day": 1,
669
+ "days": 1,
670
+ "week": 7,
671
+ "weeks": 7,
672
+ "month": 30,
673
+ "months": 30,
674
+ "year": 365,
675
+ "years": 365,
676
+ }
677
+
678
+ match = re.match(
679
+ r"(\d+)(?:\s*-\s*(\d+))?\s+(days?|weeks?|months?|years?)",
680
+ duration_str.strip(),
681
+ re.IGNORECASE,
682
+ )
683
+ if not match:
684
+ return None
685
+
686
+ low = float(match.group(1))
687
+ high = float(match.group(2)) if match.group(2) else low
688
+ unit = match.group(3).lower()
689
+
690
+ avg = (low + high) / 2
691
+ return avg * unit_to_days[unit]
692
+
693
+
694
+ def create_hair_medical_collection(
695
+ client: WeaviateClient, vectorizer: str = "text2vec_weaviate", nrows: int = 1000
696
+ ):
697
+ # check existence of collection
698
+ if client.collections.exists("Hair_Medical"):
699
+ print(
700
+ f"Collection 'Hair_Medical' already exists. Cannot create. Returning.",
701
+ file=sys.stderr,
702
+ )
703
+ return
704
+
705
+ print(f"Creating collection 'Hair_Medical'...", file=sys.stderr)
706
+ collection = client.collections.create(
707
+ "Hair_Medical",
708
+ description="Hair disease diagnoses with associated symptoms, medications, side effects, severity, and treatment duration.",
709
+ properties=[
710
+ Property(
711
+ name="side_effects",
712
+ data_type=DataType.TEXT,
713
+ description="Known side effects of the prescribed medication",
714
+ ),
715
+ Property(
716
+ name="avg_duration_days",
717
+ data_type=DataType.NUMBER,
718
+ index_range_filters=True,
719
+ description="Average treatment duration in days",
720
+ ),
721
+ Property(
722
+ name="symptoms",
723
+ data_type=DataType.TEXT,
724
+ description="Symptoms associated with the hair disease",
725
+ ),
726
+ Property(
727
+ name="medication_description",
728
+ data_type=DataType.TEXT,
729
+ description="Description and mechanism of action of the medication",
730
+ ),
731
+ Property(
732
+ name="hair_disease",
733
+ data_type=DataType.TEXT,
734
+ description="Name of the hair disease or condition being treated",
735
+ ),
736
+ Property(
737
+ name="medication",
738
+ data_type=DataType.TEXT,
739
+ description="Name of the prescribed medication",
740
+ ),
741
+ Property(
742
+ name="disease_description",
743
+ data_type=DataType.TEXT,
744
+ description="Detailed description of the hair disease or condition",
745
+ ),
746
+ Property(
747
+ name="disease_severity",
748
+ data_type=DataType.TEXT,
749
+ description="Severity level of the disease (e.g., 'Mild', 'Moderate', 'Severe')",
750
+ ),
751
+ ],
752
+ vector_config=VECTORIZER_MAP[vectorizer](),
753
+ inverted_index_config=Configure.inverted_index(index_null_state=True),
754
+ )
755
+
756
+ dataset = load_dataset("Amod/hair_medical_sit", split="train", keep_in_memory=True)
757
+
758
+ nrows = nrows or len(dataset)
759
+
760
+ with collection.batch.fixed_size(batch_size=100) as batch:
761
+ for i in range(min(nrows, len(dataset))):
762
+ item = dataset[i]
763
+
764
+ if i % int(min(nrows, len(dataset)) / 10) == 0:
765
+ print(
766
+ f"Importing {i}/{min(nrows, len(dataset))} objects... (Hair_Medical)",
767
+ file=sys.stderr,
768
+ )
769
+ if item and isinstance(item, dict):
770
+ batch.add_object(
771
+ properties={
772
+ "side_effects": item["Side Effects"],
773
+ "avg_duration_days": duration_to_days(item["Duration"]),
774
+ "symptoms": item["Symptoms"],
775
+ "medication_description": item["Medication Description"],
776
+ "hair_disease": item["Hair Disease"],
777
+ "medication": item["Medication"],
778
+ "disease_description": item["Disease Description"],
779
+ "disease_severity": item[" Severity of Disease"],
780
+ }
781
+ )
782
+ if batch.number_errors > 10:
783
+ print(
784
+ "Batch import stopped due to excessive errors. Returning.",
785
+ file=sys.stderr,
786
+ )
787
+ break
788
+
789
+ failed_objects = collection.batch.failed_objects
790
+
791
+ if failed_objects:
792
+ print(
793
+ f"Number of failed imports: {len(failed_objects)}",
794
+ file=sys.stderr,
795
+ )
796
+ print(f"First failed object: {failed_objects[0]}", file=sys.stderr)
797
+ return
798
+
799
+ print(
800
+ f"Created collection 'Hair_Medical' with {len(collection)} objects.",
801
+ file=sys.stderr,
802
+ )
803
+
804
+
805
+ def create_helpdesk_tickets_collection(
806
+ client: WeaviateClient, vectorizer: str = "text2vec_weaviate", nrows: int = 1000
807
+ ):
808
+ # check existence of collection
809
+ if client.collections.exists("IT_Support_Tickets"):
810
+ print(
811
+ f"Collection 'IT_Support_Tickets' already exists. Cannot create. Returning.",
812
+ file=sys.stderr,
813
+ )
814
+ return
815
+
816
+ print(f"Creating collection 'IT_Support_Tickets'...", file=sys.stderr)
817
+ collection = client.collections.create(
818
+ "IT_Support_Tickets",
819
+ description="Synthetic IT helpdesk support tickets with subject, description, priority, category, and requester details.",
820
+ properties=[
821
+ Property(
822
+ name="ticket_id",
823
+ data_type=DataType.TEXT,
824
+ index_searchable=False,
825
+ description="Unique identifier for the support ticket",
826
+ ),
827
+ Property(
828
+ name="subject",
829
+ data_type=DataType.TEXT,
830
+ description="Short subject line summarizing the IT issue",
831
+ ),
832
+ Property(
833
+ name="description",
834
+ data_type=DataType.TEXT,
835
+ description="Detailed description of the IT support issue reported by the requester",
836
+ ),
837
+ Property(
838
+ name="priority",
839
+ data_type=DataType.TEXT,
840
+ description="Priority level of the ticket (e.g., 'Low', 'Medium', 'High', 'Critical')",
841
+ ),
842
+ Property(
843
+ name="category",
844
+ data_type=DataType.TEXT,
845
+ description="Category of the IT issue (e.g., 'Hardware', 'Software', 'Network', 'Access')",
846
+ ),
847
+ Property(
848
+ name="createdAt",
849
+ data_type=DataType.DATE,
850
+ index_range_filters=True,
851
+ description="Date and time when the ticket was created",
852
+ ),
853
+ Property(
854
+ name="requesterEmail",
855
+ data_type=DataType.TEXT,
856
+ description="Email address of the person who submitted the ticket",
857
+ ),
858
+ ],
859
+ vector_config=VECTORIZER_MAP[vectorizer](),
860
+ inverted_index_config=Configure.inverted_index(index_null_state=True),
861
+ )
862
+
863
+ dataset = load_dataset(
864
+ "Console-AI/IT-helpdesk-synthetic-tickets", split="train", keep_in_memory=True
865
+ )
866
+
867
+ nrows = nrows or len(dataset)
868
+
869
+ with collection.batch.fixed_size(batch_size=100) as batch:
870
+ for i in range(min(nrows, len(dataset))):
871
+ item = dataset[i]
872
+
873
+ if i % int(min(nrows, len(dataset)) / 10) == 0:
874
+ print(
875
+ f"Importing {i}/{min(nrows, len(dataset))} objects... (IT_Support_Tickets)",
876
+ file=sys.stderr,
877
+ )
878
+
879
+ if item and isinstance(item, dict):
880
+ batch.add_object(
881
+ properties={
882
+ "ticket_id": item["id"],
883
+ "subject": item["subject"],
884
+ "description": item["description"],
885
+ "priority": item["priority"],
886
+ "category": item["category"],
887
+ "createdAt": datetime.strptime(
888
+ item["createdAt"], "%Y-%m-%dT%H:%M:%S.%fZ"
889
+ ).replace(tzinfo=timezone.utc),
890
+ "requesterEmail": item["requesterEmail"],
891
+ }
892
+ )
893
+ if batch.number_errors > 10:
894
+ print(
895
+ "Batch import stopped due to excessive errors. Returning.",
896
+ file=sys.stderr,
897
+ )
898
+ break
899
+
900
+ failed_objects = collection.batch.failed_objects
901
+
902
+ if failed_objects:
903
+ print(
904
+ f"Number of failed imports: {len(failed_objects)}",
905
+ file=sys.stderr,
906
+ )
907
+ print(f"First failed object: {failed_objects[0]}", file=sys.stderr)
908
+ return
909
+
910
+ print(
911
+ f"Created collection 'IT_Support_Tickets' with {len(collection)} objects.",
912
+ file=sys.stderr,
913
+ )
914
+
915
+
916
+ @app.command()
917
+ def main(
918
+ domain: str = typer.Option("academic", "--domain", "-d"),
919
+ nrows: int = typer.Option(None, "--nrows", "-n"),
920
+ vectorizer: str = typer.Option(
921
+ "text2vec_weaviate",
922
+ "--vectorizer",
923
+ "-v",
924
+ help=f"Vectorizer to use. Options: {', '.join(VECTORIZER_MAP.keys())}",
925
+ ),
926
+ ):
927
+ """Download an example dataset from the Hugging Face dataset hub."""
928
+ with get_client() as client:
929
+ if domain == "academic":
930
+ create_ai_arxiv_collection(client, vectorizer, nrows)
931
+ elif domain == "finance":
932
+ create_income_tax_returns_collection(client, vectorizer, nrows)
933
+ elif domain == "ecommerce":
934
+ create_product_catalog_collection(client, vectorizer, nrows)
935
+ elif domain == "medical":
936
+ create_hair_medical_collection(client, vectorizer, nrows)
937
+ elif domain == "customer_support":
938
+ create_helpdesk_tickets_collection(client, vectorizer, nrows)
939
+ else:
940
+ print(f"Domain '{domain}' not supported. Returning.", file=sys.stderr)
941
+ raise typer.Exit(1)
942
+
943
+
944
+ if __name__ == "__main__":
945
+ app()