Skip to content

Commit 5325c82

Browse files
Merge branch 'main' into issue-18
2 parents b340f53 + 09eadb1 commit 5325c82

File tree

16 files changed

+762
-77
lines changed

16 files changed

+762
-77
lines changed

.github/workflows/cla.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
name: "MindsDB CLA Assistant"
2+
on:
3+
issue_comment:
4+
types: [created]
5+
pull_request_target:
6+
types: [opened,closed,synchronize]
7+
jobs:
8+
CLAssistant:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- name: "CLA Assistant"
12+
if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target'
13+
uses: contributor-assistant/[email protected]
14+
env:
15+
GITHUB_TOKEN: ${{ secrets.CLA_TOKEN }}
16+
PERSONAL_ACCESS_TOKEN : ${{ secrets.CLA_TOKEN }}
17+
with:
18+
path-to-signatures: 'assets/contributions-agreement/cla.json'
19+
# Add path to the CLA here
20+
path-to-document: 'https://github.com/mindsdb/mindsdb/blob/main/assets/contributions-agreement/individual-contributor.md'
21+
branch: 'cla'
22+
allowlist: bot*, ZoranPandovski, torrmal, Stpmax, mindsdbadmin, ea-rus, tmichaeldb, dusvyat, hamishfagg, MinuraPunchihewa, martyna-mindsdb, lucas-koontz

.github/workflows/test_on_deploy.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99
runs-on: ubuntu-latest
1010
strategy:
1111
matrix:
12-
python-version: ['3.8', '3.9','3.10', '3.11']
12+
python-version: ['3.10']
1313
steps:
1414
- name: Checkout code
1515
uses: actions/checkout@v2
@@ -28,4 +28,4 @@ jobs:
2828
env:
2929
PYTHONPATH: ./
3030
API_KEY: ${{ secrets.API_KEY }}
31-
BASE_URL: ${{ secrets.BASE_URL }}
31+
BASE_URL: 'https://mdb.ai'

README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,12 @@ client.datasources.drop('my_datasource')
149149
```
150150
>Note: The SDK currently does not support automatically removing a data source if it is no longer connected to any mind.
151151
152-
153152
### Other SDKs
154-
#### [Javascript](https://github.com/scshiv29-dev/mindsbd_sdk_js)
153+
- [Ruby-SDK](https://github.com/tungnt1203/minds_ruby_sdk)
154+
- [Dart-SDK](https://github.com/ArnavK-09/mdb_dart)
155+
- [Javascript](https://github.com/scshiv29-dev/mindsbd_sdk_js)
156+
157+
#### Command Line Tools
158+
- [Minds CLI](https://github.com/Better-Boy/minds-cli-sdk)
159+
160+

assets/contributions-agreement/cla.json

Whitespace-only changes.

minds/__about__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
__title__ = 'minds_sdk'
22
__package_name__ = 'minds'
3-
__version__ = '1.0.7'
3+
__version__ = '1.2.0'
44
__description__ = 'An AI-Data Mind is an LLM with the built-in power to answer data questions for Agents'
55
__email__ = '[email protected]'
66
__author__ = 'MindsDB Inc'

minds/client.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from minds.rest_api import RestAPI
33

44
from minds.datasources import Datasources
5+
from minds.knowledge_bases import KnowledgeBases
56
from minds.minds import Minds
67

78

@@ -12,5 +13,6 @@ def __init__(self, api_key, base_url=None):
1213
self.api = RestAPI(api_key, base_url)
1314

1415
self.datasources = Datasources(self)
16+
self.knowledge_bases = KnowledgeBases(self)
1517

1618
self.minds = Minds(self)

minds/datasources/datasources.py

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from typing import List, Optional, Union
22

33
from pydantic import BaseModel, Field
4-
4+
import minds.utils as utils
55
import minds.exceptions as exc
66

77
class DatabaseConfig(BaseModel):
@@ -16,11 +16,12 @@ class DatabaseConfig(BaseModel):
1616
class Datasource(DatabaseConfig):
1717
...
1818

19+
1920
class Datasources:
2021
def __init__(self, client):
2122
self.api = client.api
2223

23-
def create(self, ds_config: DatabaseConfig, replace=False):
24+
def create(self, ds_config: DatabaseConfig, update=False):
2425
"""
2526
Create new datasource and return it
2627
@@ -30,19 +31,18 @@ def create(self, ds_config: DatabaseConfig, replace=False):
3031
- description: str, description of the database. Used by mind to know what data can be got from it.
3132
- connection_data: dict, optional, credentials to connect to database
3233
- tables: list of str, optional, list of allowed tables
34+
:param update: if true - to update datasourse if exists, default is false
3335
:return: datasource object
3436
"""
3537

3638
name = ds_config.name
3739

38-
if replace:
39-
try:
40-
self.get(name)
41-
self.drop(name)
42-
except exc.ObjectNotFound:
43-
...
40+
utils.validate_datasource_name(name)
4441

45-
self.api.post('/datasources', data=ds_config.model_dump())
42+
if update:
43+
self.api.put(f'/datasources/{name}', data=ds_config.model_dump())
44+
else:
45+
self.api.post('/datasources', data=ds_config.model_dump())
4646
return self.get(name)
4747

4848
def list(self) -> List[Datasource]:
@@ -76,11 +76,15 @@ def get(self, name: str) -> Datasource:
7676
raise exc.ObjectNotSupported(f'Wrong type of datasource: {name}')
7777
return Datasource(**data)
7878

79-
def drop(self, name: str):
79+
def drop(self, name: str, force=False):
8080
"""
8181
Drop datasource by name
8282
8383
:param name: name of datasource
84+
:param force: if True - remove from all minds, default: False
8485
"""
86+
data = None
87+
if force:
88+
data = {'cascade': True}
8589

86-
self.api.delete(f'/datasources/{name}')
90+
self.api.delete(f'/datasources/{name}', data=data)

minds/exceptions.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,10 @@ class Unauthorized(Exception):
1818
class UnknownError(Exception):
1919
...
2020

21+
22+
class MindNameInvalid(Exception):
23+
...
24+
25+
26+
class DatasourceNameInvalid(Exception):
27+
...

minds/knowledge_bases/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from .knowledge_bases import *
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
from typing import Any, Dict, List, Optional, Union
2+
3+
from pydantic import BaseModel
4+
5+
from minds.knowledge_bases.preprocessing import PreprocessingConfig
6+
from minds.rest_api import RestAPI
7+
8+
9+
class VectorStoreConfig(BaseModel):
10+
'''Configuration for the underlying vector store for knowledge base embeddings'''
11+
engine: str
12+
connection_data: Dict[str, Any]
13+
table: str = 'embeddings'
14+
15+
16+
class EmbeddingConfig(BaseModel):
17+
'''Configuration for embeddings to use with underlying vector store for knowledge base'''
18+
provider: str
19+
model: str
20+
params: Optional[Dict[str, Any]] = None
21+
22+
23+
class KnowledgeBaseConfig(BaseModel):
24+
'''Configuration for a knowledge base'''
25+
name: str
26+
description: str
27+
vector_store_config: Optional[VectorStoreConfig] = None
28+
embedding_config: Optional[EmbeddingConfig] = None
29+
# Params to apply to retrieval pipeline.
30+
params: Optional[Dict] = None
31+
32+
33+
class KnowledgeBaseDocument(BaseModel):
34+
'''Represents a document that can be inserted into a knowledge base'''
35+
id: Union[int, str]
36+
content: str
37+
metadata: Optional[Dict[str, Any]] = {}
38+
39+
40+
class KnowledgeBase:
41+
def __init__(self, name, api: RestAPI):
42+
self.name = name
43+
self.api = api
44+
45+
def insert_from_select(self, query: str, preprocessing_config: PreprocessingConfig = None):
46+
'''
47+
Inserts select content of a connected datasource into this knowledge base
48+
49+
:param query: The SQL SELECT query to use to retrieve content to be inserted
50+
'''
51+
update_request = {
52+
'query': query
53+
}
54+
if preprocessing_config is not None:
55+
update_request['preprocessing'] = preprocessing_config.model_dump()
56+
_ = self.api.put(f'/knowledge_bases/{self.name}', data=update_request)
57+
58+
def insert_documents(self, documents: List[KnowledgeBaseDocument], preprocessing_config: PreprocessingConfig = None):
59+
'''
60+
Inserts documents directly into this knowledge base
61+
62+
:param documents: The documents to insert
63+
'''
64+
update_request = {
65+
'rows': [d.model_dump() for d in documents]
66+
}
67+
if preprocessing_config is not None:
68+
update_request['preprocessing'] = preprocessing_config.model_dump()
69+
_ = self.api.put(f'/knowledge_bases/{self.name}', data=update_request)
70+
71+
def insert_urls(self, urls: List[str], preprocessing_config: PreprocessingConfig = None):
72+
'''
73+
Crawls URLs & inserts the retrieved webpages into this knowledge base
74+
75+
:param urls: Valid URLs to crawl & insert
76+
'''
77+
update_request = {
78+
'urls': urls
79+
}
80+
if preprocessing_config is not None:
81+
update_request['preprocessing'] = preprocessing_config.model_dump()
82+
_ = self.api.put(f'/knowledge_bases/{self.name}', data=update_request)
83+
84+
def insert_files(self, files: List[str], preprocessing_config: PreprocessingConfig = None):
85+
'''
86+
Inserts files that have already been uploaded to MindsDB into this knowledge base
87+
88+
:param files: Names of preuploaded files to insert
89+
'''
90+
update_request = {
91+
'files': files
92+
}
93+
if preprocessing_config is not None:
94+
update_request['preprocessing'] = preprocessing_config.model_dump()
95+
_ = self.api.put(f'/knowledge_bases/{self.name}', data=update_request)
96+
97+
98+
class KnowledgeBases:
99+
def __init__(self, client):
100+
self.api = client.api
101+
102+
def create(self, config: KnowledgeBaseConfig) -> KnowledgeBase:
103+
'''
104+
Create new knowledge base and return it
105+
106+
:param config: knowledge base configuration, properties:
107+
- name: str, name of knowledge base
108+
- description: str, description of the knowledge base. Used by minds to know what data can be retrieved.
109+
- vector_store_config: VectorStoreConfig, configuration for embeddings vector store.
110+
- embedding_config: EmbeddingConfig, configuration for embeddings.
111+
:return: knowledge base object
112+
'''
113+
create_request = {
114+
'name': config.name,
115+
'description': config.description
116+
}
117+
if config.vector_store_config is not None:
118+
vector_store_data = {
119+
'engine': config.vector_store_config.engine,
120+
'connection_data': config.vector_store_config.connection_data
121+
}
122+
create_request['vector_store'] = vector_store_data
123+
if config.embedding_config is not None:
124+
embedding_data = {
125+
'provider': config.embedding_config.provider,
126+
'name': config.embedding_config.model
127+
}
128+
if config.embedding_config.params is not None:
129+
embedding_data.update(config.embedding_config.params)
130+
create_request['embedding_model'] = embedding_data
131+
if config.params is not None:
132+
create_request['params'] = config.params
133+
134+
_ = self.api.post('/knowledge_bases', data=create_request)
135+
return self.get(config.name)
136+
137+
def list(self) -> List[KnowledgeBase]:
138+
'''
139+
Returns list of knowledge bases
140+
141+
:return: iterable knowledge bases
142+
'''
143+
144+
list_knowledge_bases_response = self.api.get('/knowledge_bases')
145+
knowledge_bases = list_knowledge_bases_response.json()
146+
147+
all_knowledge_bases = []
148+
for knowledge_base in knowledge_bases:
149+
all_knowledge_bases.append(KnowledgeBase(knowledge_base['name'], self.api))
150+
return all_knowledge_bases
151+
152+
def get(self, name: str) -> KnowledgeBase:
153+
'''
154+
Get knowledge base by name
155+
156+
:param name: name of knowledge base
157+
:return: knowledge base object
158+
'''
159+
160+
knowledge_base_response = self.api.get(f'/knowledge_bases/{name}')
161+
knowledge_base = knowledge_base_response.json()
162+
return KnowledgeBase(knowledge_base['name'], self.api)
163+
164+
def drop(self, name: str, force=False):
165+
'''
166+
Drop knowledge base by name
167+
168+
:param name: name of knowledge base
169+
:param force: if True - remove from all minds, default: False
170+
'''
171+
data = None
172+
if force:
173+
data = {'cascade': True}
174+
175+
self.api.delete(f'/knowledge_bases/{name}', data=data)

0 commit comments

Comments
 (0)