asksql 2.1.0__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.
Files changed (291) hide show
  1. asksql-2.1.0.dist-info/METADATA +517 -0
  2. asksql-2.1.0.dist-info/RECORD +291 -0
  3. asksql-2.1.0.dist-info/WHEEL +4 -0
  4. asksql-2.1.0.dist-info/entry_points.txt +4 -0
  5. asksql-2.1.0.dist-info/licenses/LICENSE +21 -0
  6. vanna/__init__.py +172 -0
  7. vanna/agents/__init__.py +7 -0
  8. vanna/capabilities/__init__.py +17 -0
  9. vanna/capabilities/agent_memory/__init__.py +21 -0
  10. vanna/capabilities/agent_memory/base.py +103 -0
  11. vanna/capabilities/agent_memory/models.py +53 -0
  12. vanna/capabilities/file_system/__init__.py +14 -0
  13. vanna/capabilities/file_system/base.py +71 -0
  14. vanna/capabilities/file_system/models.py +25 -0
  15. vanna/capabilities/sql_runner/__init__.py +13 -0
  16. vanna/capabilities/sql_runner/base.py +37 -0
  17. vanna/capabilities/sql_runner/models.py +13 -0
  18. vanna/components/__init__.py +92 -0
  19. vanna/components/base.py +11 -0
  20. vanna/components/rich/__init__.py +83 -0
  21. vanna/components/rich/containers/__init__.py +7 -0
  22. vanna/components/rich/containers/card.py +20 -0
  23. vanna/components/rich/data/__init__.py +9 -0
  24. vanna/components/rich/data/chart.py +17 -0
  25. vanna/components/rich/data/dataframe.py +93 -0
  26. vanna/components/rich/feedback/__init__.py +21 -0
  27. vanna/components/rich/feedback/badge.py +16 -0
  28. vanna/components/rich/feedback/icon_text.py +14 -0
  29. vanna/components/rich/feedback/log_viewer.py +41 -0
  30. vanna/components/rich/feedback/notification.py +19 -0
  31. vanna/components/rich/feedback/progress.py +37 -0
  32. vanna/components/rich/feedback/status_card.py +28 -0
  33. vanna/components/rich/feedback/status_indicator.py +14 -0
  34. vanna/components/rich/interactive/__init__.py +21 -0
  35. vanna/components/rich/interactive/button.py +95 -0
  36. vanna/components/rich/interactive/task_list.py +58 -0
  37. vanna/components/rich/interactive/ui_state.py +93 -0
  38. vanna/components/rich/specialized/__init__.py +7 -0
  39. vanna/components/rich/specialized/artifact.py +20 -0
  40. vanna/components/rich/text.py +16 -0
  41. vanna/components/simple/__init__.py +15 -0
  42. vanna/components/simple/image.py +15 -0
  43. vanna/components/simple/link.py +15 -0
  44. vanna/components/simple/text.py +11 -0
  45. vanna/core/__init__.py +193 -0
  46. vanna/core/_compat.py +19 -0
  47. vanna/core/agent/__init__.py +10 -0
  48. vanna/core/agent/agent.py +1407 -0
  49. vanna/core/agent/config.py +123 -0
  50. vanna/core/audit/__init__.py +28 -0
  51. vanna/core/audit/base.py +299 -0
  52. vanna/core/audit/models.py +131 -0
  53. vanna/core/component_manager.py +329 -0
  54. vanna/core/components.py +53 -0
  55. vanna/core/enhancer/__init__.py +11 -0
  56. vanna/core/enhancer/base.py +94 -0
  57. vanna/core/enhancer/default.py +118 -0
  58. vanna/core/enricher/__init__.py +10 -0
  59. vanna/core/enricher/base.py +59 -0
  60. vanna/core/errors.py +47 -0
  61. vanna/core/evaluation/__init__.py +81 -0
  62. vanna/core/evaluation/base.py +186 -0
  63. vanna/core/evaluation/dataset.py +254 -0
  64. vanna/core/evaluation/evaluators.py +376 -0
  65. vanna/core/evaluation/report.py +289 -0
  66. vanna/core/evaluation/runner.py +313 -0
  67. vanna/core/filter/__init__.py +10 -0
  68. vanna/core/filter/base.py +67 -0
  69. vanna/core/lifecycle/__init__.py +10 -0
  70. vanna/core/lifecycle/base.py +83 -0
  71. vanna/core/llm/__init__.py +16 -0
  72. vanna/core/llm/base.py +40 -0
  73. vanna/core/llm/models.py +61 -0
  74. vanna/core/middleware/__init__.py +10 -0
  75. vanna/core/middleware/base.py +69 -0
  76. vanna/core/observability/__init__.py +11 -0
  77. vanna/core/observability/base.py +88 -0
  78. vanna/core/observability/models.py +47 -0
  79. vanna/core/recovery/__init__.py +11 -0
  80. vanna/core/recovery/base.py +84 -0
  81. vanna/core/recovery/models.py +32 -0
  82. vanna/core/registry.py +278 -0
  83. vanna/core/rich_component.py +156 -0
  84. vanna/core/simple_component.py +27 -0
  85. vanna/core/storage/__init__.py +14 -0
  86. vanna/core/storage/base.py +46 -0
  87. vanna/core/storage/models.py +46 -0
  88. vanna/core/system_prompt/__init__.py +13 -0
  89. vanna/core/system_prompt/base.py +36 -0
  90. vanna/core/system_prompt/default.py +157 -0
  91. vanna/core/tool/__init__.py +18 -0
  92. vanna/core/tool/base.py +70 -0
  93. vanna/core/tool/models.py +84 -0
  94. vanna/core/user/__init__.py +17 -0
  95. vanna/core/user/base.py +29 -0
  96. vanna/core/user/models.py +25 -0
  97. vanna/core/user/request_context.py +70 -0
  98. vanna/core/user/resolver.py +42 -0
  99. vanna/core/validation.py +164 -0
  100. vanna/core/workflow/__init__.py +12 -0
  101. vanna/core/workflow/base.py +254 -0
  102. vanna/core/workflow/default.py +789 -0
  103. vanna/examples/__init__.py +1 -0
  104. vanna/examples/__main__.py +44 -0
  105. vanna/examples/anthropic_quickstart.py +80 -0
  106. vanna/examples/artifact_example.py +293 -0
  107. vanna/examples/claude_sqlite_example.py +236 -0
  108. vanna/examples/coding_agent_example.py +300 -0
  109. vanna/examples/custom_system_prompt_example.py +174 -0
  110. vanna/examples/default_workflow_handler_example.py +208 -0
  111. vanna/examples/email_auth_example.py +340 -0
  112. vanna/examples/evaluation_example.py +269 -0
  113. vanna/examples/extensibility_example.py +262 -0
  114. vanna/examples/minimal_example.py +67 -0
  115. vanna/examples/mock_auth_example.py +227 -0
  116. vanna/examples/mock_custom_tool.py +311 -0
  117. vanna/examples/mock_quickstart.py +79 -0
  118. vanna/examples/mock_quota_example.py +145 -0
  119. vanna/examples/mock_rich_components_demo.py +396 -0
  120. vanna/examples/mock_sqlite_example.py +223 -0
  121. vanna/examples/openai_quickstart.py +83 -0
  122. vanna/examples/primitive_components_demo.py +305 -0
  123. vanna/examples/quota_lifecycle_example.py +139 -0
  124. vanna/examples/visualization_example.py +251 -0
  125. vanna/integrations/__init__.py +17 -0
  126. vanna/integrations/anthropic/__init__.py +9 -0
  127. vanna/integrations/anthropic/llm.py +270 -0
  128. vanna/integrations/azureopenai/__init__.py +9 -0
  129. vanna/integrations/azureopenai/llm.py +329 -0
  130. vanna/integrations/azuresearch/__init__.py +7 -0
  131. vanna/integrations/azuresearch/agent_memory.py +413 -0
  132. vanna/integrations/bigquery/__init__.py +5 -0
  133. vanna/integrations/bigquery/sql_runner.py +81 -0
  134. vanna/integrations/chromadb/__init__.py +104 -0
  135. vanna/integrations/chromadb/agent_memory.py +488 -0
  136. vanna/integrations/clickhouse/__init__.py +5 -0
  137. vanna/integrations/clickhouse/sql_runner.py +82 -0
  138. vanna/integrations/duckdb/__init__.py +5 -0
  139. vanna/integrations/duckdb/sql_runner.py +65 -0
  140. vanna/integrations/faiss/__init__.py +7 -0
  141. vanna/integrations/faiss/agent_memory.py +435 -0
  142. vanna/integrations/google/__init__.py +9 -0
  143. vanna/integrations/google/gemini.py +370 -0
  144. vanna/integrations/hive/__init__.py +5 -0
  145. vanna/integrations/hive/sql_runner.py +87 -0
  146. vanna/integrations/local/__init__.py +17 -0
  147. vanna/integrations/local/agent_memory/__init__.py +7 -0
  148. vanna/integrations/local/agent_memory/in_memory.py +285 -0
  149. vanna/integrations/local/audit.py +59 -0
  150. vanna/integrations/local/file_system.py +242 -0
  151. vanna/integrations/local/file_system_conversation_store.py +255 -0
  152. vanna/integrations/local/storage.py +62 -0
  153. vanna/integrations/marqo/__init__.py +7 -0
  154. vanna/integrations/marqo/agent_memory.py +354 -0
  155. vanna/integrations/milvus/__init__.py +7 -0
  156. vanna/integrations/milvus/agent_memory.py +458 -0
  157. vanna/integrations/mock/__init__.py +9 -0
  158. vanna/integrations/mock/llm.py +65 -0
  159. vanna/integrations/mssql/__init__.py +5 -0
  160. vanna/integrations/mssql/sql_runner.py +66 -0
  161. vanna/integrations/mysql/__init__.py +5 -0
  162. vanna/integrations/mysql/sql_runner.py +92 -0
  163. vanna/integrations/ollama/__init__.py +7 -0
  164. vanna/integrations/ollama/llm.py +252 -0
  165. vanna/integrations/openai/__init__.py +10 -0
  166. vanna/integrations/openai/llm.py +267 -0
  167. vanna/integrations/openai/responses.py +163 -0
  168. vanna/integrations/opensearch/__init__.py +7 -0
  169. vanna/integrations/opensearch/agent_memory.py +411 -0
  170. vanna/integrations/oracle/__init__.py +5 -0
  171. vanna/integrations/oracle/sql_runner.py +75 -0
  172. vanna/integrations/pinecone/__init__.py +7 -0
  173. vanna/integrations/pinecone/agent_memory.py +329 -0
  174. vanna/integrations/plotly/__init__.py +5 -0
  175. vanna/integrations/plotly/chart_generator.py +313 -0
  176. vanna/integrations/postgres/__init__.py +9 -0
  177. vanna/integrations/postgres/sql_runner.py +112 -0
  178. vanna/integrations/premium/agent_memory/__init__.py +7 -0
  179. vanna/integrations/premium/agent_memory/premium.py +186 -0
  180. vanna/integrations/presto/__init__.py +5 -0
  181. vanna/integrations/presto/sql_runner.py +107 -0
  182. vanna/integrations/qdrant/__init__.py +7 -0
  183. vanna/integrations/qdrant/agent_memory.py +466 -0
  184. vanna/integrations/snowflake/__init__.py +5 -0
  185. vanna/integrations/snowflake/sql_runner.py +147 -0
  186. vanna/integrations/sqlite/__init__.py +9 -0
  187. vanna/integrations/sqlite/sql_runner.py +65 -0
  188. vanna/integrations/weaviate/__init__.py +7 -0
  189. vanna/integrations/weaviate/agent_memory.py +428 -0
  190. vanna/legacy/ZhipuAI/ZhipuAI_Chat.py +233 -0
  191. vanna/legacy/ZhipuAI/ZhipuAI_embeddings.py +79 -0
  192. vanna/legacy/ZhipuAI/__init__.py +2 -0
  193. vanna/legacy/__init__.py +403 -0
  194. vanna/legacy/adapter.py +468 -0
  195. vanna/legacy/advanced/__init__.py +28 -0
  196. vanna/legacy/anthropic/__init__.py +1 -0
  197. vanna/legacy/anthropic/anthropic_chat.py +80 -0
  198. vanna/legacy/azuresearch/__init__.py +1 -0
  199. vanna/legacy/azuresearch/azuresearch_vector.py +274 -0
  200. vanna/legacy/base/__init__.py +1 -0
  201. vanna/legacy/base/base.py +2133 -0
  202. vanna/legacy/base/safe_exec.py +190 -0
  203. vanna/legacy/bedrock/__init__.py +1 -0
  204. vanna/legacy/bedrock/bedrock_converse.py +86 -0
  205. vanna/legacy/chromadb/__init__.py +1 -0
  206. vanna/legacy/chromadb/chromadb_vector.py +259 -0
  207. vanna/legacy/cohere/__init__.py +2 -0
  208. vanna/legacy/cohere/cohere_chat.py +99 -0
  209. vanna/legacy/cohere/cohere_embeddings.py +77 -0
  210. vanna/legacy/deepseek/__init__.py +1 -0
  211. vanna/legacy/deepseek/deepseek_chat.py +59 -0
  212. vanna/legacy/exceptions/__init__.py +46 -0
  213. vanna/legacy/faiss/__init__.py +1 -0
  214. vanna/legacy/faiss/faiss.py +230 -0
  215. vanna/legacy/flask/__init__.py +1355 -0
  216. vanna/legacy/flask/assets.py +58 -0
  217. vanna/legacy/flask/auth.py +56 -0
  218. vanna/legacy/google/__init__.py +2 -0
  219. vanna/legacy/google/bigquery_vector.py +293 -0
  220. vanna/legacy/google/gemini_chat.py +78 -0
  221. vanna/legacy/hf/__init__.py +1 -0
  222. vanna/legacy/hf/hf.py +80 -0
  223. vanna/legacy/local.py +8 -0
  224. vanna/legacy/marqo/__init__.py +1 -0
  225. vanna/legacy/marqo/marqo.py +168 -0
  226. vanna/legacy/milvus/__init__.py +1 -0
  227. vanna/legacy/milvus/milvus_vector.py +328 -0
  228. vanna/legacy/mistral/__init__.py +1 -0
  229. vanna/legacy/mistral/mistral.py +51 -0
  230. vanna/legacy/mock/__init__.py +3 -0
  231. vanna/legacy/mock/embedding.py +11 -0
  232. vanna/legacy/mock/llm.py +18 -0
  233. vanna/legacy/mock/vectordb.py +67 -0
  234. vanna/legacy/ollama/__init__.py +1 -0
  235. vanna/legacy/ollama/ollama.py +110 -0
  236. vanna/legacy/openai/__init__.py +2 -0
  237. vanna/legacy/openai/openai_chat.py +124 -0
  238. vanna/legacy/openai/openai_embeddings.py +46 -0
  239. vanna/legacy/opensearch/__init__.py +2 -0
  240. vanna/legacy/opensearch/opensearch_vector.py +369 -0
  241. vanna/legacy/opensearch/opensearch_vector_semantic.py +200 -0
  242. vanna/legacy/oracle/__init__.py +1 -0
  243. vanna/legacy/oracle/oracle_vector.py +584 -0
  244. vanna/legacy/pgvector/__init__.py +1 -0
  245. vanna/legacy/pgvector/pgvector.py +282 -0
  246. vanna/legacy/pinecone/__init__.py +3 -0
  247. vanna/legacy/pinecone/pinecone_vector.py +275 -0
  248. vanna/legacy/qdrant/__init__.py +3 -0
  249. vanna/legacy/qdrant/qdrant.py +329 -0
  250. vanna/legacy/qianfan/Qianfan_Chat.py +170 -0
  251. vanna/legacy/qianfan/Qianfan_embeddings.py +36 -0
  252. vanna/legacy/qianfan/__init__.py +2 -0
  253. vanna/legacy/qianwen/QianwenAI_chat.py +132 -0
  254. vanna/legacy/qianwen/QianwenAI_embeddings.py +46 -0
  255. vanna/legacy/qianwen/__init__.py +2 -0
  256. vanna/legacy/remote.py +79 -0
  257. vanna/legacy/types/__init__.py +292 -0
  258. vanna/legacy/utils.py +72 -0
  259. vanna/legacy/vannadb/__init__.py +1 -0
  260. vanna/legacy/vannadb/vannadb_vector.py +468 -0
  261. vanna/legacy/vllm/__init__.py +1 -0
  262. vanna/legacy/vllm/vllm.py +97 -0
  263. vanna/legacy/weaviate/__init__.py +1 -0
  264. vanna/legacy/weaviate/weaviate_vector.py +194 -0
  265. vanna/legacy/xinference/__init__.py +1 -0
  266. vanna/legacy/xinference/xinference.py +53 -0
  267. vanna/py.typed +0 -0
  268. vanna/servers/__init__.py +16 -0
  269. vanna/servers/__main__.py +8 -0
  270. vanna/servers/base/__init__.py +18 -0
  271. vanna/servers/base/chat_handler.py +65 -0
  272. vanna/servers/base/models.py +111 -0
  273. vanna/servers/base/rich_chat_handler.py +141 -0
  274. vanna/servers/base/templates.py +331 -0
  275. vanna/servers/cli/__init__.py +7 -0
  276. vanna/servers/cli/server_runner.py +204 -0
  277. vanna/servers/fastapi/__init__.py +7 -0
  278. vanna/servers/fastapi/app.py +163 -0
  279. vanna/servers/fastapi/routes.py +183 -0
  280. vanna/servers/flask/__init__.py +7 -0
  281. vanna/servers/flask/app.py +132 -0
  282. vanna/servers/flask/routes.py +137 -0
  283. vanna/tools/__init__.py +41 -0
  284. vanna/tools/agent_memory.py +322 -0
  285. vanna/tools/file_system.py +879 -0
  286. vanna/tools/python.py +222 -0
  287. vanna/tools/run_sql.py +173 -0
  288. vanna/tools/visualize_data.py +195 -0
  289. vanna/utils/__init__.py +0 -0
  290. vanna/utils/sql_safety.py +84 -0
  291. vanna/web_components/__init__.py +44 -0
@@ -0,0 +1,56 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ import flask
4
+
5
+
6
+ class AuthInterface(ABC):
7
+ @abstractmethod
8
+ def get_user(self, flask_request) -> any:
9
+ pass
10
+
11
+ @abstractmethod
12
+ def is_logged_in(self, user: any) -> bool:
13
+ pass
14
+
15
+ @abstractmethod
16
+ def override_config_for_user(self, user: any, config: dict) -> dict:
17
+ pass
18
+
19
+ @abstractmethod
20
+ def login_form(self) -> str:
21
+ pass
22
+
23
+ @abstractmethod
24
+ def login_handler(self, flask_request) -> str:
25
+ pass
26
+
27
+ @abstractmethod
28
+ def callback_handler(self, flask_request) -> str:
29
+ pass
30
+
31
+ @abstractmethod
32
+ def logout_handler(self, flask_request) -> str:
33
+ pass
34
+
35
+
36
+ class NoAuth(AuthInterface):
37
+ def get_user(self, flask_request) -> any:
38
+ return {}
39
+
40
+ def is_logged_in(self, user: any) -> bool:
41
+ return True
42
+
43
+ def override_config_for_user(self, user: any, config: dict) -> dict:
44
+ return config
45
+
46
+ def login_form(self) -> str:
47
+ return ""
48
+
49
+ def login_handler(self, flask_request) -> str:
50
+ return "No login required"
51
+
52
+ def callback_handler(self, flask_request) -> str:
53
+ return "No login required"
54
+
55
+ def logout_handler(self, flask_request) -> str:
56
+ return "No login required"
@@ -0,0 +1,2 @@
1
+ from .bigquery_vector import BigQuery_VectorStore
2
+ from .gemini_chat import GoogleGeminiChat
@@ -0,0 +1,293 @@
1
+ import datetime
2
+ import os
3
+ import uuid
4
+ from typing import List, Optional
5
+ from vertexai.language_models import TextEmbeddingInput, TextEmbeddingModel
6
+
7
+ import pandas as pd
8
+ from google.cloud import bigquery
9
+
10
+ from ..base import VannaBase
11
+
12
+
13
+ class BigQuery_VectorStore(VannaBase):
14
+ def __init__(self, config: dict, **kwargs):
15
+ self.config = config
16
+
17
+ self.n_results_sql = config.get("n_results_sql", config.get("n_results", 10))
18
+ self.n_results_documentation = config.get(
19
+ "n_results_documentation", config.get("n_results", 10)
20
+ )
21
+ self.n_results_ddl = config.get("n_results_ddl", config.get("n_results", 10))
22
+
23
+ if "api_key" in config or os.getenv("GOOGLE_API_KEY"):
24
+ """
25
+ If Google api_key is provided through config
26
+ or set as an environment variable, assign it.
27
+ """
28
+ print("Configuring genai")
29
+ self.type = "GEMINI"
30
+ import google.generativeai as genai
31
+
32
+ genai.configure(api_key=config["api_key"])
33
+
34
+ self.genai = genai
35
+ else:
36
+ self.type = "VERTEX_AI"
37
+ # Authenticate using VertexAI
38
+
39
+ if self.config.get("project_id"):
40
+ self.project_id = self.config.get("project_id")
41
+ else:
42
+ self.project_id = os.getenv("GOOGLE_CLOUD_PROJECT")
43
+
44
+ if self.project_id is None:
45
+ raise ValueError("Project ID is not set")
46
+
47
+ self.conn = bigquery.Client(project=self.project_id)
48
+
49
+ dataset_name = self.config.get("bigquery_dataset_name", "vanna_managed")
50
+ self.dataset_id = f"{self.project_id}.{dataset_name}"
51
+ dataset = bigquery.Dataset(self.dataset_id)
52
+
53
+ try:
54
+ self.conn.get_dataset(self.dataset_id) # Make an API request.
55
+ print(f"Dataset {self.dataset_id} already exists")
56
+ except Exception:
57
+ # Dataset does not exist, create it
58
+ dataset.location = "US"
59
+ self.conn.create_dataset(dataset, timeout=30) # Make an API request.
60
+ print(f"Created dataset {self.dataset_id}")
61
+
62
+ # Create a table called training_data in the dataset that contains the columns:
63
+ # id, training_data_type, question, content, embedding, created_at
64
+
65
+ self.table_id = f"{self.dataset_id}.training_data"
66
+ schema = [
67
+ bigquery.SchemaField("id", "STRING", mode="REQUIRED"),
68
+ bigquery.SchemaField("training_data_type", "STRING", mode="REQUIRED"),
69
+ bigquery.SchemaField("question", "STRING", mode="REQUIRED"),
70
+ bigquery.SchemaField("content", "STRING", mode="REQUIRED"),
71
+ bigquery.SchemaField("embedding", "FLOAT64", mode="REPEATED"),
72
+ bigquery.SchemaField("created_at", "TIMESTAMP", mode="REQUIRED"),
73
+ ]
74
+
75
+ table = bigquery.Table(self.table_id, schema=schema)
76
+
77
+ try:
78
+ self.conn.get_table(self.table_id) # Make an API request.
79
+ print(f"Table {self.table_id} already exists")
80
+ except Exception:
81
+ # Table does not exist, create it
82
+ self.conn.create_table(table, timeout=30) # Make an API request.
83
+ print(f"Created table {self.table_id}")
84
+
85
+ # Create VECTOR INDEX IF NOT EXISTS
86
+ # TODO: This requires 5000 rows before it can be created
87
+ # vector_index_query = f"""
88
+ # CREATE VECTOR INDEX IF NOT EXISTS my_index
89
+ # ON `{self.table_id}`(embedding)
90
+ # OPTIONS(
91
+ # distance_type='COSINE',
92
+ # index_type='IVF',
93
+ # ivf_options='{{"num_lists": 1000}}'
94
+ # )
95
+ # """
96
+
97
+ # try:
98
+ # self.conn.query(vector_index_query).result() # Make an API request.
99
+ # print(f"Vector index on {self.table_id} created or already exists")
100
+ # except Exception as e:
101
+ # print(f"Failed to create vector index: {e}")
102
+
103
+ def store_training_data(
104
+ self,
105
+ training_data_type: str,
106
+ question: str,
107
+ content: str,
108
+ embedding: List[float],
109
+ **kwargs,
110
+ ) -> str:
111
+ id = str(uuid.uuid4())
112
+ created_at = datetime.datetime.now()
113
+ self.conn.insert_rows_json(
114
+ self.table_id,
115
+ [
116
+ {
117
+ "id": id,
118
+ "training_data_type": training_data_type,
119
+ "question": question,
120
+ "content": content,
121
+ "embedding": embedding,
122
+ "created_at": created_at.isoformat(),
123
+ }
124
+ ],
125
+ )
126
+
127
+ return id
128
+
129
+ def fetch_similar_training_data(
130
+ self, training_data_type: str, question: str, n_results, **kwargs
131
+ ) -> pd.DataFrame:
132
+ question_embedding = self.generate_question_embedding(question)
133
+
134
+ query = f"""
135
+ SELECT
136
+ base.id as id,
137
+ base.question as question,
138
+ base.training_data_type as training_data_type,
139
+ base.content as content,
140
+ distance
141
+ FROM
142
+ VECTOR_SEARCH(
143
+ TABLE `{self.table_id}`,
144
+ 'embedding',
145
+ (SELECT * FROM UNNEST([STRUCT({question_embedding})])),
146
+ top_k => 5,
147
+ distance_type => 'COSINE',
148
+ options => '{{"use_brute_force":true}}'
149
+ )
150
+ WHERE
151
+ base.training_data_type = @training_data_type
152
+ """
153
+ job_config = bigquery.QueryJobConfig(
154
+ query_parameters=[
155
+ bigquery.ScalarQueryParameter(
156
+ "training_data_type", "STRING", training_data_type
157
+ )
158
+ ]
159
+ )
160
+
161
+ results = self.conn.query(query, job_config=job_config).result().to_dataframe()
162
+ return results
163
+
164
+ def get_embeddings(self, data: str, task: str) -> List[float]:
165
+ embeddings = None
166
+
167
+ if self.type == "VERTEX_AI":
168
+ input = [TextEmbeddingInput(data, task)]
169
+ model = TextEmbeddingModel.from_pretrained("text-embedding-004")
170
+
171
+ result = model.get_embeddings(input)
172
+
173
+ if len(result) > 0:
174
+ embeddings = result[0].values
175
+ else:
176
+ # Use Gemini Consumer API
177
+ result = self.genai.embed_content(
178
+ model="models/text-embedding-004", content=data, task_type=task
179
+ )
180
+
181
+ if "embedding" in result:
182
+ embeddings = result["embedding"]
183
+
184
+ return embeddings
185
+
186
+ def generate_question_embedding(self, data: str, **kwargs) -> List[float]:
187
+ result = self.get_embeddings(data, "RETRIEVAL_QUERY")
188
+
189
+ if result is not None:
190
+ return result
191
+ else:
192
+ raise ValueError("No embeddings returned")
193
+
194
+ def generate_storage_embedding(self, data: str, **kwargs) -> List[float]:
195
+ result = self.get_embeddings(data, "RETRIEVAL_DOCUMENT")
196
+
197
+ if result is not None:
198
+ return result
199
+ else:
200
+ raise ValueError("No embeddings returned")
201
+
202
+ # task = "RETRIEVAL_DOCUMENT"
203
+ # inputs = [TextEmbeddingInput(data, task)]
204
+ # embeddings = self.vertex_embedding_model.get_embeddings(inputs)
205
+
206
+ # if len(embeddings) == 0:
207
+ # raise ValueError("No embeddings returned")
208
+
209
+ # return embeddings[0].values
210
+
211
+ return result
212
+
213
+ def generate_embedding(self, data: str, **kwargs) -> List[float]:
214
+ return self.generate_storage_embedding(data, **kwargs)
215
+
216
+ def get_similar_question_sql(self, question: str, **kwargs) -> list:
217
+ df = self.fetch_similar_training_data(
218
+ training_data_type="sql", question=question, n_results=self.n_results_sql
219
+ )
220
+
221
+ # Return a list of dictionaries with only question, sql fields. The content field needs to be renamed to sql
222
+ return df.rename(columns={"content": "sql"})[["question", "sql"]].to_dict(
223
+ orient="records"
224
+ )
225
+
226
+ def get_related_ddl(self, question: str, **kwargs) -> list:
227
+ df = self.fetch_similar_training_data(
228
+ training_data_type="ddl", question=question, n_results=self.n_results_ddl
229
+ )
230
+
231
+ # Return a list of strings of the content
232
+ return df["content"].tolist()
233
+
234
+ def get_related_documentation(self, question: str, **kwargs) -> list:
235
+ df = self.fetch_similar_training_data(
236
+ training_data_type="documentation",
237
+ question=question,
238
+ n_results=self.n_results_documentation,
239
+ )
240
+
241
+ # Return a list of strings of the content
242
+ return df["content"].tolist()
243
+
244
+ def add_question_sql(self, question: str, sql: str, **kwargs) -> str:
245
+ doc = {"question": question, "sql": sql}
246
+
247
+ embedding = self.generate_embedding(str(doc))
248
+
249
+ return self.store_training_data(
250
+ training_data_type="sql",
251
+ question=question,
252
+ content=sql,
253
+ embedding=embedding,
254
+ )
255
+
256
+ def add_ddl(self, ddl: str, **kwargs) -> str:
257
+ embedding = self.generate_embedding(ddl)
258
+
259
+ return self.store_training_data(
260
+ training_data_type="ddl", question="", content=ddl, embedding=embedding
261
+ )
262
+
263
+ def add_documentation(self, documentation: str, **kwargs) -> str:
264
+ embedding = self.generate_embedding(documentation)
265
+
266
+ return self.store_training_data(
267
+ training_data_type="documentation",
268
+ question="",
269
+ content=documentation,
270
+ embedding=embedding,
271
+ )
272
+
273
+ def get_training_data(self, **kwargs) -> pd.DataFrame:
274
+ query = (
275
+ f"SELECT id, training_data_type, question, content FROM `{self.table_id}`"
276
+ )
277
+
278
+ return self.conn.query(query).result().to_dataframe()
279
+
280
+ def remove_training_data(self, id: str, **kwargs) -> bool:
281
+ # Pass id as a query parameter, never inside the SQL string (CVE-2026-4229)
282
+ query = f"DELETE FROM `{self.table_id}` WHERE id = @id"
283
+ job_config = bigquery.QueryJobConfig(
284
+ query_parameters=[bigquery.ScalarQueryParameter("id", "STRING", id)]
285
+ )
286
+
287
+ try:
288
+ self.conn.query(query, job_config=job_config).result()
289
+ return True
290
+
291
+ except Exception as e:
292
+ print(f"Failed to remove training data: {e}")
293
+ return False
@@ -0,0 +1,78 @@
1
+ import os
2
+
3
+ from ..base import VannaBase
4
+
5
+
6
+ class GoogleGeminiChat(VannaBase):
7
+ def __init__(self, config=None):
8
+ VannaBase.__init__(self, config=config)
9
+
10
+ # default temperature - can be overrided using config
11
+ self.temperature = 0.7
12
+
13
+ if "temperature" in config:
14
+ self.temperature = config["temperature"]
15
+
16
+ if "model_name" in config:
17
+ model_name = config["model_name"]
18
+ else:
19
+ model_name = "gemini-1.5-pro"
20
+
21
+ self.google_api_key = None
22
+
23
+ if "api_key" in config or os.getenv("GOOGLE_API_KEY"):
24
+ """
25
+ If Google api_key is provided through config
26
+ or set as an environment variable, assign it.
27
+ """
28
+ import google.generativeai as genai
29
+
30
+ genai.configure(api_key=config["api_key"])
31
+ self.chat_model = genai.GenerativeModel(model_name)
32
+ else:
33
+ # Authenticate using VertexAI
34
+ import google.auth
35
+ import vertexai
36
+ from vertexai.generative_models import GenerativeModel
37
+
38
+ json_file_path = config.get(
39
+ "google_credentials"
40
+ ) # Assuming the JSON file path is provided in the config
41
+
42
+ if not json_file_path or not os.path.exists(json_file_path):
43
+ raise FileNotFoundError(
44
+ f"JSON credentials file not found at: {json_file_path}"
45
+ )
46
+
47
+ try:
48
+ # Validate and set the JSON file path for GOOGLE_APPLICATION_CREDENTIALS
49
+ os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = json_file_path
50
+
51
+ # Initialize VertexAI with the credentials
52
+ credentials, _ = google.auth.default()
53
+ vertexai.init(credentials=credentials)
54
+ self.chat_model = GenerativeModel(model_name)
55
+ except google.auth.exceptions.DefaultCredentialsError as e:
56
+ raise RuntimeError(f"Default credentials error: {e}")
57
+ except google.auth.exceptions.TransportError as e:
58
+ raise RuntimeError(f"Transport error during authentication: {e}")
59
+ except Exception as e:
60
+ raise RuntimeError(f"Failed to authenticate using JSON file: {e}")
61
+
62
+ def system_message(self, message: str) -> any:
63
+ return message
64
+
65
+ def user_message(self, message: str) -> any:
66
+ return message
67
+
68
+ def assistant_message(self, message: str) -> any:
69
+ return message
70
+
71
+ def submit_prompt(self, prompt, **kwargs) -> str:
72
+ response = self.chat_model.generate_content(
73
+ prompt,
74
+ generation_config={
75
+ "temperature": self.temperature,
76
+ },
77
+ )
78
+ return response.text
@@ -0,0 +1 @@
1
+ from .hf import Hf
vanna/legacy/hf/hf.py ADDED
@@ -0,0 +1,80 @@
1
+ import re
2
+ from transformers import AutoTokenizer, AutoModelForCausalLM
3
+
4
+ from ..base import VannaBase
5
+
6
+
7
+ class Hf(VannaBase):
8
+ def __init__(self, config=None):
9
+ model_name_or_path = self.config.get(
10
+ "model_name_or_path", None
11
+ ) # e.g. meta-llama/Meta-Llama-3-8B-Instruct or local path to the model checkpoint files
12
+ # list of quantization methods supported by transformers package: https://huggingface.co/docs/transformers/main/en/quantization/overview
13
+ quantization_config = self.config.get("quantization_config", None)
14
+ self.tokenizer = AutoTokenizer.from_pretrained(model_name_or_path)
15
+ self.model = AutoModelForCausalLM.from_pretrained(
16
+ model_name_or_path,
17
+ quantization_config=quantization_config,
18
+ device_map="auto",
19
+ )
20
+
21
+ def system_message(self, message: str) -> any:
22
+ return {"role": "system", "content": message}
23
+
24
+ def user_message(self, message: str) -> any:
25
+ return {"role": "user", "content": message}
26
+
27
+ def assistant_message(self, message: str) -> any:
28
+ return {"role": "assistant", "content": message}
29
+
30
+ def extract_sql_query(self, text):
31
+ """
32
+ Extracts the first SQL statement after the word 'select', ignoring case,
33
+ matches until the first semicolon, three backticks, or the end of the string,
34
+ and removes three backticks if they exist in the extracted string.
35
+
36
+ Args:
37
+ - text (str): The string to search within for an SQL statement.
38
+
39
+ Returns:
40
+ - str: The first SQL statement found, with three backticks removed, or an empty string if no match is found.
41
+ """
42
+ # Regular expression to find 'select' (ignoring case) and capture until ';', '```', or end of string
43
+ pattern = re.compile(r"select.*?(?:;|```|$)", re.IGNORECASE | re.DOTALL)
44
+
45
+ match = pattern.search(text)
46
+ if match:
47
+ # Remove three backticks from the matched string if they exist
48
+ return match.group(0).replace("```", "")
49
+ else:
50
+ return text
51
+
52
+ def generate_sql(self, question: str, **kwargs) -> str:
53
+ # Use the super generate_sql
54
+ sql = super().generate_sql(question, **kwargs)
55
+
56
+ # Replace "\_" with "_"
57
+ sql = sql.replace("\\_", "_")
58
+
59
+ sql = sql.replace("\\", "")
60
+
61
+ return self.extract_sql_query(sql)
62
+
63
+ def submit_prompt(self, prompt, **kwargs) -> str:
64
+ input_ids = self.tokenizer.apply_chat_template(
65
+ prompt, add_generation_prompt=True, return_tensors="pt"
66
+ ).to(self.model.device)
67
+
68
+ outputs = self.model.generate(
69
+ input_ids,
70
+ max_new_tokens=512,
71
+ eos_token_id=self.tokenizer.eos_token_id,
72
+ do_sample=True,
73
+ temperature=1,
74
+ top_p=0.9,
75
+ )
76
+ response = outputs[0][input_ids.shape[-1] :]
77
+ response = self.tokenizer.decode(response, skip_special_tokens=True)
78
+ self.log(response)
79
+
80
+ return response
vanna/legacy/local.py ADDED
@@ -0,0 +1,8 @@
1
+ from .chromadb.chromadb_vector import ChromaDB_VectorStore
2
+ from .openai.openai_chat import OpenAI_Chat
3
+
4
+
5
+ class LocalContext_OpenAI(ChromaDB_VectorStore, OpenAI_Chat):
6
+ def __init__(self, config=None):
7
+ ChromaDB_VectorStore.__init__(self, config=config)
8
+ OpenAI_Chat.__init__(self, config=config)
@@ -0,0 +1 @@
1
+ from .marqo import Marqo_VectorStore
@@ -0,0 +1,168 @@
1
+ import uuid
2
+
3
+ import marqo
4
+ import pandas as pd
5
+
6
+ from ..base import VannaBase
7
+
8
+
9
+ class Marqo_VectorStore(VannaBase):
10
+ def __init__(self, config=None):
11
+ VannaBase.__init__(self, config=config)
12
+
13
+ if config is not None and "marqo_url" in config:
14
+ marqo_url = config["marqo_url"]
15
+ else:
16
+ marqo_url = "http://localhost:8882"
17
+
18
+ if config is not None and "marqo_model" in config:
19
+ marqo_model = config["marqo_model"]
20
+ else:
21
+ marqo_model = "hf/all_datasets_v4_MiniLM-L6"
22
+
23
+ self.mq = marqo.Client(url=marqo_url)
24
+
25
+ for index in ["vanna-sql", "vanna-ddl", "vanna-doc"]:
26
+ try:
27
+ self.mq.create_index(index, model=marqo_model)
28
+ except Exception as e:
29
+ print(e)
30
+ print(f"Marqo index {index} already exists")
31
+ pass
32
+
33
+ def generate_embedding(self, data: str, **kwargs) -> list[float]:
34
+ # Marqo doesn't need to generate embeddings
35
+ pass
36
+
37
+ def add_question_sql(self, question: str, sql: str, **kwargs) -> str:
38
+ id = str(uuid.uuid4()) + "-sql"
39
+ question_sql_dict = {
40
+ "question": question,
41
+ "sql": sql,
42
+ "_id": id,
43
+ }
44
+
45
+ self.mq.index("vanna-sql").add_documents(
46
+ [question_sql_dict],
47
+ tensor_fields=["question", "sql"],
48
+ )
49
+
50
+ return id
51
+
52
+ def add_ddl(self, ddl: str, **kwargs) -> str:
53
+ id = str(uuid.uuid4()) + "-ddl"
54
+ ddl_dict = {
55
+ "ddl": ddl,
56
+ "_id": id,
57
+ }
58
+
59
+ self.mq.index("vanna-ddl").add_documents(
60
+ [ddl_dict],
61
+ tensor_fields=["ddl"],
62
+ )
63
+ return id
64
+
65
+ def add_documentation(self, documentation: str, **kwargs) -> str:
66
+ id = str(uuid.uuid4()) + "-doc"
67
+ doc_dict = {
68
+ "doc": documentation,
69
+ "_id": id,
70
+ }
71
+
72
+ self.mq.index("vanna-doc").add_documents(
73
+ [doc_dict],
74
+ tensor_fields=["doc"],
75
+ )
76
+ return id
77
+
78
+ def get_training_data(self, **kwargs) -> pd.DataFrame:
79
+ data = []
80
+
81
+ for hit in self.mq.index("vanna-doc").search("", limit=1000)["hits"]:
82
+ data.append(
83
+ {
84
+ "id": hit["_id"],
85
+ "training_data_type": "documentation",
86
+ "question": "",
87
+ "content": hit["doc"],
88
+ }
89
+ )
90
+
91
+ for hit in self.mq.index("vanna-ddl").search("", limit=1000)["hits"]:
92
+ data.append(
93
+ {
94
+ "id": hit["_id"],
95
+ "training_data_type": "ddl",
96
+ "question": "",
97
+ "content": hit["ddl"],
98
+ }
99
+ )
100
+
101
+ for hit in self.mq.index("vanna-sql").search("", limit=1000)["hits"]:
102
+ data.append(
103
+ {
104
+ "id": hit["_id"],
105
+ "training_data_type": "sql",
106
+ "question": hit["question"],
107
+ "content": hit["sql"],
108
+ }
109
+ )
110
+
111
+ df = pd.DataFrame(data)
112
+
113
+ return df
114
+
115
+ def remove_training_data(self, id: str, **kwargs) -> bool:
116
+ if id.endswith("-sql"):
117
+ self.mq.index("vanna-sql").delete_documents(ids=[id])
118
+ return True
119
+ elif id.endswith("-ddl"):
120
+ self.mq.index("vanna-ddl").delete_documents(ids=[id])
121
+ return True
122
+ elif id.endswith("-doc"):
123
+ self.mq.index("vanna-doc").delete_documents(ids=[id])
124
+ return True
125
+ else:
126
+ return False
127
+
128
+ # Static method to extract the documents from the results of a query
129
+ @staticmethod
130
+ def _extract_documents(data) -> list:
131
+ # Check if 'hits' key is in the dictionary and if it's a list
132
+ if "hits" in data and isinstance(data["hits"], list):
133
+ # Iterate over each item in 'hits'
134
+
135
+ if len(data["hits"]) == 0:
136
+ return []
137
+
138
+ # If there is a "doc" key, return the value of that key
139
+ if "doc" in data["hits"][0]:
140
+ return [hit["doc"] for hit in data["hits"]]
141
+
142
+ # If there is a "ddl" key, return the value of that key
143
+ if "ddl" in data["hits"][0]:
144
+ return [hit["ddl"] for hit in data["hits"]]
145
+
146
+ # Otherwise return the entire hit
147
+ return [
148
+ {key: value for key, value in hit.items() if not key.startswith("_")}
149
+ for hit in data["hits"]
150
+ ]
151
+ else:
152
+ # Return an empty list if 'hits' is not found or not a list
153
+ return []
154
+
155
+ def get_similar_question_sql(self, question: str, **kwargs) -> list:
156
+ return Marqo_VectorStore._extract_documents(
157
+ self.mq.index("vanna-sql").search(question)
158
+ )
159
+
160
+ def get_related_ddl(self, question: str, **kwargs) -> list:
161
+ return Marqo_VectorStore._extract_documents(
162
+ self.mq.index("vanna-ddl").search(question)
163
+ )
164
+
165
+ def get_related_documentation(self, question: str, **kwargs) -> list:
166
+ return Marqo_VectorStore._extract_documents(
167
+ self.mq.index("vanna-doc").search(question)
168
+ )