data-ops-cli 0.5.0__tar.gz → 0.5.1__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.
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/PKG-INFO +1 -1
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/data_ops_cli.egg-info/PKG-INFO +1 -1
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/data_ops_cli.egg-info/SOURCES.txt +1 -0
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/__init__.py +1 -1
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/factory.py +2 -1
- data_ops_cli-0.5.1/src/dataops_cli/cli/kb.py +248 -0
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/ontology.py +94 -0
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/skill.py +68 -24
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/README.md +0 -0
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/pyproject.toml +0 -0
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/setup.cfg +0 -0
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/data_ops_cli.egg-info/dependency_links.txt +0 -0
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/data_ops_cli.egg-info/entry_points.txt +0 -0
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/data_ops_cli.egg-info/requires.txt +0 -0
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/data_ops_cli.egg-info/top_level.txt +0 -0
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/_compat.py +0 -0
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/__init__.py +0 -0
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/alarm.py +0 -0
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/api.py +0 -0
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/auth.py +0 -0
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/data_table.py +0 -0
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/dataset.py +0 -0
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/datasource.py +0 -0
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/dict_.py +0 -0
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/hazard.py +0 -0
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/metrics.py +0 -0
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/ref.py +0 -0
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/report.py +0 -0
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/table.py +0 -0
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/tag.py +0 -0
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/utils.py +0 -0
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/widget.py +0 -0
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/workflow.py +0 -0
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/exceptions.py +0 -0
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/runner.py +0 -0
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/schems.py +0 -0
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/sdk.py +0 -0
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/session.py +0 -0
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/utils.py +0 -0
- {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/tests/test_table_relation.py +0 -0
|
@@ -53,6 +53,7 @@ def create_app():
|
|
|
53
53
|
from dataops_cli.cli.datasource import datasource_typer
|
|
54
54
|
from dataops_cli.cli.dict_ import dict_typer
|
|
55
55
|
from dataops_cli.cli.hazard import hazard_typer
|
|
56
|
+
from dataops_cli.cli.kb import kb_typer
|
|
56
57
|
from dataops_cli.cli.metrics import metrics_typer
|
|
57
58
|
from dataops_cli.cli.ontology import ontology_typer
|
|
58
59
|
from dataops_cli.cli.ref import ref_typer
|
|
@@ -84,7 +85,7 @@ def create_app():
|
|
|
84
85
|
app.add_typer(widget_typer)
|
|
85
86
|
app.add_typer(dict_typer)
|
|
86
87
|
app.add_typer(hazard_typer)
|
|
87
|
-
|
|
88
|
+
app.add_typer(kb_typer)
|
|
88
89
|
app.add_typer(tag_typer)
|
|
89
90
|
|
|
90
91
|
app.registered_callback = TyperInfo(callback=main)
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
"""Knowledge Base(知识库)管理命令组.
|
|
2
|
+
|
|
3
|
+
- 服务层函数 (service_*):纯 Python 接口,返回原始数据
|
|
4
|
+
- CLI 命令:基于服务层的薄包装,负责格式化输出
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Annotated
|
|
11
|
+
|
|
12
|
+
import typer
|
|
13
|
+
from dataops_cli.cli.utils import print_list
|
|
14
|
+
from dataops_sdk.exceptions import DataOpsError
|
|
15
|
+
from dataops_sdk.schemas.wiki import KbType
|
|
16
|
+
from dataops_sdk.services.wiki import (
|
|
17
|
+
service_get_knowledge_base,
|
|
18
|
+
service_list_knowledge_bases,
|
|
19
|
+
service_list_knowledge_documents,
|
|
20
|
+
service_search_knowledge,
|
|
21
|
+
service_search_wiki_pages,
|
|
22
|
+
service_upload_knowledge_file,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
kb_typer = typer.Typer(
|
|
26
|
+
name="kb",
|
|
27
|
+
help="知识库管理",
|
|
28
|
+
no_args_is_help=True,
|
|
29
|
+
)
|
|
30
|
+
doc_typer = typer.Typer(name="doc", help="知识库文档", no_args_is_help=True)
|
|
31
|
+
page_typer = typer.Typer(name="page", help="Wiki 页面", no_args_is_help=True)
|
|
32
|
+
kb_typer.add_typer(doc_typer)
|
|
33
|
+
kb_typer.add_typer(page_typer)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@kb_typer.command("list")
|
|
37
|
+
def kb_list_cmd(
|
|
38
|
+
kb_type: Annotated[
|
|
39
|
+
KbType | None,
|
|
40
|
+
typer.Option("--type", "-t", help="知识库类型:document / faq / wiki"),
|
|
41
|
+
] = None,
|
|
42
|
+
page: Annotated[int, typer.Option("--page", help="页码", min=1)] = 1,
|
|
43
|
+
page_size: Annotated[int, typer.Option("--page-size", help="每页条数", min=1)] = 20,
|
|
44
|
+
) -> None:
|
|
45
|
+
"""列出知识库。
|
|
46
|
+
|
|
47
|
+
Examples:
|
|
48
|
+
>>> data-ops-cli kb list
|
|
49
|
+
>>> data-ops-cli kb list --type wiki
|
|
50
|
+
"""
|
|
51
|
+
try:
|
|
52
|
+
result = service_list_knowledge_bases(page=page, page_size=page_size, kb_type=kb_type)
|
|
53
|
+
except DataOpsError as e:
|
|
54
|
+
typer.echo(f"错误: {e.message}")
|
|
55
|
+
raise typer.Exit(code=1) from None
|
|
56
|
+
|
|
57
|
+
if not result.items:
|
|
58
|
+
print("未查询到知识库")
|
|
59
|
+
return
|
|
60
|
+
|
|
61
|
+
print_list(
|
|
62
|
+
("id", "name", "type", "knowledge_count"),
|
|
63
|
+
[
|
|
64
|
+
[
|
|
65
|
+
it.id,
|
|
66
|
+
it.name,
|
|
67
|
+
it.type or "",
|
|
68
|
+
it.knowledge_count if it.knowledge_count is not None else "",
|
|
69
|
+
]
|
|
70
|
+
for it in result.items
|
|
71
|
+
],
|
|
72
|
+
)
|
|
73
|
+
print(f"total={result.total} page={result.page} page_size={result.page_size}")
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@kb_typer.command("detail", no_args_is_help=True)
|
|
77
|
+
def kb_detail_cmd(
|
|
78
|
+
kb_id: Annotated[str, typer.Argument(help="知识库 ID")],
|
|
79
|
+
) -> None:
|
|
80
|
+
"""查看知识库详情。
|
|
81
|
+
|
|
82
|
+
Examples:
|
|
83
|
+
>>> data-ops-cli kb detail <kb_id>
|
|
84
|
+
"""
|
|
85
|
+
try:
|
|
86
|
+
kb = service_get_knowledge_base(kb_id)
|
|
87
|
+
except DataOpsError as e:
|
|
88
|
+
typer.echo(f"错误: {e.message}")
|
|
89
|
+
raise typer.Exit(code=1) from None
|
|
90
|
+
|
|
91
|
+
print_list(
|
|
92
|
+
("field", "value"),
|
|
93
|
+
[
|
|
94
|
+
["id", kb.id],
|
|
95
|
+
["name", kb.name],
|
|
96
|
+
["type", kb.type or ""],
|
|
97
|
+
["description", kb.description or ""],
|
|
98
|
+
["knowledge_count", kb.knowledge_count if kb.knowledge_count is not None else ""],
|
|
99
|
+
["chunk_count", kb.chunk_count if kb.chunk_count is not None else ""],
|
|
100
|
+
],
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@doc_typer.command("list", no_args_is_help=True)
|
|
105
|
+
def doc_list_cmd(
|
|
106
|
+
kb_id: Annotated[str, typer.Argument(help="知识库 ID")],
|
|
107
|
+
keyword: Annotated[
|
|
108
|
+
str | None,
|
|
109
|
+
typer.Option("--keyword", "-k", help="关键词"),
|
|
110
|
+
] = None,
|
|
111
|
+
page: Annotated[int, typer.Option("--page", help="页码", min=1)] = 1,
|
|
112
|
+
page_size: Annotated[int, typer.Option("--page-size", help="每页条数", min=1)] = 20,
|
|
113
|
+
) -> None:
|
|
114
|
+
"""列出知识库文档。
|
|
115
|
+
|
|
116
|
+
Examples:
|
|
117
|
+
>>> data-ops-cli kb doc list <kb_id>
|
|
118
|
+
>>> data-ops-cli kb doc list <kb_id> --keyword "故障处理"
|
|
119
|
+
"""
|
|
120
|
+
try:
|
|
121
|
+
result = service_list_knowledge_documents(
|
|
122
|
+
kb_id, page=page, page_size=page_size, keyword=keyword
|
|
123
|
+
)
|
|
124
|
+
except DataOpsError as e:
|
|
125
|
+
typer.echo(f"错误: {e.message}")
|
|
126
|
+
raise typer.Exit(code=1) from None
|
|
127
|
+
|
|
128
|
+
if not result.items:
|
|
129
|
+
print("未查询到文档")
|
|
130
|
+
return
|
|
131
|
+
|
|
132
|
+
print_list(
|
|
133
|
+
("id", "title", "file_name", "parse_status"),
|
|
134
|
+
[
|
|
135
|
+
[
|
|
136
|
+
it.id,
|
|
137
|
+
it.title or "",
|
|
138
|
+
it.file_name or "",
|
|
139
|
+
it.parse_status or "",
|
|
140
|
+
]
|
|
141
|
+
for it in result.items
|
|
142
|
+
],
|
|
143
|
+
)
|
|
144
|
+
print(f"total={result.total} page={result.page} page_size={result.page_size}")
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
@doc_typer.command("upload", no_args_is_help=True)
|
|
148
|
+
def doc_upload_cmd(
|
|
149
|
+
kb_id: Annotated[str, typer.Argument(help="知识目录 CUID")],
|
|
150
|
+
file: Annotated[Path, typer.Argument(help="本地文件路径", exists=True, readable=True)],
|
|
151
|
+
name: Annotated[
|
|
152
|
+
str | None,
|
|
153
|
+
typer.Option("--name", help="覆盖上传文件名"),
|
|
154
|
+
] = None,
|
|
155
|
+
security_level: Annotated[
|
|
156
|
+
str,
|
|
157
|
+
typer.Option(
|
|
158
|
+
"--security-level",
|
|
159
|
+
help="文档密级:PUBLIC / INTERNAL / CONFIDENTIAL / SECRET",
|
|
160
|
+
),
|
|
161
|
+
] = "INTERNAL",
|
|
162
|
+
) -> None:
|
|
163
|
+
"""上传文件到知识库。
|
|
164
|
+
|
|
165
|
+
Examples:
|
|
166
|
+
>>> data-ops-cli kb doc upload <kb_id> ./manual.pdf
|
|
167
|
+
"""
|
|
168
|
+
try:
|
|
169
|
+
doc = service_upload_knowledge_file(
|
|
170
|
+
kb_id, file, file_name=name, security_level=security_level
|
|
171
|
+
)
|
|
172
|
+
except (DataOpsError, FileNotFoundError) as e:
|
|
173
|
+
msg = getattr(e, "message", None) or str(e)
|
|
174
|
+
typer.echo(f"错误: {msg}")
|
|
175
|
+
raise typer.Exit(code=1) from None
|
|
176
|
+
|
|
177
|
+
print(f"上传成功: id={doc.id} title={doc.title or ''} file_name={doc.file_name or ''}")
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
@kb_typer.command("search", no_args_is_help=True)
|
|
181
|
+
def search_cmd(
|
|
182
|
+
keyword: Annotated[str, typer.Argument(help="检索关键词")],
|
|
183
|
+
limit: Annotated[int, typer.Option("--limit", help="返回条数", min=1)] = 20,
|
|
184
|
+
offset: Annotated[int, typer.Option("--offset", help="偏移量", min=0)] = 0,
|
|
185
|
+
) -> None:
|
|
186
|
+
"""全局关键词检索知识内容。
|
|
187
|
+
|
|
188
|
+
Examples:
|
|
189
|
+
>>> data-ops-cli kb search "网络割接"
|
|
190
|
+
"""
|
|
191
|
+
try:
|
|
192
|
+
result = service_search_knowledge(keyword, limit=limit, offset=offset)
|
|
193
|
+
except DataOpsError as e:
|
|
194
|
+
typer.echo(f"错误: {e.message}")
|
|
195
|
+
raise typer.Exit(code=1) from None
|
|
196
|
+
|
|
197
|
+
if not result.items:
|
|
198
|
+
print("未检索到内容")
|
|
199
|
+
return
|
|
200
|
+
|
|
201
|
+
print_list(
|
|
202
|
+
("title", "kb_name", "score", "content"),
|
|
203
|
+
[
|
|
204
|
+
[
|
|
205
|
+
it.title or it.knowledge_title or "",
|
|
206
|
+
it.kb_name or "",
|
|
207
|
+
f"{it.score:.4f}" if it.score is not None else "",
|
|
208
|
+
(it.content or "")[:80],
|
|
209
|
+
]
|
|
210
|
+
for it in result.items
|
|
211
|
+
],
|
|
212
|
+
)
|
|
213
|
+
print(f"total={result.total}")
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
@page_typer.command("search", no_args_is_help=True)
|
|
217
|
+
def page_search_cmd(
|
|
218
|
+
kb_id: Annotated[str, typer.Argument(help="Wiki 资源 CUID(非目录 CUID)")],
|
|
219
|
+
query: Annotated[str, typer.Argument(help="检索词")],
|
|
220
|
+
limit: Annotated[int, typer.Option("--limit", help="返回条数", min=1)] = 20,
|
|
221
|
+
) -> None:
|
|
222
|
+
"""检索知识库 Wiki 页面。
|
|
223
|
+
|
|
224
|
+
Examples:
|
|
225
|
+
>>> data-ops-cli kb page search <kb_id> "运维手册"
|
|
226
|
+
"""
|
|
227
|
+
try:
|
|
228
|
+
pages = service_search_wiki_pages(kb_id, query, limit=limit)
|
|
229
|
+
except DataOpsError as e:
|
|
230
|
+
typer.echo(f"错误: {e.message}")
|
|
231
|
+
raise typer.Exit(code=1) from None
|
|
232
|
+
|
|
233
|
+
if not pages:
|
|
234
|
+
print("未检索到 Wiki 页面")
|
|
235
|
+
return
|
|
236
|
+
|
|
237
|
+
print_list(
|
|
238
|
+
("slug", "title", "page_type", "summary"),
|
|
239
|
+
[
|
|
240
|
+
[
|
|
241
|
+
it.slug,
|
|
242
|
+
it.title or "",
|
|
243
|
+
it.page_type or "",
|
|
244
|
+
(it.summary or "")[:60],
|
|
245
|
+
]
|
|
246
|
+
for it in pages
|
|
247
|
+
],
|
|
248
|
+
)
|
|
@@ -11,22 +11,30 @@ from typing import Annotated, Any
|
|
|
11
11
|
|
|
12
12
|
import typer
|
|
13
13
|
from dataops_sdk.exceptions import DataOpsError
|
|
14
|
+
from dataops_sdk.schemas.ontology import BUILTIN_SKILL_KINDS, OntologyBuiltinSkillKind
|
|
14
15
|
from dataops_sdk.services.ontology import (
|
|
16
|
+
get_scenario_skill_code,
|
|
15
17
|
service_get_ontology_by_code,
|
|
16
18
|
service_get_ontology_by_name,
|
|
17
19
|
service_list_ontologies,
|
|
20
|
+
service_list_ontology_apis,
|
|
21
|
+
service_list_ontology_metrics,
|
|
22
|
+
service_reset_ontology_builtin_skill,
|
|
18
23
|
service_tree_ontology,
|
|
19
24
|
service_update_ontology_basic,
|
|
20
25
|
service_update_ontology_constraints,
|
|
21
26
|
service_update_ontology_notes,
|
|
22
27
|
service_update_ontology_relations,
|
|
28
|
+
service_update_ontology_scenarios,
|
|
23
29
|
)
|
|
24
30
|
|
|
25
31
|
from dataops_cli.cli.utils import print_group_tree, print_list
|
|
26
32
|
|
|
27
33
|
ontology_typer = typer.Typer(name="ontology", help="本体管理", no_args_is_help=True)
|
|
28
34
|
update_typer = typer.Typer(name="update", help="更新本体配置", no_args_is_help=True)
|
|
35
|
+
builtin_skill_typer = typer.Typer(name="builtin-skill", help="本体内置技能", no_args_is_help=True)
|
|
29
36
|
ontology_typer.add_typer(update_typer)
|
|
37
|
+
ontology_typer.add_typer(builtin_skill_typer)
|
|
30
38
|
|
|
31
39
|
|
|
32
40
|
def _read_json_payload(
|
|
@@ -133,9 +141,18 @@ def detail_ontology(
|
|
|
133
141
|
|
|
134
142
|
data = meta.data
|
|
135
143
|
print(f"本体: {meta.name} ({meta.title})")
|
|
144
|
+
print(f"编码: {meta.code}")
|
|
136
145
|
print(f"备注: {meta.remark or '-'}")
|
|
137
146
|
print(f"多维表格: {data.data_table or '-'}")
|
|
147
|
+
if data.skills:
|
|
148
|
+
print("内置技能 name 映射:")
|
|
149
|
+
for kind in BUILTIN_SKILL_KINDS:
|
|
150
|
+
if kind in data.skills:
|
|
151
|
+
print(f" {kind}: {data.skills[kind]}")
|
|
138
152
|
print(f"场景数: {len(data.scenarios)}")
|
|
153
|
+
for scenario in data.scenarios:
|
|
154
|
+
skill_code = get_scenario_skill_code(scenario)
|
|
155
|
+
print(f" - {scenario.id}: {scenario.name or '-'} → skill {skill_code or '-'}")
|
|
139
156
|
print(f"约束数: {len(data.constraints)}")
|
|
140
157
|
print(f"关系数: {len(data.relations)}")
|
|
141
158
|
if data.notes:
|
|
@@ -289,3 +306,80 @@ def update_relations(
|
|
|
289
306
|
raise typer.Exit(code=1) from None
|
|
290
307
|
assert result.data is not None
|
|
291
308
|
typer.echo(f"本体 {result.name} 关联关系已更新(共 {len(result.data.relations)} 条)")
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
@update_typer.command("scenarios", no_args_is_help=True)
|
|
312
|
+
def update_scenarios(
|
|
313
|
+
name: Annotated[str, typer.Argument(help="本体编码或业务名")],
|
|
314
|
+
file: Annotated[
|
|
315
|
+
Path | None,
|
|
316
|
+
typer.Option("--file", "-f", help="场景 JSON 文件路径(数组)"),
|
|
317
|
+
] = None,
|
|
318
|
+
content: Annotated[
|
|
319
|
+
str | None,
|
|
320
|
+
typer.Option("--content", "-c", help="场景 JSON 内容(数组)"),
|
|
321
|
+
] = None,
|
|
322
|
+
) -> None:
|
|
323
|
+
"""全量替换本体场景列表(内置场景 id 不可删除)。"""
|
|
324
|
+
payload = _read_json_payload(file, content)
|
|
325
|
+
if not isinstance(payload, list):
|
|
326
|
+
typer.echo("错误: 场景内容必须是 JSON 数组", err=True)
|
|
327
|
+
raise typer.Exit(code=1)
|
|
328
|
+
try:
|
|
329
|
+
result = service_update_ontology_scenarios(name, payload)
|
|
330
|
+
except DataOpsError as e:
|
|
331
|
+
typer.echo(f"错误: {e.message}", err=True)
|
|
332
|
+
raise typer.Exit(code=1) from None
|
|
333
|
+
assert result.data is not None
|
|
334
|
+
typer.echo(f"本体 {result.name} 场景已更新(共 {len(result.data.scenarios)} 条)")
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
@ontology_typer.command("metrics", no_args_is_help=True)
|
|
338
|
+
def list_metrics(
|
|
339
|
+
code: Annotated[str, typer.Argument(help="本体编码")],
|
|
340
|
+
) -> None:
|
|
341
|
+
"""查询本体关联的指标列表。"""
|
|
342
|
+
try:
|
|
343
|
+
items = service_list_ontology_metrics(code)
|
|
344
|
+
except DataOpsError as e:
|
|
345
|
+
typer.echo(f"错误: {e.message}", err=True)
|
|
346
|
+
raise typer.Exit(code=1) from None
|
|
347
|
+
print(json.dumps(items, ensure_ascii=False, indent=2))
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
@ontology_typer.command("apis", no_args_is_help=True)
|
|
351
|
+
def list_apis(
|
|
352
|
+
code: Annotated[str, typer.Argument(help="本体编码")],
|
|
353
|
+
) -> None:
|
|
354
|
+
"""查询本体关联的接口列表。"""
|
|
355
|
+
try:
|
|
356
|
+
items = service_list_ontology_apis(code)
|
|
357
|
+
except DataOpsError as e:
|
|
358
|
+
typer.echo(f"错误: {e.message}", err=True)
|
|
359
|
+
raise typer.Exit(code=1) from None
|
|
360
|
+
print(json.dumps(items, ensure_ascii=False, indent=2))
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
@builtin_skill_typer.command("reset", no_args_is_help=True)
|
|
364
|
+
def reset_builtin_skill(
|
|
365
|
+
name_or_code: Annotated[str, typer.Argument(help="本体编码或业务名")],
|
|
366
|
+
kind: Annotated[
|
|
367
|
+
OntologyBuiltinSkillKind,
|
|
368
|
+
typer.Argument(help="内置技能类型: query/create/delete/update"),
|
|
369
|
+
],
|
|
370
|
+
) -> None:
|
|
371
|
+
"""重置本体内置技能并回填场景绑定。"""
|
|
372
|
+
try:
|
|
373
|
+
meta = service_get_ontology_by_name(name_or_code)
|
|
374
|
+
except DataOpsError:
|
|
375
|
+
try:
|
|
376
|
+
meta = service_get_ontology_by_code(name_or_code)
|
|
377
|
+
except DataOpsError as e:
|
|
378
|
+
typer.echo(f"错误: {e.message}", err=True)
|
|
379
|
+
raise typer.Exit(code=1) from None
|
|
380
|
+
try:
|
|
381
|
+
result = service_reset_ontology_builtin_skill(meta.code, kind)
|
|
382
|
+
except DataOpsError as e:
|
|
383
|
+
typer.echo(f"错误: {e.message}", err=True)
|
|
384
|
+
raise typer.Exit(code=1) from None
|
|
385
|
+
print(json.dumps(result, ensure_ascii=False, indent=2))
|
|
@@ -11,10 +11,8 @@ from pathlib import Path
|
|
|
11
11
|
from typing import Annotated
|
|
12
12
|
|
|
13
13
|
import typer
|
|
14
|
-
from dataops_cli.cli.utils import paginate_with_line_numbers, print_list
|
|
15
14
|
from dataops_sdk.exceptions import DataOpsError
|
|
16
15
|
from dataops_sdk.schemas import MetaSkillFileSubType, MetaSkillSubType, MetaType
|
|
17
|
-
from dataops_sdk.schemas.enums import GroupNodeRefType
|
|
18
16
|
from dataops_sdk.services import (
|
|
19
17
|
SkillPackValidationError,
|
|
20
18
|
service_delete_skill,
|
|
@@ -25,6 +23,9 @@ from dataops_sdk.services import (
|
|
|
25
23
|
service_skill_call_by_name,
|
|
26
24
|
service_skill_delete_sub_file,
|
|
27
25
|
service_skill_download,
|
|
26
|
+
service_skill_list_ontologies_by_codes,
|
|
27
|
+
service_skill_list_ontology_options,
|
|
28
|
+
service_skill_list_skill_codes_by_ontology,
|
|
28
29
|
service_skill_update,
|
|
29
30
|
service_skill_upload,
|
|
30
31
|
service_skill_upload_sub_file,
|
|
@@ -33,6 +34,8 @@ from dataops_sdk.tiptap import TableStyle, TipTapTool
|
|
|
33
34
|
from pydantic_core import from_json
|
|
34
35
|
from rich.console import Console
|
|
35
36
|
|
|
37
|
+
from dataops_cli.cli.utils import paginate_with_line_numbers, print_list
|
|
38
|
+
|
|
36
39
|
# ---------------------------------------------------------------------------
|
|
37
40
|
# CLI 命令
|
|
38
41
|
# ---------------------------------------------------------------------------
|
|
@@ -47,10 +50,70 @@ skill_file_typer = typer.Typer(
|
|
|
47
50
|
help="技能文件管理",
|
|
48
51
|
no_args_is_help=True,
|
|
49
52
|
)
|
|
53
|
+
skill_ontology_typer = typer.Typer(
|
|
54
|
+
name="ontology",
|
|
55
|
+
help="技能与本体归属",
|
|
56
|
+
no_args_is_help=True,
|
|
57
|
+
)
|
|
50
58
|
skill_typer.add_typer(skill_file_typer)
|
|
59
|
+
skill_typer.add_typer(skill_ontology_typer)
|
|
51
60
|
MAKRDOWN_TABLE_STYLE = TableStyle.MARKDOWN
|
|
52
61
|
|
|
53
62
|
|
|
63
|
+
@skill_ontology_typer.command("options")
|
|
64
|
+
def ontology_options_cmd() -> None:
|
|
65
|
+
"""列出已绑定技能的本体(用于技能中心筛选)。"""
|
|
66
|
+
try:
|
|
67
|
+
items = service_skill_list_ontology_options()
|
|
68
|
+
except DataOpsError as e:
|
|
69
|
+
typer.echo(f"错误: {e.message}")
|
|
70
|
+
raise typer.Exit(code=1) from None
|
|
71
|
+
if not items:
|
|
72
|
+
print("未查询到本体选项")
|
|
73
|
+
return
|
|
74
|
+
print_list(
|
|
75
|
+
("code", "title"),
|
|
76
|
+
[[it.code, it.title] for it in items],
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@skill_ontology_typer.command("by-codes", no_args_is_help=True)
|
|
81
|
+
def ontology_by_codes_cmd(
|
|
82
|
+
codes: Annotated[
|
|
83
|
+
str,
|
|
84
|
+
typer.Option("--codes", "-c", help="技能 code 列表,逗号分隔"),
|
|
85
|
+
],
|
|
86
|
+
) -> None:
|
|
87
|
+
"""批量查询技能归属的本体。"""
|
|
88
|
+
code_list = [c.strip() for c in codes.split(",") if c.strip()]
|
|
89
|
+
if not code_list:
|
|
90
|
+
typer.echo("错误: --codes 不能为空")
|
|
91
|
+
raise typer.Exit(code=1)
|
|
92
|
+
try:
|
|
93
|
+
mapping = service_skill_list_ontologies_by_codes(code_list)
|
|
94
|
+
except DataOpsError as e:
|
|
95
|
+
typer.echo(f"错误: {e.message}")
|
|
96
|
+
raise typer.Exit(code=1) from None
|
|
97
|
+
payload = {key: [vo.model_dump() for vo in val] for key, val in mapping.items()}
|
|
98
|
+
print(json.dumps(payload, ensure_ascii=False, indent=2))
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@skill_ontology_typer.command("skill-codes", no_args_is_help=True)
|
|
102
|
+
def ontology_skill_codes_cmd(
|
|
103
|
+
ontology_code: Annotated[
|
|
104
|
+
str,
|
|
105
|
+
typer.Option("--ontology-code", help="本体编码"),
|
|
106
|
+
],
|
|
107
|
+
) -> None:
|
|
108
|
+
"""按本体查询绑定的技能 code 列表。"""
|
|
109
|
+
try:
|
|
110
|
+
codes = service_skill_list_skill_codes_by_ontology(ontology_code)
|
|
111
|
+
except DataOpsError as e:
|
|
112
|
+
typer.echo(f"错误: {e.message}")
|
|
113
|
+
raise typer.Exit(code=1) from None
|
|
114
|
+
print(json.dumps(codes, ensure_ascii=False, indent=2))
|
|
115
|
+
|
|
116
|
+
|
|
54
117
|
@skill_typer.command("list")
|
|
55
118
|
def list_cmd(
|
|
56
119
|
sub_types: Annotated[
|
|
@@ -125,46 +188,27 @@ def detail_cmd(
|
|
|
125
188
|
|
|
126
189
|
@skill_typer.command("upload", no_args_is_help=True)
|
|
127
190
|
def upload_cmd(
|
|
128
|
-
space_code: Annotated[str, typer.Argument(help="空间编码 (通过 ``report space list`` 查看)")],
|
|
129
191
|
file: Annotated[Path, typer.Argument(help="技能 ZIP 文件路径")],
|
|
130
192
|
dtype: Annotated[
|
|
131
193
|
MetaSkillSubType,
|
|
132
194
|
typer.Option("--type", help="技能子类型"),
|
|
133
195
|
],
|
|
134
|
-
ref_node_id: Annotated[
|
|
135
|
-
str | None,
|
|
136
|
-
typer.Option(
|
|
137
|
-
"--ref-node-id",
|
|
138
|
-
help="文档中心分组节点 ID(可选;通过 ``report tree`` 查看,需挂到树上时填写)",
|
|
139
|
-
),
|
|
140
|
-
] = None,
|
|
141
|
-
ref_type: Annotated[
|
|
142
|
-
GroupNodeRefType,
|
|
143
|
-
typer.Option("--ref-type", help="引用节点类型 (放置在引用节点前、后还是内)"),
|
|
144
|
-
] = GroupNodeRefType.AFTER,
|
|
145
196
|
title: Annotated[str | None, typer.Option("--title", help="技能简体中文名称")] = None,
|
|
146
197
|
) -> None:
|
|
147
|
-
"""从 ZIP
|
|
198
|
+
"""从 ZIP 包导入技能到技能中心。
|
|
148
199
|
|
|
149
200
|
Examples:
|
|
150
|
-
|
|
151
|
-
>>> data-ops-cli skill upload default my-skill.zip --type llm
|
|
152
|
-
|
|
153
|
-
挂到文档中心某分组节点内
|
|
154
|
-
>>> data-ops-cli skill upload default my-skill.zip --type api --ref-node-id {node-id} --ref-type inner
|
|
201
|
+
>>> data-ops-cli skill upload my-skill.zip --type llm
|
|
155
202
|
"""
|
|
156
203
|
if not file.exists():
|
|
157
204
|
typer.echo(f"错误: 文件不存在 {file}")
|
|
158
205
|
raise typer.Exit(code=2)
|
|
159
206
|
|
|
160
207
|
try:
|
|
161
|
-
|
|
208
|
+
service_skill_upload(
|
|
162
209
|
file_path=str(file),
|
|
163
210
|
sub_type=dtype,
|
|
164
211
|
title=title,
|
|
165
|
-
group_name=space_code,
|
|
166
|
-
ref_node_id=ref_node_id,
|
|
167
|
-
ref_type=ref_type,
|
|
168
212
|
)
|
|
169
213
|
except DataOpsError as e:
|
|
170
214
|
typer.echo(f"错误: {e.message}")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|