style(lint): 优化格式
This commit is contained in:
parent
56d11db978
commit
dbc230e205
8
Makefile
8
Makefile
@ -30,13 +30,9 @@ logs:
|
|||||||
# LINTING AND FORMATTING
|
# LINTING AND FORMATTING
|
||||||
######################
|
######################
|
||||||
|
|
||||||
lint:
|
|
||||||
cd backend && uv run ruff check package
|
|
||||||
cd backend && uv run ruff format --check package
|
|
||||||
cd backend && uv run ruff check --select I package
|
|
||||||
|
|
||||||
format:
|
format:
|
||||||
cd backend && uv run ruff format package
|
cd backend && uv run ruff format package
|
||||||
cd backend && uv run ruff check package --fix
|
cd backend && uv run ruff check package --fix
|
||||||
cd backend && uv run ruff check --select I package --fix
|
cd backend && uv run ruff check --select I package --fix
|
||||||
docker compose exec -T web pnpm run format
|
cd web && pnpm run format
|
||||||
|
cd web && pnpm run lint
|
||||||
|
|||||||
@ -10,8 +10,8 @@ from .paths import (
|
|||||||
virtual_path_for_thread_file,
|
virtual_path_for_thread_file,
|
||||||
)
|
)
|
||||||
from .provider import (
|
from .provider import (
|
||||||
SandboxConnection,
|
|
||||||
ProvisionerSandboxProvider,
|
ProvisionerSandboxProvider,
|
||||||
|
SandboxConnection,
|
||||||
get_sandbox_provider,
|
get_sandbox_provider,
|
||||||
init_sandbox_provider,
|
init_sandbox_provider,
|
||||||
sandbox_id_for_thread,
|
sandbox_id_for_thread,
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import asyncio
|
|
||||||
import os
|
import os
|
||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@ -11,8 +10,9 @@ from langgraph.graph.state import CompiledStateGraph
|
|||||||
|
|
||||||
from yuxi import config as sys_config
|
from yuxi import config as sys_config
|
||||||
from yuxi.agents.context import BaseContext
|
from yuxi.agents.context import BaseContext
|
||||||
from yuxi.utils import logger
|
|
||||||
from yuxi.storage.postgres.manager import pg_manager
|
from yuxi.storage.postgres.manager import pg_manager
|
||||||
|
from yuxi.utils import logger
|
||||||
|
|
||||||
|
|
||||||
class BaseAgent:
|
class BaseAgent:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -21,10 +21,7 @@ from .prompt import PROMPT
|
|||||||
|
|
||||||
async def _build_middlewares(context):
|
async def _build_middlewares(context):
|
||||||
"""构建中间件列表"""
|
"""构建中间件列表"""
|
||||||
all_mcp_tools = (
|
all_mcp_tools = await get_tools_from_all_servers() # 因为异步加载,无法放在 RuntimeConfigMiddleware 的 __init__ 中
|
||||||
await get_tools_from_all_servers()
|
|
||||||
) # 因为异步加载,无法放在 RuntimeConfigMiddleware 的 __init__ 中
|
|
||||||
|
|
||||||
|
|
||||||
# summary middleware
|
# summary middleware
|
||||||
# 主 Agent 上下文优化:90k tokens 触发压缩(128k context window 的 70%)
|
# 主 Agent 上下文优化:90k tokens 触发压缩(128k context window 的 70%)
|
||||||
@ -80,7 +77,6 @@ class ChatbotAgent(BaseAgent):
|
|||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
async def get_graph(self, context=None, **kwargs):
|
async def get_graph(self, context=None, **kwargs):
|
||||||
|
|
||||||
context = context or self.context_schema() # 获取上下文配置
|
context = context or self.context_schema() # 获取上下文配置
|
||||||
|
|||||||
@ -83,4 +83,4 @@ DEEP_PROMPT = """你是一位专家级研究员。你的工作是进行彻底的
|
|||||||
- /home/gem/user-data/workspace/:用于存放工作文件和中间结果
|
- /home/gem/user-data/workspace/:用于存放工作文件和中间结果
|
||||||
- /home/gem/user-data/outputs/:用于存放最终输出结果
|
- /home/gem/user-data/outputs/:用于存放最终输出结果
|
||||||
- /home/gem/user-data/uploads/:用于存放用户上传的文件
|
- /home/gem/user-data/uploads/:用于存放用户上传的文件
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -405,7 +405,13 @@ class SkillsMiddleware(AgentMiddleware):
|
|||||||
pure = PurePosixPath(raw if raw.startswith("/") else f"/{raw}")
|
pure = PurePosixPath(raw if raw.startswith("/") else f"/{raw}")
|
||||||
parts = [p for p in pure.parts if p not in ("/", "")]
|
parts = [p for p in pure.parts if p not in ("/", "")]
|
||||||
slug: str | None = None
|
slug: str | None = None
|
||||||
if len(parts) == 5 and parts[0] == "home" and parts[1] == "gem" and parts[2] == "skills" and parts[4] == "SKILL.md":
|
if (
|
||||||
|
len(parts) == 5
|
||||||
|
and parts[0] == "home"
|
||||||
|
and parts[1] == "gem"
|
||||||
|
and parts[2] == "skills"
|
||||||
|
and parts[4] == "SKILL.md"
|
||||||
|
):
|
||||||
slug = parts[3]
|
slug = parts[3]
|
||||||
|
|
||||||
if not is_valid_skill_slug(slug):
|
if not is_valid_skill_slug(slug):
|
||||||
|
|||||||
@ -221,9 +221,7 @@ class Config(BaseModel):
|
|||||||
if os.path.exists(self.model_dir):
|
if os.path.exists(self.model_dir):
|
||||||
logger.debug(f"Model directory ({self.model_dir}) contains: {os.listdir(self.model_dir)}")
|
logger.debug(f"Model directory ({self.model_dir}) contains: {os.listdir(self.model_dir)}")
|
||||||
else:
|
else:
|
||||||
logger.debug(
|
logger.debug(f"Model directory ({self.model_dir}) does not exist. If not configured, please ignore it.")
|
||||||
f"Model directory ({self.model_dir}) does not exist. If not configured, please ignore it."
|
|
||||||
)
|
|
||||||
|
|
||||||
# 检查模型提供商的环境变量
|
# 检查模型提供商的环境变量
|
||||||
self.model_provider_status = {}
|
self.model_provider_status = {}
|
||||||
|
|||||||
@ -1,28 +1,23 @@
|
|||||||
import uuid
|
import uuid
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from datetime import UTC, datetime
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import aiofiles
|
import aiofiles
|
||||||
from fastapi import HTTPException, UploadFile
|
from fastapi import HTTPException, UploadFile
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from yuxi.agents.backends.sandbox import (
|
from yuxi.agents.backends.sandbox import (
|
||||||
ensure_thread_dirs,
|
ensure_thread_dirs,
|
||||||
sandbox_uploads_dir,
|
sandbox_uploads_dir,
|
||||||
)
|
)
|
||||||
from yuxi.services.doc_converter import ATTACHMENT_ALLOWED_EXTENSIONS, MAX_ATTACHMENT_SIZE_BYTES
|
|
||||||
|
|
||||||
UPLOADS_VIRTUAL_PREFIX = "/home/gem/user-data/uploads"
|
|
||||||
from yuxi.agents.buildin import agent_manager
|
from yuxi.agents.buildin import agent_manager
|
||||||
from yuxi.config import config as app_config
|
from yuxi.config import config as app_config
|
||||||
from yuxi.plugins.parser import Parser
|
from yuxi.plugins.parser import Parser
|
||||||
from yuxi.repositories.conversation_repository import ConversationRepository
|
from yuxi.repositories.conversation_repository import ConversationRepository
|
||||||
|
from yuxi.services.doc_converter import ATTACHMENT_ALLOWED_EXTENSIONS, MAX_ATTACHMENT_SIZE_BYTES
|
||||||
from yuxi.utils.datetime_utils import utc_isoformat
|
from yuxi.utils.datetime_utils import utc_isoformat
|
||||||
from yuxi.utils.logging_config import logger
|
from yuxi.utils.logging_config import logger
|
||||||
|
|
||||||
ATTACHMENT_ALLOWED_EXTENSIONS: tuple[str, ...] = (".txt", ".md", ".docx", ".html", ".htm")
|
UPLOADS_VIRTUAL_PREFIX = "/home/gem/user-data/uploads"
|
||||||
MAX_ATTACHMENT_SIZE_BYTES = 5 * 1024 * 1024 # 5 MB
|
|
||||||
MAX_ATTACHMENT_MARKDOWN_CHARS = 32_000
|
MAX_ATTACHMENT_MARKDOWN_CHARS = 32_000
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,6 @@ from pathlib import Path
|
|||||||
|
|
||||||
import aiofiles
|
import aiofiles
|
||||||
from fastapi import UploadFile
|
from fastapi import UploadFile
|
||||||
|
|
||||||
from yuxi.config import config as app_config
|
from yuxi.config import config as app_config
|
||||||
from yuxi.plugins.parser import Parser
|
from yuxi.plugins.parser import Parser
|
||||||
from yuxi.utils import logger
|
from yuxi.utils import logger
|
||||||
|
|||||||
@ -130,8 +130,6 @@ async def build_visible_knowledge_mounts(
|
|||||||
return mounts
|
return mounts
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def cache_minio_object(*, source_url: str, metadata: dict[str, Any] | None = None) -> Path:
|
def cache_minio_object(*, source_url: str, metadata: dict[str, Any] | None = None) -> Path:
|
||||||
bucket_name, object_name = parse_minio_url(source_url)
|
bucket_name, object_name = parse_minio_url(source_url)
|
||||||
minio_client = get_minio_client()
|
minio_client = get_minio_client()
|
||||||
@ -139,7 +137,7 @@ def cache_minio_object(*, source_url: str, metadata: dict[str, Any] | None = Non
|
|||||||
etag = str(getattr(stat, "etag", "") or "")
|
etag = str(getattr(stat, "etag", "") or "")
|
||||||
last_modified = getattr(stat, "last_modified", None)
|
last_modified = getattr(stat, "last_modified", None)
|
||||||
version_key = etag or (last_modified.isoformat() if last_modified else "")
|
version_key = etag or (last_modified.isoformat() if last_modified else "")
|
||||||
cache_key = hashlib.sha256(f"{bucket_name}:{object_name}:{version_key}".encode("utf-8")).hexdigest()
|
cache_key = hashlib.sha256(f"{bucket_name}:{object_name}:{version_key}".encode()).hexdigest()
|
||||||
|
|
||||||
suffix = Path(object_name).suffix
|
suffix = Path(object_name).suffix
|
||||||
objects_root = get_kb_cache_root() / "objects"
|
objects_root = get_kb_cache_root() / "objects"
|
||||||
|
|||||||
@ -5,15 +5,14 @@ from pathlib import Path
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from fastapi import HTTPException
|
from fastapi import HTTPException
|
||||||
|
|
||||||
from yuxi import config as conf
|
from yuxi import config as conf
|
||||||
from yuxi.repositories.conversation_repository import ConversationRepository
|
|
||||||
from yuxi.agents.backends.sandbox import (
|
from yuxi.agents.backends.sandbox import (
|
||||||
ensure_thread_dirs,
|
ensure_thread_dirs,
|
||||||
resolve_virtual_path,
|
resolve_virtual_path,
|
||||||
sandbox_user_data_dir,
|
sandbox_user_data_dir,
|
||||||
virtual_path_for_thread_file,
|
virtual_path_for_thread_file,
|
||||||
)
|
)
|
||||||
|
from yuxi.repositories.conversation_repository import ConversationRepository
|
||||||
from yuxi.services.conversation_service import require_user_conversation
|
from yuxi.services.conversation_service import require_user_conversation
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -33,48 +33,47 @@
|
|||||||
.search-box {
|
.search-box {
|
||||||
padding: 8px 12px 0;
|
padding: 8px 12px 0;
|
||||||
|
|
||||||
:deep(.ant-input-affix-wrapper) {
|
:deep(.ant-input-affix-wrapper) {
|
||||||
height: 28px;
|
height: 28px;
|
||||||
padding: 0 12px;
|
padding: 0 12px;
|
||||||
|
// border: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
background-color: var(--gray-0);
|
||||||
|
box-shadow: none;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus,
|
||||||
|
&.ant-input-affix-wrapper-focused {
|
||||||
// border: none;
|
// border: none;
|
||||||
border-radius: 8px;
|
|
||||||
background-color: var(--gray-0);
|
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:focus,
|
|
||||||
&.ant-input-affix-wrapper-focused {
|
|
||||||
// border: none;
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
:deep(.ant-input-prefix) {
|
:deep(.ant-input-prefix) {
|
||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
color: var(--gray-400);
|
color: var(--gray-400);
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.ant-input) {
|
:deep(.ant-input) {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.ant-input::placeholder) {
|
:deep(.ant-input::placeholder) {
|
||||||
color: var(--gray-400);
|
color: var(--gray-400);
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.ant-input-clear-icon) {
|
:deep(.ant-input-clear-icon) {
|
||||||
color: var(--gray-400);
|
color: var(--gray-400);
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.ant-input-clear-icon:hover) {
|
:deep(.ant-input-clear-icon:hover) {
|
||||||
color: var(--gray-500);
|
color: var(--gray-500);
|
||||||
}
|
}
|
||||||
|
|
||||||
// :deep(.ant-input-outlined) {
|
|
||||||
// border: none;
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
// :deep(.ant-input-outlined) {
|
||||||
|
// border: none;
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-container {
|
.list-container {
|
||||||
|
|||||||
@ -548,22 +548,6 @@ const isReadOnlyConfig = computed(() => !userStore.isAdmin)
|
|||||||
const isSavingConfig = ref(false)
|
const isSavingConfig = ref(false)
|
||||||
const isDeletingConfig = ref(false)
|
const isDeletingConfig = ref(false)
|
||||||
|
|
||||||
const hasOtherConfigs = computed(() => {
|
|
||||||
if (isEmptyConfig.value) return false
|
|
||||||
return Object.entries(configurableItems.value).some(([, value]) => {
|
|
||||||
const isBasic =
|
|
||||||
value.template_metadata?.kind === 'prompt' || value.template_metadata?.kind === 'llm'
|
|
||||||
const isTools =
|
|
||||||
value.template_metadata?.kind === 'mcps' ||
|
|
||||||
value.template_metadata?.kind === 'knowledges' ||
|
|
||||||
value.template_metadata?.kind === 'tools' ||
|
|
||||||
value.template_metadata?.kind === 'skills' ||
|
|
||||||
value.template_metadata?.kind === 'subagents'
|
|
||||||
|
|
||||||
return !isBasic && !isTools
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
const segmentConfigKeys = computed(() => {
|
const segmentConfigKeys = computed(() => {
|
||||||
const keys = Object.keys(configurableItems.value)
|
const keys = Object.keys(configurableItems.value)
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -108,7 +108,7 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import { CaretRightOutlined, ThunderboltOutlined, LoadingOutlined } from '@ant-design/icons-vue'
|
import { CaretRightOutlined } from '@ant-design/icons-vue'
|
||||||
import RefsComponent from '@/components/RefsComponent.vue'
|
import RefsComponent from '@/components/RefsComponent.vue'
|
||||||
import { Copy, Check } from 'lucide-vue-next'
|
import { Copy, Check } from 'lucide-vue-next'
|
||||||
import { ToolCallRenderer } from '@/components/ToolCallingResult'
|
import { ToolCallRenderer } from '@/components/ToolCallingResult'
|
||||||
|
|||||||
@ -168,7 +168,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<template v-else-if="isMarkdown">
|
<template v-else-if="isMarkdown">
|
||||||
<MdPreview
|
<MdPreview
|
||||||
class="flat-md-preview "
|
class="flat-md-preview"
|
||||||
:modelValue="formatContent(currentFile?.content)"
|
:modelValue="formatContent(currentFile?.content)"
|
||||||
:theme="theme"
|
:theme="theme"
|
||||||
previewTheme="github"
|
previewTheme="github"
|
||||||
|
|||||||
@ -37,7 +37,6 @@ import { message } from 'ant-design-vue'
|
|||||||
import { multimodalApi } from '@/apis/agent_api'
|
import { multimodalApi } from '@/apis/agent_api'
|
||||||
|
|
||||||
const fileInputRef = ref(null)
|
const fileInputRef = ref(null)
|
||||||
const imageInputRef = ref(null)
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
disabled: {
|
disabled: {
|
||||||
|
|||||||
@ -92,7 +92,8 @@
|
|||||||
<div
|
<div
|
||||||
class="card card-select"
|
class="card card-select"
|
||||||
v-if="
|
v-if="
|
||||||
configStore.config?.enable_content_guard && configStore.config?.enable_content_guard_llm
|
configStore.config?.enable_content_guard &&
|
||||||
|
configStore.config?.enable_content_guard_llm
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<span class="label">{{ items?.content_guard_llm_model?.des }}</span>
|
<span class="label">{{ items?.content_guard_llm_model?.des }}</span>
|
||||||
@ -254,7 +255,6 @@ onMounted(async () => {
|
|||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.basic-settings-section {
|
.basic-settings-section {
|
||||||
|
|
||||||
.section {
|
.section {
|
||||||
background-color: var(--gray-0);
|
background-color: var(--gray-0);
|
||||||
padding: 10px 16px;
|
padding: 10px 16px;
|
||||||
|
|||||||
@ -120,7 +120,7 @@ import {
|
|||||||
Trash2,
|
Trash2,
|
||||||
MoreVertical
|
MoreVertical
|
||||||
} from 'lucide-vue-next'
|
} from 'lucide-vue-next'
|
||||||
import dayjs, { parseToShanghai } from '@/utils/time'
|
import { parseToShanghai } from '@/utils/time'
|
||||||
import { useChatUIStore } from '@/stores/chatUI'
|
import { useChatUIStore } from '@/stores/chatUI'
|
||||||
import { useInfoStore } from '@/stores/info'
|
import { useInfoStore } from '@/stores/info'
|
||||||
import { useUserStore } from '@/stores/user'
|
import { useUserStore } from '@/stores/user'
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
<div class="params-info">
|
<div class="params-info">
|
||||||
<p>调整分块参数可以控制文本的切分方式,影响检索质量和文档加载效率。</p>
|
<p>调整分块参数可以控制文本的切分方式,影响检索质量和文档加载效率。</p>
|
||||||
</div>
|
</div>
|
||||||
<a-form :model="tempChunkParams" name="chunkConfig" autocomplete="off" layout="vertical">
|
<a-form :model="localParams" name="chunkConfig" autocomplete="off" layout="vertical">
|
||||||
<a-form-item v-if="showPreset" name="chunk_preset_id">
|
<a-form-item v-if="showPreset" name="chunk_preset_id">
|
||||||
<template #label>
|
<template #label>
|
||||||
<span class="chunk-preset-label">
|
<span class="chunk-preset-label">
|
||||||
@ -14,7 +14,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<a-select
|
<a-select
|
||||||
v-model:value="tempChunkParams.chunk_preset_id"
|
v-model:value="localParams.chunk_preset_id"
|
||||||
:options="presetOptions"
|
:options="presetOptions"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
/>
|
/>
|
||||||
@ -27,7 +27,7 @@
|
|||||||
<div class="chunk-row" v-if="showChunkSizeOverlap">
|
<div class="chunk-row" v-if="showChunkSizeOverlap">
|
||||||
<a-form-item label="Chunk Size" name="chunk_size">
|
<a-form-item label="Chunk Size" name="chunk_size">
|
||||||
<a-input-number
|
<a-input-number
|
||||||
v-model:value="tempChunkParams.chunk_size"
|
v-model:value="localParams.chunk_size"
|
||||||
:min="100"
|
:min="100"
|
||||||
:max="10000"
|
:max="10000"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
@ -36,7 +36,7 @@
|
|||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="Chunk Overlap" name="chunk_overlap">
|
<a-form-item label="Chunk Overlap" name="chunk_overlap">
|
||||||
<a-input-number
|
<a-input-number
|
||||||
v-model:value="tempChunkParams.chunk_overlap"
|
v-model:value="localParams.chunk_overlap"
|
||||||
:min="0"
|
:min="0"
|
||||||
:max="1000"
|
:max="1000"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
@ -51,7 +51,7 @@
|
|||||||
name="qa_separator"
|
name="qa_separator"
|
||||||
>
|
>
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="tempChunkParams.qa_separator"
|
v-model:value="localParams.qa_separator"
|
||||||
placeholder="输入分隔符,例如 \n\n\n 或 ---"
|
placeholder="输入分隔符,例如 \n\n\n 或 ---"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
/>
|
/>
|
||||||
@ -97,6 +97,10 @@ const props = defineProps({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 使用 computed 包装,直接返回原始对象供表单修改
|
||||||
|
// 表单修改会直接作用于 tempChunkParams(父组件的ref),实现双向绑定
|
||||||
|
const localParams = computed(() => props.tempChunkParams)
|
||||||
|
|
||||||
const presetOptions = computed(() => {
|
const presetOptions = computed(() => {
|
||||||
const options = []
|
const options = []
|
||||||
const defaultPresetLabel = CHUNK_PRESET_LABEL_MAP[props.databasePresetId] || 'General'
|
const defaultPresetLabel = CHUNK_PRESET_LABEL_MAP[props.databasePresetId] || 'General'
|
||||||
|
|||||||
@ -46,7 +46,7 @@ import { message } from 'ant-design-vue'
|
|||||||
|
|
||||||
const configStore = useConfigStore()
|
const configStore = useConfigStore()
|
||||||
|
|
||||||
const props = defineProps({
|
defineProps({
|
||||||
value: {
|
value: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: ''
|
||||||
|
|||||||
@ -206,8 +206,6 @@ import {
|
|||||||
EyeOutlined,
|
EyeOutlined,
|
||||||
DownloadOutlined,
|
DownloadOutlined,
|
||||||
DeleteOutlined,
|
DeleteOutlined,
|
||||||
CheckCircleOutlined,
|
|
||||||
CloseCircleOutlined,
|
|
||||||
ReloadOutlined
|
ReloadOutlined
|
||||||
} from '@ant-design/icons-vue'
|
} from '@ant-design/icons-vue'
|
||||||
import { evaluationApi } from '@/apis/knowledge_api'
|
import { evaluationApi } from '@/apis/knowledge_api'
|
||||||
@ -429,7 +427,7 @@ const parseDownloadFilename = (contentDisposition) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const asciiMatch = contentDisposition.match(/filename=\"?([^\";]+)\"?/i)
|
const asciiMatch = contentDisposition.match(/filename="?([^";]+)"?/i)
|
||||||
if (asciiMatch && asciiMatch[1]) {
|
if (asciiMatch && asciiMatch[1]) {
|
||||||
return asciiMatch[1]
|
return asciiMatch[1]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -397,10 +397,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, watch, h } from 'vue'
|
import { ref, computed, h } from 'vue'
|
||||||
import { useDatabaseStore } from '@/stores/database'
|
import { useDatabaseStore } from '@/stores/database'
|
||||||
import { message, Modal } from 'ant-design-vue'
|
import { message, Modal } from 'ant-design-vue'
|
||||||
import { useUserStore } from '@/stores/user'
|
|
||||||
import { documentApi } from '@/apis/knowledge_api'
|
import { documentApi } from '@/apis/knowledge_api'
|
||||||
import {
|
import {
|
||||||
CheckCircleFilled,
|
CheckCircleFilled,
|
||||||
@ -420,8 +419,6 @@ import {
|
|||||||
FolderPlus,
|
FolderPlus,
|
||||||
CheckSquare,
|
CheckSquare,
|
||||||
FileText,
|
FileText,
|
||||||
FileCheck,
|
|
||||||
Plus,
|
|
||||||
Database,
|
Database,
|
||||||
FileUp,
|
FileUp,
|
||||||
Search,
|
Search,
|
||||||
@ -430,7 +427,6 @@ import {
|
|||||||
} from 'lucide-vue-next'
|
} from 'lucide-vue-next'
|
||||||
|
|
||||||
const store = useDatabaseStore()
|
const store = useDatabaseStore()
|
||||||
const userStore = useUserStore()
|
|
||||||
|
|
||||||
const sortField = ref('filename')
|
const sortField = ref('filename')
|
||||||
const sortOptions = [
|
const sortOptions = [
|
||||||
@ -485,7 +481,6 @@ const lock = computed(() => store.state.lock)
|
|||||||
const batchDeleting = computed(() => store.state.batchDeleting)
|
const batchDeleting = computed(() => store.state.batchDeleting)
|
||||||
const batchParsing = computed(() => store.state.chunkLoading)
|
const batchParsing = computed(() => store.state.chunkLoading)
|
||||||
const batchIndexing = computed(() => store.state.chunkLoading)
|
const batchIndexing = computed(() => store.state.chunkLoading)
|
||||||
const autoRefresh = computed(() => store.state.autoRefresh)
|
|
||||||
const selectedRowKeys = computed({
|
const selectedRowKeys = computed({
|
||||||
get: () => store.selectedRowKeys,
|
get: () => store.selectedRowKeys,
|
||||||
set: (keys) => (store.selectedRowKeys = keys)
|
set: (keys) => (store.selectedRowKeys = keys)
|
||||||
@ -660,7 +655,7 @@ const customRow = (record) => {
|
|||||||
onOk: async () => {
|
onOk: async () => {
|
||||||
try {
|
try {
|
||||||
await store.moveFile(file_id, record.file_id)
|
await store.moveFile(file_id, record.file_id)
|
||||||
} catch (error) {
|
} catch {
|
||||||
// error handled in store
|
// error handled in store
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -996,10 +991,6 @@ const handleRefresh = () => {
|
|||||||
store.getDatabaseInfo(undefined, true) // Skip query params for manual refresh
|
store.getDatabaseInfo(undefined, true) // Skip query params for manual refresh
|
||||||
}
|
}
|
||||||
|
|
||||||
const toggleAutoRefresh = () => {
|
|
||||||
store.toggleAutoRefresh()
|
|
||||||
}
|
|
||||||
|
|
||||||
const toggleRightPanel = () => {
|
const toggleRightPanel = () => {
|
||||||
console.log(props.rightPanelVisible)
|
console.log(props.rightPanelVisible)
|
||||||
emit('toggleRightPanel')
|
emit('toggleRightPanel')
|
||||||
@ -1039,7 +1030,7 @@ const handleDeleteFolder = (record) => {
|
|||||||
try {
|
try {
|
||||||
await store.deleteFile(record.file_id)
|
await store.deleteFile(record.file_id)
|
||||||
message.success('删除成功')
|
message.success('删除成功')
|
||||||
} catch (error) {
|
} catch {
|
||||||
// Error handled in store but we can add extra handling if needed
|
// Error handled in store but we can add extra handling if needed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1245,7 +1236,6 @@ const handleIndexConfigCancel = () => {
|
|||||||
|
|
||||||
// 导入工具函数
|
// 导入工具函数
|
||||||
import { getFileIcon, getFileIconColor, formatRelativeTime } from '@/utils/file_utils'
|
import { getFileIcon, getFileIconColor, formatRelativeTime } from '@/utils/file_utils'
|
||||||
import { parseToShanghai } from '@/utils/time'
|
|
||||||
import ChunkParamsConfig from '@/components/ChunkParamsConfig.vue'
|
import ChunkParamsConfig from '@/components/ChunkParamsConfig.vue'
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -160,8 +160,12 @@
|
|||||||
<div class="stat-pill uploading" v-if="uploadingUploadCount > 0">
|
<div class="stat-pill uploading" v-if="uploadingUploadCount > 0">
|
||||||
上传中 {{ uploadingUploadCount }}
|
上传中 {{ uploadingUploadCount }}
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-pill queued" v-if="queuedUploadCount > 0">排队 {{ queuedUploadCount }}</div>
|
<div class="stat-pill queued" v-if="queuedUploadCount > 0">
|
||||||
<div class="stat-pill error" v-if="failedUploadCount > 0">失败 {{ failedUploadCount }}</div>
|
排队 {{ queuedUploadCount }}
|
||||||
|
</div>
|
||||||
|
<div class="stat-pill error" v-if="failedUploadCount > 0">
|
||||||
|
失败 {{ failedUploadCount }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="progress-header-right">
|
<div class="progress-header-right">
|
||||||
@ -192,9 +196,7 @@
|
|||||||
<div class="progress-tip" v-if="hasPendingUploads">
|
<div class="progress-tip" v-if="hasPendingUploads">
|
||||||
文件夹上传采用队列模式,最多同时上传 {{ MAX_UPLOAD_CONCURRENCY }} 个文件。
|
文件夹上传采用队列模式,最多同时上传 {{ MAX_UPLOAD_CONCURRENCY }} 个文件。
|
||||||
</div>
|
</div>
|
||||||
<div class="progress-tip" v-else>
|
<div class="progress-tip" v-else>上传队列已完成,可点击“添加到知识库”继续下一步。</div>
|
||||||
上传队列已完成,可点击“添加到知识库”继续下一步。
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -292,12 +294,12 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, onMounted, watch } from 'vue'
|
import { ref, computed, onMounted, watch } from 'vue'
|
||||||
import { message, Upload, Tooltip, Modal } from 'ant-design-vue'
|
import { message, Upload, Modal } from 'ant-design-vue'
|
||||||
import { useUserStore } from '@/stores/user'
|
import { useUserStore } from '@/stores/user'
|
||||||
import { useDatabaseStore } from '@/stores/database'
|
import { useDatabaseStore } from '@/stores/database'
|
||||||
import { ocrApi } from '@/apis/system_api'
|
import { ocrApi } from '@/apis/system_api'
|
||||||
import { fileApi, documentApi } from '@/apis/knowledge_api'
|
import { fileApi, documentApi } from '@/apis/knowledge_api'
|
||||||
import { CheckCircleFilled, ReloadOutlined } from '@ant-design/icons-vue'
|
import { ReloadOutlined } from '@ant-design-icons-vue'
|
||||||
import {
|
import {
|
||||||
FileUp,
|
FileUp,
|
||||||
FolderUp,
|
FolderUp,
|
||||||
@ -456,7 +458,6 @@ const chunkLoading = computed(() => store.state.chunkLoading)
|
|||||||
|
|
||||||
// 上传模式
|
// 上传模式
|
||||||
const uploadMode = ref('file')
|
const uploadMode = ref('file')
|
||||||
const previousOcrSelection = ref('disable')
|
|
||||||
const MAX_UPLOAD_CONCURRENCY = 10
|
const MAX_UPLOAD_CONCURRENCY = 10
|
||||||
|
|
||||||
// 文件列表
|
// 文件列表
|
||||||
@ -596,7 +597,7 @@ const isValidUrl = (string) => {
|
|||||||
try {
|
try {
|
||||||
const url = new URL(string)
|
const url = new URL(string)
|
||||||
return url.protocol === 'http:' || url.protocol === 'https:'
|
return url.protocol === 'http:' || url.protocol === 'https:'
|
||||||
} catch (_) {
|
} catch {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -674,14 +675,6 @@ const removeUrl = (index) => {
|
|||||||
urlList.value.splice(index, 1)
|
urlList.value.splice(index, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleUrlKeydown = (e) => {
|
|
||||||
// Ctrl + Enter 提交
|
|
||||||
if (e.key === 'Enter' && e.ctrlKey) {
|
|
||||||
e.preventDefault()
|
|
||||||
handleFetchUrls()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// OCR服务健康状态
|
// OCR服务健康状态
|
||||||
const ocrHealthStatus = ref({
|
const ocrHealthStatus = ref({
|
||||||
rapid_ocr: { status: 'unknown', message: '' },
|
rapid_ocr: { status: 'unknown', message: '' },
|
||||||
@ -724,12 +717,6 @@ const buildAutoIndexParams = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算属性:是否支持QA分割
|
|
||||||
const isQaSplitSupported = computed(() => {
|
|
||||||
const type = kbType.value?.toLowerCase()
|
|
||||||
return type === 'milvus'
|
|
||||||
})
|
|
||||||
|
|
||||||
const isGraphBased = computed(() => {
|
const isGraphBased = computed(() => {
|
||||||
const type = kbType.value?.toLowerCase()
|
const type = kbType.value?.toLowerCase()
|
||||||
return type === 'lightrag'
|
return type === 'lightrag'
|
||||||
@ -926,20 +913,12 @@ const beforeUpload = (file) => {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
const formatFileSize = (bytes) => {
|
|
||||||
if (bytes === 0 || !bytes) return '0 B'
|
|
||||||
const k = 1024
|
|
||||||
const sizes = ['B', 'KB', 'MB', 'GB']
|
|
||||||
const i = Math.floor(Math.log(bytes) / Math.log(k))
|
|
||||||
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`
|
|
||||||
}
|
|
||||||
|
|
||||||
const formatFileTime = (timestamp) => {
|
const formatFileTime = (timestamp) => {
|
||||||
if (!timestamp) return ''
|
if (!timestamp) return ''
|
||||||
try {
|
try {
|
||||||
const date = new Date(timestamp)
|
const date = new Date(timestamp)
|
||||||
return date.toLocaleString()
|
return date.toLocaleString()
|
||||||
} catch (e) {
|
} catch {
|
||||||
return timestamp
|
return timestamp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { Graph } from '@antv/g6'
|
import { Graph } from '@antv/g6'
|
||||||
import { onMounted, onUnmounted, ref, watch, nextTick } from 'vue'
|
import { onMounted, onUnmounted, ref, watch } from 'vue'
|
||||||
import { useThemeStore } from '@/stores/theme'
|
import { useThemeStore } from '@/stores/theme'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@ -142,7 +142,9 @@ function initGraph() {
|
|||||||
if (graphInstance) {
|
if (graphInstance) {
|
||||||
try {
|
try {
|
||||||
graphInstance.destroy()
|
graphInstance.destroy()
|
||||||
} catch (e) {}
|
} catch {
|
||||||
|
// ignore cleanup error
|
||||||
|
}
|
||||||
graphInstance = null
|
graphInstance = null
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,7 +332,9 @@ function refreshGraph() {
|
|||||||
if (graphInstance) {
|
if (graphInstance) {
|
||||||
try {
|
try {
|
||||||
graphInstance.destroy()
|
graphInstance.destroy()
|
||||||
} catch (e) {}
|
} catch {
|
||||||
|
// ignore cleanup error
|
||||||
|
}
|
||||||
graphInstance = null
|
graphInstance = null
|
||||||
}
|
}
|
||||||
if (container.value) container.value.innerHTML = ''
|
if (container.value) container.value.innerHTML = ''
|
||||||
@ -345,13 +349,17 @@ function fitView() {
|
|||||||
if (graphInstance)
|
if (graphInstance)
|
||||||
try {
|
try {
|
||||||
graphInstance.fitView()
|
graphInstance.fitView()
|
||||||
} catch (_) {}
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
}
|
}
|
||||||
function fitCenter() {
|
function fitCenter() {
|
||||||
if (graphInstance)
|
if (graphInstance)
|
||||||
try {
|
try {
|
||||||
graphInstance.fitCenter()
|
graphInstance.fitCenter()
|
||||||
} catch (_) {}
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
}
|
}
|
||||||
function getInstance() {
|
function getInstance() {
|
||||||
return graphInstance
|
return graphInstance
|
||||||
@ -452,7 +460,9 @@ onUnmounted(() => {
|
|||||||
clearTimeout(renderTimeout)
|
clearTimeout(renderTimeout)
|
||||||
try {
|
try {
|
||||||
graphInstance?.destroy()
|
graphInstance?.destroy()
|
||||||
} catch (e) {}
|
} catch {
|
||||||
|
// ignore cleanup error
|
||||||
|
}
|
||||||
graphInstance = null
|
graphInstance = null
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { LoadingOutlined } from '@ant-design/icons-vue'
|
import { LoadingOutlined } from '@ant-design/icons-vue'
|
||||||
const props = defineProps({
|
defineProps({
|
||||||
title: {
|
title: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true
|
required: true
|
||||||
|
|||||||
@ -16,7 +16,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { X } from 'lucide-vue-next'
|
import { X } from 'lucide-vue-next'
|
||||||
|
|
||||||
const props = defineProps({
|
defineProps({
|
||||||
imageData: {
|
imageData: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: null
|
default: null
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { defineProps } from 'vue'
|
import { defineProps } from 'vue'
|
||||||
|
|
||||||
const props = defineProps({
|
defineProps({
|
||||||
visible: {
|
visible: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
|
|||||||
@ -87,7 +87,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, onMounted, onUnmounted, watch } from 'vue'
|
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||||||
import { MdPreview } from 'md-editor-v3'
|
import { MdPreview } from 'md-editor-v3'
|
||||||
import 'md-editor-v3/lib/preview.css'
|
import 'md-editor-v3/lib/preview.css'
|
||||||
import { mergeChunks, getChunkPreview } from '@/utils/chunkUtils'
|
import { mergeChunks, getChunkPreview } from '@/utils/chunkUtils'
|
||||||
|
|||||||
@ -406,9 +406,7 @@ const modelStatus = computed(() => configStore.config?.model_provider_status)
|
|||||||
// 自定义供应商计算属性
|
// 自定义供应商计算属性
|
||||||
const customProviders = computed(() => {
|
const customProviders = computed(() => {
|
||||||
const providers = configStore.config?.model_names || {}
|
const providers = configStore.config?.model_names || {}
|
||||||
return Object.fromEntries(
|
return Object.fromEntries(Object.entries(providers).filter(([, value]) => value.custom === true))
|
||||||
Object.entries(providers).filter(([key, value]) => value.custom === true)
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// 提供商配置相关状态
|
// 提供商配置相关状态
|
||||||
@ -652,22 +650,6 @@ const customProviderRules = {
|
|||||||
env: [{ required: true, message: '请输入API密钥或环境变量', trigger: 'blur' }]
|
env: [{ required: true, message: '请输入API密钥或环境变量', trigger: 'blur' }]
|
||||||
}
|
}
|
||||||
|
|
||||||
// API密钥掩码显示
|
|
||||||
const maskApiKey = (apiKey) => {
|
|
||||||
if (!apiKey) return '未配置'
|
|
||||||
|
|
||||||
// 如果是环境变量格式,直接显示
|
|
||||||
if (apiKey.startsWith('${') && apiKey.endsWith('}')) {
|
|
||||||
return apiKey
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果是直接的API密钥,进行掩码处理
|
|
||||||
if (apiKey.length > 8) {
|
|
||||||
return apiKey.substring(0, 4) + '***' + apiKey.substring(apiKey.length - 4)
|
|
||||||
}
|
|
||||||
return '***'
|
|
||||||
}
|
|
||||||
|
|
||||||
// 打开添加自定义供应商弹窗
|
// 打开添加自定义供应商弹窗
|
||||||
const openAddCustomProviderModal = () => {
|
const openAddCustomProviderModal = () => {
|
||||||
customProviderModal.visible = true
|
customProviderModal.visible = true
|
||||||
@ -735,18 +717,14 @@ const saveCustomProvider = async () => {
|
|||||||
custom: true
|
custom: true
|
||||||
}
|
}
|
||||||
|
|
||||||
let result
|
|
||||||
if (customProviderModal.isEdit) {
|
if (customProviderModal.isEdit) {
|
||||||
result = await customProviderApi.updateCustomProvider(
|
await customProviderApi.updateCustomProvider(
|
||||||
customProviderModal.data.providerId,
|
customProviderModal.data.providerId,
|
||||||
providerData
|
providerData
|
||||||
)
|
)
|
||||||
message.success('自定义供应商更新成功')
|
message.success('自定义供应商更新成功')
|
||||||
} else {
|
} else {
|
||||||
result = await customProviderApi.addCustomProvider(
|
await customProviderApi.addCustomProvider(customProviderModal.data.providerId, providerData)
|
||||||
customProviderModal.data.providerId,
|
|
||||||
providerData
|
|
||||||
)
|
|
||||||
message.success(`自定义供应商 ${customProviderModal.data.providerId} 添加成功`)
|
message.success(`自定义供应商 ${customProviderModal.data.providerId} 添加成功`)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -784,7 +762,7 @@ const cancelCustomProvider = () => {
|
|||||||
// 删除自定义供应商
|
// 删除自定义供应商
|
||||||
const deleteCustomProvider = async (providerId) => {
|
const deleteCustomProvider = async (providerId) => {
|
||||||
try {
|
try {
|
||||||
const result = await customProviderApi.deleteCustomProvider(providerId)
|
await customProviderApi.deleteCustomProvider(providerId)
|
||||||
message.success('自定义供应商删除成功')
|
message.success('自定义供应商删除成功')
|
||||||
await configStore.refreshConfig()
|
await configStore.refreshConfig()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@ -1 +1,3 @@
|
|||||||
<template></template>
|
<template>
|
||||||
|
<div class="project-overview"></div>
|
||||||
|
</template>
|
||||||
|
|||||||
@ -347,7 +347,7 @@ import { Braces, Tags, Network, Link, FileText, ArrowRight } from 'lucide-vue-ne
|
|||||||
|
|
||||||
const store = useDatabaseStore()
|
const store = useDatabaseStore()
|
||||||
|
|
||||||
const props = defineProps({
|
defineProps({
|
||||||
visible: {
|
visible: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
@ -359,15 +359,12 @@ const props = defineProps({
|
|||||||
})
|
})
|
||||||
|
|
||||||
// 声明事件
|
// 声明事件
|
||||||
const emit = defineEmits(['toggleVisible'])
|
defineEmits(['toggleVisible'])
|
||||||
|
|
||||||
const searchLoading = computed(() => store.state.searchLoading)
|
const searchLoading = computed(() => store.state.searchLoading)
|
||||||
const queryResult = ref('')
|
const queryResult = ref('')
|
||||||
const showRawData = ref(false)
|
const showRawData = ref(false)
|
||||||
|
|
||||||
// 判断是否为 LightRAG 类型知识库
|
|
||||||
const isLightRAG = computed(() => store.database?.kb_type?.toLowerCase() === 'lightrag')
|
|
||||||
|
|
||||||
// 判断是否是 LightRAG 格式的查询结果
|
// 判断是否是 LightRAG 格式的查询结果
|
||||||
const isLightRAGResult = computed(() => {
|
const isLightRAGResult = computed(() => {
|
||||||
return (
|
return (
|
||||||
@ -386,7 +383,6 @@ const queryExamples = ref([])
|
|||||||
const currentExampleIndex = ref(0)
|
const currentExampleIndex = ref(0)
|
||||||
const loadingQuestions = ref(false)
|
const loadingQuestions = ref(false)
|
||||||
const generatingQuestions = ref(false)
|
const generatingQuestions = ref(false)
|
||||||
const searchConfigModalVisible = ref(false)
|
|
||||||
|
|
||||||
// 示例轮播相关
|
// 示例轮播相关
|
||||||
let exampleCarouselInterval = null
|
let exampleCarouselInterval = null
|
||||||
@ -417,17 +413,6 @@ const extractFileName = (filePath) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 打开检索配置弹窗
|
|
||||||
const openSearchConfigModal = () => {
|
|
||||||
searchConfigModalVisible.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理检索配置保存
|
|
||||||
const handleSearchConfigSave = (config) => {
|
|
||||||
console.log('查询测试中的检索配置已更新:', config)
|
|
||||||
// 可以在这里添加配置更新后的处理逻辑,比如重新查询
|
|
||||||
}
|
|
||||||
|
|
||||||
// 加载示例问题
|
// 加载示例问题
|
||||||
const loadSampleQuestions = async () => {
|
const loadSampleQuestions = async () => {
|
||||||
if (!store.database?.db_id) return
|
if (!store.database?.db_id) return
|
||||||
|
|||||||
@ -418,7 +418,7 @@ const props = defineProps({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const emit = defineEmits(['switch-to-benchmarks'])
|
defineEmits(['switch-to-benchmarks'])
|
||||||
|
|
||||||
// 使用任务中心 store
|
// 使用任务中心 store
|
||||||
const taskerStore = useTaskerStore()
|
const taskerStore = useTaskerStore()
|
||||||
@ -572,14 +572,6 @@ const historyColumns = [
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
// 计算属性:当前选中的基准对象
|
|
||||||
const currentBenchmark = computed(() => {
|
|
||||||
if (!selectedBenchmarkId.value || !availableBenchmarks.value) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
return availableBenchmarks.value.find((b) => b.benchmark_id === selectedBenchmarkId.value)
|
|
||||||
})
|
|
||||||
|
|
||||||
// 切换错误显示模式
|
// 切换错误显示模式
|
||||||
const toggleErrorOnly = async () => {
|
const toggleErrorOnly = async () => {
|
||||||
resultsLoading.value = true
|
resultsLoading.value = true
|
||||||
@ -948,12 +940,6 @@ const deleteEvaluationRecord = async (taskId) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 工具函数
|
|
||||||
const truncateText = (text, maxLength) => {
|
|
||||||
if (!text) return ''
|
|
||||||
return text.length > maxLength ? text.substring(0, maxLength) + '...' : text
|
|
||||||
}
|
|
||||||
|
|
||||||
const formatTime = (timeStr) => {
|
const formatTime = (timeStr) => {
|
||||||
if (!timeStr) return '-'
|
if (!timeStr) return '-'
|
||||||
const date = new Date(timeStr)
|
const date = new Date(timeStr)
|
||||||
|
|||||||
@ -92,7 +92,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, reactive, watch } from 'vue'
|
import { ref, computed, reactive, watch } from 'vue'
|
||||||
import { useClipboard } from '@vueuse/core'
|
import { useClipboard } from '@vueuse/core'
|
||||||
import { message } from 'ant-design-vue'
|
import { message as antMessage } from 'ant-design-vue'
|
||||||
import {
|
import {
|
||||||
ThumbsUp,
|
ThumbsUp,
|
||||||
ThumbsDown,
|
ThumbsDown,
|
||||||
@ -151,7 +151,7 @@ const feedbackState = reactive({
|
|||||||
reason: null
|
reason: null
|
||||||
})
|
})
|
||||||
|
|
||||||
// 初始化反馈状态 - 从 message.feedback 读取历史反馈
|
// 初始化反馈状态 - 从 antMessage.feedback 读取历史反馈
|
||||||
const initFeedbackState = () => {
|
const initFeedbackState = () => {
|
||||||
if (msg.value?.feedback) {
|
if (msg.value?.feedback) {
|
||||||
feedbackState.hasSubmitted = true
|
feedbackState.hasSubmitted = true
|
||||||
@ -197,18 +197,18 @@ const copyText = async (text) => {
|
|||||||
if (isSupported) {
|
if (isSupported) {
|
||||||
try {
|
try {
|
||||||
await copy(text)
|
await copy(text)
|
||||||
message.success('文本已复制到剪贴板')
|
antMessage.success('文本已复制到剪贴板')
|
||||||
isCopied.value = true
|
isCopied.value = true
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
isCopied.value = false
|
isCopied.value = false
|
||||||
}, 2000)
|
}, 2000)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('复制失败:', error)
|
console.error('复制失败:', error)
|
||||||
message.error('复制失败,请手动复制')
|
antMessage.error('复制失败,请手动复制')
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.warn('浏览器不支持自动复制')
|
console.warn('浏览器不支持自动复制')
|
||||||
message.warning('浏览器不支持自动复制,请手动复制')
|
antMessage.warning('浏览器不支持自动复制,请手动复制')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,12 +244,12 @@ const getModelName = (msg) => {
|
|||||||
// Handle like action
|
// Handle like action
|
||||||
const likeThisResponse = async (msg) => {
|
const likeThisResponse = async (msg) => {
|
||||||
if (feedbackState.hasSubmitted) {
|
if (feedbackState.hasSubmitted) {
|
||||||
message.info('您已经提交过反馈了')
|
antMessage.info('您已经提交过反馈了')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!msg?.id) {
|
if (!msg?.id) {
|
||||||
message.error('无法提交反馈:消息ID不存在')
|
antMessage.error('无法提交反馈:消息ID不存在')
|
||||||
console.error('Message object:', msg)
|
console.error('Message object:', msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -261,14 +261,14 @@ const likeThisResponse = async (msg) => {
|
|||||||
feedbackState.hasSubmitted = true
|
feedbackState.hasSubmitted = true
|
||||||
feedbackState.rating = 'like'
|
feedbackState.rating = 'like'
|
||||||
|
|
||||||
message.success('感谢您的反馈!')
|
antMessage.success('感谢您的反馈!')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to submit like feedback:', error)
|
console.error('Failed to submit like feedback:', error)
|
||||||
if (error.message?.includes('already submitted')) {
|
if (error.message?.includes('already submitted')) {
|
||||||
message.info('您已经提交过反馈了')
|
antMessage.info('您已经提交过反馈了')
|
||||||
feedbackState.hasSubmitted = true
|
feedbackState.hasSubmitted = true
|
||||||
} else {
|
} else {
|
||||||
message.error('提交反馈失败,请稍后重试')
|
antMessage.error('提交反馈失败,请稍后重试')
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
submittingFeedback.value = false
|
submittingFeedback.value = false
|
||||||
@ -278,12 +278,12 @@ const likeThisResponse = async (msg) => {
|
|||||||
// Handle dislike action
|
// Handle dislike action
|
||||||
const dislikeThisResponse = async (msg) => {
|
const dislikeThisResponse = async (msg) => {
|
||||||
if (feedbackState.hasSubmitted) {
|
if (feedbackState.hasSubmitted) {
|
||||||
message.info('您已经提交过反馈了')
|
antMessage.info('您已经提交过反馈了')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!msg?.id) {
|
if (!msg?.id) {
|
||||||
message.error('无法提交反馈:消息ID不存在')
|
antMessage.error('无法提交反馈:消息ID不存在')
|
||||||
console.error('Message object:', msg)
|
console.error('Message object:', msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -305,15 +305,15 @@ const submitDislikeFeedback = async () => {
|
|||||||
dislikeModalVisible.value = false
|
dislikeModalVisible.value = false
|
||||||
dislikeReason.value = ''
|
dislikeReason.value = ''
|
||||||
|
|
||||||
message.success('感谢您的反馈!')
|
antMessage.success('感谢您的反馈!')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to submit dislike feedback:', error)
|
console.error('Failed to submit dislike feedback:', error)
|
||||||
if (error.message?.includes('already submitted')) {
|
if (error.message?.includes('already submitted')) {
|
||||||
message.info('您已经提交过反馈了')
|
antMessage.info('您已经提交过反馈了')
|
||||||
feedbackState.hasSubmitted = true
|
feedbackState.hasSubmitted = true
|
||||||
dislikeModalVisible.value = false
|
dislikeModalVisible.value = false
|
||||||
} else {
|
} else {
|
||||||
message.error('提交反馈失败,请稍后重试')
|
antMessage.error('提交反馈失败,请稍后重试')
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
submittingFeedback.value = false
|
submittingFeedback.value = false
|
||||||
|
|||||||
@ -206,6 +206,8 @@ const resetToDefaults = () => {
|
|||||||
message.success('已重置为默认配置')
|
message.success('已重置为默认配置')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defineExpose({ resetToDefaults })
|
||||||
|
|
||||||
// 保存配置
|
// 保存配置
|
||||||
const handleSave = async () => {
|
const handleSave = async () => {
|
||||||
// 如果没有 databaseId,不执行保存
|
// 如果没有 databaseId,不执行保存
|
||||||
|
|||||||
@ -268,7 +268,6 @@ import { MdPreview } from 'md-editor-v3'
|
|||||||
import 'md-editor-v3/lib/preview.css'
|
import 'md-editor-v3/lib/preview.css'
|
||||||
import { useThemeStore } from '@/stores/theme'
|
import { useThemeStore } from '@/stores/theme'
|
||||||
import {
|
import {
|
||||||
Upload,
|
|
||||||
RotateCw,
|
RotateCw,
|
||||||
Download,
|
Download,
|
||||||
Trash2,
|
Trash2,
|
||||||
@ -346,8 +345,6 @@ watch(selectedPath, (newPath) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const formatRelativeTime = (time) => (time ? dayjs(time).fromNow() : '-')
|
|
||||||
|
|
||||||
const toolDependencyOptions = computed(() =>
|
const toolDependencyOptions = computed(() =>
|
||||||
(dependencyOptions.tools || []).map((i) =>
|
(dependencyOptions.tools || []).map((i) =>
|
||||||
typeof i === 'object' ? { label: i.name, value: i.id } : { label: i, value: i }
|
typeof i === 'object' ? { label: i.name, value: i.id } : { label: i, value: i }
|
||||||
@ -406,7 +403,7 @@ const fetchSkills = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
await fetchDependencyOptions()
|
await fetchDependencyOptions()
|
||||||
} catch (error) {
|
} catch {
|
||||||
message.error('加载失败')
|
message.error('加载失败')
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
@ -420,7 +417,9 @@ const fetchDependencyOptions = async () => {
|
|||||||
dependencyOptions.tools = data.tools || []
|
dependencyOptions.tools = data.tools || []
|
||||||
dependencyOptions.mcps = data.mcps || []
|
dependencyOptions.mcps = data.mcps || []
|
||||||
dependencyOptions.skills = data.skills || []
|
dependencyOptions.skills = data.skills || []
|
||||||
} catch {}
|
} catch {
|
||||||
|
// ignore error
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const syncDependencyFormFromSkill = (skillRecord) => {
|
const syncDependencyFormFromSkill = (skillRecord) => {
|
||||||
@ -538,27 +537,6 @@ const handleCreateNode = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const confirmDeleteNode = () => {
|
|
||||||
if (!currentSkill.value || !selectedPath.value || selectedPath.value === 'SKILL.md') return
|
|
||||||
Modal.confirm({
|
|
||||||
title: '确认删除?',
|
|
||||||
content: `将永久删除: ${selectedPath.value}`,
|
|
||||||
okText: '删除',
|
|
||||||
okType: 'danger',
|
|
||||||
cancelText: '取消',
|
|
||||||
onOk: async () => {
|
|
||||||
try {
|
|
||||||
await skillApi.deleteSkillFile(currentSkill.value.slug, selectedPath.value)
|
|
||||||
resetFileState()
|
|
||||||
await reloadTree()
|
|
||||||
message.success('已删除')
|
|
||||||
} catch {
|
|
||||||
message.error('删除失败')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const confirmDeleteSkill = () => {
|
const confirmDeleteSkill = () => {
|
||||||
if (!currentSkill.value) return
|
if (!currentSkill.value) return
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
|
|||||||
@ -53,7 +53,6 @@ const { activeCount: activeCountRef } = storeToRefs(taskerStore)
|
|||||||
const currentTime = ref('')
|
const currentTime = ref('')
|
||||||
|
|
||||||
// 计算属性
|
// 计算属性
|
||||||
const organization = computed(() => infoStore.organization)
|
|
||||||
const branding = computed(() => infoStore.branding)
|
const branding = computed(() => infoStore.branding)
|
||||||
|
|
||||||
// 用户名计算属性
|
// 用户名计算属性
|
||||||
|
|||||||
@ -226,7 +226,18 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, computed, onMounted } from 'vue'
|
import { ref, reactive, computed, onMounted } from 'vue'
|
||||||
import { message, Modal } from 'ant-design-vue'
|
import { message, Modal } from 'ant-design-vue'
|
||||||
import { Search, Bot, Pencil, Trash2, Info, MessageSquare, FileText, Cpu, Wrench, Clock } from 'lucide-vue-next'
|
import {
|
||||||
|
Search,
|
||||||
|
Bot,
|
||||||
|
Pencil,
|
||||||
|
Trash2,
|
||||||
|
Info,
|
||||||
|
MessageSquare,
|
||||||
|
FileText,
|
||||||
|
Cpu,
|
||||||
|
Wrench,
|
||||||
|
Clock
|
||||||
|
} from 'lucide-vue-next'
|
||||||
import { subagentApi } from '@/apis/subagent_api'
|
import { subagentApi } from '@/apis/subagent_api'
|
||||||
import { toolApi } from '@/apis/tool_api'
|
import { toolApi } from '@/apis/tool_api'
|
||||||
import { formatFullDateTime } from '@/utils/time'
|
import { formatFullDateTime } from '@/utils/time'
|
||||||
|
|||||||
@ -334,18 +334,6 @@ function statusLabel(status) {
|
|||||||
return map[status] || status
|
return map[status] || status
|
||||||
}
|
}
|
||||||
|
|
||||||
function statusColor(status) {
|
|
||||||
const map = {
|
|
||||||
pending: 'blue',
|
|
||||||
queued: 'blue',
|
|
||||||
running: 'processing',
|
|
||||||
success: 'green',
|
|
||||||
failed: 'red',
|
|
||||||
cancelled: 'gray'
|
|
||||||
}
|
|
||||||
return map[status] || 'default'
|
|
||||||
}
|
|
||||||
|
|
||||||
function progressStatus(status) {
|
function progressStatus(status) {
|
||||||
if (status === 'failed') return 'exception'
|
if (status === 'failed') return 'exception'
|
||||||
if (status === 'cancelled') return 'normal'
|
if (status === 'cancelled') return 'normal'
|
||||||
|
|||||||
@ -18,9 +18,8 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import BaseToolCall from '../BaseToolCall.vue'
|
import BaseToolCall from '../BaseToolCall.vue'
|
||||||
import { NumberOutlined } from '@ant-design/icons-vue'
|
|
||||||
|
|
||||||
const props = defineProps({
|
defineProps({
|
||||||
toolCall: {
|
toolCall: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true
|
||||||
@ -31,7 +30,7 @@ const parseData = (content) => {
|
|||||||
if (typeof content === 'string') {
|
if (typeof content === 'string') {
|
||||||
try {
|
try {
|
||||||
return JSON.parse(content)
|
return JSON.parse(content)
|
||||||
} catch (error) {
|
} catch {
|
||||||
return content
|
return content
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<BaseToolCall :tool-call="toolCall">
|
<BaseToolCall :tool-call="toolCall">
|
||||||
<template #result="{ resultContent }">
|
<template #result="{}">
|
||||||
<div class="chart-result">
|
<div class="chart-result">
|
||||||
<img :src="chartUrl" />
|
<img :src="chartUrl" />
|
||||||
</div>
|
</div>
|
||||||
@ -23,7 +23,7 @@ const parseData = (content) => {
|
|||||||
if (typeof content === 'string') {
|
if (typeof content === 'string') {
|
||||||
try {
|
try {
|
||||||
return JSON.parse(content)
|
return JSON.parse(content)
|
||||||
} catch (error) {
|
} catch {
|
||||||
return content
|
return content
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,7 +35,7 @@ const parsedArgs = computed(() => {
|
|||||||
if (typeof args === 'object') return args
|
if (typeof args === 'object') return args
|
||||||
try {
|
try {
|
||||||
return JSON.parse(args)
|
return JSON.parse(args)
|
||||||
} catch (e) {
|
} catch {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@ -29,7 +29,7 @@ const parsedArgs = computed(() => {
|
|||||||
if (typeof args === 'object') return args
|
if (typeof args === 'object') return args
|
||||||
try {
|
try {
|
||||||
return JSON.parse(args)
|
return JSON.parse(args)
|
||||||
} catch (e) {
|
} catch {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@ -27,7 +27,7 @@ const parsedArgs = computed(() => {
|
|||||||
if (typeof args === 'object') return args
|
if (typeof args === 'object') return args
|
||||||
try {
|
try {
|
||||||
return JSON.parse(args)
|
return JSON.parse(args)
|
||||||
} catch (e) {
|
} catch {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@ -85,7 +85,10 @@ const targetPath = computed(() => parsedArgs.value.path || parsedArgs.value.dir_
|
|||||||
const outputMode = computed(() => parsedArgs.value.output_mode || '')
|
const outputMode = computed(() => parsedArgs.value.output_mode || '')
|
||||||
|
|
||||||
const isFileListResult = computed(() => {
|
const isFileListResult = computed(() => {
|
||||||
return Array.isArray(parsedResult.value) && parsedResult.value.every((item) => typeof item === 'string')
|
return (
|
||||||
|
Array.isArray(parsedResult.value) &&
|
||||||
|
parsedResult.value.every((item) => typeof item === 'string')
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
const fileMatches = computed(() => {
|
const fileMatches = computed(() => {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<BaseToolCall :tool-call="toolCall">
|
<BaseToolCall :tool-call="toolCall">
|
||||||
<template #result="{ resultContent }">
|
<template #result="{}">
|
||||||
<div v-if="imageUrl" class="image-result">
|
<div v-if="imageUrl" class="image-result">
|
||||||
<img :src="imageUrl" />
|
<img :src="imageUrl" />
|
||||||
</div>
|
</div>
|
||||||
@ -26,7 +26,7 @@ const parseData = (content) => {
|
|||||||
if (typeof content === 'string') {
|
if (typeof content === 'string') {
|
||||||
try {
|
try {
|
||||||
return JSON.parse(content)
|
return JSON.parse(content)
|
||||||
} catch (error) {
|
} catch {
|
||||||
return content
|
return content
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
<span class="description">{{ query }}</span>
|
<span class="description">{{ query }}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #result="{ resultContent }">
|
<template #result="{}">
|
||||||
<div class="knowledge-graph-result">
|
<div class="knowledge-graph-result">
|
||||||
<div class="result-summary">找到 {{ totalNodes }} 个节点, {{ totalRelations }} 个关系</div>
|
<div class="result-summary">找到 {{ totalNodes }} 个节点, {{ totalRelations }} 个关系</div>
|
||||||
|
|
||||||
@ -40,7 +40,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { computed, ref, watch, nextTick, onMounted, onUpdated } from 'vue'
|
import { computed, ref, watch, nextTick, onMounted, onUpdated } from 'vue'
|
||||||
import BaseToolCall from '../BaseToolCall.vue'
|
import BaseToolCall from '../BaseToolCall.vue'
|
||||||
import { DeploymentUnitOutlined, ReloadOutlined } from '@ant-design/icons-vue'
|
import { ReloadOutlined } from '@ant-design/icons-vue'
|
||||||
import GraphCanvas from '@/components/GraphCanvas.vue'
|
import GraphCanvas from '@/components/GraphCanvas.vue'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@ -54,7 +54,7 @@ const parseData = (content) => {
|
|||||||
if (typeof content === 'string') {
|
if (typeof content === 'string') {
|
||||||
try {
|
try {
|
||||||
return JSON.parse(content)
|
return JSON.parse(content)
|
||||||
} catch (error) {
|
} catch {
|
||||||
return { triples: [] }
|
return { triples: [] }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -73,7 +73,7 @@ const query = computed(() => {
|
|||||||
if (typeof args === 'string') {
|
if (typeof args === 'string') {
|
||||||
try {
|
try {
|
||||||
parsedArgs = JSON.parse(args)
|
parsedArgs = JSON.parse(args)
|
||||||
} catch (e) {
|
} catch {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,7 +31,7 @@ const parsedArgs = computed(() => {
|
|||||||
if (typeof args === 'object') return args
|
if (typeof args === 'object') return args
|
||||||
try {
|
try {
|
||||||
return JSON.parse(args)
|
return JSON.parse(args)
|
||||||
} catch (e) {
|
} catch {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
<span class="note">{{ operationLabel }}</span>
|
<span class="note">{{ operationLabel }}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #result="{ resultContent }">
|
<template #result="{}">
|
||||||
<div class="list-kbs-result">
|
<div class="list-kbs-result">
|
||||||
<div class="kb-count">共 {{ kbList.length }} 个知识库</div>
|
<div class="kb-count">共 {{ kbList.length }} 个知识库</div>
|
||||||
<div class="kb-list">
|
<div class="kb-list">
|
||||||
|
|||||||
@ -20,7 +20,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import BaseToolCall from '../BaseToolCall.vue'
|
import BaseToolCall from '../BaseToolCall.vue'
|
||||||
|
|
||||||
const props = defineProps({
|
defineProps({
|
||||||
toolCall: {
|
toolCall: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import BaseToolCall from '../BaseToolCall.vue'
|
import BaseToolCall from '../BaseToolCall.vue'
|
||||||
|
|
||||||
const props = defineProps({
|
defineProps({
|
||||||
toolCall: {
|
toolCall: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true
|
||||||
|
|||||||
@ -26,7 +26,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import BaseToolCall from '../BaseToolCall.vue'
|
import BaseToolCall from '../BaseToolCall.vue'
|
||||||
|
|
||||||
const props = defineProps({
|
defineProps({
|
||||||
toolCall: {
|
toolCall: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true
|
||||||
|
|||||||
@ -30,7 +30,7 @@ const parsedArgs = computed(() => {
|
|||||||
if (typeof args === 'object') return args
|
if (typeof args === 'object') return args
|
||||||
try {
|
try {
|
||||||
return JSON.parse(args)
|
return JSON.parse(args)
|
||||||
} catch (e) {
|
} catch {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@ -29,7 +29,7 @@ const parsedArgs = computed(() => {
|
|||||||
if (typeof args === 'object') return args
|
if (typeof args === 'object') return args
|
||||||
try {
|
try {
|
||||||
return JSON.parse(args)
|
return JSON.parse(args)
|
||||||
} catch (e) {
|
} catch {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@ -48,7 +48,7 @@ const parsedArgs = computed(() => {
|
|||||||
if (typeof args === 'object') return args
|
if (typeof args === 'object') return args
|
||||||
try {
|
try {
|
||||||
return JSON.parse(args)
|
return JSON.parse(args)
|
||||||
} catch (e) {
|
} catch {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@ -78,7 +78,7 @@ const query = computed(() => {
|
|||||||
if (typeof args === 'string') {
|
if (typeof args === 'string') {
|
||||||
try {
|
try {
|
||||||
parsedArgs = JSON.parse(args)
|
parsedArgs = JSON.parse(args)
|
||||||
} catch (e) {
|
} catch {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -92,7 +92,7 @@ const parseData = (content) => {
|
|||||||
if (typeof content === 'string') {
|
if (typeof content === 'string') {
|
||||||
try {
|
try {
|
||||||
return JSON.parse(content)
|
return JSON.parse(content)
|
||||||
} catch (error) {
|
} catch {
|
||||||
return content
|
return content
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,7 +30,7 @@ const parsedArgs = computed(() => {
|
|||||||
if (typeof args === 'object') return args
|
if (typeof args === 'object') return args
|
||||||
try {
|
try {
|
||||||
return JSON.parse(args)
|
return JSON.parse(args)
|
||||||
} catch (e) {
|
} catch {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@ -184,11 +184,9 @@ import DebugComponent from '@/components/DebugComponent.vue'
|
|||||||
import { message } from 'ant-design-vue'
|
import { message } from 'ant-design-vue'
|
||||||
import {
|
import {
|
||||||
CircleUser,
|
CircleUser,
|
||||||
UserRoundCheck,
|
|
||||||
BookOpen,
|
BookOpen,
|
||||||
Sun,
|
Sun,
|
||||||
Moon,
|
Moon,
|
||||||
User,
|
|
||||||
LogOut,
|
LogOut,
|
||||||
Upload,
|
Upload,
|
||||||
Settings,
|
Settings,
|
||||||
@ -223,7 +221,7 @@ const editedProfile = ref({
|
|||||||
phone_number: ''
|
phone_number: ''
|
||||||
})
|
})
|
||||||
|
|
||||||
const props = defineProps({
|
defineProps({
|
||||||
showRole: {
|
showRole: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
@ -234,12 +232,6 @@ const props = defineProps({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// 用户名首字母(用于显示在头像中)
|
|
||||||
const userInitial = computed(() => {
|
|
||||||
if (!userStore.username) return '?'
|
|
||||||
return userStore.username.charAt(0).toUpperCase()
|
|
||||||
})
|
|
||||||
|
|
||||||
// 用户角色显示文本
|
// 用户角色显示文本
|
||||||
const userRoleText = computed(() => {
|
const userRoleText = computed(() => {
|
||||||
switch (userStore.userRole) {
|
switch (userStore.userRole) {
|
||||||
@ -254,15 +246,6 @@ const userRoleText = computed(() => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// 用户角色徽章样式类
|
|
||||||
const userRoleClass = computed(() => {
|
|
||||||
return {
|
|
||||||
superadmin: userStore.userRole === 'superadmin',
|
|
||||||
admin: userStore.userRole === 'admin',
|
|
||||||
user: userStore.userRole === 'user'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// 退出登录
|
// 退出登录
|
||||||
const logout = () => {
|
const logout = () => {
|
||||||
userStore.logout()
|
userStore.logout()
|
||||||
@ -413,7 +396,7 @@ const handleAvatarChange = async (info) => {
|
|||||||
// 手动处理文件上传
|
// 手动处理文件上传
|
||||||
try {
|
try {
|
||||||
avatarUploading.value = true
|
avatarUploading.value = true
|
||||||
const result = await userStore.uploadAvatar(info.file.originFileObj || info.file)
|
await userStore.uploadAvatar(info.file.originFileObj || info.file)
|
||||||
message.success('头像上传成功!')
|
message.success('头像上传成功!')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('头像上传失败:', error)
|
console.error('头像上传失败:', error)
|
||||||
|
|||||||
@ -536,34 +536,6 @@ const confirmDeleteUser = (user) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 角色显示辅助函数
|
|
||||||
const getRoleLabel = (role) => {
|
|
||||||
switch (role) {
|
|
||||||
case 'superadmin':
|
|
||||||
return '超级管理员'
|
|
||||||
case 'admin':
|
|
||||||
return '管理员'
|
|
||||||
case 'user':
|
|
||||||
return '普通用户'
|
|
||||||
default:
|
|
||||||
return role
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 角色标签颜色
|
|
||||||
const getRoleColor = (role) => {
|
|
||||||
switch (role) {
|
|
||||||
case 'superadmin':
|
|
||||||
return 'red'
|
|
||||||
case 'admin':
|
|
||||||
return 'blue'
|
|
||||||
case 'user':
|
|
||||||
return 'green'
|
|
||||||
default:
|
|
||||||
return 'default'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const getRoleClass = (role) => {
|
const getRoleClass = (role) => {
|
||||||
switch (role) {
|
switch (role) {
|
||||||
case 'superadmin':
|
case 'superadmin':
|
||||||
|
|||||||
@ -220,7 +220,7 @@ const renderCallStatsChart = () => {
|
|||||||
params.forEach((param) => {
|
params.forEach((param) => {
|
||||||
total += param.value
|
total += param.value
|
||||||
const truncatedName = truncateLegend(param.seriesName)
|
const truncatedName = truncateLegend(param.seriesName)
|
||||||
result += `<span style=\"display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${param.color}\"></span>`
|
result += `<span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${param.color}"></span>`
|
||||||
result += `${truncatedName}: ${formatValueForDisplay(param.value)}<br/>`
|
result += `${truncatedName}: ${formatValueForDisplay(param.value)}<br/>`
|
||||||
})
|
})
|
||||||
const labelMap = {
|
const labelMap = {
|
||||||
@ -230,7 +230,7 @@ const renderCallStatsChart = () => {
|
|||||||
tools: '工具调用'
|
tools: '工具调用'
|
||||||
}
|
}
|
||||||
const formattedTotal = formatValueForDisplay(total)
|
const formattedTotal = formatValueForDisplay(total)
|
||||||
return `<div style=\"font-weight:bold;margin-bottom:5px\">${labelMap[callDataType.value]}</div>${result}<strong>总计: ${formattedTotal}</strong>`
|
return `<div style="font-weight:bold;margin-bottom:5px">${labelMap[callDataType.value]}</div>${result}<strong>总计: ${formattedTotal}</strong>`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { ref, computed } from 'vue'
|
import { ref } from 'vue'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} MentionFile
|
* @typedef {Object} MentionFile
|
||||||
|
|||||||
@ -73,7 +73,6 @@ const DEFAULT_OPTIONS = {
|
|||||||
reserveDecayWindowMs: 2200
|
reserveDecayWindowMs: 2200
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const getIncomingSize = (chunk) => {
|
const getIncomingSize = (chunk) => {
|
||||||
let total = 0
|
let total = 0
|
||||||
total += (chunk?.content || '').length
|
total += (chunk?.content || '').length
|
||||||
@ -274,7 +273,10 @@ export function useStreamSmoother({ getThreadState, options = {} }) {
|
|||||||
remaining -= reasoningPart.emitted.length
|
remaining -= reasoningPart.emitted.length
|
||||||
|
|
||||||
const additionalReasoningPart = takeFromBuffer(controller.additionalReasoningBuffer, remaining)
|
const additionalReasoningPart = takeFromBuffer(controller.additionalReasoningBuffer, remaining)
|
||||||
if (additionalReasoningPart.emitted || delta.additional_kwargs?.reasoning_content !== undefined) {
|
if (
|
||||||
|
additionalReasoningPart.emitted ||
|
||||||
|
delta.additional_kwargs?.reasoning_content !== undefined
|
||||||
|
) {
|
||||||
delta.additional_kwargs = {
|
delta.additional_kwargs = {
|
||||||
...(delta.additional_kwargs || {}),
|
...(delta.additional_kwargs || {}),
|
||||||
reasoning_content: additionalReasoningPart.emitted
|
reasoning_content: additionalReasoningPart.emitted
|
||||||
|
|||||||
@ -380,6 +380,7 @@ export const useAgentStore = defineStore(
|
|||||||
* 保存智能体配置
|
* 保存智能体配置
|
||||||
* @param {Object} options - 额外参数 (e.g., { reload_graph: true })
|
* @param {Object} options - 额外参数 (e.g., { reload_graph: true })
|
||||||
*/
|
*/
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
async function saveAgentConfig(options = {}) {
|
async function saveAgentConfig(options = {}) {
|
||||||
const targetAgentId = selectedAgentId.value
|
const targetAgentId = selectedAgentId.value
|
||||||
const targetConfigId = selectedAgentConfigId.value
|
const targetConfigId = selectedAgentConfigId.value
|
||||||
|
|||||||
@ -64,7 +64,7 @@ export const useGraphStore = defineStore('graph', {
|
|||||||
const dynamicIdPattern = /^(.+)-(.+)-(\d+)$/
|
const dynamicIdPattern = /^(.+)-(.+)-(\d+)$/
|
||||||
const match = state.selectedEdge.match(dynamicIdPattern)
|
const match = state.selectedEdge.match(dynamicIdPattern)
|
||||||
if (match) {
|
if (match) {
|
||||||
const [, source, target, index] = match
|
const [, source, target] = match
|
||||||
foundEdge = state.rawGraph.edges.find(
|
foundEdge = state.rawGraph.edges.find(
|
||||||
(edge) => edge.source === source && edge.target === target
|
(edge) => edge.source === source && edge.target === target
|
||||||
)
|
)
|
||||||
|
|||||||
@ -8,7 +8,6 @@ export const useInfoStore = defineStore('info', () => {
|
|||||||
const isLoading = ref(false)
|
const isLoading = ref(false)
|
||||||
const isLoaded = ref(false)
|
const isLoaded = ref(false)
|
||||||
const debugMode = ref(false)
|
const debugMode = ref(false)
|
||||||
const error = ref(null) // 错误信息
|
|
||||||
|
|
||||||
// 计算属性 - 组织信息
|
// 计算属性 - 组织信息
|
||||||
const organization = computed(
|
const organization = computed(
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { ref, watch } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { theme } from 'ant-design-vue'
|
import { theme } from 'ant-design-vue'
|
||||||
|
|
||||||
|
|||||||
@ -138,7 +138,7 @@ export const getStatusText = (status) => {
|
|||||||
processing: '处理中',
|
processing: '处理中',
|
||||||
waiting: '等待处理'
|
waiting: '等待处理'
|
||||||
}
|
}
|
||||||
return map[status] || status
|
return statusMap[status] || status
|
||||||
}
|
}
|
||||||
|
|
||||||
// 格式化文件大小
|
// 格式化文件大小
|
||||||
|
|||||||
@ -18,7 +18,6 @@ export const modelIcons = {
|
|||||||
zhipu: zhipuIcon,
|
zhipu: zhipuIcon,
|
||||||
siliconflow: siliconflowIcon,
|
siliconflow: siliconflowIcon,
|
||||||
ark: arkIcon,
|
ark: arkIcon,
|
||||||
together: togetherIcon,
|
|
||||||
openrouter: openrouterIcon,
|
openrouter: openrouterIcon,
|
||||||
modelscope: modelscopeIcon,
|
modelscope: modelscopeIcon,
|
||||||
minimax: minimaxIcon,
|
minimax: minimaxIcon,
|
||||||
|
|||||||
@ -56,7 +56,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, onMounted, onUnmounted } from 'vue'
|
import { ref, onMounted, onUnmounted } from 'vue'
|
||||||
import { message } from 'ant-design-vue'
|
import { message } from 'ant-design-vue'
|
||||||
import { dashboardApi } from '@/apis/dashboard_api'
|
import { dashboardApi } from '@/apis/dashboard_api'
|
||||||
|
|
||||||
@ -84,7 +84,6 @@ const allStatsData = ref({
|
|||||||
|
|
||||||
// 对话列表
|
// 对话列表
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const loadingDetail = ref(false)
|
|
||||||
|
|
||||||
// 调用统计子组件引用
|
// 调用统计子组件引用
|
||||||
const callStatsRef = ref(null)
|
const callStatsRef = ref(null)
|
||||||
@ -133,9 +132,6 @@ const loadAllStats = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保留原有的loadStats函数以兼容旧代码
|
|
||||||
const loadStats = loadAllStats
|
|
||||||
|
|
||||||
// 打开反馈详情弹窗
|
// 打开反馈详情弹窗
|
||||||
const handleOpenFeedback = () => {
|
const handleOpenFeedback = () => {
|
||||||
feedbackModal.value?.show()
|
feedbackModal.value?.show()
|
||||||
|
|||||||
@ -221,8 +221,7 @@
|
|||||||
{{ getKbTypeLabel(database.kb_type || 'lightrag') }}
|
{{ getKbTypeLabel(database.kb_type || 'lightrag') }}
|
||||||
</a-tag>
|
</a-tag>
|
||||||
<!-- 保留最后一个,使用 / 切分 -->
|
<!-- 保留最后一个,使用 / 切分 -->
|
||||||
<a-tag color="blue" v-if="database.embed_info?.name"
|
<a-tag color="blue" v-if="database.embed_info?.name" :bordered="false">{{
|
||||||
:bordered="false">{{
|
|
||||||
database.embed_info.name.split('/').slice(-1)[0]
|
database.embed_info.name.split('/').slice(-1)[0]
|
||||||
}}</a-tag>
|
}}</a-tag>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -204,12 +204,9 @@ import { useConfigStore } from '@/stores/config'
|
|||||||
import {
|
import {
|
||||||
UploadOutlined,
|
UploadOutlined,
|
||||||
SyncOutlined,
|
SyncOutlined,
|
||||||
GlobalOutlined,
|
|
||||||
InfoCircleOutlined,
|
|
||||||
SearchOutlined,
|
SearchOutlined,
|
||||||
ReloadOutlined,
|
ReloadOutlined,
|
||||||
LoadingOutlined,
|
LoadingOutlined,
|
||||||
HighlightOutlined,
|
|
||||||
DatabaseOutlined,
|
DatabaseOutlined,
|
||||||
ExportOutlined
|
ExportOutlined
|
||||||
} from '@ant-design/icons-vue'
|
} from '@ant-design/icons-vue'
|
||||||
@ -578,10 +575,6 @@ const getAuthHeaders = () => {
|
|||||||
return userStore.getAuthHeaders()
|
return userStore.getAuthHeaders()
|
||||||
}
|
}
|
||||||
|
|
||||||
const openLink = (url) => {
|
|
||||||
window.open(url, '_blank')
|
|
||||||
}
|
|
||||||
|
|
||||||
const getDatabaseName = () => {
|
const getDatabaseName = () => {
|
||||||
const selectedDb = state.dbOptions.find((db) => db.value === state.selectedDbId)
|
const selectedDb = state.dbOptions.find((db) => db.value === state.selectedDbId)
|
||||||
return selectedDb ? selectedDb.label : state.selectedDbId
|
return selectedDb ? selectedDb.label : state.selectedDbId
|
||||||
|
|||||||
@ -253,7 +253,7 @@ const fetchGithubStars = async () => {
|
|||||||
const data = await response.json()
|
const data = await response.json()
|
||||||
const stars = Number(data?.stargazers_count)
|
const stars = Number(data?.stargazers_count)
|
||||||
return Number.isFinite(stars) && stars > 0 ? stars : null
|
return Number.isFinite(stars) && stars > 0 ? stars : null
|
||||||
} catch (e) {
|
} catch {
|
||||||
return null
|
return null
|
||||||
} finally {
|
} finally {
|
||||||
clearTimeout(timer)
|
clearTimeout(timer)
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { defineConfig, loadEnv } from 'vite'
|
|||||||
import vue from '@vitejs/plugin-vue'
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
|
||||||
export default defineConfig(({ mode }) => {
|
export default defineConfig(({ mode }) => {
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
const env = loadEnv(mode, process.cwd(), '')
|
const env = loadEnv(mode, process.cwd(), '')
|
||||||
return {
|
return {
|
||||||
plugins: [vue()],
|
plugins: [vue()],
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user