vanna 0.7.5__py3-none-any.whl → 0.7.7__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.
vanna/base/base.py CHANGED
@@ -306,7 +306,7 @@ class VannaBase(ABC):
306
306
 
307
307
  message_log = [
308
308
  self.system_message(
309
- f"You are a helpful data assistant. The user asked the question: '{question}'\n\nThe SQL query for this question was: {sql}\n\nThe following is a pandas DataFrame with the results of the query: \n{df.to_markdown()}\n\n"
309
+ f"You are a helpful data assistant. The user asked the question: '{question}'\n\nThe SQL query for this question was: {sql}\n\nThe following is a pandas DataFrame with the results of the query: \n{df.head(25).to_markdown()}\n\n"
310
310
  ),
311
311
  self.user_message(
312
312
  f"Generate a list of {n_questions} followup questions that the user might ask about this data. Respond with a list of questions, one per line. Do not answer with any explanations -- just the questions. Remember that there should be an unambiguous SQL query that can be generated from the question. Prefer questions that are answerable outside of the context of this conversation. Prefer questions that are slight modifications of the SQL query that was generated that allow digging deeper into the data. Each question will be turned into a button that the user can click to generate a new SQL query so don't use 'example' type questions. Each question must have a one-to-one correspondence with an instantiated SQL query." +
@@ -689,6 +689,9 @@ class VannaBase(ABC):
689
689
  return response
690
690
 
691
691
  def _extract_python_code(self, markdown_string: str) -> str:
692
+ # Strip whitespace to avoid indentation errors in LLM-generated code
693
+ markdown_string = markdown_string.strip()
694
+
692
695
  # Regex pattern to match Python code blocks
693
696
  pattern = r"```[\w\s]*python\n([\s\S]*?)```|```([\s\S]*?)```"
694
697
 
@@ -1167,7 +1170,7 @@ class VannaBase(ABC):
1167
1170
  vn.connect_to_oracle(
1168
1171
  user="username",
1169
1172
  password="password",
1170
- dns="host:port/sid",
1173
+ dsn="host:port/sid",
1171
1174
  )
1172
1175
  ```
1173
1176
  Args:
@@ -0,0 +1,2 @@
1
+ from .cohere_chat import Cohere_Chat
2
+ from .cohere_embeddings import Cohere_Embeddings
@@ -0,0 +1,94 @@
1
+ import os
2
+
3
+ from openai import OpenAI
4
+
5
+ from ..base import VannaBase
6
+
7
+
8
+ class Cohere_Chat(VannaBase):
9
+ def __init__(self, client=None, config=None):
10
+ VannaBase.__init__(self, config=config)
11
+
12
+ # default parameters - can be overridden using config
13
+ self.temperature = 0.2 # Lower temperature for more precise SQL generation
14
+ self.model = "command-a-03-2025" # Cohere's default model
15
+
16
+ if config is not None:
17
+ if "temperature" in config:
18
+ self.temperature = config["temperature"]
19
+ if "model" in config:
20
+ self.model = config["model"]
21
+
22
+ if client is not None:
23
+ self.client = client
24
+ return
25
+
26
+ # Check for API key in environment variable
27
+ api_key = os.getenv("COHERE_API_KEY")
28
+
29
+ # Check for API key in config
30
+ if config is not None and "api_key" in config:
31
+ api_key = config["api_key"]
32
+
33
+ # Validate API key
34
+ if not api_key:
35
+ raise ValueError("Cohere API key is required. Please provide it via config or set the COHERE_API_KEY environment variable.")
36
+
37
+ # Initialize client with validated API key
38
+ self.client = OpenAI(
39
+ base_url="https://api.cohere.ai/compatibility/v1",
40
+ api_key=api_key,
41
+ )
42
+
43
+ def system_message(self, message: str) -> any:
44
+ return {"role": "developer", "content": message} # Cohere uses 'developer' for system role
45
+
46
+ def user_message(self, message: str) -> any:
47
+ return {"role": "user", "content": message}
48
+
49
+ def assistant_message(self, message: str) -> any:
50
+ return {"role": "assistant", "content": message}
51
+
52
+ def submit_prompt(self, prompt, **kwargs) -> str:
53
+ if prompt is None:
54
+ raise Exception("Prompt is None")
55
+
56
+ if len(prompt) == 0:
57
+ raise Exception("Prompt is empty")
58
+
59
+ # Count the number of tokens in the message log
60
+ # Use 4 as an approximation for the number of characters per token
61
+ num_tokens = 0
62
+ for message in prompt:
63
+ num_tokens += len(message["content"]) / 4
64
+
65
+ # Use model from kwargs, config, or default
66
+ model = kwargs.get("model", self.model)
67
+ if self.config is not None and "model" in self.config and model == self.model:
68
+ model = self.config["model"]
69
+
70
+ print(f"Using model {model} for {num_tokens} tokens (approx)")
71
+ try:
72
+ response = self.client.chat.completions.create(
73
+ model=model,
74
+ messages=prompt,
75
+ temperature=self.temperature,
76
+ )
77
+
78
+ # Check if response has expected structure
79
+ if not response or not hasattr(response, 'choices') or not response.choices:
80
+ raise ValueError("Received empty or malformed response from API")
81
+
82
+ if not response.choices[0] or not hasattr(response.choices[0], 'message'):
83
+ raise ValueError("Response is missing expected 'message' field")
84
+
85
+ if not hasattr(response.choices[0].message, 'content'):
86
+ raise ValueError("Response message is missing expected 'content' field")
87
+
88
+ return response.choices[0].message.content
89
+
90
+ except Exception as e:
91
+ # Log the error and raise a more informative exception
92
+ error_msg = f"Error processing Cohere chat response: {str(e)}"
93
+ print(error_msg)
94
+ raise Exception(error_msg)
@@ -0,0 +1,71 @@
1
+ import os
2
+
3
+ from openai import OpenAI
4
+
5
+ from ..base import VannaBase
6
+
7
+
8
+ class Cohere_Embeddings(VannaBase):
9
+ def __init__(self, client=None, config=None):
10
+ VannaBase.__init__(self, config=config)
11
+
12
+ # Default embedding model
13
+ self.model = "embed-multilingual-v3.0"
14
+
15
+ if config is not None and "model" in config:
16
+ self.model = config["model"]
17
+
18
+ if client is not None:
19
+ self.client = client
20
+ return
21
+
22
+ # Check for API key in environment variable
23
+ api_key = os.getenv("COHERE_API_KEY")
24
+
25
+ # Check for API key in config
26
+ if config is not None and "api_key" in config:
27
+ api_key = config["api_key"]
28
+
29
+ # Validate API key
30
+ if not api_key:
31
+ raise ValueError("Cohere API key is required. Please provide it via config or set the COHERE_API_KEY environment variable.")
32
+
33
+ # Initialize client with validated API key
34
+ self.client = OpenAI(
35
+ base_url="https://api.cohere.ai/compatibility/v1",
36
+ api_key=api_key,
37
+ )
38
+
39
+ def generate_embedding(self, data: str, **kwargs) -> list[float]:
40
+ if not data:
41
+ raise ValueError("Cannot generate embedding for empty input data")
42
+
43
+ # Use model from kwargs, config, or default
44
+ model = kwargs.get("model", self.model)
45
+ if self.config is not None and "model" in self.config and model == self.model:
46
+ model = self.config["model"]
47
+
48
+ try:
49
+ embedding = self.client.embeddings.create(
50
+ model=model,
51
+ input=data,
52
+ encoding_format="float", # Ensure we get float values
53
+ )
54
+
55
+ # Check if response has expected structure
56
+ if not embedding or not hasattr(embedding, 'data') or not embedding.data:
57
+ raise ValueError("Received empty or malformed embedding response from API")
58
+
59
+ if not embedding.data[0] or not hasattr(embedding.data[0], 'embedding'):
60
+ raise ValueError("Embedding response is missing expected 'embedding' field")
61
+
62
+ if not embedding.data[0].embedding:
63
+ raise ValueError("Received empty embedding vector")
64
+
65
+ return embedding.data[0].embedding
66
+
67
+ except Exception as e:
68
+ # Log the error and raise a more informative exception
69
+ error_msg = f"Error generating embedding with Cohere: {str(e)}"
70
+ print(error_msg)
71
+ raise Exception(error_msg)
@@ -0,0 +1 @@
1
+ from .deepseek_chat import DeepSeekChat
@@ -0,0 +1,60 @@
1
+ import os
2
+
3
+ from openai import OpenAI
4
+
5
+ from ..base import VannaBase
6
+
7
+
8
+
9
+ # from vanna.chromadb import ChromaDB_VectorStore
10
+
11
+ # class DeepSeekVanna(ChromaDB_VectorStore, DeepSeekChat):
12
+ # def __init__(self, config=None):
13
+ # ChromaDB_VectorStore.__init__(self, config=config)
14
+ # DeepSeekChat.__init__(self, config=config)
15
+
16
+ # vn = DeepSeekVanna(config={"api_key": "sk-************", "model": "deepseek-chat"})
17
+
18
+
19
+ class DeepSeekChat(VannaBase):
20
+ def __init__(self, config=None):
21
+ if config is None:
22
+ raise ValueError(
23
+ "For DeepSeek, config must be provided with an api_key and model"
24
+ )
25
+ if "api_key" not in config:
26
+ raise ValueError("config must contain a DeepSeek api_key")
27
+
28
+ if "model" not in config:
29
+ raise ValueError("config must contain a DeepSeek model")
30
+
31
+ api_key = config["api_key"]
32
+ model = config["model"]
33
+ self.model = model
34
+ self.client = OpenAI(api_key=api_key, base_url="https://api.deepseek.com/v1")
35
+
36
+ def system_message(self, message: str) -> any:
37
+ return {"role": "system", "content": message}
38
+
39
+ def user_message(self, message: str) -> any:
40
+ return {"role": "user", "content": message}
41
+
42
+ def assistant_message(self, message: str) -> any:
43
+ return {"role": "assistant", "content": message}
44
+
45
+ def generate_sql(self, question: str, **kwargs) -> str:
46
+ # 使用父类的 generate_sql
47
+ sql = super().generate_sql(question, **kwargs)
48
+
49
+ # 替换 "\_" 为 "_"
50
+ sql = sql.replace("\\_", "_")
51
+
52
+ return sql
53
+
54
+ def submit_prompt(self, prompt, **kwargs) -> str:
55
+ chat_response = self.client.chat.completions.create(
56
+ model=self.model,
57
+ messages=prompt,
58
+ )
59
+
60
+ return chat_response.choices[0].message.content
@@ -1,4 +1,5 @@
1
1
  import os
2
+
2
3
  from ..base import VannaBase
3
4
 
4
5
 
@@ -30,8 +31,29 @@ class GoogleGeminiChat(VannaBase):
30
31
  self.chat_model = genai.GenerativeModel(model_name)
31
32
  else:
32
33
  # Authenticate using VertexAI
34
+ import google.auth
35
+ import vertexai
33
36
  from vertexai.generative_models import GenerativeModel
34
- self.chat_model = GenerativeModel(model_name)
37
+
38
+ json_file_path = config.get("google_credentials") # Assuming the JSON file path is provided in the config
39
+
40
+ if not json_file_path or not os.path.exists(json_file_path):
41
+ raise FileNotFoundError(f"JSON credentials file not found at: {json_file_path}")
42
+
43
+ try:
44
+ # Validate and set the JSON file path for GOOGLE_APPLICATION_CREDENTIALS
45
+ os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = json_file_path
46
+
47
+ # Initialize VertexAI with the credentials
48
+ credentials, _ = google.auth.default()
49
+ vertexai.init(credentials=credentials)
50
+ self.chat_model = GenerativeModel(model_name)
51
+ except google.auth.exceptions.DefaultCredentialsError as e:
52
+ raise RuntimeError(f"Default credentials error: {e}")
53
+ except google.auth.exceptions.TransportError as e:
54
+ raise RuntimeError(f"Transport error during authentication: {e}")
55
+ except Exception as e:
56
+ raise RuntimeError(f"Failed to authenticate using JSON file: {e}")
35
57
 
36
58
  def system_message(self, message: str) -> any:
37
59
  return message
vanna/ollama/ollama.py CHANGED
@@ -91,7 +91,7 @@ class Ollama(VannaBase):
91
91
  f"model={self.model},\n"
92
92
  f"options={self.ollama_options},\n"
93
93
  f"keep_alive={self.keep_alive}")
94
- self.log(f"Prompt Content:\n{json.dumps(prompt)}")
94
+ self.log(f"Prompt Content:\n{json.dumps(prompt, ensure_ascii=False)}")
95
95
  response_dict = self.ollama_client.chat(model=self.model,
96
96
  messages=prompt,
97
97
  stream=False,
@@ -1 +1,2 @@
1
1
  from .opensearch_vector import OpenSearch_VectorStore
2
+ from .opensearch_vector_semantic import OpenSearch_Semantic_VectorStore
@@ -0,0 +1,175 @@
1
+ import json
2
+
3
+ import pandas as pd
4
+ from langchain_community.vectorstores import OpenSearchVectorSearch
5
+
6
+ from ..base import VannaBase
7
+ from ..utils import deterministic_uuid
8
+
9
+
10
+ class OpenSearch_Semantic_VectorStore(VannaBase):
11
+ def __init__(self, config=None):
12
+ VannaBase.__init__(self, config=config)
13
+ if config is None:
14
+ config = {}
15
+
16
+ if "embedding_function" in config:
17
+ self.embedding_function = config.get("embedding_function")
18
+ else:
19
+ from langchain_huggingface import HuggingFaceEmbeddings
20
+ self.embedding_function = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2")
21
+
22
+ self.n_results_sql = config.get("n_results_sql", config.get("n_results", 10))
23
+ self.n_results_documentation = config.get("n_results_documentation", config.get("n_results", 10))
24
+ self.n_results_ddl = config.get("n_results_ddl", config.get("n_results", 10))
25
+
26
+ self.document_index = config.get("es_document_index", "vanna_document_index")
27
+ self.ddl_index = config.get("es_ddl_index", "vanna_ddl_index")
28
+ self.question_sql_index = config.get("es_question_sql_index", "vanna_questions_sql_index")
29
+
30
+ self.log(f"OpenSearch_Semantic_VectorStore initialized with document_index: {self.document_index}, ddl_index: {self.ddl_index}, question_sql_index: {self.question_sql_index}")
31
+
32
+ es_urls = config.get("es_urls", "https://localhost:9200")
33
+ ssl = config.get("es_ssl", True)
34
+ verify_certs = config.get("es_verify_certs", True)
35
+
36
+ if "es_user" in config:
37
+ auth = (config["es_user"], config["es_password"])
38
+ else:
39
+ auth = None
40
+
41
+ headers = config.get("es_headers", None)
42
+ timeout = config.get("es_timeout", 60)
43
+ max_retries = config.get("es_max_retries", 10)
44
+
45
+ common_args = {
46
+ "opensearch_url": es_urls,
47
+ "embedding_function": self.embedding_function,
48
+ "engine": "faiss",
49
+ "http_auth": auth,
50
+ "use_ssl": ssl,
51
+ "verify_certs": verify_certs,
52
+ "timeout": timeout,
53
+ "max_retries": max_retries,
54
+ "retry_on_timeout": True,
55
+ "headers": headers,
56
+ }
57
+
58
+ self.documentation_store = OpenSearchVectorSearch(index_name=self.document_index, **common_args)
59
+ self.ddl_store = OpenSearchVectorSearch(index_name=self.ddl_index, **common_args)
60
+ self.sql_store = OpenSearchVectorSearch(index_name=self.question_sql_index, **common_args)
61
+
62
+ def add_ddl(self, ddl: str, **kwargs) -> str:
63
+ _id = deterministic_uuid(ddl) + "-ddl"
64
+ self.ddl_store.add_texts(texts=[ddl], ids=[_id], **kwargs)
65
+ return _id
66
+
67
+ def add_documentation(self, documentation: str, **kwargs) -> str:
68
+ _id = deterministic_uuid(documentation) + "-doc"
69
+ self.documentation_store.add_texts(texts=[documentation], ids=[_id], **kwargs)
70
+ return _id
71
+
72
+ def add_question_sql(self, question: str, sql: str, **kwargs) -> str:
73
+ question_sql_json = json.dumps(
74
+ {
75
+ "question": question,
76
+ "sql": sql,
77
+ },
78
+ ensure_ascii=False,
79
+ )
80
+
81
+ _id = deterministic_uuid(question_sql_json) + "-sql"
82
+ self.sql_store.add_texts(texts=[question_sql_json], ids=[_id], **kwargs)
83
+ return _id
84
+
85
+ def get_related_ddl(self, question: str, **kwargs) -> list:
86
+ documents = self.ddl_store.similarity_search(query=question, k=self.n_results_ddl)
87
+ return [document.page_content for document in documents]
88
+
89
+ def get_related_documentation(self, question: str, **kwargs) -> list:
90
+ documents = self.documentation_store.similarity_search(query=question, k=self.n_results_documentation)
91
+ return [document.page_content for document in documents]
92
+
93
+ def get_similar_question_sql(self, question: str, **kwargs) -> list:
94
+ documents = self.sql_store.similarity_search(query=question, k=self.n_results_sql)
95
+ return [json.loads(document.page_content) for document in documents]
96
+
97
+ def get_training_data(self, **kwargs) -> pd.DataFrame:
98
+ data = []
99
+ query = {
100
+ "query": {
101
+ "match_all": {}
102
+ }
103
+ }
104
+
105
+ indices = [
106
+ {"index": self.document_index, "type": "documentation"},
107
+ {"index": self.question_sql_index, "type": "sql"},
108
+ {"index": self.ddl_index, "type": "ddl"},
109
+ ]
110
+
111
+ # Use documentation_store.client consistently for search on all indices
112
+ opensearch_client = self.documentation_store.client
113
+
114
+ for index_info in indices:
115
+ index_name = index_info["index"]
116
+ training_data_type = index_info["type"]
117
+ scroll = '1m' # keep scroll context for 1 minute
118
+ response = opensearch_client.search(
119
+ index=index_name,
120
+ ignore_unavailable=True,
121
+ body=query,
122
+ scroll=scroll,
123
+ size=1000
124
+ )
125
+
126
+ scroll_id = response.get('_scroll_id')
127
+
128
+ while scroll_id:
129
+ hits = response['hits']['hits']
130
+ if not hits:
131
+ break # No more hits, exit loop
132
+
133
+ for hit in hits:
134
+ source = hit['_source']
135
+ if training_data_type == "sql":
136
+ try:
137
+ doc_dict = json.loads(source['text'])
138
+ content = doc_dict.get("sql")
139
+ question = doc_dict.get("question")
140
+ except json.JSONDecodeError as e:
141
+ self.log(f"Skipping row with custom_id {hit['_id']} due to JSON parsing error: {e}","Error")
142
+ continue
143
+ else: # documentation or ddl
144
+ content = source['text']
145
+ question = None
146
+
147
+ data.append({
148
+ "id": hit["_id"],
149
+ "training_data_type": training_data_type,
150
+ "question": question,
151
+ "content": content,
152
+ })
153
+
154
+ # Get next batch of results, using documentation_store.client.scroll
155
+ response = opensearch_client.scroll(scroll_id=scroll_id, scroll=scroll)
156
+ scroll_id = response.get('_scroll_id')
157
+
158
+ return pd.DataFrame(data)
159
+
160
+ def remove_training_data(self, id: str, **kwargs) -> bool:
161
+ try:
162
+ if id.endswith("-sql"):
163
+ return self.sql_store.delete(ids=[id], **kwargs)
164
+ elif id.endswith("-ddl"):
165
+ return self.ddl_store.delete(ids=[id], **kwargs)
166
+ elif id.endswith("-doc"):
167
+ return self.documentation_store.delete(ids=[id], **kwargs)
168
+ else:
169
+ return False
170
+ except Exception as e:
171
+ self.log(f"Error deleting training dataError deleting training data: {e}", "Error")
172
+ return False
173
+
174
+ def generate_embedding(self, data: str, **kwargs) -> list[float]:
175
+ pass
@@ -0,0 +1 @@
1
+ from .oracle_vector import Oracle_VectorStore
@@ -0,0 +1,585 @@
1
+ import json
2
+ import uuid
3
+ from typing import List, Optional, Tuple
4
+
5
+ import oracledb
6
+ import pandas as pd
7
+ from chromadb.utils import embedding_functions
8
+
9
+ from ..base import VannaBase
10
+
11
+ default_ef = embedding_functions.DefaultEmbeddingFunction()
12
+
13
+
14
+ class Oracle_VectorStore(VannaBase):
15
+ def __init__(self, config=None):
16
+ VannaBase.__init__(self, config=config)
17
+
18
+ if config is not None:
19
+ self.embedding_function = config.get(
20
+ "embedding_function",
21
+ default_ef
22
+ )
23
+ self.pre_delete_collection = config.get("pre_delete_collection",
24
+ False)
25
+ self.cmetadata = config.get("cmetadata", {"created_by": "oracle"})
26
+ else:
27
+ self.embedding_function = default_ef
28
+ self.pre_delete_collection = False
29
+ self.cmetadata = {"created_by": "oracle"}
30
+
31
+ self.oracle_conn = oracledb.connect(dsn=config.get("dsn"))
32
+ self.oracle_conn.call_timeout = 30000
33
+ self.documentation_collection = "documentation"
34
+ self.ddl_collection = "ddl"
35
+ self.sql_collection = "sql"
36
+ self.n_results = config.get("n_results", 10)
37
+ self.n_results_ddl = config.get("n_results_ddl", self.n_results)
38
+ self.n_results_sql = config.get("n_results_sql", self.n_results)
39
+ self.n_results_documentation = config.get("n_results_documentation",
40
+ self.n_results)
41
+ self.create_tables_if_not_exists()
42
+ self.create_collections_if_not_exists(self.documentation_collection)
43
+ self.create_collections_if_not_exists(self.ddl_collection)
44
+ self.create_collections_if_not_exists(self.sql_collection)
45
+
46
+ def generate_embedding(self, data: str, **kwargs) -> List[float]:
47
+ embeddings = self.embedding_function([data])
48
+ if len(embeddings) == 1:
49
+ return list(embeddings[0].astype(float))
50
+ return list(embeddings.astype(float))
51
+
52
+ def add_question_sql(self, question: str, sql: str, **kwargs) -> str:
53
+ cmetadata = self.cmetadata.copy()
54
+ collection = self.get_collection(self.sql_collection)
55
+ question_sql_json = json.dumps(
56
+ {
57
+ "question": question,
58
+ "sql": sql,
59
+ },
60
+ ensure_ascii=False,
61
+ )
62
+ id = str(uuid.uuid4())
63
+ embeddings = self.generate_embedding(question)
64
+ custom_id = id + "-sql"
65
+
66
+ cursor = self.oracle_conn.cursor()
67
+ cursor.setinputsizes(None, oracledb.DB_TYPE_VECTOR)
68
+ cursor.execute(
69
+ """
70
+ INSERT INTO oracle_embedding (
71
+ collection_id,
72
+ embedding,
73
+ document,
74
+ cmetadata,
75
+ custom_id,
76
+ uuid
77
+ ) VALUES (
78
+ :1,
79
+ TO_VECTOR(:2),
80
+ :3,
81
+ :4,
82
+ :5,
83
+ :6
84
+ )
85
+ """, [
86
+ collection["uuid"],
87
+ embeddings,
88
+ question_sql_json,
89
+ json.dumps(cmetadata),
90
+ custom_id,
91
+ id
92
+ ]
93
+ )
94
+
95
+ self.oracle_conn.commit()
96
+ cursor.close()
97
+ return id
98
+
99
+ def add_ddl(self, ddl: str, **kwargs) -> str:
100
+ collection = self.get_collection(self.ddl_collection)
101
+ question_ddl_json = json.dumps(
102
+ {
103
+ "question": None,
104
+ "ddl": ddl,
105
+ },
106
+ ensure_ascii=False,
107
+ )
108
+ id = str(uuid.uuid4())
109
+ custom_id = id + "-ddl"
110
+ cursor = self.oracle_conn.cursor()
111
+ cursor.setinputsizes(None, oracledb.DB_TYPE_VECTOR)
112
+ cursor.execute(
113
+ """
114
+ INSERT INTO oracle_embedding (
115
+ collection_id,
116
+ embedding,
117
+ document,
118
+ cmetadata,
119
+ custom_id,
120
+ uuid
121
+ ) VALUES (
122
+ :1,
123
+ TO_VECTOR(:2),
124
+ :3,
125
+ :4,
126
+ :5,
127
+ :6
128
+ )
129
+ """, [
130
+ collection["uuid"],
131
+ self.generate_embedding(ddl),
132
+ question_ddl_json,
133
+ json.dumps(self.cmetadata),
134
+ custom_id,
135
+ id
136
+ ]
137
+ )
138
+ self.oracle_conn.commit()
139
+ cursor.close()
140
+ return id
141
+
142
+ def add_documentation(self, documentation: str, **kwargs) -> str:
143
+ collection = self.get_collection(self.documentation_collection)
144
+ question_documentation_json = json.dumps(
145
+ {
146
+ "question": None,
147
+ "documentation": documentation,
148
+ },
149
+ ensure_ascii=False,
150
+ )
151
+ id = str(uuid.uuid4())
152
+ custom_id = id + "-doc"
153
+ cursor = self.oracle_conn.cursor()
154
+ cursor.setinputsizes(None, oracledb.DB_TYPE_VECTOR)
155
+ cursor.execute(
156
+ """
157
+ INSERT INTO oracle_embedding (
158
+ collection_id,
159
+ embedding,
160
+ document,
161
+ cmetadata,
162
+ custom_id,
163
+ uuid
164
+ ) VALUES (
165
+ :1,
166
+ TO_VECTOR(:2),
167
+ :3,
168
+ :4,
169
+ :5,
170
+ :6
171
+ )
172
+ """, [
173
+ collection["uuid"],
174
+ self.generate_embedding(documentation),
175
+ question_documentation_json,
176
+ json.dumps(self.cmetadata),
177
+ custom_id,
178
+ id
179
+ ]
180
+ )
181
+ self.oracle_conn.commit()
182
+ cursor.close()
183
+ return id
184
+
185
+ def get_training_data(self, **kwargs) -> pd.DataFrame:
186
+ df = pd.DataFrame()
187
+
188
+ cursor = self.oracle_conn.cursor()
189
+ sql_collection = self.get_collection(self.sql_collection)
190
+ cursor.execute(
191
+ """
192
+ SELECT
193
+ document,
194
+ uuid
195
+ FROM oracle_embedding
196
+ WHERE
197
+ collection_id = :1
198
+ """, [
199
+ sql_collection["uuid"]
200
+ ]
201
+ )
202
+ sql_data = cursor.fetchall()
203
+
204
+ if sql_data is not None:
205
+ # Extract the documents and ids
206
+ documents = [row_data[0] for row_data in sql_data]
207
+ ids = [row_data[1] for row_data in sql_data]
208
+
209
+ # Create a DataFrame
210
+ df_sql = pd.DataFrame(
211
+ {
212
+ "id": ids,
213
+ "question": [
214
+ json.loads(doc)["question"] if isinstance(doc,
215
+ str) else
216
+ doc[
217
+ "question"] for doc in documents],
218
+ "content": [
219
+ json.loads(doc)["sql"] if isinstance(doc, str) else
220
+ doc["sql"] for
221
+ doc in documents],
222
+ }
223
+ )
224
+ df_sql["training_data_type"] = "sql"
225
+ df = pd.concat([df, df_sql])
226
+
227
+ ddl_collection = self.get_collection(self.ddl_collection)
228
+ cursor.execute(
229
+ """
230
+ SELECT
231
+ document,
232
+ uuid
233
+ FROM oracle_embedding
234
+ WHERE
235
+ collection_id = :1
236
+ """, [ddl_collection["uuid"]])
237
+ ddl_data = cursor.fetchall()
238
+
239
+ if ddl_data is not None:
240
+ # Extract the documents and ids
241
+ documents = [row_data[0] for row_data in ddl_data]
242
+ ids = [row_data[1] for row_data in ddl_data]
243
+
244
+ # Create a DataFrame
245
+ df_ddl = pd.DataFrame(
246
+ {
247
+ "id": ids,
248
+ "question": [None for _ in documents],
249
+ "content": [
250
+ json.loads(doc)["ddl"] if isinstance(doc, str) else
251
+ doc["ddl"] for
252
+ doc in documents],
253
+ }
254
+ )
255
+ df_ddl["training_data_type"] = "ddl"
256
+ df = pd.concat([df, df_ddl])
257
+
258
+ doc_collection = self.get_collection(self.documentation_collection)
259
+ cursor.execute(
260
+ """
261
+ SELECT
262
+ document,
263
+ uuid
264
+ FROM oracle_embedding
265
+ WHERE
266
+ collection_id = :1
267
+ """, [doc_collection["uuid"]])
268
+ doc_data = cursor.fetchall()
269
+
270
+ if doc_data is not None:
271
+ # Extract the documents and ids
272
+ documents = [row_data[0] for row_data in doc_data]
273
+ ids = [row_data[1] for row_data in doc_data]
274
+
275
+ # Create a DataFrame
276
+ df_doc = pd.DataFrame(
277
+ {
278
+ "id": ids,
279
+ "question": [None for _ in documents],
280
+ "content": [
281
+ json.loads(doc)["documentation"] if isinstance(doc,
282
+ str) else
283
+ doc[
284
+ "documentation"] for
285
+ doc in documents],
286
+ }
287
+ )
288
+ df_doc["training_data_type"] = "documentation"
289
+ df = pd.concat([df, df_doc])
290
+
291
+ self.oracle_conn.commit()
292
+ cursor.close()
293
+ return df
294
+
295
+ def remove_training_data(self, id: str, **kwargs) -> bool:
296
+ cursor = self.oracle_conn.cursor()
297
+ cursor.execute(
298
+ """
299
+ DELETE
300
+ FROM
301
+ oracle_embedding
302
+ WHERE
303
+ uuid = :1
304
+ """, [id])
305
+
306
+ self.oracle_conn.commit()
307
+ cursor.close()
308
+ return True
309
+
310
+ def update_training_data(self, id: str, train_type: str, question: str,
311
+ **kwargs) -> bool:
312
+ print(f"{train_type=}")
313
+ update_content = kwargs["content"]
314
+ if train_type == 'sql':
315
+ update_json = json.dumps(
316
+ {
317
+ "question": question,
318
+ "sql": update_content,
319
+ }
320
+ )
321
+ elif train_type == 'ddl':
322
+ update_json = json.dumps(
323
+ {
324
+ "question": None,
325
+ "ddl": update_content,
326
+ }
327
+ )
328
+ elif train_type == 'documentation':
329
+ update_json = json.dumps(
330
+ {
331
+ "question": None,
332
+ "documentation": update_content,
333
+ }
334
+ )
335
+ else:
336
+ update_json = json.dumps(
337
+ {
338
+ "question": question,
339
+ "sql": update_content,
340
+ }
341
+ )
342
+ cursor = self.oracle_conn.cursor()
343
+ cursor.setinputsizes(oracledb.DB_TYPE_VECTOR, oracledb.DB_TYPE_JSON)
344
+ cursor.execute(
345
+ """
346
+ UPDATE
347
+ oracle_embedding
348
+ SET
349
+ embedding = TO_VECTOR(:1),
350
+ document = JSON_MERGEPATCH(document, :2)
351
+ WHERE
352
+ uuid = :3
353
+ """, [
354
+ self.generate_embedding(update_content),
355
+ update_json,
356
+ id
357
+ ]
358
+ )
359
+
360
+ self.oracle_conn.commit()
361
+ cursor.close()
362
+ return True
363
+
364
+ @staticmethod
365
+ def _extract_documents(query_results) -> list:
366
+ """
367
+ Static method to extract the documents from the results of a query.
368
+
369
+ Args:
370
+ query_results (pd.DataFrame): The dataframe to use.
371
+
372
+ Returns:
373
+ List[str] or None: The extracted documents, or an empty list or single document if an error occurred.
374
+ """
375
+ if query_results is None or len(query_results) == 0:
376
+ return []
377
+
378
+ documents = [
379
+ json.loads(row_data[0]) if isinstance(row_data[0], str) else
380
+ row_data[0]
381
+ for row_data in query_results]
382
+
383
+ return documents
384
+
385
+ def get_similar_question_sql(self, question: str, **kwargs) -> list:
386
+ embeddings = self.generate_embedding(question)
387
+ collection = self.get_collection(self.sql_collection)
388
+ cursor = self.oracle_conn.cursor()
389
+ cursor.setinputsizes(None, oracledb.DB_TYPE_VECTOR,
390
+ oracledb.DB_TYPE_VECTOR)
391
+ cursor.execute(
392
+ """
393
+ SELECT document
394
+ FROM oracle_embedding
395
+ WHERE collection_id = :1
396
+ ORDER BY VECTOR_DISTANCE(embedding, TO_VECTOR(:2), COSINE)
397
+ FETCH FIRST :3 ROWS ONLY
398
+ """, [
399
+ collection["uuid"],
400
+ embeddings,
401
+ self.n_results_sql
402
+ ]
403
+ )
404
+ results = cursor.fetchall()
405
+ cursor.close()
406
+ return self._extract_documents(results)
407
+
408
+ def get_related_ddl(self, question: str, **kwargs) -> list:
409
+ collection = self.get_collection(self.ddl_collection)
410
+ cursor = self.oracle_conn.cursor()
411
+ cursor.setinputsizes(None, oracledb.DB_TYPE_VECTOR)
412
+ cursor.execute(
413
+ """
414
+ SELECT
415
+ document
416
+ FROM oracle_embedding
417
+ WHERE
418
+ collection_id = :1
419
+ ORDER BY VECTOR_DISTANCE(embedding, TO_VECTOR(:2), COSINE)
420
+ FETCH FIRST :top_k ROWS ONLY
421
+ """, [
422
+ collection["uuid"],
423
+ self.generate_embedding(question),
424
+ 100
425
+ ]
426
+ )
427
+ results = cursor.fetchall()
428
+
429
+ self.oracle_conn.commit()
430
+ cursor.close()
431
+ return Oracle_VectorStore._extract_documents(results)
432
+
433
+ def search_tables_metadata(self,
434
+ engine: str = None,
435
+ catalog: str = None,
436
+ schema: str = None,
437
+ table_name: str = None,
438
+ ddl: str = None,
439
+ size: int = 10,
440
+ **kwargs) -> list:
441
+ pass
442
+
443
+ def get_related_documentation(self, question: str, **kwargs) -> list:
444
+ collection = self.get_collection(self.documentation_collection)
445
+ cursor = self.oracle_conn.cursor()
446
+ cursor.setinputsizes(None, oracledb.DB_TYPE_VECTOR)
447
+ cursor.execute(
448
+ """
449
+ SELECT
450
+ document
451
+ FROM oracle_embedding
452
+ WHERE
453
+ collection_id = :1
454
+ ORDER BY VECTOR_DISTANCE(embedding, TO_VECTOR(:2), DOT)
455
+ FETCH FIRST :top_k ROWS ONLY
456
+ """, [
457
+ collection["uuid"],
458
+ self.generate_embedding(question),
459
+ 100
460
+ ]
461
+ )
462
+ results = cursor.fetchall()
463
+
464
+ self.oracle_conn.commit()
465
+ cursor.close()
466
+
467
+ return Oracle_VectorStore._extract_documents(results)
468
+
469
+ def create_tables_if_not_exists(self) -> None:
470
+ cursor = self.oracle_conn.cursor()
471
+ cursor.execute(
472
+ """
473
+ CREATE TABLE IF NOT EXISTS oracle_collection (
474
+ name VARCHAR2(200) NOT NULL,
475
+ cmetadata json NOT NULL,
476
+ uuid VARCHAR2(200) NOT NULL,
477
+ CONSTRAINT oc_key_uuid PRIMARY KEY ( uuid )
478
+ )
479
+ """
480
+ )
481
+
482
+ cursor.execute(
483
+ """
484
+ CREATE TABLE IF NOT EXISTS oracle_embedding (
485
+ collection_id VARCHAR2(200) NOT NULL,
486
+ embedding vector NOT NULL,
487
+ document json NOT NULL,
488
+ cmetadata json NOT NULL,
489
+ custom_id VARCHAR2(200) NOT NULL,
490
+ uuid VARCHAR2(200) NOT NULL,
491
+ CONSTRAINT oe_key_uuid PRIMARY KEY ( uuid )
492
+ )
493
+ """
494
+ )
495
+
496
+ self.oracle_conn.commit()
497
+ cursor.close()
498
+
499
+ def create_collections_if_not_exists(
500
+ self,
501
+ name: str,
502
+ cmetadata: Optional[dict] = None,
503
+ ) -> Tuple[dict, bool]:
504
+ """
505
+ Get or create a collection.
506
+ Returns [Collection, bool] where the bool is True if the collection was created.
507
+ """
508
+ if self.pre_delete_collection:
509
+ self.delete_collection(name)
510
+ created = False
511
+ collection = self.get_collection(name)
512
+ if collection:
513
+ return collection, created
514
+
515
+ cmetadata = json.dumps(
516
+ self.cmetadata) if cmetadata is None else json.dumps(cmetadata)
517
+ collection_id = str(uuid.uuid4())
518
+ cursor = self.oracle_conn.cursor()
519
+ cursor.execute(
520
+ """
521
+ INSERT INTO oracle_collection(name, cmetadata, uuid)
522
+ VALUES (:1, :2, :3)
523
+ """, [
524
+ name,
525
+ cmetadata,
526
+ str(collection_id)
527
+ ]
528
+ )
529
+
530
+ self.oracle_conn.commit()
531
+ cursor.close()
532
+
533
+ collection = {"name": name, "cmetadata": cmetadata,
534
+ "uuid": collection_id}
535
+ created = True
536
+ return collection, created
537
+
538
+ def get_collection(self, name) -> Optional[dict]:
539
+ return self.get_by_name(name)
540
+
541
+ def get_by_name(self, name: str) -> Optional[dict]:
542
+ cursor = self.oracle_conn.cursor()
543
+ cursor.execute(
544
+ """
545
+ SELECT
546
+ name,
547
+ cmetadata,
548
+ uuid
549
+ FROM
550
+ oracle_collection
551
+ WHERE
552
+ name = :1
553
+ FETCH FIRST 1 ROWS ONLY
554
+ """, [name])
555
+
556
+ for row in cursor:
557
+ return {"name": row[0], "cmetadata": row[1], "uuid": row[2]}
558
+
559
+ return # type: ignore
560
+
561
+ def delete_collection(self, name) -> None:
562
+ collection = self.get_collection(name)
563
+ if not collection:
564
+ return
565
+
566
+ cursor = self.oracle_conn.cursor()
567
+ cursor.execute(
568
+ """
569
+ DELETE
570
+ FROM
571
+ oracle_embedding
572
+ WHERE
573
+ collection_id = ( SELECT uuid FROM oracle_collection WHERE name = :1 )
574
+ """, [name])
575
+ cursor.execute(
576
+ """
577
+ DELETE
578
+ FROM
579
+ oracle_collection
580
+ WHERE
581
+ name = :1
582
+ """, [name])
583
+
584
+ self.oracle_conn.commit()
585
+ cursor.close()
vanna/remote.py CHANGED
@@ -62,7 +62,7 @@ class VannaDefault(VannaDB_VectorStore):
62
62
 
63
63
  def submit_prompt(self, prompt, **kwargs) -> str:
64
64
  # JSON-ify the prompt
65
- json_prompt = json.dumps(prompt)
65
+ json_prompt = json.dumps(prompt, ensure_ascii=False)
66
66
 
67
67
  params = [StringData(data=json_prompt)]
68
68
 
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: vanna
3
- Version: 0.7.5
3
+ Version: 0.7.7
4
4
  Summary: Generate SQL queries from natural language
5
5
  Author-email: Zain Hoda <zain@vanna.ai>
6
6
  Requires-Python: >=3.9
@@ -8,6 +8,7 @@ Description-Content-Type: text/markdown
8
8
  Classifier: Programming Language :: Python :: 3
9
9
  Classifier: License :: OSI Approved :: MIT License
10
10
  Classifier: Operating System :: OS Independent
11
+ License-File: LICENSE
11
12
  Requires-Dist: requests
12
13
  Requires-Dist: tabulate
13
14
  Requires-Dist: plotly
@@ -40,7 +41,7 @@ Requires-Dist: httpx ; extra == "all"
40
41
  Requires-Dist: opensearch-py ; extra == "all"
41
42
  Requires-Dist: opensearch-dsl ; extra == "all"
42
43
  Requires-Dist: transformers ; extra == "all"
43
- Requires-Dist: pinecone-client ; extra == "all"
44
+ Requires-Dist: pinecone ; extra == "all"
44
45
  Requires-Dist: pymilvus[model] ; extra == "all"
45
46
  Requires-Dist: weaviate-client ; extra == "all"
46
47
  Requires-Dist: azure-search-documents ; extra == "all"
@@ -52,6 +53,8 @@ Requires-Dist: boto3 ; extra == "all"
52
53
  Requires-Dist: botocore ; extra == "all"
53
54
  Requires-Dist: langchain_core ; extra == "all"
54
55
  Requires-Dist: langchain_postgres ; extra == "all"
56
+ Requires-Dist: langchain-community ; extra == "all"
57
+ Requires-Dist: langchain-huggingface ; extra == "all"
55
58
  Requires-Dist: xinference-client ; extra == "all"
56
59
  Requires-Dist: anthropic ; extra == "anthropic"
57
60
  Requires-Dist: azure-search-documents ; extra == "azuresearch"
@@ -79,8 +82,12 @@ Requires-Dist: httpx ; extra == "ollama"
79
82
  Requires-Dist: openai ; extra == "openai"
80
83
  Requires-Dist: opensearch-py ; extra == "opensearch"
81
84
  Requires-Dist: opensearch-dsl ; extra == "opensearch"
85
+ Requires-Dist: langchain-community ; extra == "opensearch"
86
+ Requires-Dist: langchain-huggingface ; extra == "opensearch"
87
+ Requires-Dist: oracledb ; extra == "oracle"
88
+ Requires-Dist: chromadb ; extra == "oracle"
82
89
  Requires-Dist: langchain-postgres>=0.0.12 ; extra == "pgvector"
83
- Requires-Dist: pinecone-client ; extra == "pinecone"
90
+ Requires-Dist: pinecone ; extra == "pinecone"
84
91
  Requires-Dist: fastembed ; extra == "pinecone"
85
92
  Requires-Dist: psycopg2-binary ; extra == "postgres"
86
93
  Requires-Dist: db-dtypes ; extra == "postgres"
@@ -115,6 +122,7 @@ Provides-Extra: mysql
115
122
  Provides-Extra: ollama
116
123
  Provides-Extra: openai
117
124
  Provides-Extra: opensearch
125
+ Provides-Extra: oracle
118
126
  Provides-Extra: pgvector
119
127
  Provides-Extra: pinecone
120
128
  Provides-Extra: postgres
@@ -129,9 +137,9 @@ Provides-Extra: zhipuai
129
137
 
130
138
 
131
139
 
132
- | GitHub | PyPI | Documentation |
133
- | ------ | ---- | ------------- |
134
- | [![GitHub](https://img.shields.io/badge/GitHub-vanna-blue?logo=github)](https://github.com/vanna-ai/vanna) | [![PyPI](https://img.shields.io/pypi/v/vanna?logo=pypi)](https://pypi.org/project/vanna/) | [![Documentation](https://img.shields.io/badge/Documentation-vanna-blue?logo=read-the-docs)](https://vanna.ai/docs/) |
140
+ | GitHub | PyPI | Documentation | Gurubase |
141
+ | ------ | ---- | ------------- | -------- |
142
+ | [![GitHub](https://img.shields.io/badge/GitHub-vanna-blue?logo=github)](https://github.com/vanna-ai/vanna) | [![PyPI](https://img.shields.io/pypi/v/vanna?logo=pypi)](https://pypi.org/project/vanna/) | [![Documentation](https://img.shields.io/badge/Documentation-vanna-blue?logo=read-the-docs)](https://vanna.ai/docs/) | [![Gurubase](https://img.shields.io/badge/Gurubase-Ask%20Vanna%20Guru-006BFF)](https://gurubase.io/g/vanna) |
135
143
 
136
144
  # Vanna
137
145
  Vanna is an MIT-licensed open-source Python RAG (Retrieval-Augmented Generation) framework for SQL generation and related functionality.
@@ -164,6 +172,46 @@ These are some of the user interfaces that we've built using Vanna. You can use
164
172
  - [vanna-ai/vanna-flask](https://github.com/vanna-ai/vanna-flask)
165
173
  - [vanna-ai/vanna-slack](https://github.com/vanna-ai/vanna-slack)
166
174
 
175
+ ## Supported LLMs
176
+
177
+ - [OpenAI](https://github.com/vanna-ai/vanna/tree/main/src/vanna/openai)
178
+ - [Anthropic](https://github.com/vanna-ai/vanna/tree/main/src/vanna/anthropic)
179
+ - [Gemini](https://github.com/vanna-ai/vanna/blob/main/src/vanna/google/gemini_chat.py)
180
+ - [HuggingFace](https://github.com/vanna-ai/vanna/blob/main/src/vanna/hf/hf.py)
181
+ - [AWS Bedrock](https://github.com/vanna-ai/vanna/tree/main/src/vanna/bedrock)
182
+ - [Ollama](https://github.com/vanna-ai/vanna/tree/main/src/vanna/ollama)
183
+ - [Qianwen](https://github.com/vanna-ai/vanna/tree/main/src/vanna/qianwen)
184
+ - [Qianfan](https://github.com/vanna-ai/vanna/tree/main/src/vanna/qianfan)
185
+ - [Zhipu](https://github.com/vanna-ai/vanna/tree/main/src/vanna/ZhipuAI)
186
+
187
+ ## Supported VectorStores
188
+
189
+ - [AzureSearch](https://github.com/vanna-ai/vanna/tree/main/src/vanna/azuresearch)
190
+ - [Opensearch](https://github.com/vanna-ai/vanna/tree/main/src/vanna/opensearch)
191
+ - [PgVector](https://github.com/vanna-ai/vanna/tree/main/src/vanna/pgvector)
192
+ - [PineCone](https://github.com/vanna-ai/vanna/tree/main/src/vanna/pinecone)
193
+ - [ChromaDB](https://github.com/vanna-ai/vanna/tree/main/src/vanna/chromadb)
194
+ - [FAISS](https://github.com/vanna-ai/vanna/tree/main/src/vanna/faiss)
195
+ - [Marqo](https://github.com/vanna-ai/vanna/tree/main/src/vanna/marqo)
196
+ - [Milvus](https://github.com/vanna-ai/vanna/tree/main/src/vanna/milvus)
197
+ - [Qdrant](https://github.com/vanna-ai/vanna/tree/main/src/vanna/qdrant)
198
+ - [Weaviate](https://github.com/vanna-ai/vanna/tree/main/src/vanna/weaviate)
199
+ - [Oracle](https://github.com/vanna-ai/vanna/tree/main/src/vanna/oracle)
200
+
201
+ ## Supported Databases
202
+
203
+ - [PostgreSQL](https://www.postgresql.org/)
204
+ - [MySQL](https://www.mysql.com/)
205
+ - [PrestoDB](https://prestodb.io/)
206
+ - [Apache Hive](https://hive.apache.org/)
207
+ - [ClickHouse](https://clickhouse.com/)
208
+ - [Snowflake](https://www.snowflake.com/en/)
209
+ - [Oracle](https://www.oracle.com/)
210
+ - [Microsoft SQL Server](https://www.microsoft.com/en-us/sql-server/sql-server-downloads)
211
+ - [BigQuery](https://cloud.google.com/bigquery)
212
+ - [SQLite](https://www.sqlite.org/)
213
+ - [DuckDB](https://duckdb.org/)
214
+
167
215
 
168
216
  ## Getting started
169
217
  See the [documentation](https://vanna.ai/docs/) for specifics on your desired database, LLM, etc.
@@ -1,6 +1,6 @@
1
1
  vanna/__init__.py,sha256=4zz2kSkVZenjwJQg-ETWsIVYdz3gio275i9DMa_aHxM,9248
2
2
  vanna/local.py,sha256=U5s8ybCRQhBUizi8I69o3jqOpTeu_6KGYY6DMwZxjG4,313
3
- vanna/remote.py,sha256=CcScbeEkqYlzBZJMeMLDlLgmaFcG0QSUQUZybFI3Y28,1856
3
+ vanna/remote.py,sha256=3SGyXBmNWofkZL3vGevypvMAhqAYru0KzoUCpX2N6Vc,1876
4
4
  vanna/utils.py,sha256=cs0B_0MwhmPI2nWjVHifDYCmCR0kkddylQ2vloaPDSw,2247
5
5
  vanna/ZhipuAI/ZhipuAI_Chat.py,sha256=WtZKUBIwlNH0BGbb4lZbVR7pTWIrn7b4RLIk-7u0SuQ,8725
6
6
  vanna/ZhipuAI/ZhipuAI_embeddings.py,sha256=lUqzJg9fOx7rVFhjdkFjXcDeVGV4aAB5Ss0oERsa8pE,2849
@@ -11,11 +11,16 @@ vanna/anthropic/anthropic_chat.py,sha256=7X3x8SYwDY28aGyBnt0YNRMG8YY1p_t-foMfKGj
11
11
  vanna/azuresearch/__init__.py,sha256=tZfvsrCJESiL3EnxA4PrOc5NoO8MXEzCfHX_hnj8n-c,58
12
12
  vanna/azuresearch/azuresearch_vector.py,sha256=_-t53PUnJM914GYbTYlyee06ocfu7l2NkZerBQtlJcs,9566
13
13
  vanna/base/__init__.py,sha256=Sl-HM1RRYzAZoSqmL1CZQmF3ZF-byYTCFQP3JZ2A5MU,28
14
- vanna/base/base.py,sha256=j5xQmK-MeFKAuPjgYLSl1ThCHZieG-ab-RFFSkDlbiw,73679
14
+ vanna/base/base.py,sha256=dGSOuidPBCUOuKxCJ9U_B9qSQ7w5Y4XIM0olox9RCYY,73816
15
15
  vanna/bedrock/__init__.py,sha256=hRT2bgJbHEqViLdL-t9hfjSfFdIOkPU2ADBt-B1En-8,46
16
16
  vanna/bedrock/bedrock_converse.py,sha256=Nx5kYm-diAfYmsWAnTP5xnv7V84Og69-AP9b3seIe0E,2869
17
17
  vanna/chromadb/__init__.py,sha256=-iL0nW_g4uM8nWKMuWnNePfN4nb9uk8P3WzGvezOqRg,50
18
18
  vanna/chromadb/chromadb_vector.py,sha256=eKyPck99Y6Jt-BNWojvxLG-zvAERzLSm-3zY-bKXvaA,8792
19
+ vanna/cohere/__init__.py,sha256=QqNQXEixwkrQ4MIAadmg8hTrWDCHFzZoOMF9tim9Pw0,86
20
+ vanna/cohere/cohere_chat.py,sha256=f7kmhhkqoy61AGkBJBXBjVQ2AQkmLQkYnRGNTiZpfYw,3572
21
+ vanna/cohere/cohere_embeddings.py,sha256=RsbZLPVVFIqxbN4t05YM8sc7X0gmA455dhpdU9iB6x8,2646
22
+ vanna/deepseek/__init__.py,sha256=7SVY3DGJcNH7GTk7Uq922QM8yZKu3-5IO33WQ_-bgCM,40
23
+ vanna/deepseek/deepseek_chat.py,sha256=dbTIfVSNmPKYJVI8YeJu3a2Du8U6VqDHdT0gOeqISTc,1878
19
24
  vanna/exceptions/__init__.py,sha256=dJ65xxxZh1lqBeg6nz6Tq_r34jLVmjvBvPO9Q6hFaQ8,685
20
25
  vanna/faiss/__init__.py,sha256=MXuojmLPt4kUtkES9XKWJcCDHVa4L5a6YF5gebhmKLw,24
21
26
  vanna/faiss/faiss.py,sha256=HLUO5PQdnJio9OXJiJcgmRuxVWXvg_XRBnnohS21Z0w,8304
@@ -24,7 +29,7 @@ vanna/flask/assets.py,sha256=af-vact_5HSftltugBpPxzLkAI14Z0lVWcObyVe6eKE,453462
24
29
  vanna/flask/auth.py,sha256=UpKxh7W5cd43W0LGch0VqhncKwB78L6dtOQkl1JY5T0,1246
25
30
  vanna/google/__init__.py,sha256=6D8rDBjKJJm_jpVn9b4Vc2NR-R779ed_bnHhWmxCJXE,92
26
31
  vanna/google/bigquery_vector.py,sha256=mHggjvCsWMt4HK6Y4dAZUPgHi1uytxp2AEQ696TSsJA,9315
27
- vanna/google/gemini_chat.py,sha256=9xHvxArxHr7OWXHnDRz7wX7KTGbuy6xXxHMLkhOMkis,1568
32
+ vanna/google/gemini_chat.py,sha256=Tm4S0uywQNuZ5y0eQsE0-rv0NkAw_IhlyMiQqiqn8ro,2683
28
33
  vanna/hf/__init__.py,sha256=vD0bIhfLkA1UsvVSF4MAz3Da8aQunkQo3wlDztmMuj0,19
29
34
  vanna/hf/hf.py,sha256=N8N5g3xvKDBt3dez2r_U0qATxbl2pN8SVLTZK9CSRA0,3020
30
35
  vanna/marqo/__init__.py,sha256=GaAWtJ0B-H5rTY607iLCCrLD7T0zMYM5qWIomEB9gLk,37
@@ -38,12 +43,15 @@ vanna/mock/embedding.py,sha256=ggnP7KuPh6dlqeUFtoN8t0J0P7_yRNtn9rIq6h8g8-w,250
38
43
  vanna/mock/llm.py,sha256=WpG9f1pKZftPBHqgIYdARKB2Z9DZhOALYOJWoOjjFEc,518
39
44
  vanna/mock/vectordb.py,sha256=h45znfYMUnttE2BBC8v6TKeMaA58pFJL-5B3OGeRNFI,2681
40
45
  vanna/ollama/__init__.py,sha256=4xyu8aHPdnEHg5a-QAMwr5o0ns5wevsp_zkI-ndMO2k,27
41
- vanna/ollama/ollama.py,sha256=yD7UHn4GNzWfQMi2OHlfWwIEJ_sTDzpPcgv_MCGRp6E,3871
46
+ vanna/ollama/ollama.py,sha256=pqHkh2UEIAwBqxRebsLVmmkpiF30yRwCwO_92WY4p0E,3891
42
47
  vanna/openai/__init__.py,sha256=tGkeQ7wTIPsando7QhoSHehtoQVdYLwFbKNlSmCmNeQ,86
43
48
  vanna/openai/openai_chat.py,sha256=KU6ynOQ5v7vwrQQ13phXoUXeQUrH6_vmhfiPvWddTrQ,4427
44
49
  vanna/openai/openai_embeddings.py,sha256=g4pNh9LVcYP9wOoO8ecaccDFWmCUYMInebfHucAa2Gc,1260
45
- vanna/opensearch/__init__.py,sha256=0unDevWOTs7o8S79TOHUKF1mSiuQbBUVm-7k9jV5WW4,54
50
+ vanna/opensearch/__init__.py,sha256=dc9fNtIrOOpkSGp_JKOhGOk26ffyK6W1bm_Cdn9X09I,126
46
51
  vanna/opensearch/opensearch_vector.py,sha256=VhIcrSyNzWR9ZrqrJnyGFOyuQZs3swfbhr8QyVGI0eI,12226
52
+ vanna/opensearch/opensearch_vector_semantic.py,sha256=XV0ApIMXTj_dc3tnmTg4vkQXMaUxsh2Npk_JBEGIj1Q,6325
53
+ vanna/oracle/__init__.py,sha256=lE9IB9nK4wsAQ0KdAqoidMoLH80QBsB1HRbI0GQJh8c,46
54
+ vanna/oracle/oracle_vector.py,sha256=uWcDFs5uhdKdjdEhFXy4RouTOiS-XMFmaUFuuOLtqho,15974
47
55
  vanna/pgvector/__init__.py,sha256=7Wvu9qcNdNvZu26Dn53jhO9YXELm0_YsrwBab4BdgVM,37
48
56
  vanna/pgvector/pgvector.py,sha256=dJfm8rswYZvbaIbnjmyRjL071iw4siE0INibsZtaLXY,9919
49
57
  vanna/pinecone/__init__.py,sha256=eO5l8aX8vKL6aIUMgAXGPt1jdqKxB_Hic6cmoVAUrD0,90
@@ -65,6 +73,7 @@ vanna/weaviate/__init__.py,sha256=HL6PAl7ePBAkeG8uln-BmM7IUtWohyTPvDfcPzSGSCg,46
65
73
  vanna/weaviate/weaviate_vector.py,sha256=tUJIZjEy2mda8CB6C8zeN2SKkEO-UJdLsIqy69skuF0,7584
66
74
  vanna/xinference/__init__.py,sha256=EFW_sz-BSB2XgmjACOTZmneeIk3I2EiWgue-VVJpnB0,35
67
75
  vanna/xinference/xinference.py,sha256=2PI-f7XoBUyL_jfuXPqxCsd0W72h8j6CtEDneFw1AtI,1876
68
- vanna-0.7.5.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
69
- vanna-0.7.5.dist-info/METADATA,sha256=ps3MrKa5oG8XfjgG6C5u71v3OExvket22gu8uMwtufs,13048
70
- vanna-0.7.5.dist-info/RECORD,,
76
+ vanna-0.7.7.dist-info/licenses/LICENSE,sha256=VYiPMMDqj9BcxUkAYqrAzJpn5tCFXCrnglfRqS5l9Rk,1065
77
+ vanna-0.7.7.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
78
+ vanna-0.7.7.dist-info/METADATA,sha256=45kbhCcgYmsi7bDQESvhAwPg96c92NW6qwlIDouIpiQ,15608
79
+ vanna-0.7.7.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: flit 3.9.0
2
+ Generator: flit 3.12.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Vanna.AI
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.