crewplus 0.2.8__py3-none-any.whl → 0.2.10__py3-none-any.whl

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.

Potentially problematic release.


This version of crewplus might be problematic. Click here for more details.

crewplus/__init__.py CHANGED
@@ -0,0 +1,10 @@
1
+ from .services.gemini_chat_model import GeminiChatModel
2
+ from .services.model_load_balancer import ModelLoadBalancer
3
+ from .vectorstores.milvus import SchemaMilvus, VDBService
4
+
5
+ __all__ = [
6
+ "GeminiChatModel",
7
+ "ModelLoadBalancer",
8
+ "SchemaMilvus",
9
+ "VDBService"
10
+ ]
@@ -1 +1,6 @@
1
1
  from .gemini_chat_model import GeminiChatModel
2
+ from .init_services import init_load_balancer, get_model_balancer
3
+ from .model_load_balancer import ModelLoadBalancer
4
+
5
+
6
+ __all__ = ["GeminiChatModel", "init_load_balancer", "get_model_balancer", "ModelLoadBalancer"]
@@ -3,15 +3,11 @@ from crewplus.services.model_load_balancer import ModelLoadBalancer
3
3
 
4
4
  model_balancer = None
5
5
 
6
- def init_load_balancer(config_path: str = None):
6
+ def init_load_balancer():
7
7
  global model_balancer
8
8
  if model_balancer is None:
9
- # Use parameter if provided, otherwise check env var, then default
10
- final_config_path = config_path or os.getenv(
11
- "MODEL_CONFIG_PATH",
12
- "config/models_config.json" # Fixed default path
13
- )
14
- model_balancer = ModelLoadBalancer(final_config_path)
9
+ config_path = os.getenv("MODEL_CONFIG_PATH", "config/models_config.json")
10
+ model_balancer = ModelLoadBalancer(config_path)
15
11
  model_balancer.load_config() # Load initial configuration synchronously
16
12
 
17
13
  def get_model_balancer() -> ModelLoadBalancer:
@@ -141,7 +141,6 @@ class ModelLoadBalancer:
141
141
  return ChatOpenAI(**kwargs)
142
142
  elif provider == 'azure-openai-embeddings':
143
143
  return AzureOpenAIEmbeddings(
144
- model=model_config['model_name'],
145
144
  azure_deployment=model_config['deployment_name'],
146
145
  openai_api_version=model_config['api_version'],
147
146
  api_key=model_config['api_key'],
@@ -0,0 +1,4 @@
1
+ from .schema_action import Action
2
+ from .schema_document_updater import SchemaDocumentUpdater
3
+
4
+ __all__ = ["Action", "SchemaDocumentUpdater"]
@@ -0,0 +1,5 @@
1
+ from .milvus_schema_manager import MilvusSchemaManager, ZillizSchemaManager
2
+ from .schema_milvus import SchemaMilvus
3
+ from .vdb_service import VDBService
4
+
5
+ __all__ = ["MilvusSchemaManager", "ZillizSchemaManager", "VDBService"]
@@ -5,8 +5,7 @@ import json
5
5
  from pymilvus import DataType
6
6
  from langchain_milvus import Milvus
7
7
  from langchain_core.documents import Document
8
- from crewplus.utils.schema_document_updater import SchemaDocumentUpdater
9
- from crewplus.utils.schema_action import Action
8
+ from ...utils import SchemaDocumentUpdater, Action
10
9
  from .milvus_schema_manager import MilvusSchemaManager
11
10
 
12
11
 
@@ -22,22 +22,17 @@ class VDBService(object):
22
22
  and provides helper methods to get embedding functions and vector store instances.
23
23
 
24
24
  Args:
25
- settings (dict, optional): A dictionary containing configuration for the vector store
25
+ settings (dict): A dictionary containing configuration for the vector store
26
26
  and embedding models.
27
- endpoint (str, optional): The URI for the Zilliz cluster. Can be used for simple
28
- initialization instead of `settings`.
29
- token (str, optional): The token for authenticating with Zilliz. Must be provided
30
- with `endpoint`.
31
27
  schema (str, optional): The schema definition for a collection. Defaults to None.
32
28
  logger (logging.Logger, optional): An optional logger instance. Defaults to None.
33
29
 
34
30
  Raises:
35
- ValueError: If required configurations are missing.
31
+ ValueError: If required configurations are missing from the settings dictionary.
36
32
  NotImplementedError: If an unsupported provider is specified.
37
33
  RuntimeError: If the MilvusClient fails to initialize after a retry.
38
34
 
39
35
  Example:
40
- >>> # Initialize with a full settings dictionary
41
36
  >>> settings = {
42
37
  ... "embedder": {
43
38
  ... "provider": "azure-openai",
@@ -66,10 +61,6 @@ class VDBService(object):
66
61
  ... }
67
62
  ... }
68
63
  >>> vdb_service = VDBService(settings=settings)
69
- >>>
70
- >>> # Alternatively, initialize with an endpoint and token for Zilliz
71
- >>> # vdb_service_zilliz = VDBService(endpoint="YOUR_ZILLIZ_ENDPOINT", token="YOUR_ZILLIZ_TOKEN")
72
- >>>
73
64
  >>> # Get the raw Milvus client
74
65
  >>> client = vdb_service.get_vector_client()
75
66
  >>> print(client.list_collections())
@@ -91,41 +82,17 @@ class VDBService(object):
91
82
  connection_args: dict
92
83
  settings: dict
93
84
 
94
- def __init__(self, settings: dict = None, endpoint: str = None, token: str = None, schema: str = None, logger: logging.Logger = None):
85
+ def __init__(self, settings: dict, schema: str = None, logger: logging.Logger = None):
95
86
  """
96
87
  Initializes the VDBService.
97
-
98
- Can be initialized in two ways:
99
- 1. By providing a full `settings` dictionary for complex configurations.
100
- 2. By providing `endpoint` and `token` for a direct Zilliz connection.
101
- Note: When using this method, an `embedder` configuration is not created.
102
- You must either use the `ModelLoadBalancer` or pass an `Embeddings` object
103
- directly to methods like `get_vector_store`.
104
88
 
105
89
  Args:
106
- settings (dict, optional): Configuration dictionary for the service. Defaults to None.
107
- endpoint (str, optional): The URI for the Zilliz cluster. Used if `settings` is not provided.
108
- token (str, optional): The token for authenticating with the Zilliz cluster.
90
+ settings (dict): Configuration dictionary for the service.
109
91
  schema (str, optional): Default schema for new collections. Defaults to None.
110
92
  logger (logging.Logger, optional): Logger instance. Defaults to None.
111
93
  """
112
94
  self.logger = logger or logging.getLogger(__name__)
113
-
114
- if settings:
115
- self.settings = settings
116
- elif endpoint and token:
117
- self.logger.info("Initializing VDBService with endpoint and token for a Zilliz connection.")
118
- self.settings = {
119
- "vector_store": {
120
- "provider": "zilliz",
121
- "config": {
122
- "uri": endpoint,
123
- "token": token
124
- }
125
- }
126
- }
127
- else:
128
- raise ValueError("VDBService must be initialized with either a 'settings' dictionary or both 'endpoint' and 'token'.")
95
+ self.settings = settings
129
96
 
130
97
  vector_store_settings = self.settings.get("vector_store")
131
98
  if not vector_store_settings:
@@ -197,7 +164,7 @@ class VDBService(object):
197
164
  """
198
165
  return self._client
199
166
 
200
- def get_embeddings(self, from_model_balancer: bool = False, provider: Optional[str] = "azure-openai", model_type: Optional[str] = "embedding-large") -> Embeddings:
167
+ def get_embeddings(self, from_model_balancer: bool = False, model_type: Optional[str] = "embedding-large") -> Embeddings:
201
168
  """
202
169
  Gets an embedding function, either from the model balancer or directly from settings.
203
170
 
@@ -211,7 +178,7 @@ class VDBService(object):
211
178
  """
212
179
  if from_model_balancer:
213
180
  model_balancer = get_model_balancer()
214
- return model_balancer.get_model(provider=provider, model_type=model_type)
181
+ return model_balancer.get_model(model_type=model_type)
215
182
 
216
183
  embedder_config = self.settings.get("embedder")
217
184
  if not embedder_config:
@@ -248,8 +215,8 @@ class VDBService(object):
248
215
  def get_vector_store(self, collection_name: str, embeddings: Embeddings = None, metric_type: str = "L2") -> Zilliz:
249
216
  """
250
217
  Gets a vector store instance, creating it if it doesn't exist for the collection.
251
- This method validates both the embedding function and the vector store connection
252
- before caching the instance to prevent faulty instances from being reused.
218
+
219
+ This method caches instances by collection name to avoid re-instantiation.
253
220
 
254
221
  Args:
255
222
  collection_name (str): The name of the collection in the vector database.
@@ -272,19 +239,6 @@ class VDBService(object):
272
239
  if embeddings is None:
273
240
  embeddings = self.get_embeddings()
274
241
 
275
- # 1. Validate the embedding function before proceeding.
276
- try:
277
- self.logger.debug(f"Testing embedding function for collection '{collection_name}'...")
278
- embeddings.embed_query("validation_test_string")
279
- self.logger.debug("Embedding function is valid.")
280
- except Exception as e:
281
- self.logger.error(
282
- f"The provided embedding function is invalid and failed with error: {e}. "
283
- f"Cannot create a vector store for collection '{collection_name}'."
284
- )
285
- raise RuntimeError(f"Invalid embedding function provided.") from e
286
-
287
- # If embeddings are valid, proceed to create the Zilliz instance.
288
242
  index_params = self.index_params or {
289
243
  "metric_type": metric_type,
290
244
  "index_type": "AUTOINDEX",
@@ -303,48 +257,43 @@ class VDBService(object):
303
257
 
304
258
  return vdb
305
259
 
306
- def delete_old_indexes(self, url: str = None, vdb: Zilliz = None) -> (bool | None):
260
+ def delete_old_indexes(self, url: str = None, vdb: Zilliz = None) -> None:
307
261
  """ Delete old indexes of the same source_url
308
262
 
309
263
  Args:
310
264
  url (str): source url
311
- vdb (Zilliz): Zilliz instance
312
265
  """
313
- self.logger.info(f"Delete old indexes of the same source_url:{url}")
314
-
315
266
  if url is None or vdb is None:
316
- return None
267
+ return
317
268
 
318
269
  # Delete indexes of the same source_url
319
- expr = f'source_url == "{url}" or source == "{url}"'
270
+ expr = "source in [\"" + url + "\"]"
320
271
  pks = vdb.get_pks(expr)
321
272
 
322
273
  # Delete entities by pks
323
274
  if pks is not None and len(pks) > 0 :
324
- res = vdb.delete(pks)
325
- self.logger.info("Deleted old indexes result: " + str(res))
326
- return res
275
+ old_items = vdb.delete(pks)
276
+ self.logger.info("ingesting document -- delete old indexes -- " + str(old_items))
327
277
 
328
- def delete_old_indexes_by_id(self, source_id: str = None, vdb: Zilliz = None) -> (bool | None):
278
+ def delete_old_indexes_by_id(self, id: str = None, vdb: Zilliz = None) -> None:
329
279
  """ Delete old indexes of the same source_id
330
280
 
331
281
  Args:
332
- source_id (str): source id
282
+ id (str): source id
333
283
  """
334
- self.logger.info(f"Delete old indexes of the same source_id:{source_id}")
284
+ self.logger.info(f"Delete old indexes of the same source_id:{id}")
335
285
 
336
- if source_id is None or vdb is None:
337
- return None
286
+ if id is None or vdb is None:
287
+ return
338
288
 
339
289
  # Delete indexes of the same source_id
340
- expr = f'source_id == "{source_id}"'
290
+ expr = "source_id in [\"" + id + "\"]"
341
291
  pks = vdb.get_pks(expr)
342
292
 
343
293
  # Delete entities by pks
344
294
  if pks is not None and len(pks) > 0 :
345
- res = vdb.delete(pks)
346
- self.logger.info("Deleted old indexes result: " + str(res))
347
- return res
295
+ old_items = vdb.delete(pks)
296
+ self.logger.info("ingesting document -- delete old indexes -- " + str(old_items))
348
297
 
349
298
  def drop_collection(self, collection_name: str) -> None:
350
299
  """
@@ -377,13 +326,12 @@ class VDBService(object):
377
326
  self.logger.info(f"Removed '{collection_name}' from instance cache.")
378
327
 
379
328
  def delete_data_by_filter(self, collection_name: str = None, filter: str = None) -> None:
380
- """ Delete data by filter
329
+ """ Delete a collection
381
330
 
382
331
  Args:
383
- collection_name (str): collection_name
384
- filter (str): filter
332
+ collection_name (str): scollection_name
385
333
  """
386
- self.logger.info(f"Delete data by filter:{filter}")
334
+ self.logger.info(f"drop a collection by name:{collection_name}")
387
335
 
388
336
  try:
389
337
  client=self.get_vector_client()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: crewplus
3
- Version: 0.2.8
3
+ Version: 0.2.10
4
4
  Summary: Base services for CrewPlus AI applications
5
5
  Author-Email: Tim Liu <tim@opsmateai.com>
6
6
  License: MIT
@@ -45,7 +45,7 @@ CrewPlus is designed as a modular and extensible ecosystem of packages. This all
45
45
 
46
46
  - **Chat Services:** A unified interface for interacting with various chat models (e.g., `GeminiChatModel`).
47
47
  - **Model Load Balancer:** Intelligently distribute requests across multiple LLM endpoints.
48
- - **Vector DB Services:** working with popular vector stores (e.g. Milvus, Zilliz Cloud) for retrieval-augmented generation (RAG) and agent memory.
48
+ - **Vector DB Services:** Abstractions for working with popular vector stores for retrieval-augmented generation (RAG).
49
49
 
50
50
 
51
51
  ## Documentation
@@ -0,0 +1,17 @@
1
+ crewplus-0.2.10.dist-info/METADATA,sha256=dhdCQovu_z-D18b3ICUyk2URgFU8du9nv8U87BEnRbk,4882
2
+ crewplus-0.2.10.dist-info/WHEEL,sha256=9P2ygRxDrTJz3gsagc0Z96ukrxjr-LFBGOgv3AuKlCA,90
3
+ crewplus-0.2.10.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
4
+ crewplus-0.2.10.dist-info/licenses/LICENSE,sha256=2_NHSHRTKB_cTcT_GXgcenOCtIZku8j343mOgAguTfc,1087
5
+ crewplus/__init__.py,sha256=m46HkZL1Y4toD619NL47Sn2Qe084WFFSFD7e6VoYKZc,284
6
+ crewplus/services/__init__.py,sha256=ra_ciHcJN_sbv7q8UCP2kY91SbD32-QBpQLRgIosEcE,267
7
+ crewplus/services/gemini_chat_model.py,sha256=i9p5KvSJYaHSUBLPKM_bpyGVLWCDQoNeah_WjQVJRXs,26227
8
+ crewplus/services/init_services.py,sha256=5MlvZbyGPNgVA_2bPuxhhbw9TgD5rrvC0e_62YJh340,589
9
+ crewplus/services/model_load_balancer.py,sha256=a2BfcWV-OEItVf7_tTBYY0HiXxFzA5Uk7d-6AG-jLNU,8692
10
+ crewplus/utils/__init__.py,sha256=2Gk1n5srFJQnFfBuYTxktdtKOVZyNrFcNaZKhXk35Pw,142
11
+ crewplus/utils/schema_action.py,sha256=GDaBoVFQD1rXqrLVSMTfXYW1xcUu7eDcHsn57XBSnIg,422
12
+ crewplus/utils/schema_document_updater.py,sha256=frvffxn2vbi71fHFPoGb9hq7gH2azmmdq17p-Fumnvg,7322
13
+ crewplus/vectorstores/milvus/__init__.py,sha256=egGncAdjlXG6ekTQvKMKqhvKBifrUrPlsSB0-bpvq4A,229
14
+ crewplus/vectorstores/milvus/milvus_schema_manager.py,sha256=qHMVIM0NS3rLfACb8d3-tQS9hJo6_7_YP8AxVx4t1Cc,9019
15
+ crewplus/vectorstores/milvus/schema_milvus.py,sha256=5zubnhYwuA0bOoAlsOU8O3hAPjvtuFANHpO0E82b45Q,11354
16
+ crewplus/vectorstores/milvus/vdb_service.py,sha256=KiGuHWU9oz2QCCaxGECtN-F69m8ZOwjzPO0umk6ZjzA,14592
17
+ crewplus-0.2.10.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: pdm-backend (2.4.4)
2
+ Generator: pdm-backend (2.4.5)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,20 +0,0 @@
1
- crewplus-0.2.8.dist-info/METADATA,sha256=5CCjnb1jK-gH4BuW2dL2h6uQb-gcd5Kh711o5kl5NdY,4909
2
- crewplus-0.2.8.dist-info/WHEEL,sha256=tSfRZzRHthuv7vxpI4aehrdN9scLjk-dCJkPLzkHxGg,90
3
- crewplus-0.2.8.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
4
- crewplus-0.2.8.dist-info/licenses/LICENSE,sha256=2_NHSHRTKB_cTcT_GXgcenOCtIZku8j343mOgAguTfc,1087
5
- crewplus/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- crewplus/services/__init__.py,sha256=MmH2v3N0ZMsuqFNAupkXENjUqvgf5ehQ99H6EzPqLZU,48
7
- crewplus/services/gemini_chat_model.py,sha256=i9p5KvSJYaHSUBLPKM_bpyGVLWCDQoNeah_WjQVJRXs,26227
8
- crewplus/services/init_services.py,sha256=yD6gMbXnHfABa3yBxEYihiq2Kv5zxhBcyK4eNCTAETs,775
9
- crewplus/services/model_load_balancer.py,sha256=AKwgxZauXGcSQvFxYQT6tR57ZSYRVnWWZvLWAWTOewU,8743
10
- crewplus/utils/schema_action.py,sha256=GDaBoVFQD1rXqrLVSMTfXYW1xcUu7eDcHsn57XBSnIg,422
11
- crewplus/utils/schema_document_updater.py,sha256=frvffxn2vbi71fHFPoGb9hq7gH2azmmdq17p-Fumnvg,7322
12
- crewplus/vectorstores/milvus/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
- crewplus/vectorstores/milvus/milvus_schema_manager.py,sha256=qHMVIM0NS3rLfACb8d3-tQS9hJo6_7_YP8AxVx4t1Cc,9019
14
- crewplus/vectorstores/milvus/schema_milvus.py,sha256=GhHTtCH5HsIJc3RHa25RXl3aZdkS3Rba5KeuUk_Hi0k,11425
15
- crewplus/vectorstores/milvus/vdb_service.py,sha256=iCiSXcmtpD9tW1WYyJ1P0SRJEFEsUoH3lY65mnwf6R8,17524
16
- docs/GeminiChatModel.md,sha256=_IQyup3ofAa2HxfSurO1GYUEezTHYYt5Q1khYNVThGM,8040
17
- docs/ModelLoadBalancer.md,sha256=aGHES1dcXPz4c7Y8kB5-vsCNJjriH2SWmjBkSGoYKiI,4398
18
- docs/VDBService.md,sha256=Dw286Rrf_fsi13jyD3Bo4Sy7nZ_G7tYm7d8MZ2j9hxk,9375
19
- docs/index.md,sha256=3tlc15uR8lzFNM5WjdoZLw0Y9o1P1gwgbEnOdIBspqc,1643
20
- crewplus-0.2.8.dist-info/RECORD,,
docs/GeminiChatModel.md DELETED
@@ -1,226 +0,0 @@
1
- # GeminiChatModel Documentation
2
-
3
- ## 1. Introduction
4
-
5
- The `GeminiChatModel` is a custom LangChain-compatible chat model that provides a robust interface to Google's Gemini Pro and Flash models. It is designed to handle multimodal inputs, including text, images, and videos, making it a versatile tool for building advanced AI applications.
6
-
7
- ### Key Features:
8
- - **LangChain Compatibility**: Seamlessly integrates into the LangChain ecosystem as a `BaseChatModel`.
9
- - **Multimodal Support**: Natively processes text, images (from URLs, local paths, or base64), and videos (from local paths, Google Cloud URIs, or raw bytes).
10
- - **Streaming**: Supports streaming for both standard and multimodal responses.
11
- - **Advanced Configuration**: Allows fine-tuning of generation parameters like temperature, top-p, top-k, and max tokens.
12
- - **Video Segment Analysis**: Can process specific time ranges within a video using start and end offsets.
13
-
14
- ## 2. Installation
15
-
16
- To use the `GeminiChatModel`, you need to install the `crewplus` package. If you are working within the project repository, you can install it in editable mode:
17
-
18
- ```bash
19
- pip install crewplus
20
- ```
21
-
22
- ## 3. Initialization
23
-
24
- First, ensure you have set your Google API key as an environment variable:
25
-
26
- ```bash
27
- # For Linux/macOS
28
- export GOOGLE_API_KEY="YOUR_API_KEY"
29
-
30
- # For Windows PowerShell
31
- $env:GEMINI_API_KEY = "YOUR_API_KEY"
32
- ```
33
-
34
- Then, you can import and initialize the model in your Python code.
35
-
36
- ```python
37
- import logging
38
- from crewplus.services import GeminiChatModel
39
- from langchain_core.messages import HumanMessage
40
-
41
- # Optional: Configure a logger for detailed output
42
- logging.basicConfig(level=logging.INFO)
43
- test_logger = logging.getLogger(__name__)
44
-
45
- # Initialize the model
46
- # You can also pass the google_api_key directly as a parameter
47
- model = GeminiChatModel(
48
- model_name="gemini-2.5-flash", # Or "gemini-1.5-pro"
49
- logger=test_logger,
50
- temperature=0.0,
51
- )
52
- ```
53
-
54
- ## 4. Basic Usage (Text-only)
55
-
56
- The model can be used for simple text-based conversations using `.invoke()` or `.stream()`.
57
-
58
- ```python
59
- # Using invoke for a single response
60
- response = model.invoke("Hello, how are you?")
61
- print(response.content)
62
-
63
- # Using stream for a chunked response
64
- print("\\n--- Streaming Response ---")
65
- for chunk in model.stream("Tell me a short story."):
66
- print(chunk.content, end="", flush=True)
67
- ```
68
-
69
- ## 5. Image Understanding
70
-
71
- `GeminiChatModel` can understand images provided via a URL or as base64 encoded data.
72
-
73
- ### Example 1: Image from a URL
74
-
75
- You can provide a direct URL to an image.
76
-
77
- ```python
78
- from langchain_core.messages import HumanMessage
79
-
80
- url_message = HumanMessage(
81
- content=[
82
- {"type": "text", "text": "Describe this image:"},
83
- {
84
- "type": "image_url",
85
- "image_url": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg"
86
- },
87
- ]
88
- )
89
- url_response = model.invoke([url_message])
90
- print("Image response (URL):", url_response.content)
91
- ```
92
- > **Sample Output:**
93
- > The image shows a wooden boardwalk stretching into the distance through a field of tall, green grass... The overall impression is one of tranquility and natural beauty.
94
-
95
- ### Example 2: Local Image (Base64)
96
-
97
- You can also send a local image file by encoding it in base64.
98
-
99
- ```python
100
- import base64
101
- from langchain_core.messages import HumanMessage
102
-
103
- image_path = "./notebooks/test_image_202506191.jpg"
104
- try:
105
- with open(image_path, "rb") as image_file:
106
- encoded_string = base64.b64encode(image_file.read()).decode('utf-8')
107
-
108
- image_message = HumanMessage(
109
- content=[
110
- {"type": "text", "text": "Describe this photo and its background story."},
111
- {
112
- "type": "image_url",
113
- "image_url": {
114
- "url": f"data:image/jpeg;base64,{encoded_string}"
115
- }
116
- },
117
- ]
118
- )
119
- image_response = model.invoke([image_message])
120
- print("Image response (base64):", image_response.content)
121
- except FileNotFoundError:
122
- print(f"Image file not found at {image_path}, skipping base64 example.")
123
- ```
124
- > **Sample Output:**
125
- > This image is a movie still from the 2017 Japanese thriller "22 Year Old's Confession: I am the Murderer"... The four women in the photo are the victims of a serial killer...
126
-
127
- ## 6. Video Understanding
128
-
129
- The model supports video analysis from uploaded files, URIs, and raw bytes.
130
-
131
- **Important Note:** The Gemini API does **not** support common public video URLs (e.g., YouTube, Loom, or public MP4 links). Videos must be uploaded to Google's servers first to get a processable URI.
132
-
133
- ### Example 1: Large Video File (>20MB)
134
-
135
- For large videos, you must first upload the file using the `google-genai` client to get a file object.
136
-
137
- ```python
138
- from google import genai
139
- import os
140
- from langchain_core.messages import HumanMessage
141
-
142
- # Initialize the Google GenAI client
143
- client = genai.Client(api_key=os.environ["GOOGLE_API_KEY"])
144
-
145
- # Upload the video file
146
- video_path = "./notebooks/manufacturing_process_tutorial.mp4"
147
- print("Uploading video... this may take a moment.")
148
- video_file_obj = client.files.upload(file=video_path)
149
- print(f"Video uploaded successfully. File name: {video_file_obj.name}")
150
-
151
- # Use the uploaded file object in the prompt
152
- video_message = HumanMessage(
153
- content=[
154
- {"type": "text", "text": "Summarize this video and provide timestamps for key events."},
155
- {"type": "video_file", "file": video_file_obj},
156
- ]
157
- )
158
- video_response = model.invoke([video_message])
159
- print("Video response:", video_response.content)
160
- ```
161
-
162
- > **Sample Output:**
163
- > This video provides a step-by-step guide on how to correct a mis-set sidewall during tire manufacturing...
164
- > **Timestamps:**
165
- > * **0:04:** Applying product package to some material
166
- > * **0:12:** Splice product Together and Prepare some material
167
- > ...
168
-
169
- ### Example 2: Video with Time Offsets
170
-
171
- You can analyze just a specific portion of a video by providing a `start_offset` and `end_offset`. This works with video URIs obtained after uploading.
172
-
173
- ```python
174
- # Assuming 'video_file_obj' is available from the previous step
175
- video_uri = video_file_obj.uri
176
-
177
- offset_message = HumanMessage(
178
- content=[
179
- {"type": "text", "text": "Transcribe the events in this video segment."},
180
- {
181
- "type": "video_file",
182
- "url": video_uri,
183
- "start_offset": "5s",
184
- "end_offset": "30s"
185
- }
186
- ]
187
- )
188
-
189
- print("Streaming response for video segment:")
190
- for chunk in model.stream([offset_message]):
191
- print(chunk.content, end="", flush=True)
192
- ```
193
- > **Sample Output:**
194
- > This video demonstrates the process of applying Component A/Component B material to an assembly drum in a manufacturing setting...
195
- > **Transcription:**
196
- > **0:05 - 0:12:** A worker is shown applying a material...
197
- > **0:12 - 0:23:** The worker continues to prepare the material on the drum...
198
-
199
- ### Example 3: Small Video File (<20MB)
200
-
201
- For small videos, you can pass the raw bytes directly without a separate upload step.
202
-
203
- ```python
204
- from langchain_core.messages import HumanMessage
205
-
206
- try:
207
- with open("./notebooks/product_demo_v1.mp4", "rb") as video_file:
208
- video_bytes = video_file.read()
209
-
210
- video_message = HumanMessage(
211
- content=[
212
- {"type": "text", "text": "What is happening in this video?"},
213
- {
214
- "type": "video_file",
215
- "data": video_bytes,
216
- "mime_type": "video/mp4" # Mime type is required for raw data
217
- },
218
- ]
219
- )
220
- video_response = model.invoke([video_message])
221
- print("Video response (bytes):", video_response.content)
222
- except FileNotFoundError:
223
- print("Video file not found.")
224
- except Exception as e:
225
- print(f"Video processing with bytes failed: {e}")
226
- ```
docs/ModelLoadBalancer.md DELETED
@@ -1,134 +0,0 @@
1
- # ModelLoadBalancer Documentation
2
-
3
- ## 1. Introduction
4
-
5
- The `ModelLoadBalancer` is a utility class designed to manage and provide access to various language models from different providers, such as Azure OpenAI and Google GenAI. It loads model configurations from a JSON file and allows you to retrieve specific models by their deployment name or a combination of provider and type.
6
-
7
- ### Key Features:
8
- - **Centralized Model Management**: Manage all your model configurations in a single JSON file.
9
- - **On-demand Model Loading**: Models are instantiated and loaded when requested.
10
- - **Provider Agnostic**: Supports multiple model providers.
11
- - **Flexible Retrieval**: Get models by a unique deployment name.
12
-
13
- ## 2. Initialization
14
-
15
- To use the `ModelLoadBalancer`, you need to initialize it with the path to your model configuration file.
16
-
17
- ```python
18
- from crewplus.services.model_load_balancer import ModelLoadBalancer
19
-
20
- # Initialize the balancer with the path to your config file
21
- config_path = "tests/models_config.json" # Adjust the path as needed
22
- balancer = ModelLoadBalancer(config_path=config_path)
23
-
24
- # Load the configurations and instantiate the models
25
- balancer.load_config()
26
- ```
27
-
28
- ## 3. Configuration File
29
-
30
- The `ModelLoadBalancer` uses a JSON file to configure the available models. Here is an example of what the configuration file looks like. The `deployment_name` is used to retrieve a specific model.
31
-
32
- ```json
33
- {
34
- "models": [
35
- {
36
- "id": 3,
37
- "provider": "azure-openai",
38
- "type": "inference",
39
- "deployment_name": "gpt-4.1",
40
- "api_version": "2025-01-01-preview",
41
- "api_base": "https://crewplus-eastus2.openai.azure.com",
42
- "api_key": "your-api-key"
43
- },
44
- {
45
- "id": 7,
46
- "provider": "google-genai",
47
- "type": "inference",
48
- "deployment_name": "gemini-2.5-flash",
49
- "api_key": "your-google-api-key"
50
- },
51
- {
52
- "id": 8,
53
- "provider": "google-genai",
54
- "type": "ingestion",
55
- "deployment_name": "gemini-2.5-pro",
56
- "api_key": "your-google-api-key"
57
- }
58
- ]
59
- }
60
- ```
61
-
62
- ## 4. Getting a Model
63
-
64
- You can retrieve a model instance using the `get_model` method and passing the `deployment_name`.
65
-
66
- ### Get `gemini-2.5-flash`
67
- ```python
68
- gemini_flash_model = balancer.get_model(deployment_name="gemini-2.5-flash")
69
-
70
- # Now you can use the model
71
- # from langchain_core.messages import HumanMessage
72
- # response = gemini_flash_model.invoke([HumanMessage(content="Hello!")])
73
- # print(response.content)
74
- ```
75
-
76
- ### Get `gemini-2.5-pro`
77
- ```python
78
- gemini_pro_model = balancer.get_model(deployment_name="gemini-2.5-pro")
79
- ```
80
-
81
- ### Get `gpt-4.1`
82
- ```python
83
- gpt41_model = balancer.get_model(deployment_name="gpt-4.1")
84
- ```
85
-
86
- ### Get `o3mini`
87
- The model `o3mini` is identified by the deployment name `gpt-o3mini-eastus2-RPM25`.
88
- ```python
89
- o3mini_model = balancer.get_model(deployment_name="gpt-o3mini-eastus2-RPM25")
90
- ```
91
-
92
- ## 5. Global Access with `init_load_balancer`
93
-
94
- The `init_load_balancer` function provides a convenient singleton pattern for accessing the `ModelLoadBalancer` throughout your application without passing the instance around.
95
-
96
- First, you initialize the balancer once at the start of your application.
97
-
98
- ### Initialization
99
-
100
- You can initialize it in several ways:
101
-
102
- **1. Default Initialization**
103
-
104
- This will look for the `MODEL_CONFIG_PATH` environment variable, or use the default path `_config/models_config.json`.
105
-
106
- ```python
107
- from crewplus.services.init_services import init_load_balancer
108
-
109
- init_load_balancer()
110
- ```
111
-
112
- **2. Initialization with a Custom Path**
113
-
114
- You can also provide a direct path to your configuration file.
115
-
116
- ```python
117
- from crewplus.services.init_services import init_load_balancer
118
-
119
- init_load_balancer(config_path="path/to/your/models_config.json")
120
- ```
121
-
122
- ### Getting the Balancer and Models
123
-
124
- Once initialized, you can retrieve the `ModelLoadBalancer` instance from anywhere in your code using `get_model_balancer`.
125
-
126
- ```python
127
- from crewplus.services.init_services import get_model_balancer
128
-
129
- # Get the balancer instance
130
- balancer = get_model_balancer()
131
-
132
- # Get a model by deployment name
133
- gemini_flash_model = balancer.get_model(deployment_name="gemini-2.5-flash")
134
- ```
docs/VDBService.md DELETED
@@ -1,238 +0,0 @@
1
- # VDBService Documentation
2
-
3
- ## 1. Introduction
4
-
5
- The `VDBService` is a centralized service class designed to manage connections to vector databases (Milvus and Zilliz) and handle the instantiation of embedding models. It simplifies interactions with your vector store by reading all necessary configurations from a single `settings` object.
6
-
7
- ### Key Features:
8
- - **Centralized Configuration**: Manages database connections and embedding model settings from a single Python dictionary.
9
- - **Provider-Agnostic Client**: Supports both Milvus and Zilliz as vector store providers.
10
- - **Resilient Connection**: Includes a built-in retry mechanism when first connecting to the vector database.
11
- - **Instance Caching**: Caches `Zilliz` vector store instances by collection name to prevent re-instantiation and improve performance.
12
- - **Flexible Embedding Models**: Can retrieve embedding models from either the global `ModelLoadBalancer` or directly from the configuration settings.
13
-
14
- ## 2. Initialization
15
-
16
- To use the `VDBService`, you must first prepare a `settings` dictionary containing the configuration for your vector store and embedding provider. You then pass this dictionary to the service's constructor.
17
-
18
- If you plan to use embedding models from the global `ModelLoadBalancer`, you must initialize it first.
19
-
20
- ```python
21
- from crewplus.vectorstores.milvus.vdb_service import VDBService
22
- from crewplus.services.init_services import init_load_balancer
23
-
24
- # 1. (Optional) Initialize the global model load balancer if you plan to use it.
25
- # This should be done once when your application starts.
26
- init_load_balancer(config_path="path/to/your/models_config.json")
27
-
28
- # 2. Define the configuration for the VDBService
29
- settings = {
30
- "embedder": {
31
- "provider": "azure-openai",
32
- "config": {
33
- "model": "text-embedding-3-small",
34
- "api_version": "2023-05-15",
35
- "api_key": "YOUR_AZURE_OPENAI_KEY",
36
- "openai_base_url": "YOUR_AZURE_OPENAI_ENDPOINT",
37
- "embedding_dims": 1536
38
- }
39
- },
40
- "vector_store": {
41
- "provider": "milvus",
42
- "config": {
43
- "host": "localhost",
44
- "port": 19530,
45
- "user": "root",
46
- "password": "password",
47
- "db_name": "default"
48
- }
49
- },
50
- "index_params": {
51
- "metric_type": "L2",
52
- "index_type": "AUTOINDEX",
53
- "params": {}
54
- }
55
- }
56
-
57
- # 3. Initialize the VDBService with the settings
58
- vdb_service = VDBService(settings=settings)
59
-
60
- print("VDBService initialized successfully!")
61
- ```
62
-
63
- **Alternative Initialization for Zilliz**
64
-
65
- For a simpler Zilliz Cloud connection, you can initialize the service directly with your endpoint and token.
66
-
67
- ```python
68
- # Initialize directly with Zilliz credentials
69
- vdb_service_zilliz = VDBService(
70
- endpoint="YOUR_ZILLIZ_ENDPOINT",
71
- token="YOUR_ZILLIZ_TOKEN"
72
- )
73
-
74
- print("VDBService for Zilliz initialized successfully!")
75
- ```
76
-
77
- ## 3. Usage Examples
78
-
79
- ### Basic Usage: Get Vector Store with Default Embeddings
80
-
81
- This example shows how to get a vector store instance using the default embedding model specified in the `embedder` section of your settings.
82
-
83
- ```python
84
- # Get a vector store instance for the "my_documents" collection
85
- # This will use the "azure-openai" embedder from the settings by default.
86
- vector_store = vdb_service.get_vector_store(collection_name="my_documents")
87
-
88
- # You can now use the vector_store object to add or search for documents
89
- # vector_store.add_texts(["some text to embed"])
90
- print(f"Successfully retrieved vector store for collection: {vector_store.collection_name}")
91
- ```
92
-
93
- ### Advanced Usage: Using an Embedding Model from the Model Load Balancer
94
-
95
- In some cases, you may want to use a specific embedding model managed by the central `ModelLoadBalancer`. This example demonstrates how to retrieve that model first and then pass it to `get_vector_store`.
96
-
97
- This requires the `ModelLoadBalancer` to have been initialized, as shown in the Initialization section above.
98
-
99
- ```python
100
- # 1. Get a specific embedding model from the ModelLoadBalancer
101
- # The service will call get_model_balancer() internally to get the initialized instance.
102
- embedding_model = vdb_service.get_embeddings(
103
- from_model_balancer=True,
104
- provider="azure-openai-embeddings",
105
- model_type="embedding-large" # Specify the model type configured in the balancer
106
- )
107
-
108
- print(f"Retrieved embedding model from balancer: {embedding_model}")
109
-
110
- # 2. Get a vector store instance using the specified embedding model
111
- vector_store_from_balancer = vdb_service.get_vector_store(
112
- collection_name="balancer_collection",
113
- embeddings=embedding_model # Pass the specific embedding model
114
- )
115
-
116
- print(f"Successfully retrieved vector store for collection: {vector_store_from_balancer.collection_name}")
117
- ```
118
-
119
- ### Getting the Raw Milvus Client
120
-
121
- If you need to perform operations not exposed by the LangChain `Zilliz` wrapper, you can get direct access to the underlying `MilvusClient`.
122
-
123
- ```python
124
- # Get the raw Milvus client to perform advanced operations
125
- client = vdb_service.get_vector_client()
126
-
127
- # For example, list all collections in the database
128
- collections = client.list_collections()
129
- print("Available collections:", collections)
130
- ```
131
-
132
- ### Adding and Deleting Documents by Source
133
-
134
- This example shows a common workflow: adding documents with a specific `source` to a collection, and then using `delete_old_indexes` to remove them based on that source.
135
-
136
- **Note:** The `delete_old_indexes` method in this example filters on the `source` metadata field. Ensure your implementation matches the field you intend to use for filtering.
137
-
138
- ```python
139
- from langchain_core.documents import Document
140
- import time
141
-
142
- # 1. Get the vector store instance
143
- collection_name = "test_collection_for_delete"
144
- vector_store = vdb_service.get_vector_store(collection_name=collection_name)
145
-
146
- # 2. Prepare documents with 'source' in their metadata.
147
- # The delete function looks for this specific metadata field.
148
- docs_to_add = [
149
- Document(
150
- page_content="This is a test document about CrewPlus AI.",
151
- metadata={"source": "http://example.com/crewplus-docs"}
152
- ),
153
- Document(
154
- page_content="This is another test document, about LangChain.",
155
- metadata={"source": "http://example.com/langchain-docs"} # Different source
156
- )
157
- ]
158
-
159
- # 3. Add the documents to the collection
160
- ids = vector_store.add_documents(docs_to_add)
161
- print(f"Added {len(ids)} documents to collection '{collection_name}'.")
162
-
163
- # In a real application, you might need a short delay for indexing to complete.
164
- time.sleep(2)
165
-
166
- # 4. Verify the documents were added
167
- results = vector_store.similarity_search("CrewPlus", k=2)
168
- print(f"Found {len(results)} related documents before deletion.")
169
- assert len(results) > 0
170
-
171
- # 5. Delete the documents using the same source
172
- source_to_delete = "http://example.com/crewplus-docs"
173
- vdb_service.delete_old_indexes(url=source_to_delete, vdb=vector_store)
174
- print(f"Called delete_old_indexes for source: {source_to_delete}")
175
-
176
- # Allow time for the deletion to be processed.
177
- time.sleep(2)
178
-
179
- # 6. Verify the documents were deleted
180
- results_after_delete = vector_store.similarity_search("CrewPlus", k=2)
181
- print(f"Found {len(results_after_delete)} related documents after deletion.")
182
- assert len(results_after_delete) == 0
183
-
184
- # 7. Clean up by dropping the collection
185
- vdb_service.drop_collection(collection_name=collection_name)
186
- print(f"Dropped collection '{collection_name}'.")
187
- ```
188
-
189
- ### Adding and Deleting Documents by Source ID
190
-
191
- This example shows how to add documents with a `source_id` and then use `delete_old_indexes_by_id` to remove them.
192
-
193
- ```python
194
- from langchain_core.documents import Document
195
- import time
196
-
197
- # 1. Get the vector store instance
198
- collection_name = "test_collection_for_id_delete"
199
- vector_store_for_id = vdb_service.get_vector_store(collection_name=collection_name)
200
-
201
- # 2. Prepare documents with 'source_id' in their metadata.
202
- docs_with_id = [
203
- Document(
204
- page_content="Document for agent A.",
205
- metadata={"source_id": "agent-a-123"}
206
- ),
207
- Document(
208
- page_content="Another document for agent A.",
209
- metadata={"source_id": "agent-a-123"}
210
- )
211
- ]
212
-
213
- # 3. Add the documents to the collection
214
- ids = vector_store_for_id.add_documents(docs_with_id)
215
- print(f"Added {len(ids)} documents to collection '{collection_name}'.")
216
-
217
- time.sleep(2)
218
-
219
- # 4. Verify the documents were added
220
- results = vector_store_for_id.similarity_search("agent A", k=2)
221
- print(f"Found {len(results)} related documents before deletion.")
222
- assert len(results) == 2
223
-
224
- # 5. Delete the documents using the source_id
225
- id_to_delete = "agent-a-123"
226
- vdb_service.delete_old_indexes_by_id(source_id=id_to_delete, vdb=vector_store_for_id)
227
- print(f"Called delete_old_indexes_by_id for source_id: {id_to_delete}")
228
-
229
- time.sleep(2)
230
-
231
- # 6. Verify the documents were deleted
232
- results_after_delete = vector_store_for_id.similarity_search("agent A", k=2)
233
- print(f"Found {len(results_after_delete)} related documents after deletion.")
234
- assert len(results_after_delete) == 0
235
-
236
- # 7. Clean up by dropping the collection
237
- vdb_service.drop_collection(collection_name=collection_name)
238
- print(f"Dropped collection '{collection_name}'.")
docs/index.md DELETED
@@ -1,23 +0,0 @@
1
- # Welcome to CrewPlus
2
-
3
- **CrewPlus** provides the foundational services and core components for building advanced AI applications. It is the heart of the CrewPlus ecosystem, designed for scalability, extensibility, and seamless integration.
4
-
5
- ## Overview
6
-
7
- This repository, `crewplus-base`, contains the core `crewplus` Python package. It includes essential building blocks for interacting with large language models, managing vector databases, and handling application configuration. Whether you are building a simple chatbot or a complex multi-agent system, CrewPlus offers the robust foundation you need.
8
-
9
- ## The CrewPlus Ecosystem
10
-
11
- CrewPlus is designed as a modular and extensible ecosystem of packages. This allows you to adopt only the components you need for your specific use case.
12
-
13
- - **`crewplus` (This package):** The core package containing foundational services for chat, model load balancing, and vector stores.
14
- - **`crewplus-agents`:** An extension for creating and managing autonomous AI agents.
15
- - **`crewplus-ingestion`:** Provides robust pipelines for knowledge ingestion and data processing.
16
- - **`crewplus-integrations`:** A collection of third-party integrations to connect CrewPlus with other services and platforms.
17
-
18
- ## Getting Started
19
-
20
- To get started, check out our detailed user guides:
21
-
22
- - **[GeminiChatModel Guide](./GeminiChatModel.md)**: A comprehensive guide to using the `GeminiChatModel` for text, image, and video understanding.
23
- - **[ModelLoadBalancer Guide](./ModelLoadBalancer.md)**: A guide to using the `ModelLoadBalancer` for managing and accessing different language models.