veadk-python 0.2.4__py3-none-any.whl → 0.2.6__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.
Potentially problematic release.
This version of veadk-python might be problematic. Click here for more details.
- veadk/agent.py +40 -8
- veadk/cli/cli_deploy.py +5 -1
- veadk/cli/cli_init.py +25 -6
- veadk/cloud/cloud_app.py +21 -6
- veadk/consts.py +33 -1
- veadk/database/database_adapter.py +88 -0
- veadk/database/kv/redis_database.py +47 -0
- veadk/database/local_database.py +22 -4
- veadk/database/relational/mysql_database.py +58 -0
- veadk/database/vector/opensearch_vector_database.py +6 -3
- veadk/database/viking/viking_database.py +72 -3
- veadk/integrations/ve_cr/__init__.py +13 -0
- veadk/integrations/ve_cr/ve_cr.py +205 -0
- veadk/integrations/ve_faas/template/cookiecutter.json +2 -1
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/clean.py +23 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/app.py +28 -2
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/requirements.txt +3 -1
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/run.sh +5 -2
- veadk/integrations/ve_faas/ve_faas.py +2 -0
- veadk/integrations/ve_faas/web_template/cookiecutter.json +17 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/__init__.py +13 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/clean.py +23 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/config.yaml.example +2 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/deploy.py +41 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/Dockerfile +23 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/app.py +123 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/init_db.py +46 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/models.py +36 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/requirements.txt +4 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/run.sh +21 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/static/css/style.css +368 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/static/js/admin.js +0 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/dashboard.html +21 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/edit_post.html +24 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/login.html +21 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/posts.html +53 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/base.html +45 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/index.html +29 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/post.html +14 -0
- veadk/integrations/ve_tos/ve_tos.py +238 -0
- veadk/knowledgebase/knowledgebase.py +8 -0
- veadk/runner.py +140 -34
- veadk/tools/builtin_tools/image_edit.py +236 -0
- veadk/tools/builtin_tools/image_generate.py +236 -0
- veadk/tools/builtin_tools/video_generate.py +326 -0
- veadk/tools/sandbox/browser_sandbox.py +19 -9
- veadk/tools/sandbox/code_sandbox.py +21 -11
- veadk/tools/sandbox/computer_sandbox.py +16 -9
- veadk/tracing/base_tracer.py +0 -19
- veadk/tracing/telemetry/attributes/extractors/common_attributes_extractors.py +5 -0
- veadk/tracing/telemetry/attributes/extractors/llm_attributes_extractors.py +311 -128
- veadk/tracing/telemetry/attributes/extractors/tool_attributes_extractors.py +20 -14
- veadk/tracing/telemetry/attributes/extractors/types.py +15 -4
- veadk/tracing/telemetry/exporters/inmemory_exporter.py +3 -0
- veadk/tracing/telemetry/opentelemetry_tracer.py +15 -6
- veadk/tracing/telemetry/telemetry.py +128 -24
- veadk/utils/misc.py +40 -0
- veadk/version.py +1 -1
- {veadk_python-0.2.4.dist-info → veadk_python-0.2.6.dist-info}/METADATA +1 -1
- {veadk_python-0.2.4.dist-info → veadk_python-0.2.6.dist-info}/RECORD +64 -37
- {veadk_python-0.2.4.dist-info → veadk_python-0.2.6.dist-info}/WHEEL +0 -0
- {veadk_python-0.2.4.dist-info → veadk_python-0.2.6.dist-info}/entry_points.txt +0 -0
- {veadk_python-0.2.4.dist-info → veadk_python-0.2.6.dist-info}/licenses/LICENSE +0 -0
- {veadk_python-0.2.4.dist-info → veadk_python-0.2.6.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,13 @@
|
|
|
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.
|
|
@@ -0,0 +1,205 @@
|
|
|
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 veadk.utils.volcengine_sign import ve_request
|
|
16
|
+
from veadk.utils.logger import get_logger
|
|
17
|
+
from veadk.consts import (
|
|
18
|
+
DEFAULT_CR_INSTANCE_NAME,
|
|
19
|
+
DEFAULT_CR_NAMESPACE_NAME,
|
|
20
|
+
DEFAULT_CR_REPO_NAME,
|
|
21
|
+
)
|
|
22
|
+
import time
|
|
23
|
+
|
|
24
|
+
logger = get_logger(__name__)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class VeCR:
|
|
28
|
+
def __init__(self, access_key: str, secret_key: str, region: str = "cn-beijing"):
|
|
29
|
+
self.ak = access_key
|
|
30
|
+
self.sk = secret_key
|
|
31
|
+
self.region = region
|
|
32
|
+
assert region in ["cn-beijing", "cn-guangzhou", "cn-shanghai"]
|
|
33
|
+
self.version = "2022-05-12"
|
|
34
|
+
|
|
35
|
+
def _create_instance(self, instance_name: str = DEFAULT_CR_INSTANCE_NAME) -> str:
|
|
36
|
+
"""
|
|
37
|
+
create cr instance
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
instance_name: cr instance name
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
cr instance name
|
|
44
|
+
"""
|
|
45
|
+
status = self._check_instance(instance_name)
|
|
46
|
+
if status != "NONEXIST":
|
|
47
|
+
logger.debug(f"cr instance {instance_name} already running")
|
|
48
|
+
return instance_name
|
|
49
|
+
response = ve_request(
|
|
50
|
+
request_body={
|
|
51
|
+
"Name": instance_name,
|
|
52
|
+
"ResourceTags": [
|
|
53
|
+
{"Key": "provider", "Value": "veadk"},
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
action="CreateRegistry",
|
|
57
|
+
ak=self.ak,
|
|
58
|
+
sk=self.sk,
|
|
59
|
+
service="cr",
|
|
60
|
+
version=self.version,
|
|
61
|
+
region=self.region,
|
|
62
|
+
host=f"cr.{self.region}.volcengineapi.com",
|
|
63
|
+
)
|
|
64
|
+
logger.debug(f"create cr instance {instance_name}: {response}")
|
|
65
|
+
|
|
66
|
+
while True:
|
|
67
|
+
status = self._check_instance(instance_name)
|
|
68
|
+
if status == "Running":
|
|
69
|
+
break
|
|
70
|
+
elif status == "Failed":
|
|
71
|
+
raise ValueError(f"cr instance {instance_name} create failed")
|
|
72
|
+
else:
|
|
73
|
+
logger.debug(f"cr instance status: {status}")
|
|
74
|
+
time.sleep(5)
|
|
75
|
+
|
|
76
|
+
return instance_name
|
|
77
|
+
|
|
78
|
+
def _check_instance(self, instance_name: str) -> str:
|
|
79
|
+
"""
|
|
80
|
+
check cr instance status
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
instance_name: cr instance name
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
cr instance status
|
|
87
|
+
"""
|
|
88
|
+
response = ve_request(
|
|
89
|
+
request_body={
|
|
90
|
+
"Filter": {
|
|
91
|
+
"Names": [instance_name],
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
action="ListRegistries",
|
|
95
|
+
ak=self.ak,
|
|
96
|
+
sk=self.sk,
|
|
97
|
+
service="cr",
|
|
98
|
+
version=self.version,
|
|
99
|
+
region=self.region,
|
|
100
|
+
host=f"cr.{self.region}.volcengineapi.com",
|
|
101
|
+
)
|
|
102
|
+
logger.debug(f"check cr instance {instance_name}: {response}")
|
|
103
|
+
|
|
104
|
+
try:
|
|
105
|
+
if response["Result"]["TotalCount"] == 0:
|
|
106
|
+
return "NONEXIST"
|
|
107
|
+
return response["Result"]["Items"][0]["Status"]["Phase"]
|
|
108
|
+
except Exception as _:
|
|
109
|
+
raise ValueError(f"Error check cr instance {instance_name}: {response}")
|
|
110
|
+
|
|
111
|
+
def _create_namespace(
|
|
112
|
+
self,
|
|
113
|
+
instance_name: str = DEFAULT_CR_INSTANCE_NAME,
|
|
114
|
+
namespace_name: str = DEFAULT_CR_NAMESPACE_NAME,
|
|
115
|
+
) -> str:
|
|
116
|
+
"""
|
|
117
|
+
create cr namespace
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
instance_name: cr instance name
|
|
121
|
+
namespace_name: cr namespace name
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
cr namespace name
|
|
125
|
+
"""
|
|
126
|
+
response = ve_request(
|
|
127
|
+
request_body={
|
|
128
|
+
"Name": namespace_name,
|
|
129
|
+
"Registry": instance_name,
|
|
130
|
+
},
|
|
131
|
+
action="CreateNamespace",
|
|
132
|
+
ak=self.ak,
|
|
133
|
+
sk=self.sk,
|
|
134
|
+
service="cr",
|
|
135
|
+
version=self.version,
|
|
136
|
+
region=self.region,
|
|
137
|
+
host=f"cr.{self.region}.volcengineapi.com",
|
|
138
|
+
)
|
|
139
|
+
logger.debug(f"create cr namespace {namespace_name}: {response}")
|
|
140
|
+
|
|
141
|
+
if "Error" in response["ResponseMetadata"]:
|
|
142
|
+
error_code = response["ResponseMetadata"]["Error"]["Code"]
|
|
143
|
+
error_message = response["ResponseMetadata"]["Error"]["Message"]
|
|
144
|
+
if error_code == "AlreadyExists.Namespace":
|
|
145
|
+
logger.debug(f"cr namespace {namespace_name} already exists")
|
|
146
|
+
return namespace_name
|
|
147
|
+
else:
|
|
148
|
+
logger.error(
|
|
149
|
+
f"Error create cr namespace {namespace_name}: {error_code} {error_message}"
|
|
150
|
+
)
|
|
151
|
+
raise ValueError(
|
|
152
|
+
f"Error create cr namespace {namespace_name}: {error_code} {error_message}"
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
return namespace_name
|
|
156
|
+
|
|
157
|
+
def _create_repo(
|
|
158
|
+
self,
|
|
159
|
+
instance_name: str = DEFAULT_CR_INSTANCE_NAME,
|
|
160
|
+
namespace_name: str = DEFAULT_CR_NAMESPACE_NAME,
|
|
161
|
+
repo_name: str = DEFAULT_CR_REPO_NAME,
|
|
162
|
+
) -> str:
|
|
163
|
+
"""
|
|
164
|
+
create cr repo
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
instance_name: cr instance name
|
|
168
|
+
namespace_name: cr namespace name
|
|
169
|
+
repo_name: cr repo name
|
|
170
|
+
|
|
171
|
+
Returns:
|
|
172
|
+
cr repo name
|
|
173
|
+
"""
|
|
174
|
+
response = ve_request(
|
|
175
|
+
request_body={
|
|
176
|
+
"Name": repo_name,
|
|
177
|
+
"Registry": instance_name,
|
|
178
|
+
"Namespace": namespace_name,
|
|
179
|
+
"Description": "veadk cr repo",
|
|
180
|
+
},
|
|
181
|
+
action="CreateRepository",
|
|
182
|
+
ak=self.ak,
|
|
183
|
+
sk=self.sk,
|
|
184
|
+
service="cr",
|
|
185
|
+
version=self.version,
|
|
186
|
+
region=self.region,
|
|
187
|
+
host=f"cr.{self.region}.volcengineapi.com",
|
|
188
|
+
)
|
|
189
|
+
logger.debug(f"create cr repo {repo_name}: {response}")
|
|
190
|
+
|
|
191
|
+
if "Error" in response["ResponseMetadata"]:
|
|
192
|
+
error_code = response["ResponseMetadata"]["Error"]["Code"]
|
|
193
|
+
error_message = response["ResponseMetadata"]["Error"]["Message"]
|
|
194
|
+
if error_code == "AlreadyExists.Repository":
|
|
195
|
+
logger.debug(f"cr repo {repo_name} already exists")
|
|
196
|
+
return repo_name
|
|
197
|
+
else:
|
|
198
|
+
logger.error(
|
|
199
|
+
f"Error create cr repo {repo_name}: {error_code} {error_message}"
|
|
200
|
+
)
|
|
201
|
+
raise ValueError(
|
|
202
|
+
f"Error create cr repo {repo_name}: {error_code} {error_message}"
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
return repo_name
|
|
@@ -0,0 +1,23 @@
|
|
|
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 veadk.cloud.cloud_app import CloudApp
|
|
16
|
+
|
|
17
|
+
def main() -> None:
|
|
18
|
+
cloud_app = CloudApp(vefaas_application_name="{{cookiecutter.vefaas_application_name}}")
|
|
19
|
+
cloud_app.delete_self()
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
if __name__ == "__main__":
|
|
23
|
+
main()
|
|
@@ -26,6 +26,7 @@ from fastmcp import FastMCP
|
|
|
26
26
|
from starlette.routing import Route
|
|
27
27
|
|
|
28
28
|
from google.adk.a2a.utils.agent_card_builder import AgentCardBuilder
|
|
29
|
+
from a2a.types import AgentProvider
|
|
29
30
|
|
|
30
31
|
from veadk.a2a.ve_a2a_server import init_app
|
|
31
32
|
from veadk.runner import Runner
|
|
@@ -35,6 +36,8 @@ from veadk.tracing.telemetry.exporters.tls_exporter import TLSExporter
|
|
|
35
36
|
from veadk.tracing.telemetry.opentelemetry_tracer import OpentelemetryTracer
|
|
36
37
|
from veadk.types import AgentRunConfig
|
|
37
38
|
from veadk.utils.logger import get_logger
|
|
39
|
+
from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator
|
|
40
|
+
from opentelemetry import context
|
|
38
41
|
|
|
39
42
|
logger = get_logger(__name__)
|
|
40
43
|
|
|
@@ -46,7 +49,9 @@ app_name = agent_run_config.app_name
|
|
|
46
49
|
agent = agent_run_config.agent
|
|
47
50
|
short_term_memory = agent_run_config.short_term_memory
|
|
48
51
|
|
|
49
|
-
|
|
52
|
+
VEFAAS_REGION = os.getenv("APP_REGION", "cn-beijing")
|
|
53
|
+
VEFAAS_FUNC_ID = os.getenv("_FAAS_FUNC_ID", "")
|
|
54
|
+
agent_card_builder = AgentCardBuilder(agent=agent, provider=AgentProvider(organization="Volcengine Agent Development Kit (VeADK)", url=f"https://console.volcengine.com/vefaas/region:vefaas+{VEFAAS_REGION}/function/detail/{VEFAAS_FUNC_ID}"))
|
|
50
55
|
|
|
51
56
|
|
|
52
57
|
def load_tracer() -> None:
|
|
@@ -114,6 +119,8 @@ async def agent_card() -> dict:
|
|
|
114
119
|
agent_card = await agent_card_builder.build()
|
|
115
120
|
return agent_card.model_dump()
|
|
116
121
|
|
|
122
|
+
async def get_cozeloop_space_id() -> dict:
|
|
123
|
+
return {"space_id": os.getenv("OBSERVABILITY_OPENTELEMETRY_COZELOOP_SERVICE_NAME", default="")}
|
|
117
124
|
|
|
118
125
|
load_tracer()
|
|
119
126
|
|
|
@@ -129,7 +136,7 @@ a2a_app = init_app(
|
|
|
129
136
|
|
|
130
137
|
a2a_app.post("/run_agent", operation_id="run_agent", tags=["mcp"])(run_agent_func)
|
|
131
138
|
a2a_app.get("/agent_card", operation_id="agent_card", tags=["mcp"])(agent_card)
|
|
132
|
-
|
|
139
|
+
a2a_app.get("/get_cozeloop_space_id", operation_id="get_cozeloop_space_id", tags=["mcp"])(get_cozeloop_space_id)
|
|
133
140
|
|
|
134
141
|
# === Build mcp server ===
|
|
135
142
|
|
|
@@ -156,6 +163,25 @@ app = FastAPI(
|
|
|
156
163
|
redoc_url=None
|
|
157
164
|
)
|
|
158
165
|
|
|
166
|
+
@app.middleware("http")
|
|
167
|
+
async def otel_context_middleware(request, call_next):
|
|
168
|
+
carrier = {
|
|
169
|
+
"traceparent": request.headers.get("Traceparent"),
|
|
170
|
+
"tracestate": request.headers.get("Tracestate"),
|
|
171
|
+
}
|
|
172
|
+
logger.debug(f"carrier: {carrier}")
|
|
173
|
+
if carrier["traceparent"] is None:
|
|
174
|
+
return await call_next(request)
|
|
175
|
+
else:
|
|
176
|
+
ctx = TraceContextTextMapPropagator().extract(carrier=carrier)
|
|
177
|
+
logger.debug(f"ctx: {ctx}")
|
|
178
|
+
token = context.attach(ctx)
|
|
179
|
+
try:
|
|
180
|
+
response = await call_next(request)
|
|
181
|
+
finally:
|
|
182
|
+
context.detach(token)
|
|
183
|
+
return response
|
|
184
|
+
|
|
159
185
|
# Mount A2A routes to main app
|
|
160
186
|
for route in a2a_app.routes:
|
|
161
187
|
app.routes.append(route)
|
|
@@ -33,8 +33,11 @@ while [[ $# -gt 0 ]]; do
|
|
|
33
33
|
esac
|
|
34
34
|
done
|
|
35
35
|
|
|
36
|
-
#
|
|
37
|
-
|
|
36
|
+
# Check if MODEL_AGENT_API_KEY is set
|
|
37
|
+
if [ -z "$MODEL_AGENT_API_KEY" ]; then
|
|
38
|
+
echo "MODEL_AGENT_API_KEY is not set. Please set it in your environment variables."
|
|
39
|
+
exit 1
|
|
40
|
+
fi
|
|
38
41
|
|
|
39
42
|
USE_ADK_WEB=${USE_ADK_WEB:-False}
|
|
40
43
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"local_dir_name": "veadk_vefaas_web_proj",
|
|
3
|
+
"app_name": "simple-blog",
|
|
4
|
+
"vefaas_application_name": "simple-blog",
|
|
5
|
+
"veapig_instance_name": "",
|
|
6
|
+
"veapig_service_name": "",
|
|
7
|
+
"veapig_upstream_name": "",
|
|
8
|
+
"use_adk_web": false,
|
|
9
|
+
"veadk_version": "",
|
|
10
|
+
"_copy_without_render": [
|
|
11
|
+
"*.html",
|
|
12
|
+
"*.css",
|
|
13
|
+
"*.js",
|
|
14
|
+
"static/**/*",
|
|
15
|
+
"templates/**/*"
|
|
16
|
+
]
|
|
17
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
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.
|
|
@@ -0,0 +1,23 @@
|
|
|
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 veadk.cloud.cloud_app import CloudApp
|
|
16
|
+
|
|
17
|
+
def main() -> None:
|
|
18
|
+
cloud_app = CloudApp(vefaas_application_name="{{cookiecutter.vefaas_application_name}}")
|
|
19
|
+
cloud_app.delete_self()
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
if __name__ == "__main__":
|
|
23
|
+
main()
|
|
@@ -0,0 +1,41 @@
|
|
|
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
|
+
import asyncio
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
from veadk.cloud.cloud_agent_engine import CloudAgentEngine
|
|
19
|
+
|
|
20
|
+
async def main():
|
|
21
|
+
engine = CloudAgentEngine()
|
|
22
|
+
|
|
23
|
+
cloud_app = engine.deploy(
|
|
24
|
+
path=str(Path(__file__).parent / "src"),
|
|
25
|
+
application_name="{{cookiecutter.vefaas_application_name}}",
|
|
26
|
+
gateway_name="{{cookiecutter.veapig_instance_name}}",
|
|
27
|
+
gateway_service_name="{{cookiecutter.veapig_service_name}}",
|
|
28
|
+
gateway_upstream_name="{{cookiecutter.veapig_upstream_name}}",
|
|
29
|
+
use_adk_web={{cookiecutter.use_adk_web}},
|
|
30
|
+
local_test=False, # Set to True for local testing before deploy to VeFaaS
|
|
31
|
+
)
|
|
32
|
+
print(f"VeFaaS application ID: {cloud_app.vefaas_application_id}")
|
|
33
|
+
|
|
34
|
+
if {{cookiecutter.use_adk_web}}:
|
|
35
|
+
print(f"Web is running at: {cloud_app.vefaas_endpoint}")
|
|
36
|
+
else:
|
|
37
|
+
print(f"Web template does not support use_adk_web=False")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
if __name__ == "__main__":
|
|
41
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# 使用官方Python镜像作为基础镜像
|
|
2
|
+
FROM python:3.9-slim
|
|
3
|
+
|
|
4
|
+
# 设置工作目录
|
|
5
|
+
WORKDIR /app
|
|
6
|
+
|
|
7
|
+
# 复制依赖文件并安装依赖
|
|
8
|
+
COPY requirements.txt .
|
|
9
|
+
RUN pip install --no-cache-dir -r requirements.txt
|
|
10
|
+
|
|
11
|
+
# 复制项目文件
|
|
12
|
+
COPY . .
|
|
13
|
+
|
|
14
|
+
# 设置环境变量
|
|
15
|
+
ENV FLASK_APP=app.py
|
|
16
|
+
ENV FLASK_ENV=production
|
|
17
|
+
ENV PYTHONUNBUFFERED=1
|
|
18
|
+
|
|
19
|
+
# 暴露端口
|
|
20
|
+
EXPOSE 8000
|
|
21
|
+
|
|
22
|
+
# 启动命令
|
|
23
|
+
CMD ["bash", "run.sh"]
|
|
@@ -0,0 +1,123 @@
|
|
|
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 flask import Flask, render_template, request, redirect, url_for, flash, session
|
|
16
|
+
from models import db, Post, User
|
|
17
|
+
from werkzeug.security import generate_password_hash, check_password_hash
|
|
18
|
+
import os
|
|
19
|
+
|
|
20
|
+
app = Flask(__name__)
|
|
21
|
+
app.config['SECRET_KEY'] = 'your-secret-key-here'
|
|
22
|
+
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///blog.db'
|
|
23
|
+
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
|
24
|
+
app.instance_path = os.path.join("/tmp", "flask_instance")
|
|
25
|
+
os.makedirs(app.instance_path, exist_ok=True)
|
|
26
|
+
|
|
27
|
+
db.init_app(app)
|
|
28
|
+
|
|
29
|
+
# 前台首页
|
|
30
|
+
@app.route('/')
|
|
31
|
+
def index():
|
|
32
|
+
page = request.args.get('page', 1, type=int)
|
|
33
|
+
posts = Post.query.order_by(Post.created_at.desc()).paginate(
|
|
34
|
+
page=page, per_page=5, error_out=False)
|
|
35
|
+
return render_template('index.html', posts=posts)
|
|
36
|
+
|
|
37
|
+
# 文章详情页
|
|
38
|
+
@app.route('/post/<int:post_id>')
|
|
39
|
+
def post_detail(post_id):
|
|
40
|
+
post = Post.query.get_or_404(post_id)
|
|
41
|
+
return render_template('post.html', post=post)
|
|
42
|
+
|
|
43
|
+
# 后台登录页
|
|
44
|
+
@app.route('/admin/login', methods=['GET', 'POST'])
|
|
45
|
+
def admin_login():
|
|
46
|
+
if request.method == 'POST':
|
|
47
|
+
username = request.form['username']
|
|
48
|
+
password = request.form['password']
|
|
49
|
+
|
|
50
|
+
user = User.query.filter_by(username=username).first()
|
|
51
|
+
|
|
52
|
+
if user and check_password_hash(user.password, password):
|
|
53
|
+
session['admin_logged_in'] = True
|
|
54
|
+
return redirect(url_for('admin_dashboard'))
|
|
55
|
+
else:
|
|
56
|
+
flash('用户名或密码错误')
|
|
57
|
+
|
|
58
|
+
return render_template('admin/login.html')
|
|
59
|
+
|
|
60
|
+
# 后台登出
|
|
61
|
+
@app.route('/admin/logout')
|
|
62
|
+
def admin_logout():
|
|
63
|
+
session.pop('admin_logged_in', None)
|
|
64
|
+
return redirect(url_for('admin_login'))
|
|
65
|
+
|
|
66
|
+
# 后台管理面板
|
|
67
|
+
@app.route('/admin/dashboard')
|
|
68
|
+
def admin_dashboard():
|
|
69
|
+
if not session.get('admin_logged_in'):
|
|
70
|
+
return redirect(url_for('admin_login'))
|
|
71
|
+
|
|
72
|
+
post_count = Post.query.count()
|
|
73
|
+
return render_template('admin/dashboard.html', post_count=post_count)
|
|
74
|
+
|
|
75
|
+
# 文章管理
|
|
76
|
+
@app.route('/admin/posts')
|
|
77
|
+
def admin_posts():
|
|
78
|
+
if not session.get('admin_logged_in'):
|
|
79
|
+
return redirect(url_for('admin_login'))
|
|
80
|
+
|
|
81
|
+
page = request.args.get('page', 1, type=int)
|
|
82
|
+
posts = Post.query.order_by(Post.created_at.desc()).paginate(
|
|
83
|
+
page=page, per_page=10, error_out=False)
|
|
84
|
+
return render_template('admin/posts.html', posts=posts)
|
|
85
|
+
|
|
86
|
+
# 创建/编辑文章
|
|
87
|
+
@app.route('/admin/post', methods=['GET', 'POST'])
|
|
88
|
+
@app.route('/admin/post/<int:post_id>', methods=['GET', 'POST'])
|
|
89
|
+
def admin_edit_post(post_id=None):
|
|
90
|
+
if not session.get('admin_logged_in'):
|
|
91
|
+
return redirect(url_for('admin_login'))
|
|
92
|
+
|
|
93
|
+
if post_id:
|
|
94
|
+
post = Post.query.get_or_404(post_id)
|
|
95
|
+
else:
|
|
96
|
+
post = Post()
|
|
97
|
+
|
|
98
|
+
if request.method == 'POST':
|
|
99
|
+
post.title = request.form['title']
|
|
100
|
+
post.content = request.form['content']
|
|
101
|
+
|
|
102
|
+
if post_id is None:
|
|
103
|
+
db.session.add(post)
|
|
104
|
+
db.session.commit()
|
|
105
|
+
flash('文章保存成功')
|
|
106
|
+
return redirect(url_for('admin_posts'))
|
|
107
|
+
|
|
108
|
+
return render_template('admin/edit_post.html', post=post)
|
|
109
|
+
|
|
110
|
+
# 删除文章
|
|
111
|
+
@app.route('/admin/post/delete/<int:post_id>', methods=['POST'])
|
|
112
|
+
def admin_delete_post(post_id):
|
|
113
|
+
if not session.get('admin_logged_in'):
|
|
114
|
+
return redirect(url_for('admin_login'))
|
|
115
|
+
|
|
116
|
+
post = Post.query.get_or_404(post_id)
|
|
117
|
+
db.session.delete(post)
|
|
118
|
+
db.session.commit()
|
|
119
|
+
flash('文章删除成功')
|
|
120
|
+
return redirect(url_for('admin_posts'))
|
|
121
|
+
|
|
122
|
+
if __name__ == '__main__':
|
|
123
|
+
app.run(debug=True)
|
|
@@ -0,0 +1,46 @@
|
|
|
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 app import app, db
|
|
16
|
+
from models import User
|
|
17
|
+
from werkzeug.security import generate_password_hash
|
|
18
|
+
from sqlalchemy.exc import OperationalError
|
|
19
|
+
|
|
20
|
+
def init_database():
|
|
21
|
+
with app.app_context():
|
|
22
|
+
try:
|
|
23
|
+
# 创建所有数据库表
|
|
24
|
+
db.metadata.create_all(bind=db.engine, checkfirst=True)
|
|
25
|
+
print("数据库表创建成功")
|
|
26
|
+
except OperationalError as e:
|
|
27
|
+
if "table already exists" in str(e).lower():
|
|
28
|
+
print("数据库表已存在,跳过创建")
|
|
29
|
+
else:
|
|
30
|
+
print(f"创建数据库表时出错: {e}")
|
|
31
|
+
raise
|
|
32
|
+
|
|
33
|
+
# 创建默认管理员账户(如不存在)
|
|
34
|
+
if not User.query.filter_by(username='admin').first():
|
|
35
|
+
admin = User(
|
|
36
|
+
username='admin',
|
|
37
|
+
password=generate_password_hash('admin123')
|
|
38
|
+
)
|
|
39
|
+
db.session.add(admin)
|
|
40
|
+
db.session.commit()
|
|
41
|
+
print("默认管理员账户创建成功")
|
|
42
|
+
else:
|
|
43
|
+
print("默认管理员账户已存在,跳过创建")
|
|
44
|
+
|
|
45
|
+
if __name__ == '__main__':
|
|
46
|
+
init_database()
|