fix(viewer): 更新下载文件逻辑以处理大文件并返回正确的响应
This commit is contained in:
parent
1d8a5e88af
commit
637981b060
@ -117,7 +117,7 @@ DEFAULT_CHAT_MODEL_PROVIDERS: dict[str, ChatModelProvider] = {
|
||||
),
|
||||
"minimax": ChatModelProvider(
|
||||
name="MiniMax",
|
||||
url="https://platform.minimaxi.com/document/introduction",
|
||||
url="https://platform.minimaxi.com/docs/guides/models-intro",
|
||||
base_url="https://api.minimaxi.com/v1",
|
||||
default="MiniMax-M2.7",
|
||||
env="MINIMAX_API_KEY",
|
||||
|
||||
@ -7,9 +7,9 @@ from pathlib import PurePosixPath
|
||||
from urllib.parse import quote
|
||||
|
||||
from fastapi import HTTPException
|
||||
from fastapi.responses import StreamingResponse
|
||||
from fastapi.responses import FileResponse, StreamingResponse
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from yuxi.agents.backends.sandbox import SKILLS_PATH, USER_DATA_PATH
|
||||
from yuxi.agents.backends.sandbox import SKILLS_PATH, USER_DATA_PATH, resolve_virtual_path
|
||||
from yuxi.agents.backends.skills_backend import SelectedSkillsReadonlyBackend
|
||||
from yuxi.agents.middlewares.skills_middleware import normalize_selected_skills
|
||||
from yuxi.services.filesystem_service import _resolve_filesystem_state
|
||||
@ -199,7 +199,7 @@ async def download_viewer_file(
|
||||
db: AsyncSession,
|
||||
) -> StreamingResponse:
|
||||
normalized_path = _normalize_path(path)
|
||||
sandbox_backend, skills_backend, _selected_skills = await _resolve_viewer_state(
|
||||
_sandbox_backend, skills_backend, _selected_skills = await _resolve_viewer_state(
|
||||
thread_id=thread_id,
|
||||
agent_id=agent_id,
|
||||
agent_config_id=agent_config_id,
|
||||
@ -209,8 +209,20 @@ async def download_viewer_file(
|
||||
|
||||
try:
|
||||
if _is_user_data_path(normalized_path):
|
||||
responses = await asyncio.to_thread(sandbox_backend.download_files, [normalized_path])
|
||||
elif _is_skills_path(normalized_path):
|
||||
actual_path = resolve_virtual_path(thread_id, normalized_path)
|
||||
if not actual_path.exists():
|
||||
raise HTTPException(status_code=404, detail="文件不存在")
|
||||
if not actual_path.is_file():
|
||||
raise HTTPException(status_code=400, detail="当前路径是目录")
|
||||
|
||||
file_name = actual_path.name or "download"
|
||||
media_type = mimetypes.guess_type(file_name)[0] or "application/octet-stream"
|
||||
headers = {
|
||||
"Content-Disposition": f"attachment; filename*=UTF-8''{quote(file_name)}",
|
||||
}
|
||||
return FileResponse(path=actual_path, media_type=media_type, headers=headers)
|
||||
|
||||
if _is_skills_path(normalized_path):
|
||||
responses = await asyncio.to_thread(skills_backend.download_files, [_strip_skills_prefix(normalized_path)])
|
||||
else:
|
||||
raise HTTPException(
|
||||
|
||||
@ -6,6 +6,8 @@ import uuid
|
||||
|
||||
import pytest
|
||||
|
||||
from yuxi.agents.backends.sandbox import ensure_thread_dirs, sandbox_workspace_dir, virtual_path_for_thread_file
|
||||
|
||||
pytestmark = [pytest.mark.asyncio, pytest.mark.integration]
|
||||
|
||||
|
||||
@ -107,3 +109,22 @@ async def test_viewer_download_returns_attachment_response(test_client, standard
|
||||
assert "attachment;" in content_disposition
|
||||
assert "download_demo" in content_disposition
|
||||
assert "download-me" in response.text
|
||||
|
||||
async def test_viewer_download_returns_full_file_for_large_user_data_content(test_client, standard_user):
|
||||
headers = standard_user["headers"]
|
||||
thread_id = await _create_thread_for_user(test_client, headers)
|
||||
large_content = "0123456789abcdef" * 4096
|
||||
|
||||
ensure_thread_dirs(thread_id)
|
||||
actual_path = sandbox_workspace_dir(thread_id) / "large_download.txt"
|
||||
actual_path.write_text(large_content, encoding="utf-8")
|
||||
file_path = virtual_path_for_thread_file(thread_id, actual_path)
|
||||
|
||||
response = await test_client.get(
|
||||
"/api/viewer/filesystem/download",
|
||||
params={"thread_id": thread_id, "path": file_path},
|
||||
headers=headers,
|
||||
)
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.content == large_content.encode("utf-8")
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user