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.
- asksql-2.1.0.dist-info/METADATA +517 -0
- asksql-2.1.0.dist-info/RECORD +291 -0
- asksql-2.1.0.dist-info/WHEEL +4 -0
- asksql-2.1.0.dist-info/entry_points.txt +4 -0
- asksql-2.1.0.dist-info/licenses/LICENSE +21 -0
- vanna/__init__.py +172 -0
- vanna/agents/__init__.py +7 -0
- vanna/capabilities/__init__.py +17 -0
- vanna/capabilities/agent_memory/__init__.py +21 -0
- vanna/capabilities/agent_memory/base.py +103 -0
- vanna/capabilities/agent_memory/models.py +53 -0
- vanna/capabilities/file_system/__init__.py +14 -0
- vanna/capabilities/file_system/base.py +71 -0
- vanna/capabilities/file_system/models.py +25 -0
- vanna/capabilities/sql_runner/__init__.py +13 -0
- vanna/capabilities/sql_runner/base.py +37 -0
- vanna/capabilities/sql_runner/models.py +13 -0
- vanna/components/__init__.py +92 -0
- vanna/components/base.py +11 -0
- vanna/components/rich/__init__.py +83 -0
- vanna/components/rich/containers/__init__.py +7 -0
- vanna/components/rich/containers/card.py +20 -0
- vanna/components/rich/data/__init__.py +9 -0
- vanna/components/rich/data/chart.py +17 -0
- vanna/components/rich/data/dataframe.py +93 -0
- vanna/components/rich/feedback/__init__.py +21 -0
- vanna/components/rich/feedback/badge.py +16 -0
- vanna/components/rich/feedback/icon_text.py +14 -0
- vanna/components/rich/feedback/log_viewer.py +41 -0
- vanna/components/rich/feedback/notification.py +19 -0
- vanna/components/rich/feedback/progress.py +37 -0
- vanna/components/rich/feedback/status_card.py +28 -0
- vanna/components/rich/feedback/status_indicator.py +14 -0
- vanna/components/rich/interactive/__init__.py +21 -0
- vanna/components/rich/interactive/button.py +95 -0
- vanna/components/rich/interactive/task_list.py +58 -0
- vanna/components/rich/interactive/ui_state.py +93 -0
- vanna/components/rich/specialized/__init__.py +7 -0
- vanna/components/rich/specialized/artifact.py +20 -0
- vanna/components/rich/text.py +16 -0
- vanna/components/simple/__init__.py +15 -0
- vanna/components/simple/image.py +15 -0
- vanna/components/simple/link.py +15 -0
- vanna/components/simple/text.py +11 -0
- vanna/core/__init__.py +193 -0
- vanna/core/_compat.py +19 -0
- vanna/core/agent/__init__.py +10 -0
- vanna/core/agent/agent.py +1407 -0
- vanna/core/agent/config.py +123 -0
- vanna/core/audit/__init__.py +28 -0
- vanna/core/audit/base.py +299 -0
- vanna/core/audit/models.py +131 -0
- vanna/core/component_manager.py +329 -0
- vanna/core/components.py +53 -0
- vanna/core/enhancer/__init__.py +11 -0
- vanna/core/enhancer/base.py +94 -0
- vanna/core/enhancer/default.py +118 -0
- vanna/core/enricher/__init__.py +10 -0
- vanna/core/enricher/base.py +59 -0
- vanna/core/errors.py +47 -0
- vanna/core/evaluation/__init__.py +81 -0
- vanna/core/evaluation/base.py +186 -0
- vanna/core/evaluation/dataset.py +254 -0
- vanna/core/evaluation/evaluators.py +376 -0
- vanna/core/evaluation/report.py +289 -0
- vanna/core/evaluation/runner.py +313 -0
- vanna/core/filter/__init__.py +10 -0
- vanna/core/filter/base.py +67 -0
- vanna/core/lifecycle/__init__.py +10 -0
- vanna/core/lifecycle/base.py +83 -0
- vanna/core/llm/__init__.py +16 -0
- vanna/core/llm/base.py +40 -0
- vanna/core/llm/models.py +61 -0
- vanna/core/middleware/__init__.py +10 -0
- vanna/core/middleware/base.py +69 -0
- vanna/core/observability/__init__.py +11 -0
- vanna/core/observability/base.py +88 -0
- vanna/core/observability/models.py +47 -0
- vanna/core/recovery/__init__.py +11 -0
- vanna/core/recovery/base.py +84 -0
- vanna/core/recovery/models.py +32 -0
- vanna/core/registry.py +278 -0
- vanna/core/rich_component.py +156 -0
- vanna/core/simple_component.py +27 -0
- vanna/core/storage/__init__.py +14 -0
- vanna/core/storage/base.py +46 -0
- vanna/core/storage/models.py +46 -0
- vanna/core/system_prompt/__init__.py +13 -0
- vanna/core/system_prompt/base.py +36 -0
- vanna/core/system_prompt/default.py +157 -0
- vanna/core/tool/__init__.py +18 -0
- vanna/core/tool/base.py +70 -0
- vanna/core/tool/models.py +84 -0
- vanna/core/user/__init__.py +17 -0
- vanna/core/user/base.py +29 -0
- vanna/core/user/models.py +25 -0
- vanna/core/user/request_context.py +70 -0
- vanna/core/user/resolver.py +42 -0
- vanna/core/validation.py +164 -0
- vanna/core/workflow/__init__.py +12 -0
- vanna/core/workflow/base.py +254 -0
- vanna/core/workflow/default.py +789 -0
- vanna/examples/__init__.py +1 -0
- vanna/examples/__main__.py +44 -0
- vanna/examples/anthropic_quickstart.py +80 -0
- vanna/examples/artifact_example.py +293 -0
- vanna/examples/claude_sqlite_example.py +236 -0
- vanna/examples/coding_agent_example.py +300 -0
- vanna/examples/custom_system_prompt_example.py +174 -0
- vanna/examples/default_workflow_handler_example.py +208 -0
- vanna/examples/email_auth_example.py +340 -0
- vanna/examples/evaluation_example.py +269 -0
- vanna/examples/extensibility_example.py +262 -0
- vanna/examples/minimal_example.py +67 -0
- vanna/examples/mock_auth_example.py +227 -0
- vanna/examples/mock_custom_tool.py +311 -0
- vanna/examples/mock_quickstart.py +79 -0
- vanna/examples/mock_quota_example.py +145 -0
- vanna/examples/mock_rich_components_demo.py +396 -0
- vanna/examples/mock_sqlite_example.py +223 -0
- vanna/examples/openai_quickstart.py +83 -0
- vanna/examples/primitive_components_demo.py +305 -0
- vanna/examples/quota_lifecycle_example.py +139 -0
- vanna/examples/visualization_example.py +251 -0
- vanna/integrations/__init__.py +17 -0
- vanna/integrations/anthropic/__init__.py +9 -0
- vanna/integrations/anthropic/llm.py +270 -0
- vanna/integrations/azureopenai/__init__.py +9 -0
- vanna/integrations/azureopenai/llm.py +329 -0
- vanna/integrations/azuresearch/__init__.py +7 -0
- vanna/integrations/azuresearch/agent_memory.py +413 -0
- vanna/integrations/bigquery/__init__.py +5 -0
- vanna/integrations/bigquery/sql_runner.py +81 -0
- vanna/integrations/chromadb/__init__.py +104 -0
- vanna/integrations/chromadb/agent_memory.py +488 -0
- vanna/integrations/clickhouse/__init__.py +5 -0
- vanna/integrations/clickhouse/sql_runner.py +82 -0
- vanna/integrations/duckdb/__init__.py +5 -0
- vanna/integrations/duckdb/sql_runner.py +65 -0
- vanna/integrations/faiss/__init__.py +7 -0
- vanna/integrations/faiss/agent_memory.py +435 -0
- vanna/integrations/google/__init__.py +9 -0
- vanna/integrations/google/gemini.py +370 -0
- vanna/integrations/hive/__init__.py +5 -0
- vanna/integrations/hive/sql_runner.py +87 -0
- vanna/integrations/local/__init__.py +17 -0
- vanna/integrations/local/agent_memory/__init__.py +7 -0
- vanna/integrations/local/agent_memory/in_memory.py +285 -0
- vanna/integrations/local/audit.py +59 -0
- vanna/integrations/local/file_system.py +242 -0
- vanna/integrations/local/file_system_conversation_store.py +255 -0
- vanna/integrations/local/storage.py +62 -0
- vanna/integrations/marqo/__init__.py +7 -0
- vanna/integrations/marqo/agent_memory.py +354 -0
- vanna/integrations/milvus/__init__.py +7 -0
- vanna/integrations/milvus/agent_memory.py +458 -0
- vanna/integrations/mock/__init__.py +9 -0
- vanna/integrations/mock/llm.py +65 -0
- vanna/integrations/mssql/__init__.py +5 -0
- vanna/integrations/mssql/sql_runner.py +66 -0
- vanna/integrations/mysql/__init__.py +5 -0
- vanna/integrations/mysql/sql_runner.py +92 -0
- vanna/integrations/ollama/__init__.py +7 -0
- vanna/integrations/ollama/llm.py +252 -0
- vanna/integrations/openai/__init__.py +10 -0
- vanna/integrations/openai/llm.py +267 -0
- vanna/integrations/openai/responses.py +163 -0
- vanna/integrations/opensearch/__init__.py +7 -0
- vanna/integrations/opensearch/agent_memory.py +411 -0
- vanna/integrations/oracle/__init__.py +5 -0
- vanna/integrations/oracle/sql_runner.py +75 -0
- vanna/integrations/pinecone/__init__.py +7 -0
- vanna/integrations/pinecone/agent_memory.py +329 -0
- vanna/integrations/plotly/__init__.py +5 -0
- vanna/integrations/plotly/chart_generator.py +313 -0
- vanna/integrations/postgres/__init__.py +9 -0
- vanna/integrations/postgres/sql_runner.py +112 -0
- vanna/integrations/premium/agent_memory/__init__.py +7 -0
- vanna/integrations/premium/agent_memory/premium.py +186 -0
- vanna/integrations/presto/__init__.py +5 -0
- vanna/integrations/presto/sql_runner.py +107 -0
- vanna/integrations/qdrant/__init__.py +7 -0
- vanna/integrations/qdrant/agent_memory.py +466 -0
- vanna/integrations/snowflake/__init__.py +5 -0
- vanna/integrations/snowflake/sql_runner.py +147 -0
- vanna/integrations/sqlite/__init__.py +9 -0
- vanna/integrations/sqlite/sql_runner.py +65 -0
- vanna/integrations/weaviate/__init__.py +7 -0
- vanna/integrations/weaviate/agent_memory.py +428 -0
- vanna/legacy/ZhipuAI/ZhipuAI_Chat.py +233 -0
- vanna/legacy/ZhipuAI/ZhipuAI_embeddings.py +79 -0
- vanna/legacy/ZhipuAI/__init__.py +2 -0
- vanna/legacy/__init__.py +403 -0
- vanna/legacy/adapter.py +468 -0
- vanna/legacy/advanced/__init__.py +28 -0
- vanna/legacy/anthropic/__init__.py +1 -0
- vanna/legacy/anthropic/anthropic_chat.py +80 -0
- vanna/legacy/azuresearch/__init__.py +1 -0
- vanna/legacy/azuresearch/azuresearch_vector.py +274 -0
- vanna/legacy/base/__init__.py +1 -0
- vanna/legacy/base/base.py +2133 -0
- vanna/legacy/base/safe_exec.py +190 -0
- vanna/legacy/bedrock/__init__.py +1 -0
- vanna/legacy/bedrock/bedrock_converse.py +86 -0
- vanna/legacy/chromadb/__init__.py +1 -0
- vanna/legacy/chromadb/chromadb_vector.py +259 -0
- vanna/legacy/cohere/__init__.py +2 -0
- vanna/legacy/cohere/cohere_chat.py +99 -0
- vanna/legacy/cohere/cohere_embeddings.py +77 -0
- vanna/legacy/deepseek/__init__.py +1 -0
- vanna/legacy/deepseek/deepseek_chat.py +59 -0
- vanna/legacy/exceptions/__init__.py +46 -0
- vanna/legacy/faiss/__init__.py +1 -0
- vanna/legacy/faiss/faiss.py +230 -0
- vanna/legacy/flask/__init__.py +1355 -0
- vanna/legacy/flask/assets.py +58 -0
- vanna/legacy/flask/auth.py +56 -0
- vanna/legacy/google/__init__.py +2 -0
- vanna/legacy/google/bigquery_vector.py +293 -0
- vanna/legacy/google/gemini_chat.py +78 -0
- vanna/legacy/hf/__init__.py +1 -0
- vanna/legacy/hf/hf.py +80 -0
- vanna/legacy/local.py +8 -0
- vanna/legacy/marqo/__init__.py +1 -0
- vanna/legacy/marqo/marqo.py +168 -0
- vanna/legacy/milvus/__init__.py +1 -0
- vanna/legacy/milvus/milvus_vector.py +328 -0
- vanna/legacy/mistral/__init__.py +1 -0
- vanna/legacy/mistral/mistral.py +51 -0
- vanna/legacy/mock/__init__.py +3 -0
- vanna/legacy/mock/embedding.py +11 -0
- vanna/legacy/mock/llm.py +18 -0
- vanna/legacy/mock/vectordb.py +67 -0
- vanna/legacy/ollama/__init__.py +1 -0
- vanna/legacy/ollama/ollama.py +110 -0
- vanna/legacy/openai/__init__.py +2 -0
- vanna/legacy/openai/openai_chat.py +124 -0
- vanna/legacy/openai/openai_embeddings.py +46 -0
- vanna/legacy/opensearch/__init__.py +2 -0
- vanna/legacy/opensearch/opensearch_vector.py +369 -0
- vanna/legacy/opensearch/opensearch_vector_semantic.py +200 -0
- vanna/legacy/oracle/__init__.py +1 -0
- vanna/legacy/oracle/oracle_vector.py +584 -0
- vanna/legacy/pgvector/__init__.py +1 -0
- vanna/legacy/pgvector/pgvector.py +282 -0
- vanna/legacy/pinecone/__init__.py +3 -0
- vanna/legacy/pinecone/pinecone_vector.py +275 -0
- vanna/legacy/qdrant/__init__.py +3 -0
- vanna/legacy/qdrant/qdrant.py +329 -0
- vanna/legacy/qianfan/Qianfan_Chat.py +170 -0
- vanna/legacy/qianfan/Qianfan_embeddings.py +36 -0
- vanna/legacy/qianfan/__init__.py +2 -0
- vanna/legacy/qianwen/QianwenAI_chat.py +132 -0
- vanna/legacy/qianwen/QianwenAI_embeddings.py +46 -0
- vanna/legacy/qianwen/__init__.py +2 -0
- vanna/legacy/remote.py +79 -0
- vanna/legacy/types/__init__.py +292 -0
- vanna/legacy/utils.py +72 -0
- vanna/legacy/vannadb/__init__.py +1 -0
- vanna/legacy/vannadb/vannadb_vector.py +468 -0
- vanna/legacy/vllm/__init__.py +1 -0
- vanna/legacy/vllm/vllm.py +97 -0
- vanna/legacy/weaviate/__init__.py +1 -0
- vanna/legacy/weaviate/weaviate_vector.py +194 -0
- vanna/legacy/xinference/__init__.py +1 -0
- vanna/legacy/xinference/xinference.py +53 -0
- vanna/py.typed +0 -0
- vanna/servers/__init__.py +16 -0
- vanna/servers/__main__.py +8 -0
- vanna/servers/base/__init__.py +18 -0
- vanna/servers/base/chat_handler.py +65 -0
- vanna/servers/base/models.py +111 -0
- vanna/servers/base/rich_chat_handler.py +141 -0
- vanna/servers/base/templates.py +331 -0
- vanna/servers/cli/__init__.py +7 -0
- vanna/servers/cli/server_runner.py +204 -0
- vanna/servers/fastapi/__init__.py +7 -0
- vanna/servers/fastapi/app.py +163 -0
- vanna/servers/fastapi/routes.py +183 -0
- vanna/servers/flask/__init__.py +7 -0
- vanna/servers/flask/app.py +132 -0
- vanna/servers/flask/routes.py +137 -0
- vanna/tools/__init__.py +41 -0
- vanna/tools/agent_memory.py +322 -0
- vanna/tools/file_system.py +879 -0
- vanna/tools/python.py +222 -0
- vanna/tools/run_sql.py +173 -0
- vanna/tools/visualize_data.py +195 -0
- vanna/utils/__init__.py +0 -0
- vanna/utils/sql_safety.py +84 -0
- vanna/web_components/__init__.py +44 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import weaviate
|
|
2
|
+
import weaviate.classes as wvc
|
|
3
|
+
from fastembed import TextEmbedding
|
|
4
|
+
|
|
5
|
+
from vanna.base import VannaBase
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class WeaviateDatabase(VannaBase):
|
|
9
|
+
def __init__(self, config=None):
|
|
10
|
+
"""
|
|
11
|
+
Initialize the VannaEnhanced class with the provided configuration.
|
|
12
|
+
|
|
13
|
+
:param config: Dictionary containing configuration parameters.
|
|
14
|
+
|
|
15
|
+
params:
|
|
16
|
+
weaviate_url (str): Weaviate cluster URL while using weaviate cloud,
|
|
17
|
+
weaviate_api_key (str): Weaviate API key while using weaviate cloud,
|
|
18
|
+
weaviate_port (num): Weaviate port while using local weaviate,
|
|
19
|
+
weaviate_grpc (num): Weaviate gRPC port while using local weaviate,
|
|
20
|
+
fastembed_model (str): Fastembed model name for text embeddings. BAAI/bge-small-en-v1.5 by default.
|
|
21
|
+
|
|
22
|
+
"""
|
|
23
|
+
super().__init__(config=config)
|
|
24
|
+
|
|
25
|
+
if config is None:
|
|
26
|
+
raise ValueError("config is required")
|
|
27
|
+
|
|
28
|
+
self.n_results = config.get("n_results", 3)
|
|
29
|
+
self.fastembed_model = config.get("fastembed_model", "BAAI/bge-small-en-v1.5")
|
|
30
|
+
self.weaviate_api_key = config.get("weaviate_api_key")
|
|
31
|
+
self.weaviate_url = config.get("weaviate_url")
|
|
32
|
+
self.weaviate_port = config.get("weaviate_port")
|
|
33
|
+
self.weaviate_grpc_port = config.get("weaviate_grpc", 50051)
|
|
34
|
+
|
|
35
|
+
if not self.weaviate_api_key and not self.weaviate_port:
|
|
36
|
+
raise ValueError("Add proper credentials to connect to weaviate")
|
|
37
|
+
|
|
38
|
+
self.weaviate_client = self._initialize_weaviate_client()
|
|
39
|
+
self.embeddings = TextEmbedding(model_name=self.fastembed_model)
|
|
40
|
+
|
|
41
|
+
self.training_data_cluster = {
|
|
42
|
+
"sql": "SQLTrainingDataEntry",
|
|
43
|
+
"ddl": "DDLEntry",
|
|
44
|
+
"doc": "DocumentationEntry",
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
self._create_collections_if_not_exist()
|
|
48
|
+
|
|
49
|
+
def _create_collections_if_not_exist(self):
|
|
50
|
+
properties_dict = {
|
|
51
|
+
self.training_data_cluster["ddl"]: [
|
|
52
|
+
wvc.config.Property(
|
|
53
|
+
name="description", data_type=wvc.config.DataType.TEXT
|
|
54
|
+
),
|
|
55
|
+
],
|
|
56
|
+
self.training_data_cluster["doc"]: [
|
|
57
|
+
wvc.config.Property(
|
|
58
|
+
name="description", data_type=wvc.config.DataType.TEXT
|
|
59
|
+
),
|
|
60
|
+
],
|
|
61
|
+
self.training_data_cluster["sql"]: [
|
|
62
|
+
wvc.config.Property(name="sql", data_type=wvc.config.DataType.TEXT),
|
|
63
|
+
wvc.config.Property(
|
|
64
|
+
name="natural_language_question", data_type=wvc.config.DataType.TEXT
|
|
65
|
+
),
|
|
66
|
+
],
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
for cluster, properties in properties_dict.items():
|
|
70
|
+
if not self.weaviate_client.collections.exists(cluster):
|
|
71
|
+
self.weaviate_client.collections.create(
|
|
72
|
+
name=cluster, properties=properties
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
def _initialize_weaviate_client(self):
|
|
76
|
+
if self.weaviate_api_key:
|
|
77
|
+
return weaviate.connect_to_wcs(
|
|
78
|
+
cluster_url=self.weaviate_url,
|
|
79
|
+
auth_credentials=weaviate.auth.AuthApiKey(self.weaviate_api_key),
|
|
80
|
+
additional_config=weaviate.config.AdditionalConfig(timeout=(10, 300)),
|
|
81
|
+
skip_init_checks=True,
|
|
82
|
+
)
|
|
83
|
+
else:
|
|
84
|
+
return weaviate.connect_to_local(
|
|
85
|
+
port=self.weaviate_port,
|
|
86
|
+
grpc_port=self.weaviate_grpc_port,
|
|
87
|
+
additional_config=weaviate.config.AdditionalConfig(timeout=(10, 300)),
|
|
88
|
+
skip_init_checks=True,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
def generate_embedding(self, data: str, **kwargs):
|
|
92
|
+
embedding_model = TextEmbedding(model_name=self.fastembed_model)
|
|
93
|
+
embedding = next(embedding_model.embed(data))
|
|
94
|
+
return embedding.tolist()
|
|
95
|
+
|
|
96
|
+
def _insert_data(self, cluster_key: str, data_object: dict, vector: list) -> str:
|
|
97
|
+
self.weaviate_client.connect()
|
|
98
|
+
response = self.weaviate_client.collections.get(
|
|
99
|
+
self.training_data_cluster[cluster_key]
|
|
100
|
+
).data.insert(properties=data_object, vector=vector)
|
|
101
|
+
self.weaviate_client.close()
|
|
102
|
+
return response
|
|
103
|
+
|
|
104
|
+
def add_ddl(self, ddl: str, **kwargs) -> str:
|
|
105
|
+
data_object = {
|
|
106
|
+
"description": ddl,
|
|
107
|
+
}
|
|
108
|
+
response = self._insert_data("ddl", data_object, self.generate_embedding(ddl))
|
|
109
|
+
return f"{response}-ddl"
|
|
110
|
+
|
|
111
|
+
def add_documentation(self, doc: str, **kwargs) -> str:
|
|
112
|
+
data_object = {
|
|
113
|
+
"description": doc,
|
|
114
|
+
}
|
|
115
|
+
response = self._insert_data("doc", data_object, self.generate_embedding(doc))
|
|
116
|
+
return f"{response}-doc"
|
|
117
|
+
|
|
118
|
+
def add_question_sql(self, question: str, sql: str, **kwargs) -> str:
|
|
119
|
+
data_object = {
|
|
120
|
+
"sql": sql,
|
|
121
|
+
"natural_language_question": question,
|
|
122
|
+
}
|
|
123
|
+
response = self._insert_data(
|
|
124
|
+
"sql", data_object, self.generate_embedding(question)
|
|
125
|
+
)
|
|
126
|
+
return f"{response}-sql"
|
|
127
|
+
|
|
128
|
+
def _query_collection(
|
|
129
|
+
self, cluster_key: str, vector_input: list, return_properties: list
|
|
130
|
+
) -> list:
|
|
131
|
+
self.weaviate_client.connect()
|
|
132
|
+
collection = self.weaviate_client.collections.get(
|
|
133
|
+
self.training_data_cluster[cluster_key]
|
|
134
|
+
)
|
|
135
|
+
response = collection.query.near_vector(
|
|
136
|
+
near_vector=vector_input,
|
|
137
|
+
limit=self.n_results,
|
|
138
|
+
return_properties=return_properties,
|
|
139
|
+
)
|
|
140
|
+
response_list = [item.properties for item in response.objects]
|
|
141
|
+
self.weaviate_client.close()
|
|
142
|
+
return response_list
|
|
143
|
+
|
|
144
|
+
def get_related_ddl(self, question: str, **kwargs) -> list:
|
|
145
|
+
vector_input = self.generate_embedding(question)
|
|
146
|
+
response_list = self._query_collection("ddl", vector_input, ["description"])
|
|
147
|
+
return [item["description"] for item in response_list]
|
|
148
|
+
|
|
149
|
+
def get_related_documentation(self, question: str, **kwargs) -> list:
|
|
150
|
+
vector_input = self.generate_embedding(question)
|
|
151
|
+
response_list = self._query_collection("doc", vector_input, ["description"])
|
|
152
|
+
return [item["description"] for item in response_list]
|
|
153
|
+
|
|
154
|
+
def get_similar_question_sql(self, question: str, **kwargs) -> list:
|
|
155
|
+
vector_input = self.generate_embedding(question)
|
|
156
|
+
response_list = self._query_collection(
|
|
157
|
+
"sql", vector_input, ["sql", "natural_language_question"]
|
|
158
|
+
)
|
|
159
|
+
return [
|
|
160
|
+
{"question": item["natural_language_question"], "sql": item["sql"]}
|
|
161
|
+
for item in response_list
|
|
162
|
+
]
|
|
163
|
+
|
|
164
|
+
def get_training_data(self, **kwargs) -> list:
|
|
165
|
+
self.weaviate_client.connect()
|
|
166
|
+
combined_response_list = []
|
|
167
|
+
for collection_name in self.training_data_cluster.values():
|
|
168
|
+
if self.weaviate_client.collections.exists(collection_name):
|
|
169
|
+
collection = self.weaviate_client.collections.get(collection_name)
|
|
170
|
+
response_list = [item.properties for item in collection.iterator()]
|
|
171
|
+
combined_response_list.extend(response_list)
|
|
172
|
+
self.weaviate_client.close()
|
|
173
|
+
return combined_response_list
|
|
174
|
+
|
|
175
|
+
def remove_training_data(self, id: str, **kwargs) -> bool:
|
|
176
|
+
self.weaviate_client.connect()
|
|
177
|
+
success = False
|
|
178
|
+
if id.endswith("-sql"):
|
|
179
|
+
id = id.replace("-sql", "")
|
|
180
|
+
success = self.weaviate_client.collections.get(
|
|
181
|
+
self.training_data_cluster["sql"]
|
|
182
|
+
).data.delete_by_id(id)
|
|
183
|
+
elif id.endswith("-ddl"):
|
|
184
|
+
id = id.replace("-ddl", "")
|
|
185
|
+
success = self.weaviate_client.collections.get(
|
|
186
|
+
self.training_data_cluster["ddl"]
|
|
187
|
+
).data.delete_by_id(id)
|
|
188
|
+
elif id.endswith("-doc"):
|
|
189
|
+
id = id.replace("-doc", "")
|
|
190
|
+
success = self.weaviate_client.collections.get(
|
|
191
|
+
self.training_data_cluster["doc"]
|
|
192
|
+
).data.delete_by_id(id)
|
|
193
|
+
self.weaviate_client.close()
|
|
194
|
+
return success
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .xinference import Xinference
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from xinference_client.client.restful.restful_client import (
|
|
2
|
+
Client,
|
|
3
|
+
RESTfulChatModelHandle,
|
|
4
|
+
)
|
|
5
|
+
|
|
6
|
+
from ..base import VannaBase
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Xinference(VannaBase):
|
|
10
|
+
def __init__(self, config=None):
|
|
11
|
+
VannaBase.__init__(self, config=config)
|
|
12
|
+
|
|
13
|
+
if not config or "base_url" not in config:
|
|
14
|
+
raise ValueError("config must contain at least Xinference base_url")
|
|
15
|
+
|
|
16
|
+
base_url = config["base_url"]
|
|
17
|
+
api_key = config.get("api_key", "not empty")
|
|
18
|
+
self.xinference_client = Client(base_url=base_url, api_key=api_key)
|
|
19
|
+
|
|
20
|
+
def system_message(self, message: str) -> any:
|
|
21
|
+
return {"role": "system", "content": message}
|
|
22
|
+
|
|
23
|
+
def user_message(self, message: str) -> any:
|
|
24
|
+
return {"role": "user", "content": message}
|
|
25
|
+
|
|
26
|
+
def assistant_message(self, message: str) -> any:
|
|
27
|
+
return {"role": "assistant", "content": message}
|
|
28
|
+
|
|
29
|
+
def submit_prompt(self, prompt, **kwargs) -> str:
|
|
30
|
+
if prompt is None:
|
|
31
|
+
raise Exception("Prompt is None")
|
|
32
|
+
|
|
33
|
+
if len(prompt) == 0:
|
|
34
|
+
raise Exception("Prompt is empty")
|
|
35
|
+
|
|
36
|
+
num_tokens = 0
|
|
37
|
+
for message in prompt:
|
|
38
|
+
num_tokens += len(message["content"]) / 4
|
|
39
|
+
|
|
40
|
+
model_uid = kwargs.get("model_uid") or self.config.get("model_uid", None)
|
|
41
|
+
if model_uid is None:
|
|
42
|
+
raise ValueError("model_uid is required")
|
|
43
|
+
|
|
44
|
+
xinference_model = self.xinference_client.get_model(model_uid)
|
|
45
|
+
if isinstance(xinference_model, RESTfulChatModelHandle):
|
|
46
|
+
print(f"Using model_uid {model_uid} for {num_tokens} tokens (approx)")
|
|
47
|
+
|
|
48
|
+
response = xinference_model.chat(prompt)
|
|
49
|
+
return response["choices"][0]["message"]["content"]
|
|
50
|
+
else:
|
|
51
|
+
raise NotImplementedError(
|
|
52
|
+
f"Xinference model handle type {type(xinference_model)} is not supported, required RESTfulChatModelHandle"
|
|
53
|
+
)
|
vanna/py.typed
ADDED
|
File without changes
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Server implementations for the Vanna Agents framework.
|
|
3
|
+
|
|
4
|
+
This module provides Flask and FastAPI server factories for serving
|
|
5
|
+
Vanna agents over HTTP with SSE, WebSocket, and polling endpoints.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from .base import ChatHandler, ChatRequest, ChatStreamChunk
|
|
9
|
+
from .cli.server_runner import ExampleAgentLoader
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"ChatHandler",
|
|
13
|
+
"ChatRequest",
|
|
14
|
+
"ChatStreamChunk",
|
|
15
|
+
"ExampleAgentLoader",
|
|
16
|
+
]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Base server components for the Vanna Agents framework.
|
|
3
|
+
|
|
4
|
+
This module provides framework-agnostic components for handling chat
|
|
5
|
+
requests and responses.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from .chat_handler import ChatHandler
|
|
9
|
+
from .models import ChatRequest, ChatStreamChunk, ChatResponse
|
|
10
|
+
from .templates import INDEX_HTML
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"ChatHandler",
|
|
14
|
+
"ChatRequest",
|
|
15
|
+
"ChatStreamChunk",
|
|
16
|
+
"ChatResponse",
|
|
17
|
+
"INDEX_HTML",
|
|
18
|
+
]
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Framework-agnostic chat handling logic.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import uuid
|
|
6
|
+
from typing import AsyncGenerator, List
|
|
7
|
+
|
|
8
|
+
from ...core import Agent
|
|
9
|
+
from .models import ChatRequest, ChatResponse, ChatStreamChunk
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ChatHandler:
|
|
13
|
+
"""Core chat handling logic - framework agnostic."""
|
|
14
|
+
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
agent: Agent,
|
|
18
|
+
):
|
|
19
|
+
"""Initialize chat handler.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
agent: The agent to handle chat requests
|
|
23
|
+
"""
|
|
24
|
+
self.agent = agent
|
|
25
|
+
|
|
26
|
+
async def handle_stream(
|
|
27
|
+
self, request: ChatRequest
|
|
28
|
+
) -> AsyncGenerator[ChatStreamChunk, None]:
|
|
29
|
+
"""Stream chat responses.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
request: Chat request
|
|
33
|
+
|
|
34
|
+
Yields:
|
|
35
|
+
Chat stream chunks
|
|
36
|
+
"""
|
|
37
|
+
conversation_id = request.conversation_id or self._generate_conversation_id()
|
|
38
|
+
# Use request_id from client for tracking, or use the one generated internally
|
|
39
|
+
request_id = request.request_id or str(uuid.uuid4())
|
|
40
|
+
|
|
41
|
+
async for component in self.agent.send_message(
|
|
42
|
+
request_context=request.request_context,
|
|
43
|
+
message=request.message,
|
|
44
|
+
conversation_id=conversation_id,
|
|
45
|
+
):
|
|
46
|
+
yield ChatStreamChunk.from_component(component, conversation_id, request_id)
|
|
47
|
+
|
|
48
|
+
async def handle_poll(self, request: ChatRequest) -> ChatResponse:
|
|
49
|
+
"""Handle polling-based chat.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
request: Chat request
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
Complete chat response
|
|
56
|
+
"""
|
|
57
|
+
chunks = []
|
|
58
|
+
async for chunk in self.handle_stream(request):
|
|
59
|
+
chunks.append(chunk)
|
|
60
|
+
|
|
61
|
+
return ChatResponse.from_chunks(chunks)
|
|
62
|
+
|
|
63
|
+
def _generate_conversation_id(self) -> str:
|
|
64
|
+
"""Generate new conversation ID."""
|
|
65
|
+
return f"conv_{uuid.uuid4().hex[:8]}"
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Request and response models for server endpoints.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import time
|
|
6
|
+
import uuid
|
|
7
|
+
from typing import Any, Dict, List, Optional, Union
|
|
8
|
+
|
|
9
|
+
from pydantic import BaseModel, Field
|
|
10
|
+
|
|
11
|
+
from ...components import UiComponent, RichComponent
|
|
12
|
+
from ...core.component_manager import ComponentUpdate
|
|
13
|
+
from ...core.user.request_context import RequestContext
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ChatRequest(BaseModel):
|
|
17
|
+
"""Request model for chat endpoints."""
|
|
18
|
+
|
|
19
|
+
message: str = Field(description="User message")
|
|
20
|
+
conversation_id: Optional[str] = Field(default=None, description="Conversation ID")
|
|
21
|
+
request_id: Optional[str] = Field(
|
|
22
|
+
default=None, description="Request ID for tracing"
|
|
23
|
+
)
|
|
24
|
+
request_context: RequestContext = Field(
|
|
25
|
+
default_factory=RequestContext,
|
|
26
|
+
description="Request context for user resolution",
|
|
27
|
+
)
|
|
28
|
+
metadata: Dict[str, Any] = Field(
|
|
29
|
+
default_factory=dict, description="Additional metadata"
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class ChatStreamChunk(BaseModel):
|
|
34
|
+
"""Single chunk in a streaming chat response."""
|
|
35
|
+
|
|
36
|
+
rich: Dict[str, Any] = Field(description="Rich component data for advanced UIs")
|
|
37
|
+
simple: Optional[Dict[str, Any]] = Field(
|
|
38
|
+
default=None, description="Simple component data for basic UIs"
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
# Stream metadata
|
|
42
|
+
conversation_id: str = Field(description="Conversation ID")
|
|
43
|
+
request_id: str = Field(description="Request ID")
|
|
44
|
+
timestamp: float = Field(default_factory=time.time, description="Timestamp")
|
|
45
|
+
|
|
46
|
+
@classmethod
|
|
47
|
+
def from_component(
|
|
48
|
+
cls,
|
|
49
|
+
component: Union[UiComponent, RichComponent],
|
|
50
|
+
conversation_id: str,
|
|
51
|
+
request_id: str,
|
|
52
|
+
) -> "ChatStreamChunk":
|
|
53
|
+
"""Create chunk from UI component or rich component."""
|
|
54
|
+
|
|
55
|
+
if isinstance(component, UiComponent):
|
|
56
|
+
# Full UiComponent with both rich and simple
|
|
57
|
+
rich_data = component.rich_component.serialize_for_frontend()
|
|
58
|
+
simple_data = None
|
|
59
|
+
if component.simple_component:
|
|
60
|
+
simple_data = component.simple_component.serialize_for_frontend()
|
|
61
|
+
|
|
62
|
+
return cls(
|
|
63
|
+
rich=rich_data,
|
|
64
|
+
simple=simple_data,
|
|
65
|
+
conversation_id=conversation_id,
|
|
66
|
+
request_id=request_id,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# Rich component only (no simple fallback)
|
|
70
|
+
rich_data = component.serialize_for_frontend()
|
|
71
|
+
return cls(
|
|
72
|
+
rich=rich_data,
|
|
73
|
+
simple=None,
|
|
74
|
+
conversation_id=conversation_id,
|
|
75
|
+
request_id=request_id,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
@classmethod
|
|
79
|
+
def from_component_update(
|
|
80
|
+
cls, update: ComponentUpdate, conversation_id: str, request_id: str
|
|
81
|
+
) -> "ChatStreamChunk":
|
|
82
|
+
"""Create chunk from component update."""
|
|
83
|
+
update_payload = update.serialize_for_frontend()
|
|
84
|
+
return cls(
|
|
85
|
+
rich=update_payload,
|
|
86
|
+
simple=None, # Component updates don't have simple representations
|
|
87
|
+
conversation_id=conversation_id,
|
|
88
|
+
request_id=request_id,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class ChatResponse(BaseModel):
|
|
93
|
+
"""Complete chat response for polling endpoints."""
|
|
94
|
+
|
|
95
|
+
chunks: List[ChatStreamChunk] = Field(description="Response chunks")
|
|
96
|
+
conversation_id: str = Field(description="Conversation ID")
|
|
97
|
+
request_id: str = Field(description="Request ID")
|
|
98
|
+
total_chunks: int = Field(description="Total number of chunks")
|
|
99
|
+
|
|
100
|
+
@classmethod
|
|
101
|
+
def from_chunks(cls, chunks: List[ChatStreamChunk]) -> "ChatResponse":
|
|
102
|
+
"""Create response from chunks."""
|
|
103
|
+
if not chunks:
|
|
104
|
+
return cls(chunks=[], conversation_id="", request_id="", total_chunks=0)
|
|
105
|
+
|
|
106
|
+
return cls(
|
|
107
|
+
chunks=chunks,
|
|
108
|
+
conversation_id=chunks[0].conversation_id,
|
|
109
|
+
request_id=chunks[0].request_id,
|
|
110
|
+
total_chunks=len(chunks),
|
|
111
|
+
)
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# """
|
|
2
|
+
# Rich component-aware chat handling logic.
|
|
3
|
+
# """
|
|
4
|
+
|
|
5
|
+
# import uuid
|
|
6
|
+
# from typing import AsyncGenerator, Callable, List, Optional, Union
|
|
7
|
+
|
|
8
|
+
# from ...core import Agent, User
|
|
9
|
+
# from ...core.rich_components import RichComponent
|
|
10
|
+
# from ...core.component_manager import ComponentManager, ComponentUpdate
|
|
11
|
+
# from .models import ChatRequest, ChatResponse, ChatStreamChunk
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# class RichChatHandler:
|
|
15
|
+
# """Rich component-aware chat handling logic."""
|
|
16
|
+
|
|
17
|
+
# def __init__(
|
|
18
|
+
# self,
|
|
19
|
+
# agent: Agent,
|
|
20
|
+
# default_user_factory: Optional[Callable[[Optional[str]], User]] = None,
|
|
21
|
+
# ):
|
|
22
|
+
# """Initialize rich chat handler.
|
|
23
|
+
|
|
24
|
+
# Args:
|
|
25
|
+
# agent: The agent to handle chat requests
|
|
26
|
+
# default_user_factory: Function to create default user from user_id
|
|
27
|
+
# """
|
|
28
|
+
# self.agent = agent
|
|
29
|
+
# self.default_user_factory = default_user_factory or self._create_default_user
|
|
30
|
+
# self.component_managers: dict[str, ComponentManager] = {} # Per conversation
|
|
31
|
+
|
|
32
|
+
# async def handle_stream(
|
|
33
|
+
# self, request: ChatRequest
|
|
34
|
+
# ) -> AsyncGenerator[ChatStreamChunk, None]:
|
|
35
|
+
# """Stream chat responses with rich component support.
|
|
36
|
+
|
|
37
|
+
# Args:
|
|
38
|
+
# request: Chat request
|
|
39
|
+
|
|
40
|
+
# Yields:
|
|
41
|
+
# Chat stream chunks including rich component updates
|
|
42
|
+
# """
|
|
43
|
+
# user = self._resolve_user(request.user_id)
|
|
44
|
+
# conversation_id = request.conversation_id or self._generate_conversation_id()
|
|
45
|
+
# request_id = request.request_id or str(uuid.uuid4())
|
|
46
|
+
|
|
47
|
+
# # Get or create component manager for this conversation
|
|
48
|
+
# if conversation_id not in self.component_managers:
|
|
49
|
+
# self.component_managers[conversation_id] = ComponentManager()
|
|
50
|
+
|
|
51
|
+
# component_manager = self.component_managers[conversation_id]
|
|
52
|
+
|
|
53
|
+
# async for component in self.agent.send_message(
|
|
54
|
+
# conversation_id=conversation_id,
|
|
55
|
+
# user=user,
|
|
56
|
+
# message=request.message,
|
|
57
|
+
# request_id=request_id,
|
|
58
|
+
# ):
|
|
59
|
+
# if isinstance(component, RichComponent):
|
|
60
|
+
# # Handle rich component through manager
|
|
61
|
+
# update = component_manager.emit(component)
|
|
62
|
+
# yield ChatStreamChunk.from_component_update(update, conversation_id, request_id)
|
|
63
|
+
# else:
|
|
64
|
+
# # Handle legacy components
|
|
65
|
+
# yield ChatStreamChunk.from_component(component, conversation_id, request_id)
|
|
66
|
+
|
|
67
|
+
# async def handle_poll(self, request: ChatRequest) -> ChatResponse:
|
|
68
|
+
# """Handle polling request with rich component support.
|
|
69
|
+
|
|
70
|
+
# Args:
|
|
71
|
+
# request: Chat request
|
|
72
|
+
|
|
73
|
+
# Returns:
|
|
74
|
+
# Complete chat response with all components
|
|
75
|
+
# """
|
|
76
|
+
# chunks: List[ChatStreamChunk] = []
|
|
77
|
+
|
|
78
|
+
# async for chunk in self.handle_stream(request):
|
|
79
|
+
# chunks.append(chunk)
|
|
80
|
+
|
|
81
|
+
# return ChatResponse.from_chunks(chunks)
|
|
82
|
+
|
|
83
|
+
# def get_component_manager(self, conversation_id: str) -> Optional[ComponentManager]:
|
|
84
|
+
# """Get the component manager for a conversation."""
|
|
85
|
+
# return self.component_managers.get(conversation_id)
|
|
86
|
+
|
|
87
|
+
# def get_component(self, conversation_id: str, component_id: str) -> Optional[RichComponent]:
|
|
88
|
+
# """Get a specific component from a conversation."""
|
|
89
|
+
# manager = self.get_component_manager(conversation_id)
|
|
90
|
+
# return manager.get_component(component_id) if manager else None
|
|
91
|
+
|
|
92
|
+
# def get_all_components(self, conversation_id: str) -> List[RichComponent]:
|
|
93
|
+
# """Get all components in a conversation."""
|
|
94
|
+
# manager = self.get_component_manager(conversation_id)
|
|
95
|
+
# return manager.get_all_components() if manager else []
|
|
96
|
+
|
|
97
|
+
# def update_component(
|
|
98
|
+
# self,
|
|
99
|
+
# conversation_id: str,
|
|
100
|
+
# component_id: str,
|
|
101
|
+
# **updates
|
|
102
|
+
# ) -> Optional[ComponentUpdate]:
|
|
103
|
+
# """Update a component in a conversation."""
|
|
104
|
+
# manager = self.get_component_manager(conversation_id)
|
|
105
|
+
# return manager.update_component(component_id, **updates) if manager else None
|
|
106
|
+
|
|
107
|
+
# def remove_component(
|
|
108
|
+
# self,
|
|
109
|
+
# conversation_id: str,
|
|
110
|
+
# component_id: str
|
|
111
|
+
# ) -> Optional[ComponentUpdate]:
|
|
112
|
+
# """Remove a component from a conversation."""
|
|
113
|
+
# manager = self.get_component_manager(conversation_id)
|
|
114
|
+
# return manager.remove_component(component_id) if manager else None
|
|
115
|
+
|
|
116
|
+
# def clear_conversation_components(self, conversation_id: str):
|
|
117
|
+
# """Clear all components for a conversation."""
|
|
118
|
+
# if conversation_id in self.component_managers:
|
|
119
|
+
# del self.component_managers[conversation_id]
|
|
120
|
+
|
|
121
|
+
# def _resolve_user(self, user_id: Optional[str]) -> User:
|
|
122
|
+
# """Resolve user from ID or create default."""
|
|
123
|
+
# if user_id:
|
|
124
|
+
# # In a real implementation, you'd fetch from a user store
|
|
125
|
+
# return User(id=user_id, username=f"user_{user_id}", email="", permissions=[])
|
|
126
|
+
|
|
127
|
+
# return self.default_user_factory(user_id)
|
|
128
|
+
|
|
129
|
+
# def _create_default_user(self, user_id: Optional[str]) -> User:
|
|
130
|
+
# """Create a default user."""
|
|
131
|
+
# user_id = user_id or "anonymous"
|
|
132
|
+
# return User(
|
|
133
|
+
# id=user_id,
|
|
134
|
+
# username=f"user_{user_id}",
|
|
135
|
+
# email="",
|
|
136
|
+
# permissions=[]
|
|
137
|
+
# )
|
|
138
|
+
|
|
139
|
+
# def _generate_conversation_id(self) -> str:
|
|
140
|
+
# """Generate a new conversation ID."""
|
|
141
|
+
# return str(uuid.uuid4())
|