Skip to content

Commit 7f19c35

Browse files
author
wangjiaju.716
committed
Merge branch 'main' of https://github.com/doraemonlove/veadk-python into fix/verc
2 parents 4c1e816 + 1368a10 commit 7f19c35

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1686
-35
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
name: Push Preview Image to Volcengine Container Registry
16+
17+
permissions:
18+
contents: read
19+
20+
on:
21+
push:
22+
branches:
23+
- main
24+
workflow_dispatch:
25+
26+
jobs:
27+
build-and-push:
28+
runs-on: ubuntu-latest
29+
30+
# To avoid forked repo execute this workflow
31+
if: github.repository == 'volcengine/veadk-python'
32+
33+
# Set global environments
34+
env:
35+
CR_URL: veadk-cn-beijing.cr.volces.com
36+
CR_NAMESPACE: veadk
37+
CR_REPO: veadk-python
38+
DOCKERFILE: docker/Dockerfile.preview
39+
40+
steps:
41+
- name: Checkout code
42+
uses: actions/checkout@v4
43+
with:
44+
fetch-depth: 0
45+
46+
- name: Set up Docker Buildx
47+
uses: docker/setup-buildx-action@v3
48+
49+
- name: Login to Volcengine Container Registry
50+
run: |
51+
echo "${{ secrets.VE_CR_PASSWORD }}" | \
52+
docker login veadk-cn-beijing.cr.volces.com \
53+
-u "${{ secrets.VE_CR_USERNAME }}" \
54+
--password-stdin
55+
56+
# Specify a platform, as VeFaaS required `linux/amd64`
57+
- name: Build and push
58+
run: |
59+
IMAGE_TAG=$CR_URL/$CR_NAMESPACE/$CR_REPO:preview
60+
docker buildx build \
61+
--file $DOCKERFILE \
62+
--tag $IMAGE_TAG \
63+
--platform linux/amd64 \
64+
--push \
65+
--cache-from=type=gha \
66+
--cache-to=type=gha,mode=max \
67+
.
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
name: Push Stable Image to Volcengine Container Registry
16+
17+
on:
18+
push:
19+
# Trigger only when creating tags
20+
tags:
21+
- '*'
22+
workflow_dispatch:
23+
24+
jobs:
25+
build-and-push:
26+
runs-on: ubuntu-latest
27+
permissions:
28+
contents: read
29+
30+
# To avoid forked repo execute this workflow
31+
if: github.repository == 'volcengine/veadk-python'
32+
33+
# Set global environments
34+
env:
35+
CR_URL: veadk-cn-beijing.cr.volces.com
36+
CR_NAMESPACE: veadk
37+
CR_REPO: veadk-python
38+
DOCKERFILE: docker/Dockerfile.stable
39+
40+
steps:
41+
- name: Checkout code
42+
uses: actions/checkout@v4
43+
with:
44+
fetch-depth: 0
45+
46+
- name: Set up Docker Buildx
47+
uses: docker/setup-buildx-action@v3
48+
49+
- name: Login to Volcengine Container Registry
50+
run: |
51+
echo "${{ secrets.VE_CR_PASSWORD }}" | \
52+
docker login veadk-cn-beijing.cr.volces.com \
53+
-u "${{ secrets.VE_CR_USERNAME }}" \
54+
--password-stdin
55+
56+
# Specify a platform, as VeFaaS required `linux/amd64`
57+
# push 2 tags (x.x.x and latest) in one push
58+
- name: Build and push
59+
run: |
60+
LATEST_TAG=$CR_URL/$CR_NAMESPACE/$CR_REPO:latest
61+
VERSION_TAG=$CR_URL/$CR_NAMESPACE/$CR_REPO:$GITHUB_REF_NAME
62+
docker buildx build \
63+
--file $DOCKERFILE \
64+
--tag $VERSION_TAG \
65+
--tag $LATEST_TAG \
66+
--platform linux/amd64 \
67+
--push \
68+
--cache-from=type=gha \
69+
--cache-to=type=gha,mode=max \
70+
.

docker/Dockerfile.preview

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
FROM python:3.12
16+
17+
# Install git and install veadk-python via git
18+
RUN apt-get install -y git && \
19+
pip3 install --no-cache-dir git+https://github.com/volcengine/veadk-python.git && \
20+
apt-get clean && rm -rf /var/lib/apt/lists/*

docker/Dockerfile.stable

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
FROM python:3.12
16+
17+
# In order to avoid PyPI not update VeADK new package,
18+
# we still use git code to build image here.
19+
# TODO: use PyPI source
20+
RUN apt-get install -y git && \
21+
pip3 install --no-cache-dir git+https://github.com/volcengine/veadk-python.git && \
22+
apt-get clean && rm -rf /var/lib/apt/lists/*

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,5 +74,6 @@ include-package-data = true
7474

7575
[tool.ruff]
7676
exclude = [
77-
"veadk/integrations/ve_faas/template/*"
77+
"veadk/integrations/ve_faas/template/*",
78+
"veadk/integrations/ve_faas/web_template/*"
7879
]

tests/test_tos.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ async def test_upload_bytes_success(tos_client, mock_client):
108108
data = b"hello world"
109109

110110
result = await tos_client.upload("obj-key", data)
111-
assert result is True
111+
assert result is None
112112
mock_client.put_object.assert_called_once()
113113
mock_client.close.assert_called_once()
114114

@@ -121,7 +121,7 @@ async def test_upload_file_success(tmp_path, tos_client, mock_client):
121121
file_path.write_text("hello file")
122122

123123
result = await tos_client.upload("obj-key", str(file_path))
124-
assert result is True
124+
assert result is None
125125
mock_client.put_object_from_file.assert_called_once()
126126
mock_client.close.assert_called_once()
127127

veadk/cli/cli_init.py

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import click
1919
from veadk.version import VERSION
2020

21+
2122
warnings.filterwarnings(
2223
"ignore", category=UserWarning, module="pydantic._internal._fields"
2324
)
@@ -64,18 +65,31 @@ def _render_prompts() -> dict[str, Any]:
6465

6566

6667
@click.command()
67-
def init() -> None:
68-
"""Init a veadk project that can be deployed to Volcengine VeFaaS."""
68+
@click.option(
69+
"--vefaas-template-type", default="template", help="Expected template type"
70+
)
71+
def init(
72+
vefaas_template_type: str,
73+
) -> None:
74+
"""Init a veadk project that can be deployed to Volcengine VeFaaS.
75+
76+
`template` is A2A/MCP/Web server template, `web_template` is for web applications (i.e., a simple blog).
77+
"""
6978
import shutil
7079
from pathlib import Path
7180

7281
from cookiecutter.main import cookiecutter
7382

7483
import veadk.integrations.ve_faas as vefaas
7584

76-
click.echo(
77-
"Welcome use VeADK to create your project. We will generate a `weather-reporter` application for you."
78-
)
85+
if vefaas_template_type == "web_template":
86+
click.echo(
87+
"Welcome use VeADK to create your project. We will generate a `simple-blog` web application for you."
88+
)
89+
else:
90+
click.echo(
91+
"Welcome use VeADK to create your project. We will generate a `weather-reporter` application for you."
92+
)
7993

8094
cwd = Path.cwd()
8195
local_dir_name = click.prompt("Local directory name", default="veadk-cloud-proj")
@@ -91,7 +105,10 @@ def init() -> None:
91105
settings = _render_prompts()
92106
settings["local_dir_name"] = local_dir_name
93107

94-
template_dir_path = Path(vefaas.__file__).parent / "template"
108+
if not vefaas_template_type:
109+
vefaas_template_type = "template"
110+
111+
template_dir_path = Path(vefaas.__file__).parent / vefaas_template_type
95112

96113
cookiecutter(
97114
template=str(template_dir_path),

veadk/database/database_adapter.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,33 @@ def query(self, query: str, index: str, top_k: int = 0) -> list:
5454
logger.error(f"Failed to search from Redis: index={index} error={e}")
5555
raise e
5656

57+
def delete_doc(self, index: str, id: str) -> bool:
58+
logger.debug(f"Deleting document from Redis database: index={index} id={id}")
59+
try:
60+
# For Redis, we need to handle deletion differently since RedisDatabase.delete_doc
61+
# takes a key and a single id
62+
result = self.client.delete_doc(key=index, id=id)
63+
return result
64+
except Exception as e:
65+
logger.error(
66+
f"Failed to delete document from Redis database: index={index} id={id} error={e}"
67+
)
68+
return False
69+
70+
def list_docs(self, index: str, offset: int = 0, limit: int = 100) -> list[dict]:
71+
logger.debug(f"Listing documents from Redis database: index={index}")
72+
try:
73+
# Get all documents from Redis
74+
docs = self.client.list_docs(key=index)
75+
76+
# Apply offset and limit for pagination
77+
return docs[offset : offset + limit]
78+
except Exception as e:
79+
logger.error(
80+
f"Failed to list documents from Redis database: index={index} error={e}"
81+
)
82+
return []
83+
5784

5885
class RelationalDatabaseAdapter:
5986
def __init__(self, client):
@@ -108,6 +135,28 @@ def query(self, query: str, index: str, top_k: int) -> list[str]:
108135

109136
return [item["data"] for item in results]
110137

138+
def delete_doc(self, index: str, id: str) -> bool:
139+
logger.debug(f"Deleting document from SQL database: table_name={index} id={id}")
140+
try:
141+
# Convert single id to list for the client method
142+
result = self.client.delete_doc(table=index, ids=[int(id)])
143+
return result
144+
except Exception as e:
145+
logger.error(
146+
f"Failed to delete document from SQL database: table_name={index} id={id} error={e}"
147+
)
148+
return False
149+
150+
def list_docs(self, index: str, offset: int = 0, limit: int = 100) -> list[dict]:
151+
logger.debug(f"Listing documents from SQL database: table_name={index}")
152+
try:
153+
return self.client.list_docs(table=index, offset=offset, limit=limit)
154+
except Exception as e:
155+
logger.error(
156+
f"Failed to list documents from SQL database: table_name={index} error={e}"
157+
)
158+
return []
159+
111160

112161
class VectorDatabaseAdapter:
113162
def __init__(self, client):
@@ -152,6 +201,23 @@ def query(self, query: str, index: str, top_k: int) -> list[str]:
152201
top_k=top_k,
153202
)
154203

204+
def delete_doc(self, index: str, id: str) -> bool:
205+
self._validate_index(index)
206+
logger.debug(f"Deleting documents from vector database: index={index} id={id}")
207+
try:
208+
self.client.delete_by_id(collection_name=index, id=id)
209+
return True
210+
except Exception as e:
211+
logger.error(
212+
f"Failed to delete document from vector database: index={index} id={id} error={e}"
213+
)
214+
return False
215+
216+
def list_docs(self, index: str, offset: int = 0, limit: int = 1000) -> list[dict]:
217+
self._validate_index(index)
218+
logger.debug(f"Listing documents from vector database: index={index}")
219+
return self.client.list_docs(collection_name=index, offset=offset, limit=limit)
220+
155221

156222
class VikingDatabaseAdapter:
157223
def __init__(self, client):
@@ -212,6 +278,16 @@ def query(self, query: str, index: str, top_k: int) -> list[str]:
212278

213279
return self.client.query(query, collection_name=index, top_k=top_k)
214280

281+
def delete_doc(self, index: str, id: str) -> bool:
282+
self._validate_index(index)
283+
logger.debug(f"Deleting documents from vector database: index={index} id={id}")
284+
return self.client.delete_by_id(collection_name=index, id=id)
285+
286+
def list_docs(self, index: str, offset: int, limit: int) -> list[dict]:
287+
self._validate_index(index)
288+
logger.debug(f"Listing documents from vector database: index={index}")
289+
return self.client.list_docs(collection_name=index, offset=offset, limit=limit)
290+
215291

216292
class VikingMemoryDatabaseAdapter:
217293
def __init__(self, client):
@@ -248,6 +324,12 @@ def query(self, query: str, index: str, top_k: int, **kwargs):
248324
result = self.client.query(query, collection_name=index, top_k=top_k, **kwargs)
249325
return result
250326

327+
def delete_docs(self, index: str, ids: list[int]):
328+
raise NotImplementedError("VikingMemoryDatabase does not support delete_docs")
329+
330+
def list_docs(self, index: str):
331+
raise NotImplementedError("VikingMemoryDatabase does not support list_docs")
332+
251333

252334
class LocalDatabaseAdapter:
253335
def __init__(self, client):
@@ -261,6 +343,12 @@ def add(self, data: list[str], **kwargs):
261343
def query(self, query: str, **kwargs):
262344
return self.client.query(query, **kwargs)
263345

346+
def delete_doc(self, index: str, id: str) -> bool:
347+
return self.client.delete_doc(id)
348+
349+
def list_docs(self, index: str, offset: int = 0, limit: int = 100) -> list[dict]:
350+
return self.client.list_docs(offset=offset, limit=limit)
351+
264352

265353
MAPPING = {
266354
"RedisDatabase": KVDatabaseAdapter,

0 commit comments

Comments
 (0)