test news page
This commit is contained in:
parent
bc38ea49bb
commit
793262f8b1
@ -1,14 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="diagram-item-record" v-if="props.dataView && props.dataView.tool">
|
<div class="diagram-item-record" v-if="props.dataView && props.dataView.tool">
|
||||||
<div class="item-status" :class="props.dataView.status">{{ props.dataView.status }}</div>
|
|
||||||
|
|
||||||
<div class="item-header">
|
<div class="item-header">
|
||||||
<span class="item-title">{{ props.dataView.tool.name }}</span>
|
<span class="item-title">{{ props.dataView.tool.name }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="item-desc">{{ props.dataView.tool.description }}</div>
|
<div class="item-desc">{{ props.dataView.tool.description }}</div>
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<div v-if="props.dataView.function !== undefined" class="item-result">
|
<div v-if="props.dataView.function !== undefined" class="item-result">
|
||||||
<span class="item-label">Arguments</span>
|
<span class="item-label">Arguments</span>
|
||||||
@ -17,8 +14,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<div v-if="props.dataView.result !== undefined" class="item-result">
|
<div v-if="props.dataView.result !== undefined" class="item-result">
|
||||||
<span class="item-label">Result</span>
|
<span class="item-label">Result</span>
|
||||||
<template v-if="Array.isArray(props.dataView.result)">
|
<template v-if="Array.isArray(props.dataView.result)">
|
||||||
@ -33,6 +28,49 @@
|
|||||||
v-else-if="typeof props.dataView.result === 'string'">{{ props.dataView.result }}</pre>
|
v-else-if="typeof props.dataView.result === 'string'">{{ props.dataView.result }}</pre>
|
||||||
<pre class="item-json" v-else>{{ formatJson(props.dataView.result) }}</pre>
|
<pre class="item-json" v-else>{{ formatJson(props.dataView.result) }}</pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<div class="item-meta">
|
||||||
|
<span v-if="props.dataView.createAt" class="item-meta-label">
|
||||||
|
Created: <b>{{ formatTime(props.dataView.createAt) }}</b>
|
||||||
|
</span>
|
||||||
|
<!-- <span v-if="props.dataView.finishAt" class="item-meta-label">
|
||||||
|
Finished: <b>{{ formatTime(props.dataView.finishAt) }}</b>
|
||||||
|
</span> -->
|
||||||
|
<!-- -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="item-timecost" v-if="props.dataView.llmTimecost !== undefined || props.dataView.toolcallTimecost !== undefined">
|
||||||
|
<template v-if="props.dataView.llmTimecost !== undefined && props.dataView.toolcallTimecost !== undefined">
|
||||||
|
<div class="timecost-bar">
|
||||||
|
<div
|
||||||
|
class="timecost-segment llm"
|
||||||
|
:style="{ width: llmPercent + '%' }"
|
||||||
|
:title="`LLM: ${props.dataView.llmTimecost}ms`"
|
||||||
|
></div>
|
||||||
|
<div
|
||||||
|
class="timecost-segment toolcall"
|
||||||
|
:style="{ width: toolcallPercent + '%' }"
|
||||||
|
:title="`ToolCall: ${props.dataView.toolcallTimecost}ms`"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
<div class="timecost-labels">
|
||||||
|
<span class="llm-label">LLM: <b>{{ props.dataView.llmTimecost }}ms</b> ({{ llmPercent }}%)</span>
|
||||||
|
<span class="toolcall-label">ToolCall: <b>{{ props.dataView.toolcallTimecost }}ms</b> ({{ toolcallPercent }}%)</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="props.dataView.llmTimecost !== undefined">
|
||||||
|
<div class="timecost-labels">
|
||||||
|
<span class="llm-label">LLM: <b>{{ props.dataView.llmTimecost }}ms</b></span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<div class="timecost-labels">
|
||||||
|
<span class="toolcall-label">ToolCall: <b>{{ props.dataView.toolcallTimecost }}ms</b></span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="diagram-item-record">
|
<div v-else class="diagram-item-record">
|
||||||
<div class="item-header">
|
<div class="item-header">
|
||||||
@ -47,6 +85,7 @@ import type { PropType } from 'vue';
|
|||||||
import type { NodeDataView } from './diagram';
|
import type { NodeDataView } from './diagram';
|
||||||
|
|
||||||
import JsonRender from '@/components/json-render/index.vue';
|
import JsonRender from '@/components/json-render/index.vue';
|
||||||
|
import { computed } from 'vue';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
dataView: {
|
dataView: {
|
||||||
@ -62,6 +101,27 @@ function formatJson(obj: any) {
|
|||||||
return String(obj)
|
return String(obj)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 优雅格式化时间
|
||||||
|
function formatTime(val: string | number | Date) {
|
||||||
|
if (!val) return '-';
|
||||||
|
const d = new Date(val);
|
||||||
|
if (isNaN(d.getTime())) return '-';
|
||||||
|
return d.toLocaleString();
|
||||||
|
}
|
||||||
|
|
||||||
|
const llmPercent = computed(() => {
|
||||||
|
const l = props.dataView!.llmTimecost ?? 0;
|
||||||
|
const t = props.dataView!.toolcallTimecost ?? 0;
|
||||||
|
const sum = l + t;
|
||||||
|
return sum > 0 ? Math.round((l / sum) * 100) : 0;
|
||||||
|
});
|
||||||
|
const toolcallPercent = computed(() => {
|
||||||
|
const l = props.dataView!.llmTimecost ?? 0;
|
||||||
|
const t = props.dataView!.toolcallTimecost ?? 0;
|
||||||
|
const sum = l + t;
|
||||||
|
return sum > 0 ? Math.round((t / sum) * 100) : 0;
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@ -94,32 +154,25 @@ function formatJson(obj: any) {
|
|||||||
text-transform: capitalize;
|
text-transform: capitalize;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-status.running {
|
|
||||||
color: #2196f3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-status.success {
|
|
||||||
color: #43a047;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-status.error {
|
|
||||||
color: #e53935;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-status.waiting {
|
|
||||||
color: #aaa;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-status.default {
|
|
||||||
color: #888;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-desc {
|
.item-desc {
|
||||||
margin-bottom: 8px;
|
margin-bottom: 15px;
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.item-meta {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #888;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.item-meta-label b {
|
||||||
|
color: var(--main-color, #409EFF);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
.item-label {
|
.item-label {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
margin-right: 4px;
|
margin-right: 4px;
|
||||||
@ -148,6 +201,7 @@ function formatJson(obj: any) {
|
|||||||
|
|
||||||
.item-result {
|
.item-result {
|
||||||
margin-top: 6px;
|
margin-top: 6px;
|
||||||
|
margin-bottom: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.result-block {
|
.result-block {
|
||||||
@ -158,7 +212,6 @@ function formatJson(obj: any) {
|
|||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.result-block.error {
|
.result-block.error {
|
||||||
background-color: rgba(245, 108, 108, 0.5);
|
background-color: rgba(245, 108, 108, 0.5);
|
||||||
}
|
}
|
||||||
@ -166,4 +219,49 @@ function formatJson(obj: any) {
|
|||||||
.result-block.success {
|
.result-block.success {
|
||||||
background-color: rgba(67, 160, 71, 0.5);
|
background-color: rgba(67, 160, 71, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.item-timecost {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
margin-top: 2px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timecost-bar {
|
||||||
|
display: flex;
|
||||||
|
height: 12px;
|
||||||
|
border-radius: 6px;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #f0eaff;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
box-shadow: 0 1px 2px rgba(185,136,209,0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.timecost-segment {
|
||||||
|
height: 100%;
|
||||||
|
transition: width 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.llm {
|
||||||
|
background: #B988D1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolcall {
|
||||||
|
background: #A1A7F6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timecost-labels {
|
||||||
|
display: flex;
|
||||||
|
gap: 18px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
.llm-label b {
|
||||||
|
color: #B988D1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolcall-label b {
|
||||||
|
color: #A1A7F6;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
@ -41,6 +41,10 @@ export interface NodeDataView {
|
|||||||
tool: ToolItem;
|
tool: ToolItem;
|
||||||
status: 'default' | 'running' | 'waiting' | 'success' | 'error';
|
status: 'default' | 'running' | 'waiting' | 'success' | 'error';
|
||||||
function?: ChatCompletionChunk.Choice.Delta.ToolCall.Function;
|
function?: ChatCompletionChunk.Choice.Delta.ToolCall.Function;
|
||||||
|
createAt?: number;
|
||||||
|
llmTimecost?: number;
|
||||||
|
toolcallTimecost?: number;
|
||||||
|
finishAt?: number;
|
||||||
result?: any;
|
result?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,6 +172,8 @@ export async function makeNodeTest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
dataView.status = 'running';
|
dataView.status = 'running';
|
||||||
|
const createAt = Date.now();
|
||||||
|
dataView.createAt = createAt;
|
||||||
context.render();
|
context.render();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -197,20 +203,19 @@ export async function makeNodeTest(
|
|||||||
|
|
||||||
loop.registerOnToolCall(toolCall => {
|
loop.registerOnToolCall(toolCall => {
|
||||||
dataView.function = toolCall.function;
|
dataView.function = toolCall.function;
|
||||||
|
dataView.llmTimecost = Date.now() - createAt;
|
||||||
|
|
||||||
if (toolCall.function?.name === dataView.tool?.name) {
|
if (toolCall.function?.name === dataView.tool?.name) {
|
||||||
try {
|
try {
|
||||||
const toolArgs = JSON.parse(toolCall.function?.arguments || '{}');
|
const toolArgs = JSON.parse(toolCall.function?.arguments || '{}');
|
||||||
aiMockJson = toolArgs;
|
aiMockJson = toolArgs;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// ElMessage.error('AI 生成的 JSON 解析错误');
|
|
||||||
dataView.status = 'error';
|
dataView.status = 'error';
|
||||||
dataView.result = t('ai-gen-error-json');
|
dataView.result = t('ai-gen-error-json');
|
||||||
context.render();
|
context.render();
|
||||||
loop.abort();
|
loop.abort();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// ElMessage.error('AI 调用了未知的工具');
|
|
||||||
dataView.status = 'error';
|
dataView.status = 'error';
|
||||||
dataView.result = t('ai-invoke-unknown-tool') + ' ' + toolCall.function?.name;
|
dataView.result = t('ai-invoke-unknown-tool') + ' ' + toolCall.function?.name;
|
||||||
context.render();
|
context.render();
|
||||||
@ -220,6 +225,8 @@ export async function makeNodeTest(
|
|||||||
});
|
});
|
||||||
|
|
||||||
loop.registerOnToolCalled(toolCalled => {
|
loop.registerOnToolCalled(toolCalled => {
|
||||||
|
dataView.toolcallTimecost = Date.now() - createAt - dataView.llmTimecost!;
|
||||||
|
|
||||||
if (toolCalled.state === MessageState.Success) {
|
if (toolCalled.state === MessageState.Success) {
|
||||||
dataView.status = 'success';
|
dataView.status = 'success';
|
||||||
dataView.result = toolCalled.content;
|
dataView.result = toolCalled.content;
|
||||||
@ -240,6 +247,8 @@ export async function makeNodeTest(
|
|||||||
await loop.start(chatStorage, usePrompt);
|
await loop.start(chatStorage, usePrompt);
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
|
dataView.finishAt = Date.now();
|
||||||
|
|
||||||
if (dataView.status === 'running') {
|
if (dataView.status === 'running') {
|
||||||
dataView.status = 'success';
|
dataView.status = 'success';
|
||||||
context.render();
|
context.render();
|
||||||
|
@ -2,7 +2,13 @@
|
|||||||
<div style="display: flex; align-items: flex-start; gap: 32px;">
|
<div style="display: flex; align-items: flex-start; gap: 32px;">
|
||||||
<div ref="svgContainer" class="diagram-container"></div>
|
<div ref="svgContainer" class="diagram-container"></div>
|
||||||
<div class="diagram-info-panel">
|
<div class="diagram-info-panel">
|
||||||
<div style="display: flex; justify-content: flex-end; align-items: center;">
|
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||||
|
<div v-if="infoNodeId && state.dataView.get(infoNodeId)" class="item-status" :class="state.dataView.get(infoNodeId)?.status || 'waiting'">
|
||||||
|
{{ state.dataView.get(infoNodeId)?.status || 'waiting' }}
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
{{ "Unknown Status" }}
|
||||||
|
</div>
|
||||||
<el-button
|
<el-button
|
||||||
circle
|
circle
|
||||||
size="small"
|
size="small"
|
||||||
@ -21,10 +27,9 @@
|
|||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<div class="diagram-info-empty">
|
<div class="diagram-info-empty">
|
||||||
<el-icon style="font-size: 32px; color: #bbb; margin-bottom: 8px;">
|
<div style="color: #bbb; font-size: 15px;">
|
||||||
<i-ep-InfoFilled />
|
{{ t('diagram-node-empty') }}
|
||||||
</el-icon>
|
</div>
|
||||||
<div style="color: #bbb; font-size: 15px;">暂无节点信息</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
@ -80,7 +85,11 @@ if (autoDetectDiagram) {
|
|||||||
tool: item.tool,
|
tool: item.tool,
|
||||||
function: item.function,
|
function: item.function,
|
||||||
status: item.status || 'waiting',
|
status: item.status || 'waiting',
|
||||||
result: item.result || null
|
result: item.result || null,
|
||||||
|
createAt: item.createAt,
|
||||||
|
finishAt: item.finishAt,
|
||||||
|
llmTimecost: item.llmTimecost,
|
||||||
|
toolcallTimecost: item.toolcallTimecost
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -90,9 +99,6 @@ if (autoDetectDiagram) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(tabStorage.autoDetectDiagram!.views);
|
|
||||||
console.log(state.dataView);
|
|
||||||
|
|
||||||
|
|
||||||
let cancelHoverHandler: NodeJS.Timeout | undefined = undefined;
|
let cancelHoverHandler: NodeJS.Timeout | undefined = undefined;
|
||||||
|
|
||||||
@ -216,7 +222,7 @@ const drawDiagram = async () => {
|
|||||||
// 如果 dataView 中没有该工具,则初始化
|
// 如果 dataView 中没有该工具,则初始化
|
||||||
state.dataView.set(tool.name, {
|
state.dataView.set(tool.name, {
|
||||||
tool,
|
tool,
|
||||||
status: 'waiting'
|
status: 'waiting',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -728,4 +734,25 @@ function getNodePopupStyle(node: any): any {
|
|||||||
opacity: 0.85;
|
opacity: 0.85;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.item-status.running {
|
||||||
|
color: var(--main-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-status.success {
|
||||||
|
color: #43a047;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-status.error {
|
||||||
|
color: #e53935;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-status.waiting {
|
||||||
|
color: #aaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-status.default {
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
@ -58,7 +58,7 @@
|
|||||||
<el-tooltip
|
<el-tooltip
|
||||||
placement="top"
|
placement="top"
|
||||||
effect="light"
|
effect="light"
|
||||||
content="点击连接线取消连接,点击节点以创建连接"
|
:content="t('self-detect-caption')"
|
||||||
>
|
>
|
||||||
<span class="iconfont icon-about"></span>
|
<span class="iconfont icon-about"></span>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
@ -158,8 +158,14 @@ async function onTestConfirm() {
|
|||||||
tool: view.tool,
|
tool: view.tool,
|
||||||
status: view.status,
|
status: view.status,
|
||||||
function: view.function,
|
function: view.function,
|
||||||
result: view.result
|
result: view.result,
|
||||||
|
createAt: view.createAt,
|
||||||
|
finishAt: view.finishAt,
|
||||||
|
llmTimecost: view.llmTimecost,
|
||||||
|
toolcallTimecost: view.toolcallTimecost,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
context.render();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -195,5 +195,7 @@
|
|||||||
"ai-invoke-unknown-tool": "استدعت الذكاء الاصطناعي أداة غير معروفة",
|
"ai-invoke-unknown-tool": "استدعت الذكاء الاصطناعي أداة غير معروفة",
|
||||||
"click-edge-to-delete": "انقر على الحافة للحذف",
|
"click-edge-to-delete": "انقر على الحافة للحذف",
|
||||||
"select-node-define-test-tomo": "اختر عقدة أخرى لتحديد طوبولوجيا الاختبار",
|
"select-node-define-test-tomo": "اختر عقدة أخرى لتحديد طوبولوجيا الاختبار",
|
||||||
"tool-self-detect": "الفحص الذاتي للأداة"
|
"tool-self-detect": "الفحص الذاتي للأداة",
|
||||||
|
"self-detect-caption": "انقر على خط الاتصال لإلغاء التوصيل، انقر على العقدة لإنشاء اتصال",
|
||||||
|
"diagram-node-empty": "لا توجد معلومات عن العقدة"
|
||||||
}
|
}
|
@ -195,5 +195,7 @@
|
|||||||
"ai-invoke-unknown-tool": "KI hat ein unbekanntes Tool aufgerufen",
|
"ai-invoke-unknown-tool": "KI hat ein unbekanntes Tool aufgerufen",
|
||||||
"click-edge-to-delete": "Klicken Sie auf die Kante, um sie zu löschen",
|
"click-edge-to-delete": "Klicken Sie auf die Kante, um sie zu löschen",
|
||||||
"select-node-define-test-tomo": "Wählen Sie einen anderen Knoten aus, um die Testtopologie zu definieren",
|
"select-node-define-test-tomo": "Wählen Sie einen anderen Knoten aus, um die Testtopologie zu definieren",
|
||||||
"tool-self-detect": "Werkzeug-Selbsttest"
|
"tool-self-detect": "Werkzeug-Selbsttest",
|
||||||
|
"self-detect-caption": "Klicken Sie auf die Verbindungslinie, um die Verbindung aufzuheben, klicken Sie auf den Knoten, um eine Verbindung herzustellen",
|
||||||
|
"diagram-node-empty": "Keine Knoteninformationen"
|
||||||
}
|
}
|
@ -195,5 +195,7 @@
|
|||||||
"ai-invoke-unknown-tool": "AI called an unknown tool",
|
"ai-invoke-unknown-tool": "AI called an unknown tool",
|
||||||
"click-edge-to-delete": "Click the edge to delete",
|
"click-edge-to-delete": "Click the edge to delete",
|
||||||
"select-node-define-test-tomo": "Select another node to define the test topology",
|
"select-node-define-test-tomo": "Select another node to define the test topology",
|
||||||
"tool-self-detect": "Tool Self-Check"
|
"tool-self-detect": "Tool Self-Check",
|
||||||
|
"self-detect-caption": "Click on the connection line to cancel the connection, click on the node to create a connection",
|
||||||
|
"diagram-node-empty": "No node information"
|
||||||
}
|
}
|
@ -195,5 +195,7 @@
|
|||||||
"ai-invoke-unknown-tool": "L'IA a appelé un outil inconnu",
|
"ai-invoke-unknown-tool": "L'IA a appelé un outil inconnu",
|
||||||
"click-edge-to-delete": "Cliquez sur le bord pour supprimer",
|
"click-edge-to-delete": "Cliquez sur le bord pour supprimer",
|
||||||
"select-node-define-test-tomo": "Sélectionnez un autre nœud pour définir la topologie de test",
|
"select-node-define-test-tomo": "Sélectionnez un autre nœud pour définir la topologie de test",
|
||||||
"tool-self-detect": "Auto-vérification de l'outil"
|
"tool-self-detect": "Auto-vérification de l'outil",
|
||||||
|
"self-detect-caption": "Cliquez sur la ligne de connexion pour annuler la connexion, cliquez sur le nœud pour créer une connexion",
|
||||||
|
"diagram-node-empty": "Aucune information sur le nœud"
|
||||||
}
|
}
|
@ -195,5 +195,7 @@
|
|||||||
"ai-invoke-unknown-tool": "AIが未知のツールを呼び出しました",
|
"ai-invoke-unknown-tool": "AIが未知のツールを呼び出しました",
|
||||||
"click-edge-to-delete": "クリックして削除",
|
"click-edge-to-delete": "クリックして削除",
|
||||||
"select-node-define-test-tomo": "テストトポロジを定義するために別のノードを選択してください",
|
"select-node-define-test-tomo": "テストトポロジを定義するために別のノードを選択してください",
|
||||||
"tool-self-detect": "ツール自己診断"
|
"tool-self-detect": "ツール自己診断",
|
||||||
|
"self-detect-caption": "接続線をクリックして接続を解除し、ノードをクリックして接続を作成します",
|
||||||
|
"diagram-node-empty": "ノード情報なし"
|
||||||
}
|
}
|
@ -195,5 +195,7 @@
|
|||||||
"ai-invoke-unknown-tool": "AI가 알 수 없는 도구를 호출했습니다",
|
"ai-invoke-unknown-tool": "AI가 알 수 없는 도구를 호출했습니다",
|
||||||
"click-edge-to-delete": "가장자리를 클릭하여 삭제",
|
"click-edge-to-delete": "가장자리를 클릭하여 삭제",
|
||||||
"select-node-define-test-tomo": "테스트 토폴로지를 정의하려면 다른 노드를 선택하세요",
|
"select-node-define-test-tomo": "테스트 토폴로지를 정의하려면 다른 노드를 선택하세요",
|
||||||
"tool-self-detect": "도구 자체 점검"
|
"tool-self-detect": "도구 자체 점검",
|
||||||
|
"self-detect-caption": "연결선을 클릭하여 연결을 취소하고, 노드를 클릭하여 연결을 생성합니다",
|
||||||
|
"diagram-node-empty": "노드 정보 없음"
|
||||||
}
|
}
|
@ -195,5 +195,7 @@
|
|||||||
"ai-invoke-unknown-tool": "ИИ вызвал неизвестный инструмент",
|
"ai-invoke-unknown-tool": "ИИ вызвал неизвестный инструмент",
|
||||||
"click-edge-to-delete": "Нажмите на край, чтобы удалить",
|
"click-edge-to-delete": "Нажмите на край, чтобы удалить",
|
||||||
"select-node-define-test-tomo": "Выберите другой узел для определения тестовой топологии",
|
"select-node-define-test-tomo": "Выберите другой узел для определения тестовой топологии",
|
||||||
"tool-self-detect": "Самопроверка инструмента"
|
"tool-self-detect": "Самопроверка инструмента",
|
||||||
|
"self-detect-caption": "Нажмите на линию соединения, чтобы отменить соединение, нажмите на узел, чтобы создать соединение",
|
||||||
|
"diagram-node-empty": "Нет информации об узле"
|
||||||
}
|
}
|
@ -195,5 +195,7 @@
|
|||||||
"ai-invoke-unknown-tool": "AI 调用了未知的工具",
|
"ai-invoke-unknown-tool": "AI 调用了未知的工具",
|
||||||
"click-edge-to-delete": "点击边以删除",
|
"click-edge-to-delete": "点击边以删除",
|
||||||
"select-node-define-test-tomo": "选择另一个节点以定义测试拓扑",
|
"select-node-define-test-tomo": "选择另一个节点以定义测试拓扑",
|
||||||
"tool-self-detect": "工具自检"
|
"tool-self-detect": "工具自检",
|
||||||
|
"self-detect-caption": "点击连接线取消连接,点击节点以创建连接",
|
||||||
|
"diagram-node-empty": "暂无节点信息"
|
||||||
}
|
}
|
@ -195,5 +195,7 @@
|
|||||||
"ai-invoke-unknown-tool": "AI調用了未知的工具",
|
"ai-invoke-unknown-tool": "AI調用了未知的工具",
|
||||||
"click-edge-to-delete": "點擊邊緣以刪除",
|
"click-edge-to-delete": "點擊邊緣以刪除",
|
||||||
"select-node-define-test-tomo": "選擇另一個節點以定義測試拓撲",
|
"select-node-define-test-tomo": "選擇另一個節點以定義測試拓撲",
|
||||||
"tool-self-detect": "工具自檢"
|
"tool-self-detect": "工具自檢",
|
||||||
|
"self-detect-caption": "點擊連接線取消連接,點擊節點以創建連接",
|
||||||
|
"diagram-node-empty": "暫無節點資訊"
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user