Skip to content

Commit c9b1915

Browse files
authored
release: version 0.1.1
1. support vector Exceptions, code should be string 2. add retry and ping in vector 3. update examples for easy usage
2 parents b406fcd + 6f95377 commit c9b1915

32 files changed

+1254
-1140
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,6 @@ venv
1010
AGENTS.md
1111
.env
1212

13-
dist/
13+
dist/
14+
.pytest_cache/
15+
.ruff_cache/

README.md

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ This package provides an idiomatic Python interface to the VikingDB v2 data-plan
1414
Clone the repository and install the SDK in editable mode:
1515

1616
```bash
17-
pip install -e .
17+
uv add vikingdb-python-sdk
1818
```
1919

2020
> **Dependencies:** The SDK relies on `requests`, `pydantic>=2.5`, and the Volcano Engine base SDK (`volcengine`) for request signing.
@@ -24,34 +24,24 @@ pip install -e .
2424
#### Vector Database
2525

2626
```python
27+
import os
2728
from vikingdb import IAM
28-
from vikingdb.vector import UpsertDataRequest, VikingVector
29+
from vikingdb.vector import SearchByRandomRequest, VikingVector
2930

30-
auth = IAM(ak="<AK>", sk="<SK>")
31+
auth = IAM(ak=os.environ["VIKINGDB_AK"], sk=os.environ["VIKINGDB_SK"])
3132
client = VikingVector(
32-
host="api.vector.bytedance.com",
33-
region="cn-beijing",
33+
host=os.environ["VIKINGDB_HOST"],
34+
region=os.environ["VIKINGDB_REGION"],
3435
auth=auth,
3536
scheme="https",
3637
timeout=30,
3738
)
38-
39-
collection = client.collection(collection_name="demo_collection")
40-
index = client.index(collection_name="demo_collection", index_name="demo_index")
41-
embedding = client.embedding()
42-
43-
# Upsert documents into a collection
44-
upsert_request = UpsertDataRequest(
45-
data=[
46-
{"title": "Demo Chapter", "paragraph": 1, "score": 42.0, "text": "hello vikingdb"},
47-
]
39+
index = client.index(
40+
collection_name=os.environ["VIKINGDB_COLLECTION"],
41+
index_name=os.environ["VIKINGDB_INDEX"],
4842
)
49-
response = collection.upsert(upsert_request)
50-
print("request_id:", response.request_id, "result:", response.result)
51-
52-
# Run a quick search
53-
search_response = index.search_by_random({"limit": 1})
54-
print("search hits:", len(search_response.result.data) if search_response.result else 0)
43+
resp = index.search_by_random(SearchByRandomRequest(limit=1))
44+
print(f"request_id={resp.request_id} hits={len(resp.result.data or [])}")
5545
```
5646

5747
#### Memory Management
@@ -107,6 +97,8 @@ The integration guides under `examples/vector` mirror the Go SDK walkthroughs (`
10797
```
10898
VIKINGDB_AK=your-access-key
10999
VIKINGDB_SK=your-secret-key
100+
VIKINGDB_COLLECTION=demo_collection
101+
VIKINGDB_INDEX=demo_index
110102
# Optional:
111103
# VIKINGDB_PROJECT=project-name
112104
# VIKINGDB_RESOURCE_ID=resource-id
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
"""
5+
Example 4: Exceptions
6+
"""
7+
8+
import os
9+
import time
10+
11+
from vikingdb import IAM
12+
from vikingdb.memory import VikingMem
13+
14+
15+
# Initialize client
16+
_auth = IAM(
17+
ak=os.getenv("VIKINGDB_AK", "your_ak"),
18+
sk=os.getenv("VIKINGDB_SK", "your_sk"),
19+
)
20+
client = VikingMem(
21+
host="api-knowledgebase.mlp.cn-beijing.volces.com",
22+
region="cn-beijing",
23+
auth=_auth,
24+
scheme="http",
25+
)
26+
27+
28+
def add_session_exception():
29+
collection = client.get_collection(
30+
collection_name="sdk_missing",
31+
project_name="default"
32+
)
33+
now_ts = int(time.time() * 1000)
34+
# Add session messages
35+
result = collection.add_session(
36+
session_id="session_001",
37+
messages=[
38+
{
39+
"role": "user",
40+
"content": "Hello, how is the weather today?"
41+
},
42+
{
43+
"role": "assistant",
44+
"content": "Today is sunny with a temperature of 22 degrees, perfect for going out."
45+
}
46+
],
47+
metadata = {
48+
"default_user_id": "user_3",
49+
"default_user_name": "Li",
50+
"default_assistant_id": "111",
51+
"default_assistant_name": "Smart Assistant",
52+
# "group_id": "",
53+
"time": now_ts,
54+
}
55+
)
56+
57+
return result
58+
59+
60+
61+
62+
if __name__ == "__main__":
63+
print("Viking Memory Add Session Messages Example\n")
64+
65+
add_session_exception()

examples/vector/1_connectivity.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
from __future__ import annotations
5+
6+
import os
7+
import json
8+
9+
from vikingdb import IAM
10+
from vikingdb.vector import SearchByRandomRequest, VikingVector
11+
12+
13+
def main() -> None:
14+
"""Connectivity quickstart mirroring the snippet test."""
15+
auth = IAM(
16+
ak=os.environ["VIKINGDB_AK"],
17+
sk=os.environ["VIKINGDB_SK"],
18+
)
19+
client = VikingVector(
20+
host=os.environ["VIKINGDB_HOST"],
21+
region=os.environ["VIKINGDB_REGION"],
22+
auth=auth,
23+
scheme="https",
24+
timeout=30,
25+
)
26+
index_client = client.index(
27+
collection_name=os.environ["VIKINGDB_COLLECTION"],
28+
index_name=os.environ["VIKINGDB_INDEX"],
29+
)
30+
31+
response = index_client.search_by_random(SearchByRandomRequest(limit=1))
32+
data = []
33+
if response.result and response.result.data:
34+
data = response.result.data
35+
hits = len(data)
36+
print(f"SearchByRandom request_id={response.request_id} hits={hits}")
37+
# Pretty print full JSON response if available
38+
if hasattr(response, "model_dump"):
39+
try:
40+
print(response.model_dump_json(indent=2, by_alias=True) if hasattr(response, "model_dump_json") else json.dumps(response.model_dump(by_alias=True, mode="json"), ensure_ascii=False, indent=2, sort_keys=True))
41+
except Exception:
42+
pass
43+
44+
45+
if __name__ == "__main__":
46+
main()
Lines changed: 10 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,11 @@
11
# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd.
22
# SPDX-License-Identifier: Apache-2.0
33

4-
"""
5-
Scenario 2 – Collection Lifecycle
6-
7-
Follows the Go reference by showing both an inline lifecycle walkthrough and a helper-based scenario.
8-
"""
94
from __future__ import annotations
105

116
import os
127
import time
13-
14-
import pytest
8+
import json
159

1610
from vikingdb import IAM
1711
from vikingdb.vector import (
@@ -23,28 +17,9 @@
2317
VikingVector,
2418
)
2519

26-
from .guide_helpers import (
27-
Clients,
28-
assign_chapter_ids_via_search,
29-
build_clients,
30-
build_request_options,
31-
build_story_chapters,
32-
chapters_to_upsert,
33-
cleanup_chapters,
34-
load_config,
35-
new_session_tag,
36-
)
37-
3820

39-
def test_snippet_collection_lifecycle() -> None:
40-
"""
41-
Inline lifecycle flow mirroring the Go snippet:
42-
1. Upsert a chapter.
43-
2. Search to hydrate the chapter ID.
44-
3. Update scalar fields.
45-
4. Fetch to verify.
46-
5. Delete the record.
47-
"""
21+
def main() -> None:
22+
"""Inline lifecycle flow: upsert → search → update → fetch → delete."""
4823
auth = IAM(
4924
ak=os.environ["VIKINGDB_AK"],
5025
sk=os.environ["VIKINGDB_SK"],
@@ -71,6 +46,7 @@ def test_snippet_collection_lifecycle() -> None:
7146
}
7247
upsert_resp = collection_client.upsert(UpsertDataRequest(data=[chapter]))
7348
print(f"Upsert request_id={upsert_resp.request_id}")
49+
print(upsert_resp.model_dump_json(indent=2, by_alias=True) if hasattr(upsert_resp, "model_dump_json") else json.dumps(upsert_resp.model_dump(by_alias=True, mode="json"), ensure_ascii=False, indent=2, sort_keys=True))
7450

7551
time.sleep(2)
7652

@@ -81,6 +57,7 @@ def test_snippet_collection_lifecycle() -> None:
8157
output_fields=["title", "score"],
8258
)
8359
search_resp = index_client.search_by_multi_modal(search_req)
60+
print(search_resp.model_dump_json(indent=2, by_alias=True) if hasattr(search_resp, "model_dump_json") else json.dumps(search_resp.model_dump(by_alias=True, mode="json"), ensure_ascii=False, indent=2, sort_keys=True))
8461
if not search_resp.result or not search_resp.result.data:
8562
print("SearchByMultiModal returned no hits")
8663
return
@@ -94,59 +71,19 @@ def test_snippet_collection_lifecycle() -> None:
9471
UpdateDataRequest(data=[{"__AUTO_ID__": chapter_id, "score": new_score}])
9572
)
9673
print(f"Update request_id={update_resp.request_id}")
74+
print(update_resp.model_dump_json(indent=2, by_alias=True) if hasattr(update_resp, "model_dump_json") else json.dumps(update_resp.model_dump(by_alias=True, mode="json"), ensure_ascii=False, indent=2, sort_keys=True))
9775

9876
fetch_resp = collection_client.fetch(FetchDataInCollectionRequest(ids=[chapter_id]))
77+
print(fetch_resp.model_dump_json(indent=2, by_alias=True) if hasattr(fetch_resp, "model_dump_json") else json.dumps(fetch_resp.model_dump(by_alias=True, mode="json"), ensure_ascii=False, indent=2, sort_keys=True))
9978
if fetch_resp.result and fetch_resp.result.items:
10079
fetched = fetch_resp.result.items[0].fields.get("score")
10180
fetched_score = float(fetched) if fetched is not None else None
10281
print(f"Fetch request_id={fetch_resp.request_id} score={fetched_score}")
10382

10483
delete_resp = collection_client.delete(DeleteDataRequest(ids=[chapter_id]))
10584
print(f"Delete request_id={delete_resp.request_id}")
85+
print(delete_resp.model_dump_json(indent=2, by_alias=True) if hasattr(delete_resp, "model_dump_json") else json.dumps(delete_resp.model_dump(by_alias=True, mode="json"), ensure_ascii=False, indent=2, sort_keys=True))
10686

10787

108-
@pytest.fixture(scope="module")
109-
def collection_clients() -> Clients:
110-
return build_clients(load_config())
111-
112-
113-
def test_scenario_collection_lifecycle(collection_clients: Clients) -> None:
114-
session_tag = new_session_tag("collection-lifecycle")
115-
request_options = build_request_options(session_tag)
116-
base_paragraph = int(time.time()) % 1_000_000
117-
chapters = build_story_chapters(session_tag, base_paragraph)
118-
119-
try:
120-
for payload in chapters_to_upsert(chapters):
121-
response = collection_clients.collection.upsert(
122-
UpsertDataRequest(data=[payload]),
123-
request_options=request_options,
124-
)
125-
assert response.request_id
126-
127-
assign_chapter_ids_via_search(
128-
collection_clients.index,
129-
chapters,
130-
output_fields=["title", "paragraph", "score"],
131-
request_options=request_options,
132-
)
133-
134-
target = next(ch for ch in chapters if ch.key == "retrieval-lab")
135-
assert target.chapter_id is not None
136-
137-
new_score = target.score + 4.25
138-
update_resp = collection_clients.collection.update(
139-
UpdateDataRequest(data=[{"__AUTO_ID__": target.chapter_id, "score": new_score}]),
140-
request_options=request_options,
141-
)
142-
assert update_resp.request_id
143-
144-
fetch_resp = collection_clients.collection.fetch(
145-
FetchDataInCollectionRequest(ids=[target.chapter_id]),
146-
request_options=request_options,
147-
)
148-
assert fetch_resp.result and fetch_resp.result.items
149-
fetched_score = fetch_resp.result.items[0].fields.get("score")
150-
assert fetched_score == pytest.approx(new_score)
151-
finally:
152-
cleanup_chapters(collection_clients.collection, chapters, request_options=request_options)
88+
if __name__ == "__main__":
89+
main()
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
from __future__ import annotations
5+
6+
import os
7+
import time
8+
import json
9+
10+
from vikingdb import IAM
11+
from vikingdb.vector import SearchByMultiModalRequest, UpsertDataRequest, VikingVector
12+
13+
14+
def main() -> None:
15+
"""Inline multi-modal search showing filters and output fields."""
16+
auth = IAM(
17+
ak=os.environ["VIKINGDB_AK"],
18+
sk=os.environ["VIKINGDB_SK"],
19+
)
20+
client = VikingVector(
21+
host=os.environ["VIKINGDB_HOST"],
22+
region=os.environ["VIKINGDB_REGION"],
23+
auth=auth,
24+
scheme="https",
25+
timeout=30,
26+
)
27+
collection_client = client.collection(collection_name=os.environ["VIKINGDB_COLLECTION"])
28+
index_client = client.index(
29+
collection_name=os.environ["VIKINGDB_COLLECTION"],
30+
index_name=os.environ["VIKINGDB_INDEX"],
31+
)
32+
33+
base_paragraph = int(time.time() * 1e6) % 1_000_000
34+
chapters = [
35+
{
36+
"title": "Session kickoff",
37+
"paragraph": base_paragraph,
38+
"score": 73.0,
39+
"text": "This kickoff chapter keeps the reference search grounded.",
40+
},
41+
{
42+
"title": "Session filters",
43+
"paragraph": base_paragraph + 1,
44+
"score": 91.0,
45+
"text": "Filter walkthrough for multi-modal search.",
46+
},
47+
]
48+
49+
for payload in chapters:
50+
collection_client.upsert(UpsertDataRequest(data=[payload]))
51+
52+
time.sleep(2)
53+
54+
filter_map = {"op": "range", "field": "paragraph", "gte": base_paragraph, "lte": base_paragraph + 1}
55+
search_req = SearchByMultiModalRequest(
56+
text="Which chapter explains the session filters?",
57+
need_instruction=False,
58+
limit=2,
59+
output_fields=["title", "score", "paragraph"],
60+
filter=filter_map,
61+
)
62+
response = index_client.search_by_multi_modal(search_req)
63+
hits = response.result.data if response.result and response.result.data else []
64+
print(f"SearchByMultiModal request_id={response.request_id} hits={len(hits)}")
65+
print(response.model_dump_json(indent=2, by_alias=True) if hasattr(response, "model_dump_json") else json.dumps(response.model_dump(by_alias=True, mode="json"), ensure_ascii=False, indent=2, sort_keys=True))
66+
67+
68+
if __name__ == "__main__":
69+
main()

0 commit comments

Comments
 (0)