feat(paths): 引入虚拟路径常量,重构路径管理逻辑
This commit is contained in:
parent
3ec8305eab
commit
da6b9691af
@ -4,21 +4,19 @@ import re
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from yuxi import config as conf
|
from yuxi import config as conf
|
||||||
|
from yuxi.utils.paths import (
|
||||||
|
VIRTUAL_PATH_PREFIX,
|
||||||
|
WORKSPACE_DIR_NAME,
|
||||||
|
OUTPUTS_DIR_NAME,
|
||||||
|
UPLOADS_DIR_NAME
|
||||||
|
)
|
||||||
|
|
||||||
DEFAULT_VIRTUAL_PATH_PREFIX = "/home/gem/user-data"
|
|
||||||
VIRTUAL_PATH_PREFIX = DEFAULT_VIRTUAL_PATH_PREFIX
|
|
||||||
_WORKSPACE_DIR_NAME = "workspace"
|
|
||||||
_UPLOADS_DIR_NAME = "uploads"
|
|
||||||
_OUTPUTS_DIR_NAME = "outputs"
|
|
||||||
|
|
||||||
_SAFE_THREAD_ID_RE = re.compile(r"^[A-Za-z0-9_-]+$")
|
_SAFE_THREAD_ID_RE = re.compile(r"^[A-Za-z0-9_-]+$")
|
||||||
|
|
||||||
|
|
||||||
def get_virtual_path_prefix() -> str:
|
def get_virtual_path_prefix() -> str:
|
||||||
configured = str(getattr(conf, "sandbox_virtual_path_prefix", "") or "").strip()
|
return "/" + VIRTUAL_PATH_PREFIX.strip("/")
|
||||||
if not configured:
|
|
||||||
return DEFAULT_VIRTUAL_PATH_PREFIX
|
|
||||||
return "/" + configured.strip("/")
|
|
||||||
|
|
||||||
|
|
||||||
def _validate_thread_id(thread_id: str) -> str:
|
def _validate_thread_id(thread_id: str) -> str:
|
||||||
@ -46,15 +44,15 @@ def sandbox_user_data_dir(thread_id: str) -> Path:
|
|||||||
|
|
||||||
def sandbox_workspace_dir(thread_id: str) -> Path:
|
def sandbox_workspace_dir(thread_id: str) -> Path:
|
||||||
_validate_thread_id(thread_id)
|
_validate_thread_id(thread_id)
|
||||||
return _global_user_data_dir() / _WORKSPACE_DIR_NAME
|
return _global_user_data_dir() / WORKSPACE_DIR_NAME
|
||||||
|
|
||||||
|
|
||||||
def sandbox_uploads_dir(thread_id: str) -> Path:
|
def sandbox_uploads_dir(thread_id: str) -> Path:
|
||||||
return _thread_root_dir(thread_id) / _UPLOADS_DIR_NAME
|
return _thread_root_dir(thread_id) / UPLOADS_DIR_NAME
|
||||||
|
|
||||||
|
|
||||||
def sandbox_outputs_dir(thread_id: str) -> Path:
|
def sandbox_outputs_dir(thread_id: str) -> Path:
|
||||||
return _thread_root_dir(thread_id) / _OUTPUTS_DIR_NAME
|
return _thread_root_dir(thread_id) / OUTPUTS_DIR_NAME
|
||||||
|
|
||||||
|
|
||||||
def ensure_thread_dirs(thread_id: str) -> None:
|
def ensure_thread_dirs(thread_id: str) -> None:
|
||||||
@ -72,16 +70,16 @@ def _resolve_user_data_base_dir(thread_id: str, relative_path: str) -> tuple[Pat
|
|||||||
return base_dir.resolve(), base_dir.resolve()
|
return base_dir.resolve(), base_dir.resolve()
|
||||||
|
|
||||||
namespace = parts[0]
|
namespace = parts[0]
|
||||||
if namespace == _WORKSPACE_DIR_NAME:
|
if namespace == WORKSPACE_DIR_NAME:
|
||||||
# Workspace is shared across threads, so it lives outside the per-thread root.
|
# Workspace is shared across threads, so it lives outside the per-thread root.
|
||||||
base_dir = sandbox_workspace_dir(thread_id)
|
base_dir = sandbox_workspace_dir(thread_id)
|
||||||
target_path = base_dir.joinpath(*parts[1:]) if len(parts) > 1 else base_dir
|
target_path = base_dir.joinpath(*parts[1:]) if len(parts) > 1 else base_dir
|
||||||
return base_dir.resolve(), target_path.resolve()
|
return base_dir.resolve(), target_path.resolve()
|
||||||
if namespace == _UPLOADS_DIR_NAME:
|
if namespace == UPLOADS_DIR_NAME:
|
||||||
base_dir = sandbox_uploads_dir(thread_id)
|
base_dir = sandbox_uploads_dir(thread_id)
|
||||||
target_path = base_dir.joinpath(*parts[1:]) if len(parts) > 1 else base_dir
|
target_path = base_dir.joinpath(*parts[1:]) if len(parts) > 1 else base_dir
|
||||||
return base_dir.resolve(), target_path.resolve()
|
return base_dir.resolve(), target_path.resolve()
|
||||||
if namespace == _OUTPUTS_DIR_NAME:
|
if namespace == OUTPUTS_DIR_NAME:
|
||||||
base_dir = sandbox_outputs_dir(thread_id)
|
base_dir = sandbox_outputs_dir(thread_id)
|
||||||
target_path = base_dir.joinpath(*parts[1:]) if len(parts) > 1 else base_dir
|
target_path = base_dir.joinpath(*parts[1:]) if len(parts) > 1 else base_dir
|
||||||
return base_dir.resolve(), target_path.resolve()
|
return base_dir.resolve(), target_path.resolve()
|
||||||
@ -124,7 +122,7 @@ def virtual_path_for_thread_file(thread_id: str, path: str | Path) -> str:
|
|||||||
else:
|
else:
|
||||||
workspace_relative = relative_path.as_posix()
|
workspace_relative = relative_path.as_posix()
|
||||||
relative_path_str = (
|
relative_path_str = (
|
||||||
_WORKSPACE_DIR_NAME if workspace_relative in {"", "."} else f"{_WORKSPACE_DIR_NAME}/{workspace_relative}"
|
WORKSPACE_DIR_NAME if workspace_relative in {"", "."} else f"{WORKSPACE_DIR_NAME}/{workspace_relative}"
|
||||||
)
|
)
|
||||||
|
|
||||||
prefix = get_virtual_path_prefix().rstrip("/")
|
prefix = get_virtual_path_prefix().rstrip("/")
|
||||||
|
|||||||
@ -1,19 +1,28 @@
|
|||||||
PROMPT = """
|
from yuxi.utils.paths import (
|
||||||
|
VIRTUAL_PATH_PREFIX,
|
||||||
|
VIRTUAL_PATH_WORKSPACE,
|
||||||
|
VIRTUAL_PATH_OUTPUTS,
|
||||||
|
VIRTUAL_PATH_UPLOADS,
|
||||||
|
VIRTUAL_KBS_PATH
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
PROMPT = f"""
|
||||||
你是一个人工智能助手 “语析”,专门用来回答用户的问题。请根据用户提供的信息,尽可能详细地回答问题。
|
你是一个人工智能助手 “语析”,专门用来回答用户的问题。请根据用户提供的信息,尽可能详细地回答问题。
|
||||||
如果你不确定答案,可以说你不知道,但请尽量提供相关的信息或建议。请保持礼貌和专业。
|
如果你不确定答案,可以说你不知道,但请尽量提供相关的信息或建议。请保持礼貌和专业。
|
||||||
|
|
||||||
系统主要工作路径为 /home/gem/user-data/,但必须遵守规范:
|
系统主要工作路径为 {VIRTUAL_PATH_PREFIX},但必须遵守规范:
|
||||||
- /home/gem/user-data/workspace/:用于存放工作文件(用户目录,不要轻易写入)
|
- {VIRTUAL_PATH_WORKSPACE}:用于存放工作文件(用户目录,不要轻易写入)
|
||||||
- /home/gem/user-data/outputs/:用于写入的文件夹
|
- {VIRTUAL_PATH_OUTPUTS}:用于写入的文件夹
|
||||||
- /home/gem/user-data/outputs/tmp/:用于存放中间结果或备份内容
|
- {VIRTUAL_PATH_OUTPUTS}/tmp/:用于存放中间结果或备份内容
|
||||||
- /home/gem/user-data/uploads/:用于存放用户上传的文件
|
- {VIRTUAL_PATH_UPLOADS}:用于存放用户上传的文件
|
||||||
|
|
||||||
非必要不写入其他路径
|
非必要不写入其他路径
|
||||||
|
|
||||||
如果启用了知识库,除了使用知识库工具之外,
|
如果启用了知识库,除了使用知识库工具之外,
|
||||||
当需要精准获取信息的时候,或者 query_kb 中没有找到相关的内容,还可以直接访问知识库文件系统
|
当需要精准获取信息的时候,或者 query_kb 中没有找到相关的内容,还可以直接访问知识库文件系统
|
||||||
(路径为 /home/gem/kbs/)来获取信息。
|
(路径为 {VIRTUAL_KBS_PATH})来获取信息。
|
||||||
源文件可能无法解析,可以在 /home/gem/kbs/<db_name>/parsed/ 中找到解析后的 markdown 文件。
|
源文件可能无法解析,可以在 {VIRTUAL_KBS_PATH}/<db_name>/parsed/ 中找到解析后的 markdown 文件。
|
||||||
|
|
||||||
你需要根据任务的复杂程度来使用 write_todos 来记录规划和待办事项,确保任务的每个步骤都被记录和跟踪。
|
你需要根据任务的复杂程度来使用 write_todos 来记录规划和待办事项,确保任务的每个步骤都被记录和跟踪。
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -1,4 +1,12 @@
|
|||||||
DEEP_PROMPT = """你是一位专家级研究员。你的工作是进行彻底的研究,然后撰写一份精美的报告。
|
from yuxi.utils.paths import (
|
||||||
|
VIRTUAL_PATH_PREFIX,
|
||||||
|
VIRTUAL_PATH_WORKSPACE,
|
||||||
|
VIRTUAL_PATH_OUTPUTS,
|
||||||
|
VIRTUAL_PATH_UPLOADS,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
DEEP_PROMPT = f"""你是一位专家级研究员。你的工作是进行彻底的研究,然后撰写一份精美的报告。
|
||||||
|
|
||||||
你应该做的第一件事是把原始的用户问题写入 `question.txt`,以便你有一个记录。
|
你应该做的第一件事是把原始的用户问题写入 `question.txt`,以便你有一个记录。
|
||||||
|
|
||||||
@ -78,9 +86,9 @@ DEEP_PROMPT = """你是一位专家级研究员。你的工作是进行彻底的
|
|||||||
|
|
||||||
你可以使用一些工具。
|
你可以使用一些工具。
|
||||||
|
|
||||||
允许的写入路径为 /home/gem/user-data/,请将需要保存的文件写入该目录下。
|
系统主要工作路径为 {VIRTUAL_PATH_PREFIX},但必须遵守规范:
|
||||||
推荐使用的路径:
|
- {VIRTUAL_PATH_WORKSPACE}:用于存放工作文件(用户目录,不要轻易写入)
|
||||||
- /home/gem/user-data/workspace/:用于存放工作文件和中间结果
|
- {VIRTUAL_PATH_OUTPUTS}:用于写入的文件夹
|
||||||
- /home/gem/user-data/outputs/:用于存放最终输出结果
|
- {VIRTUAL_PATH_OUTPUTS}/tmp/:用于存放中间结果或备份内容
|
||||||
- /home/gem/user-data/uploads/:用于存放用户上传的文件
|
- {VIRTUAL_PATH_UPLOADS}:用于存放用户上传的文件
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -16,6 +16,7 @@ from yuxi.agents.toolkits.registry import ToolExtraMetadata, _all_tool_instances
|
|||||||
from yuxi.storage.minio import aupload_file_to_minio
|
from yuxi.storage.minio import aupload_file_to_minio
|
||||||
from yuxi.utils import logger
|
from yuxi.utils import logger
|
||||||
from yuxi.utils.question_utils import normalize_questions
|
from yuxi.utils.question_utils import normalize_questions
|
||||||
|
from yuxi.utils.paths import VIRTUAL_PATH_OUTPUTS
|
||||||
|
|
||||||
# Lazy initialization for TavilySearch (only when API key is available)
|
# Lazy initialization for TavilySearch (only when API key is available)
|
||||||
_tavily_search_instance = None
|
_tavily_search_instance = None
|
||||||
@ -67,7 +68,7 @@ class PresentArtifactsInput(BaseModel):
|
|||||||
"""Expose artifact files to the frontend after the agent finishes."""
|
"""Expose artifact files to the frontend after the agent finishes."""
|
||||||
|
|
||||||
filepaths: list[str] = Field(
|
filepaths: list[str] = Field(
|
||||||
description="需要展示给用户的文件绝对路径列表,只允许位于 /home/gem/user-data/outputs/ 下"
|
description=f"需要展示给用户的文件绝对路径列表,只允许位于 {VIRTUAL_PATH_OUTPUTS} 下"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -130,16 +131,16 @@ def calculator(a: float, b: float, operation: str) -> float:
|
|||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
PRESENT_ARTIFACTS_DESCRIPTION = """
|
PRESENT_ARTIFACTS_DESCRIPTION = f"""
|
||||||
将已经生成好的结果文件展示给用户。
|
将已经生成好的结果文件展示给用户。
|
||||||
|
|
||||||
使用场景:
|
使用场景:
|
||||||
1. 你已经在 `/home/gem/user-data/outputs/` 下写好了最终结果文件
|
1. 你已经在 `{VIRTUAL_PATH_OUTPUTS}` 下写好了最终结果文件
|
||||||
2. 你希望前端在对话结束后显示这些结果文件卡片
|
2. 你希望前端在对话结束后显示这些结果文件卡片
|
||||||
3. 这些文件需要支持下载或预览
|
3. 这些文件需要支持下载或预览
|
||||||
|
|
||||||
注意事项:
|
注意事项:
|
||||||
1. 只能传入 `/home/gem/user-data/outputs/` 下的文件
|
1. 只能传入 `{VIRTUAL_PATH_OUTPUTS}` 下的文件
|
||||||
2. 不要传入中间过程文件,只有真正需要给用户看的结果文件才调用
|
2. 不要传入中间过程文件,只有真正需要给用户看的结果文件才调用
|
||||||
3. 可以一次传多个文件
|
3. 可以一次传多个文件
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -13,12 +13,14 @@ 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
|
||||||
|
from yuxi.utils.paths import VIRTUAL_PATH_UPLOADS
|
||||||
|
|
||||||
UPLOADS_VIRTUAL_PREFIX = "/home/gem/user-data/uploads"
|
ATTACHMENT_ALLOWED_EXTENSIONS: tuple[str, ...] = ()
|
||||||
|
MAX_ATTACHMENT_SIZE_BYTES = 5 * 1024 * 1024 # 5 MB
|
||||||
MAX_ATTACHMENT_MARKDOWN_CHARS = 32_000
|
MAX_ATTACHMENT_MARKDOWN_CHARS = 32_000
|
||||||
|
MAX_ATTACHMENT_MARKDOWN_CHARS = 32_000 # TODO: 转 MARKDOWN的时候,不应该裁剪
|
||||||
|
|
||||||
|
|
||||||
@dataclass(slots=True)
|
@dataclass(slots=True)
|
||||||
@ -107,7 +109,7 @@ async def require_user_conversation(conv_repo: ConversationRepository, thread_id
|
|||||||
|
|
||||||
def _make_upload_virtual_path(file_name: str) -> str:
|
def _make_upload_virtual_path(file_name: str) -> str:
|
||||||
safe_name = file_name.replace("/", "_").replace("\\", "_").strip(" .")
|
safe_name = file_name.replace("/", "_").replace("\\", "_").strip(" .")
|
||||||
return f"{UPLOADS_VIRTUAL_PREFIX}/{safe_name or 'attachment.bin'}"
|
return f"{VIRTUAL_PATH_UPLOADS}/{safe_name or 'attachment.bin'}"
|
||||||
|
|
||||||
|
|
||||||
def _make_attachment_path(file_name: str) -> str:
|
def _make_attachment_path(file_name: str) -> str:
|
||||||
@ -127,7 +129,7 @@ def _make_attachment_path(file_name: str) -> str:
|
|||||||
def _build_attachment_storage_path(*, user_id: str, thread_id: str, file_name: str) -> tuple[str, Path]:
|
def _build_attachment_storage_path(*, user_id: str, thread_id: str, file_name: str) -> tuple[str, Path]:
|
||||||
"""返回附件虚拟路径和宿主机落盘路径。"""
|
"""返回附件虚拟路径和宿主机落盘路径。"""
|
||||||
relative_name = _make_attachment_path(file_name)
|
relative_name = _make_attachment_path(file_name)
|
||||||
virtual_path = f"/home/gem/user-data/uploads/attachments/{relative_name}"
|
virtual_path = f"{VIRTUAL_PATH_UPLOADS}/attachments/{relative_name}"
|
||||||
|
|
||||||
host_dir = Path(app_config.save_dir) / "threads" / thread_id / "user-data" / "uploads" / "attachments"
|
host_dir = Path(app_config.save_dir) / "threads" / thread_id / "user-data" / "uploads" / "attachments"
|
||||||
host_dir.mkdir(parents=True, exist_ok=True)
|
host_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|||||||
@ -1,94 +0,0 @@
|
|||||||
"""Helpers for converting uploaded documents into markdown snippets."""
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import uuid
|
|
||||||
from dataclasses import dataclass
|
|
||||||
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
|
|
||||||
|
|
||||||
ATTACHMENT_ALLOWED_EXTENSIONS: tuple[str, ...] = ()
|
|
||||||
MAX_ATTACHMENT_SIZE_BYTES = 5 * 1024 * 1024 # 5 MB
|
|
||||||
MAX_ATTACHMENT_MARKDOWN_CHARS = 32_000
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass(slots=True)
|
|
||||||
class ConversionResult:
|
|
||||||
"""Represents the normalized output of an uploaded attachment."""
|
|
||||||
|
|
||||||
file_id: str
|
|
||||||
file_name: str
|
|
||||||
file_type: str | None
|
|
||||||
file_size: int
|
|
||||||
markdown: str
|
|
||||||
truncated: bool
|
|
||||||
|
|
||||||
|
|
||||||
def _ensure_workdir() -> Path:
|
|
||||||
workdir = Path(app_config.save_dir) / "uploads" / "chat_attachments"
|
|
||||||
workdir.mkdir(parents=True, exist_ok=True)
|
|
||||||
return workdir
|
|
||||||
|
|
||||||
|
|
||||||
async def _write_upload_to_disk(upload: UploadFile, dest: Path) -> int:
|
|
||||||
await upload.seek(0)
|
|
||||||
written = 0
|
|
||||||
chunk_size = 1024 * 1024
|
|
||||||
|
|
||||||
async with aiofiles.open(dest, "wb") as buffer:
|
|
||||||
while True:
|
|
||||||
chunk = await upload.read(chunk_size)
|
|
||||||
if not chunk:
|
|
||||||
break
|
|
||||||
written += len(chunk)
|
|
||||||
if written > MAX_ATTACHMENT_SIZE_BYTES:
|
|
||||||
raise ValueError("附件过大,当前仅支持 5 MB 以内的文件")
|
|
||||||
await buffer.write(chunk)
|
|
||||||
|
|
||||||
return written
|
|
||||||
|
|
||||||
|
|
||||||
def _truncate_markdown(markdown: str) -> tuple[str, bool]:
|
|
||||||
if len(markdown) <= MAX_ATTACHMENT_MARKDOWN_CHARS:
|
|
||||||
return markdown, False
|
|
||||||
|
|
||||||
truncated_content = markdown[: MAX_ATTACHMENT_MARKDOWN_CHARS - 100].rstrip()
|
|
||||||
truncated_content = f"{truncated_content}\n\n[内容已截断,超出 {MAX_ATTACHMENT_MARKDOWN_CHARS} 字符限制]"
|
|
||||||
return truncated_content, True
|
|
||||||
|
|
||||||
|
|
||||||
async def convert_upload_to_markdown(upload: UploadFile) -> ConversionResult:
|
|
||||||
"""Persist an UploadFile temporarily, convert it to markdown, and clean up."""
|
|
||||||
if not upload.filename:
|
|
||||||
raise ValueError("无法识别的文件名")
|
|
||||||
|
|
||||||
file_name = Path(upload.filename).name
|
|
||||||
suffix = Path(file_name).suffix.lower()
|
|
||||||
|
|
||||||
if ATTACHMENT_ALLOWED_EXTENSIONS and suffix not in ATTACHMENT_ALLOWED_EXTENSIONS:
|
|
||||||
allowed = ", ".join(ATTACHMENT_ALLOWED_EXTENSIONS)
|
|
||||||
raise ValueError(f"不支持的文件类型: {suffix or '未知'},当前仅支持 {allowed}")
|
|
||||||
|
|
||||||
temp_dir = _ensure_workdir()
|
|
||||||
temp_path = temp_dir / f"{uuid.uuid4().hex}{suffix}"
|
|
||||||
|
|
||||||
try:
|
|
||||||
file_size = await _write_upload_to_disk(upload, temp_path)
|
|
||||||
markdown = await Parser.aparse(str(temp_path))
|
|
||||||
markdown, truncated = _truncate_markdown(markdown)
|
|
||||||
return ConversionResult(
|
|
||||||
file_id=uuid.uuid4().hex,
|
|
||||||
file_name=file_name,
|
|
||||||
file_type=upload.content_type,
|
|
||||||
file_size=file_size,
|
|
||||||
markdown=markdown,
|
|
||||||
truncated=truncated,
|
|
||||||
)
|
|
||||||
except Exception as exc: # noqa: BLE001
|
|
||||||
logger.error("Attachment conversion failed: %s", exc)
|
|
||||||
raise
|
|
||||||
25
backend/package/yuxi/utils/paths.py
Normal file
25
backend/package/yuxi/utils/paths.py
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
from yuxi import config
|
||||||
|
|
||||||
|
VIRTUAL_PATH_PREFIX = config.sandbox_virtual_path_prefix
|
||||||
|
WORKSPACE_DIR_NAME = "workspace"
|
||||||
|
UPLOADS_DIR_NAME = "uploads"
|
||||||
|
OUTPUTS_DIR_NAME = "outputs"
|
||||||
|
VIRTUAL_SKILLS_PATH = "/home/gem/skills"
|
||||||
|
VIRTUAL_KBS_PATH = "/home/gem/kbs"
|
||||||
|
|
||||||
|
VIRTUAL_PATH_WORKSPACE = (Path(VIRTUAL_PATH_PREFIX) / WORKSPACE_DIR_NAME).as_posix()
|
||||||
|
VIRTUAL_PATH_UPLOADS = (Path(VIRTUAL_PATH_PREFIX) / UPLOADS_DIR_NAME).as_posix()
|
||||||
|
VIRTUAL_PATH_OUTPUTS = (Path(VIRTUAL_PATH_PREFIX) / OUTPUTS_DIR_NAME).as_posix()
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"VIRTUAL_PATH_PREFIX",
|
||||||
|
"WORKSPACE_DIR_NAME",
|
||||||
|
"UPLOADS_DIR_NAME",
|
||||||
|
"OUTPUTS_DIR_NAME",
|
||||||
|
"VIRTUAL_PATH_WORKSPACE",
|
||||||
|
"VIRTUAL_PATH_UPLOADS",
|
||||||
|
"VIRTUAL_PATH_OUTPUTS",
|
||||||
|
"VIRTUAL_SKILLS_PATH",
|
||||||
|
"VIRTUAL_KBS_PATH",
|
||||||
|
]
|
||||||
@ -43,6 +43,7 @@ from yuxi.services.feedback_service import get_message_feedback_view, submit_mes
|
|||||||
from yuxi.repositories.agent_config_repository import AgentConfigRepository
|
from yuxi.repositories.agent_config_repository import AgentConfigRepository
|
||||||
from yuxi.utils.logging_config import logger
|
from yuxi.utils.logging_config import logger
|
||||||
from yuxi.utils.image_processor import process_uploaded_image
|
from yuxi.utils.image_processor import process_uploaded_image
|
||||||
|
from yuxi.utils.paths import VIRTUAL_PATH_PREFIX
|
||||||
|
|
||||||
|
|
||||||
# TODO:当前文件的功能过于庞杂,路由标签混乱
|
# TODO:当前文件的功能过于庞杂,路由标签混乱
|
||||||
@ -817,7 +818,7 @@ async def delete_thread_attachment(
|
|||||||
@chat.get("/thread/{thread_id}/files", response_model=ThreadFileListResponse)
|
@chat.get("/thread/{thread_id}/files", response_model=ThreadFileListResponse)
|
||||||
async def list_thread_files(
|
async def list_thread_files(
|
||||||
thread_id: str,
|
thread_id: str,
|
||||||
path: str = Query("/home/gem/user-data"),
|
path: str = Query(f"{VIRTUAL_PATH_PREFIX}"),
|
||||||
recursive: bool = Query(False),
|
recursive: bool = Query(False),
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_db),
|
||||||
current_user: User = Depends(get_required_user),
|
current_user: User = Depends(get_required_user),
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user