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