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,428 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Weaviate vector database implementation of AgentMemory.
|
|
3
|
+
|
|
4
|
+
This implementation uses Weaviate for semantic search and storage of tool usage patterns.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
import uuid
|
|
9
|
+
from datetime import datetime
|
|
10
|
+
from typing import Any, Dict, List, Optional
|
|
11
|
+
import asyncio
|
|
12
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
13
|
+
|
|
14
|
+
try:
|
|
15
|
+
import weaviate
|
|
16
|
+
from weaviate.classes.config import (
|
|
17
|
+
Configure,
|
|
18
|
+
Property,
|
|
19
|
+
DataType as WeaviateDataType,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
WEAVIATE_AVAILABLE = True
|
|
23
|
+
except ImportError:
|
|
24
|
+
WEAVIATE_AVAILABLE = False
|
|
25
|
+
|
|
26
|
+
from vanna.capabilities.agent_memory import (
|
|
27
|
+
AgentMemory,
|
|
28
|
+
TextMemory,
|
|
29
|
+
TextMemorySearchResult,
|
|
30
|
+
ToolMemory,
|
|
31
|
+
ToolMemorySearchResult,
|
|
32
|
+
)
|
|
33
|
+
from vanna.core.tool import ToolContext
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class WeaviateAgentMemory(AgentMemory):
|
|
37
|
+
"""Weaviate-based implementation of AgentMemory."""
|
|
38
|
+
|
|
39
|
+
def __init__(
|
|
40
|
+
self,
|
|
41
|
+
collection_name: str = "ToolMemory",
|
|
42
|
+
url: str = "http://localhost:8080",
|
|
43
|
+
api_key: Optional[str] = None,
|
|
44
|
+
dimension: int = 384,
|
|
45
|
+
):
|
|
46
|
+
if not WEAVIATE_AVAILABLE:
|
|
47
|
+
raise ImportError(
|
|
48
|
+
"Weaviate is required for WeaviateAgentMemory. Install with: pip install weaviate-client"
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
self.collection_name = collection_name
|
|
52
|
+
self.url = url
|
|
53
|
+
self.api_key = api_key
|
|
54
|
+
self.dimension = dimension
|
|
55
|
+
self._client = None
|
|
56
|
+
self._executor = ThreadPoolExecutor(max_workers=2)
|
|
57
|
+
|
|
58
|
+
def _get_client(self):
|
|
59
|
+
"""Get or create Weaviate client."""
|
|
60
|
+
if self._client is None:
|
|
61
|
+
if self.api_key:
|
|
62
|
+
self._client = weaviate.connect_to_weaviate_cloud(
|
|
63
|
+
cluster_url=self.url,
|
|
64
|
+
auth_credentials=weaviate.auth.AuthApiKey(self.api_key),
|
|
65
|
+
)
|
|
66
|
+
else:
|
|
67
|
+
self._client = weaviate.connect_to_local(
|
|
68
|
+
host=self.url.replace("http://", "").replace("https://", "")
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
# Create collection if it doesn't exist
|
|
72
|
+
if not self._client.collections.exists(self.collection_name):
|
|
73
|
+
self._client.collections.create(
|
|
74
|
+
name=self.collection_name,
|
|
75
|
+
vectorizer_config=Configure.Vectorizer.none(),
|
|
76
|
+
properties=[
|
|
77
|
+
Property(name="question", data_type=WeaviateDataType.TEXT),
|
|
78
|
+
Property(name="tool_name", data_type=WeaviateDataType.TEXT),
|
|
79
|
+
Property(name="args_json", data_type=WeaviateDataType.TEXT),
|
|
80
|
+
Property(name="timestamp", data_type=WeaviateDataType.TEXT),
|
|
81
|
+
Property(name="success", data_type=WeaviateDataType.BOOL),
|
|
82
|
+
Property(name="metadata_json", data_type=WeaviateDataType.TEXT),
|
|
83
|
+
],
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
return self._client
|
|
87
|
+
|
|
88
|
+
def _create_embedding(self, text: str) -> List[float]:
|
|
89
|
+
"""Create a simple embedding from text (placeholder)."""
|
|
90
|
+
import hashlib
|
|
91
|
+
|
|
92
|
+
hash_val = int(hashlib.md5(text.encode()).hexdigest(), 16)
|
|
93
|
+
return [(hash_val >> i) % 100 / 100.0 for i in range(self.dimension)]
|
|
94
|
+
|
|
95
|
+
async def save_tool_usage(
|
|
96
|
+
self,
|
|
97
|
+
question: str,
|
|
98
|
+
tool_name: str,
|
|
99
|
+
args: Dict[str, Any],
|
|
100
|
+
context: ToolContext,
|
|
101
|
+
success: bool = True,
|
|
102
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
103
|
+
) -> None:
|
|
104
|
+
"""Save a tool usage pattern."""
|
|
105
|
+
|
|
106
|
+
def _save():
|
|
107
|
+
client = self._get_client()
|
|
108
|
+
collection = client.collections.get(self.collection_name)
|
|
109
|
+
|
|
110
|
+
memory_id = str(uuid.uuid4())
|
|
111
|
+
timestamp = datetime.now().isoformat()
|
|
112
|
+
embedding = self._create_embedding(question)
|
|
113
|
+
|
|
114
|
+
properties = {
|
|
115
|
+
"question": question,
|
|
116
|
+
"tool_name": tool_name,
|
|
117
|
+
"args_json": json.dumps(args),
|
|
118
|
+
"timestamp": timestamp,
|
|
119
|
+
"success": success,
|
|
120
|
+
"metadata_json": json.dumps(metadata or {}),
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
collection.data.insert(
|
|
124
|
+
properties=properties, vector=embedding, uuid=memory_id
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
await asyncio.get_event_loop().run_in_executor(self._executor, _save)
|
|
128
|
+
|
|
129
|
+
async def search_similar_usage(
|
|
130
|
+
self,
|
|
131
|
+
question: str,
|
|
132
|
+
context: ToolContext,
|
|
133
|
+
*,
|
|
134
|
+
limit: int = 10,
|
|
135
|
+
similarity_threshold: float = 0.7,
|
|
136
|
+
tool_name_filter: Optional[str] = None,
|
|
137
|
+
) -> List[ToolMemorySearchResult]:
|
|
138
|
+
"""Search for similar tool usage patterns."""
|
|
139
|
+
|
|
140
|
+
def _search():
|
|
141
|
+
client = self._get_client()
|
|
142
|
+
collection = client.collections.get(self.collection_name)
|
|
143
|
+
|
|
144
|
+
embedding = self._create_embedding(question)
|
|
145
|
+
|
|
146
|
+
# Build filter
|
|
147
|
+
filters = weaviate.classes.query.Filter.by_property("success").equal(True)
|
|
148
|
+
if tool_name_filter:
|
|
149
|
+
filters = filters & weaviate.classes.query.Filter.by_property(
|
|
150
|
+
"tool_name"
|
|
151
|
+
).equal(tool_name_filter)
|
|
152
|
+
|
|
153
|
+
response = collection.query.near_vector(
|
|
154
|
+
near_vector=embedding,
|
|
155
|
+
limit=limit,
|
|
156
|
+
filters=filters,
|
|
157
|
+
return_metadata=weaviate.classes.query.MetadataQuery(distance=True),
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
search_results = []
|
|
161
|
+
for i, obj in enumerate(response.objects):
|
|
162
|
+
# Weaviate returns distance, convert to similarity
|
|
163
|
+
distance = obj.metadata.distance if obj.metadata else 1.0
|
|
164
|
+
similarity_score = 1 - distance
|
|
165
|
+
|
|
166
|
+
if similarity_score >= similarity_threshold:
|
|
167
|
+
properties = obj.properties
|
|
168
|
+
args = json.loads(properties.get("args_json", "{}"))
|
|
169
|
+
metadata_dict = json.loads(properties.get("metadata_json", "{}"))
|
|
170
|
+
|
|
171
|
+
memory = ToolMemory(
|
|
172
|
+
memory_id=str(obj.uuid),
|
|
173
|
+
question=properties.get("question"),
|
|
174
|
+
tool_name=properties.get("tool_name"),
|
|
175
|
+
args=args,
|
|
176
|
+
timestamp=properties.get("timestamp"),
|
|
177
|
+
success=properties.get("success", True),
|
|
178
|
+
metadata=metadata_dict,
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
search_results.append(
|
|
182
|
+
ToolMemorySearchResult(
|
|
183
|
+
memory=memory, similarity_score=similarity_score, rank=i + 1
|
|
184
|
+
)
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
return search_results
|
|
188
|
+
|
|
189
|
+
return await asyncio.get_event_loop().run_in_executor(self._executor, _search)
|
|
190
|
+
|
|
191
|
+
async def get_recent_memories(
|
|
192
|
+
self, context: ToolContext, limit: int = 10
|
|
193
|
+
) -> List[ToolMemory]:
|
|
194
|
+
"""Get recently added memories."""
|
|
195
|
+
|
|
196
|
+
def _get_recent():
|
|
197
|
+
client = self._get_client()
|
|
198
|
+
collection = client.collections.get(self.collection_name)
|
|
199
|
+
|
|
200
|
+
# Query and sort by timestamp
|
|
201
|
+
response = collection.query.fetch_objects(limit=1000)
|
|
202
|
+
|
|
203
|
+
# Convert to list and sort
|
|
204
|
+
objects_list = list(response.objects)
|
|
205
|
+
sorted_objects = sorted(
|
|
206
|
+
objects_list,
|
|
207
|
+
key=lambda o: o.properties.get("timestamp", ""),
|
|
208
|
+
reverse=True,
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
memories = []
|
|
212
|
+
for obj in sorted_objects[:limit]:
|
|
213
|
+
properties = obj.properties
|
|
214
|
+
args = json.loads(properties.get("args_json", "{}"))
|
|
215
|
+
metadata_dict = json.loads(properties.get("metadata_json", "{}"))
|
|
216
|
+
|
|
217
|
+
memory = ToolMemory(
|
|
218
|
+
memory_id=str(obj.uuid),
|
|
219
|
+
question=properties.get("question"),
|
|
220
|
+
tool_name=properties.get("tool_name"),
|
|
221
|
+
args=args,
|
|
222
|
+
timestamp=properties.get("timestamp"),
|
|
223
|
+
success=properties.get("success", True),
|
|
224
|
+
metadata=metadata_dict,
|
|
225
|
+
)
|
|
226
|
+
memories.append(memory)
|
|
227
|
+
|
|
228
|
+
return memories
|
|
229
|
+
|
|
230
|
+
return await asyncio.get_event_loop().run_in_executor(
|
|
231
|
+
self._executor, _get_recent
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
async def delete_by_id(self, context: ToolContext, memory_id: str) -> bool:
|
|
235
|
+
"""Delete a memory by its ID."""
|
|
236
|
+
|
|
237
|
+
def _delete():
|
|
238
|
+
client = self._get_client()
|
|
239
|
+
collection = client.collections.get(self.collection_name)
|
|
240
|
+
|
|
241
|
+
try:
|
|
242
|
+
collection.data.delete_by_id(uuid=memory_id)
|
|
243
|
+
return True
|
|
244
|
+
except Exception:
|
|
245
|
+
return False
|
|
246
|
+
|
|
247
|
+
return await asyncio.get_event_loop().run_in_executor(self._executor, _delete)
|
|
248
|
+
|
|
249
|
+
async def save_text_memory(self, content: str, context: ToolContext) -> TextMemory:
|
|
250
|
+
"""Save a text memory."""
|
|
251
|
+
|
|
252
|
+
def _save():
|
|
253
|
+
client = self._get_client()
|
|
254
|
+
collection = client.collections.get(self.collection_name)
|
|
255
|
+
|
|
256
|
+
memory_id = str(uuid.uuid4())
|
|
257
|
+
timestamp = datetime.now().isoformat()
|
|
258
|
+
embedding = self._create_embedding(content)
|
|
259
|
+
|
|
260
|
+
properties = {
|
|
261
|
+
"question": content, # Using question field for content
|
|
262
|
+
"tool_name": "", # Empty for text memories
|
|
263
|
+
"args_json": "",
|
|
264
|
+
"timestamp": timestamp,
|
|
265
|
+
"success": True,
|
|
266
|
+
"metadata_json": json.dumps({"is_text_memory": True}),
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
collection.data.insert(
|
|
270
|
+
properties=properties, vector=embedding, uuid=memory_id
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
return TextMemory(memory_id=memory_id, content=content, timestamp=timestamp)
|
|
274
|
+
|
|
275
|
+
return await asyncio.get_event_loop().run_in_executor(self._executor, _save)
|
|
276
|
+
|
|
277
|
+
async def search_text_memories(
|
|
278
|
+
self,
|
|
279
|
+
query: str,
|
|
280
|
+
context: ToolContext,
|
|
281
|
+
*,
|
|
282
|
+
limit: int = 10,
|
|
283
|
+
similarity_threshold: float = 0.7,
|
|
284
|
+
) -> List[TextMemorySearchResult]:
|
|
285
|
+
"""Search for similar text memories."""
|
|
286
|
+
|
|
287
|
+
def _search():
|
|
288
|
+
client = self._get_client()
|
|
289
|
+
collection = client.collections.get(self.collection_name)
|
|
290
|
+
|
|
291
|
+
embedding = self._create_embedding(query)
|
|
292
|
+
|
|
293
|
+
# Build filter for text memories (empty tool_name)
|
|
294
|
+
filters = weaviate.classes.query.Filter.by_property("tool_name").equal("")
|
|
295
|
+
|
|
296
|
+
response = collection.query.near_vector(
|
|
297
|
+
near_vector=embedding,
|
|
298
|
+
limit=limit,
|
|
299
|
+
filters=filters,
|
|
300
|
+
return_metadata=weaviate.classes.query.MetadataQuery(distance=True),
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
search_results = []
|
|
304
|
+
for i, obj in enumerate(response.objects):
|
|
305
|
+
distance = obj.metadata.distance if obj.metadata else 1.0
|
|
306
|
+
similarity_score = 1 - distance
|
|
307
|
+
|
|
308
|
+
if similarity_score >= similarity_threshold:
|
|
309
|
+
properties = obj.properties
|
|
310
|
+
content = properties.get("question", "")
|
|
311
|
+
|
|
312
|
+
memory = TextMemory(
|
|
313
|
+
memory_id=str(obj.uuid),
|
|
314
|
+
content=content,
|
|
315
|
+
timestamp=properties.get("timestamp"),
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
search_results.append(
|
|
319
|
+
TextMemorySearchResult(
|
|
320
|
+
memory=memory, similarity_score=similarity_score, rank=i + 1
|
|
321
|
+
)
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
return search_results
|
|
325
|
+
|
|
326
|
+
return await asyncio.get_event_loop().run_in_executor(self._executor, _search)
|
|
327
|
+
|
|
328
|
+
async def get_recent_text_memories(
|
|
329
|
+
self, context: ToolContext, limit: int = 10
|
|
330
|
+
) -> List[TextMemory]:
|
|
331
|
+
"""Get recently added text memories."""
|
|
332
|
+
|
|
333
|
+
def _get_recent():
|
|
334
|
+
client = self._get_client()
|
|
335
|
+
collection = client.collections.get(self.collection_name)
|
|
336
|
+
|
|
337
|
+
# Query text memories (empty tool_name) and sort by timestamp
|
|
338
|
+
response = collection.query.fetch_objects(
|
|
339
|
+
filters=weaviate.classes.query.Filter.by_property("tool_name").equal(
|
|
340
|
+
""
|
|
341
|
+
),
|
|
342
|
+
limit=1000,
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
# Convert to list and sort
|
|
346
|
+
objects_list = list(response.objects)
|
|
347
|
+
sorted_objects = sorted(
|
|
348
|
+
objects_list,
|
|
349
|
+
key=lambda o: o.properties.get("timestamp", ""),
|
|
350
|
+
reverse=True,
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
memories = []
|
|
354
|
+
for obj in sorted_objects[:limit]:
|
|
355
|
+
properties = obj.properties
|
|
356
|
+
content = properties.get("question", "")
|
|
357
|
+
|
|
358
|
+
memory = TextMemory(
|
|
359
|
+
memory_id=str(obj.uuid),
|
|
360
|
+
content=content,
|
|
361
|
+
timestamp=properties.get("timestamp"),
|
|
362
|
+
)
|
|
363
|
+
memories.append(memory)
|
|
364
|
+
|
|
365
|
+
return memories
|
|
366
|
+
|
|
367
|
+
return await asyncio.get_event_loop().run_in_executor(
|
|
368
|
+
self._executor, _get_recent
|
|
369
|
+
)
|
|
370
|
+
|
|
371
|
+
async def delete_text_memory(self, context: ToolContext, memory_id: str) -> bool:
|
|
372
|
+
"""Delete a text memory by its ID."""
|
|
373
|
+
|
|
374
|
+
def _delete():
|
|
375
|
+
client = self._get_client()
|
|
376
|
+
collection = client.collections.get(self.collection_name)
|
|
377
|
+
|
|
378
|
+
try:
|
|
379
|
+
collection.data.delete_by_id(uuid=memory_id)
|
|
380
|
+
return True
|
|
381
|
+
except Exception:
|
|
382
|
+
return False
|
|
383
|
+
|
|
384
|
+
return await asyncio.get_event_loop().run_in_executor(self._executor, _delete)
|
|
385
|
+
|
|
386
|
+
async def clear_memories(
|
|
387
|
+
self,
|
|
388
|
+
context: ToolContext,
|
|
389
|
+
tool_name: Optional[str] = None,
|
|
390
|
+
before_date: Optional[str] = None,
|
|
391
|
+
) -> int:
|
|
392
|
+
"""Clear stored memories."""
|
|
393
|
+
|
|
394
|
+
def _clear():
|
|
395
|
+
client = self._get_client()
|
|
396
|
+
collection = client.collections.get(self.collection_name)
|
|
397
|
+
|
|
398
|
+
# Build filter
|
|
399
|
+
if tool_name and before_date:
|
|
400
|
+
filters = weaviate.classes.query.Filter.by_property("tool_name").equal(
|
|
401
|
+
tool_name
|
|
402
|
+
) & weaviate.classes.query.Filter.by_property("timestamp").less_than(
|
|
403
|
+
before_date
|
|
404
|
+
)
|
|
405
|
+
elif tool_name:
|
|
406
|
+
filters = weaviate.classes.query.Filter.by_property("tool_name").equal(
|
|
407
|
+
tool_name
|
|
408
|
+
)
|
|
409
|
+
elif before_date:
|
|
410
|
+
filters = weaviate.classes.query.Filter.by_property(
|
|
411
|
+
"timestamp"
|
|
412
|
+
).less_than(before_date)
|
|
413
|
+
else:
|
|
414
|
+
filters = None
|
|
415
|
+
|
|
416
|
+
if filters:
|
|
417
|
+
collection.data.delete_many(where=filters)
|
|
418
|
+
else:
|
|
419
|
+
# Delete all
|
|
420
|
+
collection.data.delete_many(
|
|
421
|
+
where=weaviate.classes.query.Filter.by_property(
|
|
422
|
+
"success"
|
|
423
|
+
).contains_any([True, False])
|
|
424
|
+
)
|
|
425
|
+
|
|
426
|
+
return 0
|
|
427
|
+
|
|
428
|
+
return await asyncio.get_event_loop().run_in_executor(self._executor, _clear)
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from typing import List
|
|
3
|
+
|
|
4
|
+
import pandas as pd
|
|
5
|
+
from zhipuai import ZhipuAI
|
|
6
|
+
|
|
7
|
+
from ..base import VannaBase
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ZhipuAI_Chat(VannaBase):
|
|
11
|
+
def __init__(self, config=None):
|
|
12
|
+
VannaBase.__init__(self, config=config)
|
|
13
|
+
if config is None:
|
|
14
|
+
return
|
|
15
|
+
if "api_key" not in config:
|
|
16
|
+
raise Exception("Missing api_key in config")
|
|
17
|
+
self.api_key = config["api_key"]
|
|
18
|
+
self.model = config["model"] if "model" in config else "glm-4"
|
|
19
|
+
self.api_url = "https://open.bigmodel.cn/api/paas/v4/chat/completions"
|
|
20
|
+
|
|
21
|
+
# Static methods similar to those in ZhipuAI_Chat for message formatting and utility
|
|
22
|
+
@staticmethod
|
|
23
|
+
def system_message(message: str) -> dict:
|
|
24
|
+
return {"role": "system", "content": message}
|
|
25
|
+
|
|
26
|
+
@staticmethod
|
|
27
|
+
def user_message(message: str) -> dict:
|
|
28
|
+
return {"role": "user", "content": message}
|
|
29
|
+
|
|
30
|
+
@staticmethod
|
|
31
|
+
def assistant_message(message: str) -> dict:
|
|
32
|
+
return {"role": "assistant", "content": message}
|
|
33
|
+
|
|
34
|
+
@staticmethod
|
|
35
|
+
def str_to_approx_token_count(string: str) -> int:
|
|
36
|
+
return len(string) / 4
|
|
37
|
+
|
|
38
|
+
@staticmethod
|
|
39
|
+
def add_ddl_to_prompt(
|
|
40
|
+
initial_prompt: str, ddl_list: List[str], max_tokens: int = 14000
|
|
41
|
+
) -> str:
|
|
42
|
+
if len(ddl_list) > 0:
|
|
43
|
+
initial_prompt += "\nYou may use the following DDL statements as a reference for what tables might be available. Use responses to past questions also to guide you:\n\n"
|
|
44
|
+
|
|
45
|
+
for ddl in ddl_list:
|
|
46
|
+
if (
|
|
47
|
+
ZhipuAI_Chat.str_to_approx_token_count(initial_prompt)
|
|
48
|
+
+ ZhipuAI_Chat.str_to_approx_token_count(ddl)
|
|
49
|
+
< max_tokens
|
|
50
|
+
):
|
|
51
|
+
initial_prompt += f"{ddl}\n\n"
|
|
52
|
+
|
|
53
|
+
return initial_prompt
|
|
54
|
+
|
|
55
|
+
@staticmethod
|
|
56
|
+
def add_documentation_to_prompt(
|
|
57
|
+
initial_prompt: str, documentation_List: List[str], max_tokens: int = 14000
|
|
58
|
+
) -> str:
|
|
59
|
+
if len(documentation_List) > 0:
|
|
60
|
+
initial_prompt += "\nYou may use the following documentation as a reference for what tables might be available. Use responses to past questions also to guide you:\n\n"
|
|
61
|
+
|
|
62
|
+
for documentation in documentation_List:
|
|
63
|
+
if (
|
|
64
|
+
ZhipuAI_Chat.str_to_approx_token_count(initial_prompt)
|
|
65
|
+
+ ZhipuAI_Chat.str_to_approx_token_count(documentation)
|
|
66
|
+
< max_tokens
|
|
67
|
+
):
|
|
68
|
+
initial_prompt += f"{documentation}\n\n"
|
|
69
|
+
|
|
70
|
+
return initial_prompt
|
|
71
|
+
|
|
72
|
+
@staticmethod
|
|
73
|
+
def add_sql_to_prompt(
|
|
74
|
+
initial_prompt: str, sql_List: List[str], max_tokens: int = 14000
|
|
75
|
+
) -> str:
|
|
76
|
+
if len(sql_List) > 0:
|
|
77
|
+
initial_prompt += "\nYou may use the following SQL statements as a reference for what tables might be available. Use responses to past questions also to guide you:\n\n"
|
|
78
|
+
|
|
79
|
+
for question in sql_List:
|
|
80
|
+
if (
|
|
81
|
+
ZhipuAI_Chat.str_to_approx_token_count(initial_prompt)
|
|
82
|
+
+ ZhipuAI_Chat.str_to_approx_token_count(question["sql"])
|
|
83
|
+
< max_tokens
|
|
84
|
+
):
|
|
85
|
+
initial_prompt += f"{question['question']}\n{question['sql']}\n\n"
|
|
86
|
+
|
|
87
|
+
return initial_prompt
|
|
88
|
+
|
|
89
|
+
def get_sql_prompt(
|
|
90
|
+
self,
|
|
91
|
+
question: str,
|
|
92
|
+
question_sql_list: List,
|
|
93
|
+
ddl_list: List,
|
|
94
|
+
doc_list: List,
|
|
95
|
+
**kwargs,
|
|
96
|
+
):
|
|
97
|
+
initial_prompt = "The user provides a question and you provide SQL. You will only respond with SQL code and not with any explanations.\n\nRespond with only SQL code. Do not answer with any explanations -- just the code.\n"
|
|
98
|
+
|
|
99
|
+
initial_prompt = ZhipuAI_Chat.add_ddl_to_prompt(
|
|
100
|
+
initial_prompt, ddl_list, max_tokens=14000
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
initial_prompt = ZhipuAI_Chat.add_documentation_to_prompt(
|
|
104
|
+
initial_prompt, doc_list, max_tokens=14000
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
message_log = [ZhipuAI_Chat.system_message(initial_prompt)]
|
|
108
|
+
|
|
109
|
+
for example in question_sql_list:
|
|
110
|
+
if example is None:
|
|
111
|
+
print("example is None")
|
|
112
|
+
else:
|
|
113
|
+
if example is not None and "question" in example and "sql" in example:
|
|
114
|
+
message_log.append(ZhipuAI_Chat.user_message(example["question"]))
|
|
115
|
+
message_log.append(ZhipuAI_Chat.assistant_message(example["sql"]))
|
|
116
|
+
|
|
117
|
+
message_log.append({"role": "user", "content": question})
|
|
118
|
+
|
|
119
|
+
return message_log
|
|
120
|
+
|
|
121
|
+
def get_followup_questions_prompt(
|
|
122
|
+
self,
|
|
123
|
+
question: str,
|
|
124
|
+
df: pd.DataFrame,
|
|
125
|
+
question_sql_list: List,
|
|
126
|
+
ddl_list: List,
|
|
127
|
+
doc_list: List,
|
|
128
|
+
**kwargs,
|
|
129
|
+
):
|
|
130
|
+
initial_prompt = f"The user initially asked the question: '{question}': \n\n"
|
|
131
|
+
|
|
132
|
+
initial_prompt = ZhipuAI_Chat.add_ddl_to_prompt(
|
|
133
|
+
initial_prompt, ddl_list, max_tokens=14000
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
initial_prompt = ZhipuAI_Chat.add_documentation_to_prompt(
|
|
137
|
+
initial_prompt, doc_list, max_tokens=14000
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
initial_prompt = ZhipuAI_Chat.add_sql_to_prompt(
|
|
141
|
+
initial_prompt, question_sql_list, max_tokens=14000
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
message_log = [ZhipuAI_Chat.system_message(initial_prompt)]
|
|
145
|
+
message_log.append(
|
|
146
|
+
ZhipuAI_Chat.user_message(
|
|
147
|
+
"Generate a List of 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."
|
|
148
|
+
)
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
return message_log
|
|
152
|
+
|
|
153
|
+
def generate_question(self, sql: str, **kwargs) -> str:
|
|
154
|
+
response = self.submit_prompt(
|
|
155
|
+
[
|
|
156
|
+
self.system_message(
|
|
157
|
+
"The user will give you SQL and you will try to guess what the business question this query is answering. Return just the question without any additional explanation. Do not reference the table name in the question."
|
|
158
|
+
),
|
|
159
|
+
self.user_message(sql),
|
|
160
|
+
],
|
|
161
|
+
**kwargs,
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
return response
|
|
165
|
+
|
|
166
|
+
def _extract_python_code(self, markdown_string: str) -> str:
|
|
167
|
+
# Regex pattern to match Python code blocks
|
|
168
|
+
pattern = r"```[\w\s]*python\n([\s\S]*?)```|```([\s\S]*?)```"
|
|
169
|
+
|
|
170
|
+
# Find all matches in the markdown string
|
|
171
|
+
matches = re.findall(pattern, markdown_string, re.IGNORECASE)
|
|
172
|
+
|
|
173
|
+
# Extract the Python code from the matches
|
|
174
|
+
python_code = []
|
|
175
|
+
for match in matches:
|
|
176
|
+
python = match[0] if match[0] else match[1]
|
|
177
|
+
python_code.append(python.strip())
|
|
178
|
+
|
|
179
|
+
if len(python_code) == 0:
|
|
180
|
+
return markdown_string
|
|
181
|
+
|
|
182
|
+
return python_code[0]
|
|
183
|
+
|
|
184
|
+
def _sanitize_plotly_code(self, raw_plotly_code: str) -> str:
|
|
185
|
+
# Remove the fig.show() statement from the plotly code
|
|
186
|
+
plotly_code = raw_plotly_code.replace("fig.show()", "")
|
|
187
|
+
|
|
188
|
+
return plotly_code
|
|
189
|
+
|
|
190
|
+
def generate_plotly_code(
|
|
191
|
+
self, question: str = None, sql: str = None, df_metadata: str = None, **kwargs
|
|
192
|
+
) -> str:
|
|
193
|
+
if question is not None:
|
|
194
|
+
system_msg = f"The following is a pandas DataFrame that contains the results of the query that answers the question the user asked: '{question}'"
|
|
195
|
+
else:
|
|
196
|
+
system_msg = "The following is a pandas DataFrame "
|
|
197
|
+
|
|
198
|
+
if sql is not None:
|
|
199
|
+
system_msg += f"\n\nThe DataFrame was produced using this query: {sql}\n\n"
|
|
200
|
+
|
|
201
|
+
system_msg += f"The following is information about the resulting pandas DataFrame 'df': \n{df_metadata}"
|
|
202
|
+
|
|
203
|
+
message_log = [
|
|
204
|
+
self.system_message(system_msg),
|
|
205
|
+
self.user_message(
|
|
206
|
+
"Can you generate the Python plotly code to chart the results of the dataframe? Assume the data is in a pandas dataframe called 'df'. If there is only one value in the dataframe, use an Indicator. Respond with only Python code. Do not answer with any explanations -- just the code."
|
|
207
|
+
),
|
|
208
|
+
]
|
|
209
|
+
|
|
210
|
+
plotly_code = self.submit_prompt(message_log, kwargs=kwargs)
|
|
211
|
+
|
|
212
|
+
return self._sanitize_plotly_code(self._extract_python_code(plotly_code))
|
|
213
|
+
|
|
214
|
+
def submit_prompt(
|
|
215
|
+
self, prompt, max_tokens=500, temperature=0.7, top_p=0.7, stop=None, **kwargs
|
|
216
|
+
):
|
|
217
|
+
if prompt is None:
|
|
218
|
+
raise Exception("Prompt is None")
|
|
219
|
+
|
|
220
|
+
if len(prompt) == 0:
|
|
221
|
+
raise Exception("Prompt is empty")
|
|
222
|
+
|
|
223
|
+
client = ZhipuAI(api_key=self.api_key)
|
|
224
|
+
response = client.chat.completions.create(
|
|
225
|
+
model="glm-4",
|
|
226
|
+
max_tokens=max_tokens,
|
|
227
|
+
temperature=temperature,
|
|
228
|
+
top_p=top_p,
|
|
229
|
+
stop=stop,
|
|
230
|
+
messages=prompt,
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
return response.choices[0].message.content
|