squidcloud-client 1.0.0__tar.gz
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.
- squidcloud_client-1.0.0/PKG-INFO +21 -0
- squidcloud_client-1.0.0/pyproject.toml +37 -0
- squidcloud_client-1.0.0/setup.cfg +4 -0
- squidcloud_client-1.0.0/squidcloud/__init__.py +110 -0
- squidcloud_client-1.0.0/squidcloud/ai.py +411 -0
- squidcloud_client-1.0.0/squidcloud/client.py +180 -0
- squidcloud_client-1.0.0/squidcloud/extraction.py +97 -0
- squidcloud_client-1.0.0/squidcloud/http.py +161 -0
- squidcloud_client-1.0.0/squidcloud/matchmaking.py +144 -0
- squidcloud_client-1.0.0/squidcloud/types.py +433 -0
- squidcloud_client-1.0.0/squidcloud/web.py +86 -0
- squidcloud_client-1.0.0/squidcloud_client.egg-info/PKG-INFO +21 -0
- squidcloud_client-1.0.0/squidcloud_client.egg-info/SOURCES.txt +14 -0
- squidcloud_client-1.0.0/squidcloud_client.egg-info/dependency_links.txt +1 -0
- squidcloud_client-1.0.0/squidcloud_client.egg-info/requires.txt +5 -0
- squidcloud_client-1.0.0/squidcloud_client.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: squidcloud-client
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Squid Cloud Python client SDK
|
|
5
|
+
Author-email: Squid Cloud <support@squid.cloud>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://squid.cloud
|
|
8
|
+
Project-URL: Documentation, https://docs.squid.cloud
|
|
9
|
+
Project-URL: Repository, https://github.com/squid-cloud/squid-cloud
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Typing :: Typed
|
|
17
|
+
Requires-Python: >=3.11
|
|
18
|
+
Requires-Dist: httpx>=0.27.0
|
|
19
|
+
Provides-Extra: dev
|
|
20
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
21
|
+
Requires-Dist: pytest-asyncio>=0.21; extra == "dev"
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "squidcloud-client"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Squid Cloud Python client SDK"
|
|
9
|
+
requires-python = ">=3.11"
|
|
10
|
+
license = {text = "MIT"}
|
|
11
|
+
authors = [{name = "Squid Cloud", email = "support@squid.cloud"}]
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Programming Language :: Python :: 3",
|
|
14
|
+
"Programming Language :: Python :: 3.11",
|
|
15
|
+
"Programming Language :: Python :: 3.12",
|
|
16
|
+
"Programming Language :: Python :: 3.13",
|
|
17
|
+
"License :: OSI Approved :: MIT License",
|
|
18
|
+
"Operating System :: OS Independent",
|
|
19
|
+
"Typing :: Typed",
|
|
20
|
+
]
|
|
21
|
+
dependencies = [
|
|
22
|
+
"httpx>=0.27.0",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
[project.urls]
|
|
26
|
+
Homepage = "https://squid.cloud"
|
|
27
|
+
Documentation = "https://docs.squid.cloud"
|
|
28
|
+
Repository = "https://github.com/squid-cloud/squid-cloud"
|
|
29
|
+
|
|
30
|
+
[project.optional-dependencies]
|
|
31
|
+
dev = [
|
|
32
|
+
"pytest>=7.0",
|
|
33
|
+
"pytest-asyncio>=0.21",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
[tool.setuptools.packages.find]
|
|
37
|
+
include = ["squidcloud*"]
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"""Squid Cloud Python client SDK.
|
|
2
|
+
|
|
3
|
+
Usage::
|
|
4
|
+
|
|
5
|
+
from squidcloud import Squid
|
|
6
|
+
|
|
7
|
+
squid = Squid(
|
|
8
|
+
app_id="my-app",
|
|
9
|
+
api_key="my-api-key",
|
|
10
|
+
region="us-east-1.aws",
|
|
11
|
+
environment_id="dev",
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
# AI agents
|
|
15
|
+
response = await squid.ai().agent("my-agent").ask("Hello!")
|
|
16
|
+
|
|
17
|
+
# Execute backend function
|
|
18
|
+
result = await squid.execute_function("MyService:greet", "World")
|
|
19
|
+
|
|
20
|
+
# Web utilities
|
|
21
|
+
content = await squid.web().get_url_content("https://example.com")
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from squidcloud.client import Squid
|
|
25
|
+
from squidcloud.types import (
|
|
26
|
+
AiAgentExecutionPlanOptions,
|
|
27
|
+
AiAgentMemoryOptions,
|
|
28
|
+
AiAgentResponseFormat,
|
|
29
|
+
AiAudioCreateSpeechOptions,
|
|
30
|
+
AiChatModelSelection,
|
|
31
|
+
AiChatOptions,
|
|
32
|
+
AiChatPromptQuotas,
|
|
33
|
+
AiConnectedAgentMetadata,
|
|
34
|
+
AiConnectedIntegrationMetadata,
|
|
35
|
+
AiConnectedKnowledgeBaseMetadata,
|
|
36
|
+
AiContextFileOptions,
|
|
37
|
+
AiContextTextOptions,
|
|
38
|
+
AiFileUrl,
|
|
39
|
+
AiKnowledgeBaseMetadataField,
|
|
40
|
+
AiStructuredOutputFormat,
|
|
41
|
+
ContextRequest,
|
|
42
|
+
CreatePdfDimensionsOptions,
|
|
43
|
+
CreatePdfFormatOptions,
|
|
44
|
+
CreatePdfOutputOptions,
|
|
45
|
+
DallEOptions,
|
|
46
|
+
ExtractDataFromDocumentOptions,
|
|
47
|
+
FileContextRequest,
|
|
48
|
+
FluxOptions,
|
|
49
|
+
GuardrailsOptions,
|
|
50
|
+
ImageGenerateOptions,
|
|
51
|
+
IntegrationModelSpec,
|
|
52
|
+
KnowledgeBaseSearchOptions,
|
|
53
|
+
MmCategory,
|
|
54
|
+
MmEntity,
|
|
55
|
+
MmFindMatchesOptions,
|
|
56
|
+
MmListEntitiesOptions,
|
|
57
|
+
StableDiffusionOptions,
|
|
58
|
+
TextContextRequest,
|
|
59
|
+
UpsertAgentOptions,
|
|
60
|
+
WebAiSearchResponse,
|
|
61
|
+
WebShortUrlBulkResponse,
|
|
62
|
+
WebShortUrlResponse,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
__all__ = [
|
|
66
|
+
"Squid",
|
|
67
|
+
# AI Chat
|
|
68
|
+
"AiChatOptions",
|
|
69
|
+
"AiChatModelSelection",
|
|
70
|
+
"AiAgentMemoryOptions",
|
|
71
|
+
"AiAgentResponseFormat",
|
|
72
|
+
"AiStructuredOutputFormat",
|
|
73
|
+
"AiConnectedAgentMetadata",
|
|
74
|
+
"AiConnectedIntegrationMetadata",
|
|
75
|
+
"AiConnectedKnowledgeBaseMetadata",
|
|
76
|
+
"AiFileUrl",
|
|
77
|
+
"AiChatPromptQuotas",
|
|
78
|
+
"AiAgentExecutionPlanOptions",
|
|
79
|
+
"AiAudioCreateSpeechOptions",
|
|
80
|
+
"GuardrailsOptions",
|
|
81
|
+
"IntegrationModelSpec",
|
|
82
|
+
"UpsertAgentOptions",
|
|
83
|
+
# Knowledge Base
|
|
84
|
+
"AiKnowledgeBaseMetadataField",
|
|
85
|
+
"KnowledgeBaseSearchOptions",
|
|
86
|
+
"TextContextRequest",
|
|
87
|
+
"FileContextRequest",
|
|
88
|
+
"ContextRequest",
|
|
89
|
+
"AiContextTextOptions",
|
|
90
|
+
"AiContextFileOptions",
|
|
91
|
+
# Image
|
|
92
|
+
"ImageGenerateOptions",
|
|
93
|
+
"DallEOptions",
|
|
94
|
+
"FluxOptions",
|
|
95
|
+
"StableDiffusionOptions",
|
|
96
|
+
# Matchmaking
|
|
97
|
+
"MmCategory",
|
|
98
|
+
"MmEntity",
|
|
99
|
+
"MmFindMatchesOptions",
|
|
100
|
+
"MmListEntitiesOptions",
|
|
101
|
+
# Extraction
|
|
102
|
+
"CreatePdfOutputOptions",
|
|
103
|
+
"CreatePdfFormatOptions",
|
|
104
|
+
"CreatePdfDimensionsOptions",
|
|
105
|
+
"ExtractDataFromDocumentOptions",
|
|
106
|
+
# Web
|
|
107
|
+
"WebAiSearchResponse",
|
|
108
|
+
"WebShortUrlResponse",
|
|
109
|
+
"WebShortUrlBulkResponse",
|
|
110
|
+
]
|
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
"""AI client — agents, knowledge base, audio, image.
|
|
2
|
+
|
|
3
|
+
Covers all /squid-api/v1/ai/* endpoints from the OpenAPI spec.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
from typing import TYPE_CHECKING, Any, Optional, Union
|
|
10
|
+
|
|
11
|
+
from squidcloud.types import (
|
|
12
|
+
AiAudioCreateSpeechOptions,
|
|
13
|
+
AiChatModelSelection,
|
|
14
|
+
AiChatOptions,
|
|
15
|
+
AiConnectedAgentMetadata,
|
|
16
|
+
AiKnowledgeBaseMetadataField,
|
|
17
|
+
ContextRequest,
|
|
18
|
+
GuardrailsOptions,
|
|
19
|
+
ImageGenerateOptions,
|
|
20
|
+
KnowledgeBaseSearchOptions,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
from squidcloud.http import HttpTransport
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class AiClient:
|
|
28
|
+
"""Entry point for AI operations: agents, knowledge base, audio, image."""
|
|
29
|
+
|
|
30
|
+
def __init__(self, http: HttpTransport) -> None:
|
|
31
|
+
self._http = http
|
|
32
|
+
|
|
33
|
+
def agent(self, agent_id: str) -> AgentClient:
|
|
34
|
+
return AgentClient(self._http, agent_id)
|
|
35
|
+
|
|
36
|
+
def knowledge_base(self, knowledge_base_id: str) -> KnowledgeBaseClient:
|
|
37
|
+
return KnowledgeBaseClient(self._http, knowledge_base_id)
|
|
38
|
+
|
|
39
|
+
def image(self) -> ImageClient:
|
|
40
|
+
return ImageClient(self._http)
|
|
41
|
+
|
|
42
|
+
def audio(self) -> AudioClient:
|
|
43
|
+
return AudioClient(self._http)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# ---------------------------------------------------------------------------
|
|
47
|
+
# Agent
|
|
48
|
+
# ---------------------------------------------------------------------------
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class AgentClient:
|
|
52
|
+
"""Operations on a single AI agent."""
|
|
53
|
+
|
|
54
|
+
def __init__(self, http: HttpTransport, agent_id: str) -> None:
|
|
55
|
+
self._http = http
|
|
56
|
+
self._agent_id = agent_id
|
|
57
|
+
|
|
58
|
+
# --- Chat ---
|
|
59
|
+
|
|
60
|
+
async def ask(
|
|
61
|
+
self,
|
|
62
|
+
prompt: str,
|
|
63
|
+
options: Optional[AiChatOptions] = None,
|
|
64
|
+
) -> str:
|
|
65
|
+
"""Ask the agent a question. Returns the response string."""
|
|
66
|
+
result = await self._http.post(
|
|
67
|
+
"squid-api/v1/ai/agent/ask",
|
|
68
|
+
{"agentId": self._agent_id, "prompt": prompt, "options": options or {}},
|
|
69
|
+
)
|
|
70
|
+
return result.get("responseString", "") if result else ""
|
|
71
|
+
|
|
72
|
+
async def ask_with_annotations(
|
|
73
|
+
self,
|
|
74
|
+
prompt: str,
|
|
75
|
+
options: Optional[AiChatOptions] = None,
|
|
76
|
+
) -> dict:
|
|
77
|
+
"""Ask the agent and get response with annotations.
|
|
78
|
+
|
|
79
|
+
Returns dict with 'responseString' and 'annotations'.
|
|
80
|
+
"""
|
|
81
|
+
return await self._http.post(
|
|
82
|
+
"squid-api/v1/ai/agent/askWithAnnotations",
|
|
83
|
+
{"agentId": self._agent_id, "prompt": prompt, "options": options or {}},
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
# --- Management ---
|
|
87
|
+
|
|
88
|
+
async def get(self) -> Optional[dict]:
|
|
89
|
+
"""Get agent configuration.
|
|
90
|
+
|
|
91
|
+
Returns AiAgent dict with: id, createdAt, updatedAt, description,
|
|
92
|
+
isPublic, auditLog, options, apiKey. Returns None if not found.
|
|
93
|
+
"""
|
|
94
|
+
return await self._http.get(f"squid-api/v1/ai/agent/get/{self._agent_id}")
|
|
95
|
+
|
|
96
|
+
async def upsert(
|
|
97
|
+
self,
|
|
98
|
+
*,
|
|
99
|
+
description: Optional[str] = None,
|
|
100
|
+
is_public: Optional[bool] = None,
|
|
101
|
+
audit_log: Optional[bool] = None,
|
|
102
|
+
api_key: Optional[str] = None,
|
|
103
|
+
options: Optional[AiChatOptions] = None,
|
|
104
|
+
) -> None:
|
|
105
|
+
"""Create or update the agent."""
|
|
106
|
+
body: dict[str, Any] = {"id": self._agent_id}
|
|
107
|
+
if description is not None:
|
|
108
|
+
body["description"] = description
|
|
109
|
+
if is_public is not None:
|
|
110
|
+
body["isPublic"] = is_public
|
|
111
|
+
if audit_log is not None:
|
|
112
|
+
body["auditLog"] = audit_log
|
|
113
|
+
if api_key is not None:
|
|
114
|
+
body["apiKey"] = api_key
|
|
115
|
+
if options is not None:
|
|
116
|
+
body["options"] = options
|
|
117
|
+
await self._http.post("squid-api/v1/ai/agent/upsert", body)
|
|
118
|
+
|
|
119
|
+
async def delete(self) -> None:
|
|
120
|
+
"""Delete the agent."""
|
|
121
|
+
await self._http.post(
|
|
122
|
+
"squid-api/v1/ai/agent/delete", {"agentId": self._agent_id}
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
async def update_instructions(self, instructions: str) -> None:
|
|
126
|
+
"""Update the agent's system instructions."""
|
|
127
|
+
await self._http.post(
|
|
128
|
+
"squid-api/v1/ai/agent/updateInstructions",
|
|
129
|
+
{"agentId": self._agent_id, "instructions": instructions},
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
async def update_model(self, model: AiChatModelSelection) -> None:
|
|
133
|
+
"""Update the agent's default model."""
|
|
134
|
+
await self._http.post(
|
|
135
|
+
"squid-api/v1/ai/agent/updateModel",
|
|
136
|
+
{"agentId": self._agent_id, "model": model},
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
async def update_connected_agents(
|
|
140
|
+
self, connected_agents: list[AiConnectedAgentMetadata]
|
|
141
|
+
) -> None:
|
|
142
|
+
"""Update connected agents."""
|
|
143
|
+
await self._http.post(
|
|
144
|
+
"squid-api/v1/ai/agent/updateConnectedAgents",
|
|
145
|
+
{"agentId": self._agent_id, "connectedAgents": connected_agents},
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
async def update_guardrails(self, guardrails: GuardrailsOptions) -> None:
|
|
149
|
+
"""Update agent guardrails."""
|
|
150
|
+
await self._http.post(
|
|
151
|
+
"squid-api/v1/ai/agent/updateGuardrails",
|
|
152
|
+
{"agentId": self._agent_id, "guardrails": guardrails},
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
async def update_custom_guardrails(self, custom_guardrail: str) -> None:
|
|
156
|
+
"""Update custom guardrail instruction text."""
|
|
157
|
+
await self._http.post(
|
|
158
|
+
"squid-api/v1/ai/agent/updateCustomGuardrails",
|
|
159
|
+
{"agentId": self._agent_id, "customGuardrail": custom_guardrail},
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
async def delete_custom_guardrails(self) -> None:
|
|
163
|
+
"""Delete the custom guardrail."""
|
|
164
|
+
await self._http.post(
|
|
165
|
+
"squid-api/v1/ai/agent/deleteCustomGuardrails",
|
|
166
|
+
{"agentId": self._agent_id},
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
# --- Revisions ---
|
|
170
|
+
|
|
171
|
+
async def list_revisions(self) -> list[dict]:
|
|
172
|
+
"""List agent revisions."""
|
|
173
|
+
result = await self._http.get(
|
|
174
|
+
f"squid-api/v1/ai/agent/revisions/{self._agent_id}"
|
|
175
|
+
)
|
|
176
|
+
return result.get("revisions", []) if result else []
|
|
177
|
+
|
|
178
|
+
async def restore_revision(self, revision_number: int) -> None:
|
|
179
|
+
"""Restore the agent to a specific revision."""
|
|
180
|
+
await self._http.post(
|
|
181
|
+
"squid-api/v1/ai/agent/restoreRevision",
|
|
182
|
+
{"agentId": self._agent_id, "revisionNumber": revision_number},
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
async def delete_revision(self, revision_number: int) -> None:
|
|
186
|
+
"""Delete a specific revision."""
|
|
187
|
+
await self._http.post(
|
|
188
|
+
"squid-api/v1/ai/agent/deleteRevision",
|
|
189
|
+
{"agentId": self._agent_id, "revisionNumber": revision_number},
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
# ---------------------------------------------------------------------------
|
|
194
|
+
# Knowledge Base
|
|
195
|
+
# ---------------------------------------------------------------------------
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
class KnowledgeBaseClient:
|
|
199
|
+
"""Operations on a single knowledge base."""
|
|
200
|
+
|
|
201
|
+
def __init__(self, http: HttpTransport, kb_id: str) -> None:
|
|
202
|
+
self._http = http
|
|
203
|
+
self._kb_id = kb_id
|
|
204
|
+
|
|
205
|
+
async def get(self) -> Optional[dict]:
|
|
206
|
+
"""Get knowledge base details."""
|
|
207
|
+
return await self._http.get(
|
|
208
|
+
f"squid-api/v1/ai/knowledge-base/get/{self._kb_id}"
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
async def upsert(
|
|
212
|
+
self,
|
|
213
|
+
*,
|
|
214
|
+
description: Optional[str] = None,
|
|
215
|
+
metadata_fields: Optional[list[AiKnowledgeBaseMetadataField]] = None,
|
|
216
|
+
embedding_model: Optional[str] = None,
|
|
217
|
+
chat_model: Optional[AiChatModelSelection] = None,
|
|
218
|
+
name: Optional[str] = None,
|
|
219
|
+
) -> None:
|
|
220
|
+
"""Create or update the knowledge base."""
|
|
221
|
+
kb: dict[str, Any] = {"id": self._kb_id}
|
|
222
|
+
if description is not None:
|
|
223
|
+
kb["description"] = description
|
|
224
|
+
if metadata_fields is not None:
|
|
225
|
+
kb["metadataFields"] = metadata_fields
|
|
226
|
+
if embedding_model is not None:
|
|
227
|
+
kb["embeddingModel"] = embedding_model
|
|
228
|
+
if chat_model is not None:
|
|
229
|
+
kb["chatModel"] = chat_model
|
|
230
|
+
if name is not None:
|
|
231
|
+
kb["name"] = name
|
|
232
|
+
await self._http.post(
|
|
233
|
+
"squid-api/v1/ai/knowledge-base/upsert", {"knowledgeBase": kb}
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
async def delete(self) -> None:
|
|
237
|
+
"""Delete the knowledge base."""
|
|
238
|
+
await self._http.post(
|
|
239
|
+
"squid-api/v1/ai/knowledge-base/delete", {"id": self._kb_id}
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
# --- Contexts ---
|
|
243
|
+
|
|
244
|
+
async def get_context(self, context_id: str) -> Optional[dict]:
|
|
245
|
+
"""Get a specific context."""
|
|
246
|
+
return await self._http.get(
|
|
247
|
+
f"squid-api/v1/ai/knowledge-base/getContext/{self._kb_id}/{context_id}"
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
async def list_contexts(self) -> list[dict]:
|
|
251
|
+
"""List all contexts in the knowledge base."""
|
|
252
|
+
result = await self._http.get(
|
|
253
|
+
f"squid-api/v1/ai/knowledge-base/listContexts/{self._kb_id}"
|
|
254
|
+
)
|
|
255
|
+
return result.get("contexts", []) if result else []
|
|
256
|
+
|
|
257
|
+
async def upsert_contexts(
|
|
258
|
+
self,
|
|
259
|
+
contexts: list[ContextRequest],
|
|
260
|
+
files: Optional[list[tuple[str, bytes, str]]] = None,
|
|
261
|
+
) -> dict:
|
|
262
|
+
"""Add or update contexts.
|
|
263
|
+
|
|
264
|
+
Args:
|
|
265
|
+
contexts: List of TextContextRequest or FileContextRequest.
|
|
266
|
+
files: Optional list of (filename, data, content_type) tuples.
|
|
267
|
+
|
|
268
|
+
Returns:
|
|
269
|
+
dict with 'failures' list.
|
|
270
|
+
"""
|
|
271
|
+
form_data = {
|
|
272
|
+
"knowledgeBaseId": self._kb_id,
|
|
273
|
+
"contexts": json.dumps(contexts),
|
|
274
|
+
}
|
|
275
|
+
file_tuples = []
|
|
276
|
+
if files:
|
|
277
|
+
for fname, fdata, ftype in files:
|
|
278
|
+
file_tuples.append(("files", (fname, fdata, ftype)))
|
|
279
|
+
return await self._http.post_form(
|
|
280
|
+
"squid-api/v1/ai/knowledge-base/upsertContexts",
|
|
281
|
+
data=form_data,
|
|
282
|
+
files=file_tuples,
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
async def delete_contexts(self, context_ids: list[str]) -> None:
|
|
286
|
+
"""Delete contexts by IDs."""
|
|
287
|
+
await self._http.post(
|
|
288
|
+
"squid-api/v1/ai/knowledge-base/deleteContexts",
|
|
289
|
+
{"knowledgeBaseId": self._kb_id, "contextIds": context_ids},
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
# --- Search ---
|
|
293
|
+
|
|
294
|
+
async def search(
|
|
295
|
+
self,
|
|
296
|
+
prompt: str,
|
|
297
|
+
options: Optional[KnowledgeBaseSearchOptions] = None,
|
|
298
|
+
) -> list[dict]:
|
|
299
|
+
"""Search the knowledge base. Returns list of result chunks."""
|
|
300
|
+
search_options: dict[str, Any] = {"prompt": prompt, **(options or {})}
|
|
301
|
+
result = await self._http.post(
|
|
302
|
+
"squid-api/v1/ai/knowledge-base/search",
|
|
303
|
+
{
|
|
304
|
+
"knowledgeBaseId": self._kb_id,
|
|
305
|
+
"prompt": prompt,
|
|
306
|
+
"options": search_options,
|
|
307
|
+
},
|
|
308
|
+
)
|
|
309
|
+
return result.get("chunks", []) if result else []
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
# ---------------------------------------------------------------------------
|
|
313
|
+
# Image
|
|
314
|
+
# ---------------------------------------------------------------------------
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
class ImageClient:
|
|
318
|
+
"""Image generation and processing."""
|
|
319
|
+
|
|
320
|
+
def __init__(self, http: HttpTransport) -> None:
|
|
321
|
+
self._http = http
|
|
322
|
+
|
|
323
|
+
async def generate(
|
|
324
|
+
self,
|
|
325
|
+
prompt: str,
|
|
326
|
+
options: Optional[ImageGenerateOptions] = None,
|
|
327
|
+
) -> str:
|
|
328
|
+
"""Generate an image from a text prompt. Returns image URL."""
|
|
329
|
+
result = await self._http.post(
|
|
330
|
+
"squid-api/v1/ai/image/generate",
|
|
331
|
+
{"prompt": prompt, "options": options or {}},
|
|
332
|
+
)
|
|
333
|
+
return result if isinstance(result, str) else str(result)
|
|
334
|
+
|
|
335
|
+
async def remove_background(
|
|
336
|
+
self,
|
|
337
|
+
image_data: bytes,
|
|
338
|
+
filename: str = "image.png",
|
|
339
|
+
content_type: str = "image/png",
|
|
340
|
+
) -> str:
|
|
341
|
+
"""Remove background from an image. Returns result image URL."""
|
|
342
|
+
result = await self._http.post_form(
|
|
343
|
+
"squid-api/v1/ai/image/removeBackground",
|
|
344
|
+
data={},
|
|
345
|
+
files=[("file", (filename, image_data, content_type))],
|
|
346
|
+
)
|
|
347
|
+
return result if isinstance(result, str) else str(result)
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
# ---------------------------------------------------------------------------
|
|
351
|
+
# Audio
|
|
352
|
+
# ---------------------------------------------------------------------------
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
class AudioClient:
|
|
356
|
+
"""Audio transcription and speech synthesis."""
|
|
357
|
+
|
|
358
|
+
def __init__(self, http: HttpTransport) -> None:
|
|
359
|
+
self._http = http
|
|
360
|
+
|
|
361
|
+
async def transcribe(
|
|
362
|
+
self,
|
|
363
|
+
audio_data: bytes,
|
|
364
|
+
filename: str = "audio.wav",
|
|
365
|
+
content_type: str = "audio/wav",
|
|
366
|
+
*,
|
|
367
|
+
options: Optional[dict[str, Any]] = None,
|
|
368
|
+
) -> str:
|
|
369
|
+
"""Transcribe audio to text."""
|
|
370
|
+
form_data: dict[str, str] = {}
|
|
371
|
+
if options:
|
|
372
|
+
form_data["optionsJson"] = json.dumps(options)
|
|
373
|
+
result = await self._http.post_form(
|
|
374
|
+
"squid-api/v1/ai/audio/transcribe",
|
|
375
|
+
data=form_data,
|
|
376
|
+
files=[("file", (filename, audio_data, content_type))],
|
|
377
|
+
)
|
|
378
|
+
return result if isinstance(result, str) else str(result)
|
|
379
|
+
|
|
380
|
+
async def create_speech(
|
|
381
|
+
self,
|
|
382
|
+
text: str,
|
|
383
|
+
options: AiAudioCreateSpeechOptions,
|
|
384
|
+
) -> dict:
|
|
385
|
+
"""Generate speech from text. Returns SquidFile dict with audio data."""
|
|
386
|
+
return await self._http.post(
|
|
387
|
+
"squid-api/v1/ai/audio/createSpeech",
|
|
388
|
+
{"input": text, "options": options},
|
|
389
|
+
)
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
# ---------------------------------------------------------------------------
|
|
393
|
+
# AI Query
|
|
394
|
+
# ---------------------------------------------------------------------------
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
async def execute_ai_query(
|
|
398
|
+
http: HttpTransport,
|
|
399
|
+
integration_id: str,
|
|
400
|
+
prompt: str,
|
|
401
|
+
*,
|
|
402
|
+
response_format: Optional[dict[str, Any]] = None,
|
|
403
|
+
) -> dict:
|
|
404
|
+
"""Execute an AI-powered database query. Returns AiQueryResponse."""
|
|
405
|
+
body: dict[str, Any] = {
|
|
406
|
+
"integrationId": integration_id,
|
|
407
|
+
"prompt": prompt,
|
|
408
|
+
}
|
|
409
|
+
if response_format is not None:
|
|
410
|
+
body["responseFormat"] = response_format
|
|
411
|
+
return await http.post("squid-api/v1/db/executeAiQuery", body)
|