Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
113 commits
Select commit Hold shift + click to select a range
cb83813
✨ Enhance error handling and messaging for model operations: Added ne…
Zhi-a Mar 4, 2026
516cc95
implement DashScope and TokenPony model providers
wadecrack Mar 3, 2026
463ebd5
New Requirement: Support for provider Zhipu AI Models (LLM and Embedd…
wadecrack Mar 4, 2026
eb12b0a
New Requirement: Support for provider dashscope and tokenpony Models …
wadecrack Mar 4, 2026
36b8be9
bug fix : embedding model max_tokens changes
wadecrack Mar 5, 2026
3470662
bug fix : embedding model max_tokens changes
wadecrack Mar 5, 2026
fb16d93
create test files for the backend providers
wadecrack Mar 5, 2026
941cac2
bugfix for test files of the backend providers
wadecrack Mar 5, 2026
96a1c5b
Merge branch 'develop' into develop-xq-260225
wadecrack Mar 5, 2026
9580a2d
Merge branch 'xq/develop_models_providers' of https://github.com/Mode…
wadecrack Mar 5, 2026
7b12f12
Refactor: Source the default available model from configuration, not …
xuyaqist Mar 6, 2026
147d61f
Bugfix: Stop directly modifying agent-tool when toggling tool selections
xuyaqist Mar 6, 2026
f3ed9a3
Bugfix: Always recalculate hasUnsavedChanges to fix false positive di…
xuyaqist Mar 6, 2026
60036e7
Bugfix: Refactor tool config save logic and fix array parameter compa…
xuyaqist Mar 6, 2026
c1fc826
Bugfix: reset when user enter /agent page
xuyaqist Mar 6, 2026
a8cbe49
Update opensource-memorial-wall.md
huminghe Mar 6, 2026
ec13753
✨File preview: Add file preview backend service
Stockton11 Mar 6, 2026
57a24a4
improve codecov for testfiles
wadecrack Mar 6, 2026
00854ca
implement DashScope and TokenPony model providers
wadecrack Mar 3, 2026
97bcb3b
New Requirement: Support for provider Zhipu AI Models (LLM and Embedd…
wadecrack Mar 4, 2026
a552e12
New Requirement: Support for provider dashscope and tokenpony Models …
wadecrack Mar 4, 2026
e21157d
bug fix : embedding model max_tokens changes
wadecrack Mar 5, 2026
b70e45c
bug fix : embedding model max_tokens changes
wadecrack Mar 5, 2026
2f3af41
create test files for the backend providers
wadecrack Mar 5, 2026
0515bd3
bugfix for test files of the backend providers
wadecrack Mar 5, 2026
74e3c1a
improve codecov for testfiles
wadecrack Mar 6, 2026
019a15c
Merge remote-tracking branch 'upstream/xq/develop_models_providers' i…
wadecrack Mar 6, 2026
064552f
Increase patch coverage
Stockton11 Mar 6, 2026
e4d4d97
fix issues and update tests
Stockton11 Mar 6, 2026
18ddb91
add test for existing lock
Stockton11 Mar 6, 2026
d0651a8
Add tip section for GZX with gratitude message
CHGZX Mar 8, 2026
4a502e1
Merge branch 'develop' of https://github.com/ModelEngine-Group/nexent…
Zhi-a Mar 9, 2026
2dbc9bb
✨ Update exception handling in tests: Change expected error codes to …
Zhi-a Mar 9, 2026
5909e4f
Delete install of LibreOffice
Stockton11 Mar 9, 2026
6572f3b
✨ implemetion of providers Dashscope and Tokenpony
WMC001 Mar 9, 2026
622f318
✨ Enhance test configurations: Add language support, message roles, a…
Zhi-a Mar 9, 2026
da4b453
Update opensource-memorial-wall.md
fenghuaof2011 Mar 9, 2026
92444cd
Unify tavily search's record starting index as 1
SimengBian Mar 9, 2026
e7c6fe1
✨File preview: Add file preview backend service
WMC001 Mar 9, 2026
866ffce
🐛 Bugfix: Fixed an issue where starting a container resulted in an un…
YehongPan Mar 9, 2026
b598956
🐛 Bugfix: Fixed the issue of suadmin account not being generated in i…
YehongPan Mar 9, 2026
0ef721e
Unify model list logic to show only availiable LLMs
SimengBian Mar 9, 2026
edef55f
🐛 Bugfix: Fix the issue where MCP services with the same tool cannot …
YehongPan Mar 10, 2026
9481891
🐛 Bugfix: Fix the issue where MCP services with the same tool cannot …
YehongPan Mar 10, 2026
b98d6fa
Bugfix: cookie need to be send evne through http
xuyaqist Mar 10, 2026
38339d5
🐛 Bugfix: Failed to modify Tenant Name
WMC001 Mar 10, 2026
f858d33
🐛 Bugfix: Failed to modify Tenant Name 2
WMC001 Mar 10, 2026
10577d7
🐛 Bugfix: Unify model list logic to show only available LLMs
WMC001 Mar 10, 2026
b61dfac
🐛 Bugfix: cookie need to be send evne through http
WMC001 Mar 10, 2026
5cb3508
🐛 Bugfix: Fixed an issue where starting a container resulted in an un…
WMC001 Mar 10, 2026
b6c75a3
🐛 Bugfix: Fix the issue where MCP services with the same tool cannot …
WMC001 Mar 10, 2026
452415e
🐛 Bugfix: Failed to modify Tenant Name
WMC001 Mar 10, 2026
72716cb
Merge pull request #2655 from ModelEngine-Group/pyh/feat_suadmin_crea…
WMC001 Mar 10, 2026
06cfeb4
🐛 Bugfix: False Success Prompt When Model Shows Green But Disconnected
WMC001 Mar 10, 2026
eabd2a3
Merge branch 'develop' into xyq/bugfix_frontend
xuyaqist Mar 10, 2026
bb1e8ae
Update opensource-memorial-wall.md from huminghe/patch-1
WMC001 Mar 10, 2026
84b72fd
Merge branch 'develop' into patch-1
WMC001 Mar 10, 2026
accbc2b
Add tip section for GZX with gratitude message from CHGZX/patch-1
WMC001 Mar 10, 2026
2503cde
Merge branch 'develop' into patch-1
WMC001 Mar 10, 2026
12d1eb9
Update opensource-memorial-wall.md from fenghuaof2011/patch-1
WMC001 Mar 10, 2026
bcbee5e
🐛 Bugfix: Stop directly modifying agent-tool when toggling tool selec…
WMC001 Mar 10, 2026
24e32d8
🐛 Bugfix: Solving the problem of duplicate tool instances in intellig…
YehongPan Mar 10, 2026
b7ef52c
✨ Add access key in user profile page
Jasonxia007 Mar 10, 2026
0d08718
Merge remote-tracking branch 'refs/remotes/origin/develop' into xyc/n…
Jasonxia007 Mar 10, 2026
17719c3
🐛 Bugfix: Solving the problem of duplicate tool instances in intellig…
YehongPan Mar 10, 2026
dea344b
🐛 Bugfix: Solving the problem of duplicate tool instances in intellig…
WMC001 Mar 10, 2026
2f5af7e
Update opensource-memorial-wall.md
ichigo-ichie27 Mar 10, 2026
4e794fe
Bugfix: the title of teanant resource management is not flex-start
xuyaqist Mar 10, 2026
df132c1
✨ Enhance Debugging Experience: Implement caching for debug errors an…
Zhi-a Mar 10, 2026
b33d608
Bugfix: the title of teanant resource management is not flex-start
xuyaqist Mar 10, 2026
2430dac
Bugfix: Enhance homepage layout and styling for better adaptation to …
xuyaqist Mar 10, 2026
1f7015b
Bugfix: Fix responsive issues on small screens
xuyaqist Mar 10, 2026
79f2b93
Merge branch 'xyq/bugfix_frontend' of https://github.com/ModelEngine-…
xuyaqist Mar 10, 2026
dcb6503
Bugfix: make auth prompt modal open in full version
xuyaqist Mar 10, 2026
174b0b0
Add test case
SimengBian Mar 10, 2026
58ca3fe
✨ Feature: idata search tool development #2666
YehongPan Mar 11, 2026
1313abc
🐛 Bugfix: app config icon not refreshed
Jasonxia007 Mar 11, 2026
04400ed
✨ Feature: idata search tool development #2666
YehongPan Mar 11, 2026
3326a3b
✨ Feature: idata search tool development #2666
YehongPan Mar 11, 2026
2b895ca
📝 Document Updated: Installation Process Optimized
WMC001 Mar 11, 2026
6105d32
🐛 Bugfix: northbound log failed
Jasonxia007 Mar 11, 2026
5601a91
🐛 Bugfix: Unify all search tool's record index starting from 1
WMC001 Mar 12, 2026
9119ead
✨ Feature: idata search tool development #2666
WMC001 Mar 12, 2026
99b99f1
✨ Enhance Debugging Experience: Implement caching for debug errors an…
WMC001 Mar 12, 2026
93f2297
🐛 Bugfix: the title of teanant resource management is not flex-start
WMC001 Mar 12, 2026
70c438b
🧪 Update unit tests
Jasonxia007 Mar 12, 2026
7f6879c
🐛 Bugfix: autologin when create new admin on tenant management page
Jasonxia007 Mar 12, 2026
71d94c7
Update opensource-memorial-wall.md from ichigo-ichie27/patch-1
WMC001 Mar 12, 2026
3c6a9ec
🐛 Bugfix: Cannot select user groups when suggesting private permissio…
Jasonxia007 Mar 12, 2026
8fb4a76
Delete unused code
xuyaqist Mar 5, 2026
d0030b6
solve conflict
xuyaqist Mar 12, 2026
b02a82d
Refactor: Redesign left sidebar with responsive collapse
xuyaqist Mar 10, 2026
e528716
Bugfix: Fix background color of root container to white
xuyaqist Mar 11, 2026
0ab6107
resolve conflict
xuyaqist Mar 12, 2026
b2a7cc6
♻️ Refactor: redesign left sidebar with responsive collapse
WMC001 Mar 12, 2026
cbb4c1c
🐛 Bugfix: On the knowledge base page, when a knowledge base is select…
Jasonxia007 Mar 12, 2026
82ebcde
🐛 Bugfix: Fix the issue that the Q&A results show the thinking proces…
YehongPan Mar 12, 2026
ad095ae
Improvement: On each SSE chunk, only the currently streaming assistan…
xuyaqist Mar 12, 2026
7a51074
🐛 Bugfix: Fix the issue that the Q&A results show the thinking process
WMC001 Mar 12, 2026
8406efb
♻️ Improvement: On each SSE chunk, only the currently streaming assis…
WMC001 Mar 12, 2026
b8ce553
🐛 Bugfix: On the knowledge base page, when a knowledge base is select…
Jasonxia007 Mar 12, 2026
c0880b3
♻️ Rename sql to v1.8.1
Jasonxia007 Mar 12, 2026
7bebfbe
Merge pull request #2675 from ModelEngine-Group/xyc/bugfix-1803
WMC001 Mar 12, 2026
6081712
✨ Add access key in user profile page
Jasonxia007 Mar 12, 2026
58303bf
🐛 Bugfix: After creating a new tenant in tenant config page, the sess…
Jasonxia007 Mar 12, 2026
73064d7
♻️ Improvement: When selecting a tool with the same name, a prompt sh…
YehongPan Mar 13, 2026
4ae4519
🐛 Bugfix: After creating a new tenant in tenant config page, the sess…
WMC001 Mar 13, 2026
efe6486
♻️ Improvement: When selecting a tool with the same name, a prompt sh…
WMC001 Mar 13, 2026
98b8927
Bugfix: Ensure "more" button is visible only during hover
xuyaqist Mar 13, 2026
e3181db
Bugfix: Ensure "more" button is visible only during hover
WMC001 Mar 13, 2026
4754afb
Update APP_VERSION to v1.8.1
WMC001 Mar 13, 2026
2f19f91
Bugfix: Optimize title editing styles and implement error tip when re…
xuyaqist Mar 13, 2026
7ca3790
♻️ Bugfix: Optimize title editing styles and implement error tip when…
WMC001 Mar 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions backend/apps/config_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from apps.datamate_app import router as datamate_router
from apps.vectordatabase_app import router as vectordatabase_router
from apps.dify_app import router as dify_router
from apps.idata_app import router as idata_router
from apps.file_management_app import file_management_config_router as file_manager_router
from apps.image_app import router as proxy_router
from apps.knowledge_summary_app import router as summary_router
Expand Down Expand Up @@ -39,6 +40,7 @@
app.include_router(proxy_router)
app.include_router(tool_config_router)
app.include_router(dify_router)
app.include_router(idata_router)

# Choose user management router based on IS_SPEED_MODE
if IS_SPEED_MODE:
Expand Down
33 changes: 33 additions & 0 deletions backend/apps/data_process_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
ConvertStateRequest,
TaskRequest,
)
from consts.exceptions import OfficeConversionException
from data_process.tasks import process_and_forward, process_sync
from services.data_process_service import get_data_process_service

Expand Down Expand Up @@ -311,3 +312,35 @@ async def convert_state(request: ConvertStateRequest):
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
detail=f"Error converting state: {str(e)}"
)


@router.post("/convert_to_pdf")
async def convert_office_to_pdf(
object_name: str = Form(...),
pdf_object_name: str = Form(...)
):
"""
Convert an Office document stored in MinIO to PDF.

Parameters:
object_name: Source Office file path in MinIO
pdf_object_name: Destination PDF path in MinIO
"""
try:
await service.convert_office_to_pdf_impl(
object_name=object_name,
pdf_object_name=pdf_object_name,
)
return JSONResponse(status_code=HTTPStatus.OK, content={"success": True})
except OfficeConversionException as exc:
logger.error(f"Office conversion failed for '{object_name}': {exc}")
raise HTTPException(
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
detail=str(exc)
)
except Exception as exc:
logger.error(f"Unexpected error during conversion for '{object_name}': {exc}")
raise HTTPException(
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
detail=f"Office conversion failed: {exc}"
)
85 changes: 79 additions & 6 deletions backend/apps/file_management_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,29 @@
from fastapi import APIRouter, Body, File, Form, Header, HTTPException, Path as PathParam, Query, UploadFile
from fastapi.responses import JSONResponse, RedirectResponse, StreamingResponse

from consts.exceptions import FileTooLargeException, NotFoundException, OfficeConversionException, UnsupportedFileTypeException
from consts.model import ProcessParams
from services.file_management_service import upload_to_minio, upload_files_impl, \
get_file_url_impl, get_file_stream_impl, delete_file_impl, list_files_impl
get_file_url_impl, get_file_stream_impl, delete_file_impl, list_files_impl, \
preview_file_impl
from utils.file_management_utils import trigger_data_process

logger = logging.getLogger("file_management_app")


def build_content_disposition_header(filename: Optional[str]) -> str:
def build_content_disposition_header(filename: Optional[str], inline: bool = False) -> str:
"""
Build a Content-Disposition header that keeps the original filename.

Args:
filename: Original filename to include in header
inline: If True, use 'inline' disposition (for preview); otherwise 'attachment' (for download)

- ASCII filenames are returned directly.
- Non-ASCII filenames include both an ASCII fallback and RFC 5987 encoded value
so modern browsers keep the original name.
"""
disposition = "inline" if inline else "attachment"
safe_name = (filename or "download").strip() or "download"

def _sanitize_ascii(value: str) -> str:
Expand All @@ -40,26 +47,26 @@ def _sanitize_ascii(value: str) -> str:

try:
safe_name.encode("ascii")
return f'attachment; filename="{_sanitize_ascii(safe_name)}"'
return f'{disposition}; filename="{_sanitize_ascii(safe_name)}"'
except UnicodeEncodeError:
try:
encoded = quote(safe_name, safe="")
except Exception:
# quote failure, fallback to sanitized ASCII only
logger.warning("Failed to encode filename '%s', using fallback", safe_name)
return f'attachment; filename="{_sanitize_ascii(safe_name)}"'
return f'{disposition}; filename="{_sanitize_ascii(safe_name)}"'

fallback = _sanitize_ascii(
safe_name.encode("ascii", "ignore").decode("ascii") or "download"
)
return f'attachment; filename="{fallback}"; filename*=UTF-8\'\'{encoded}'
return f'{disposition}; filename="{fallback}"; filename*=UTF-8\'\'{encoded}'
except Exception as exc: # pragma: no cover
logger.warning(
"Failed to encode filename '%s': %s. Using fallback.",
safe_name,
exc,
)
return 'attachment; filename="download"'
return f'{disposition}; filename="download"'

# Create API router
file_management_runtime_router = APIRouter(prefix="/file")
Expand Down Expand Up @@ -567,3 +574,69 @@ async def get_storage_file_batch_urls(
"failed_count": sum(1 for r in results if not r.get("success", False)),
"results": results
}

@file_management_config_router.get("/preview/{object_name:path}")
async def preview_file(
object_name: str = PathParam(..., description="File object name to preview"),
filename: Optional[str] = Query(None, description="Original filename for display (optional)")
):
"""
Preview file inline in browser

- **object_name**: File object name in storage
- **filename**: Original filename for Content-Disposition header (optional)

Returns file stream with Content-Disposition: inline for browser preview
"""
try:
# Get file stream from preview service
file_stream, content_type = await preview_file_impl(object_name=object_name)

# Use provided filename or extract from object_name
display_filename = filename
if not display_filename:
display_filename = object_name.split("/")[-1] if "/" in object_name else object_name

# Build Content-Disposition header for inline display
content_disposition = build_content_disposition_header(display_filename, inline=True)

return StreamingResponse(
file_stream,
media_type=content_type,
headers={
"Content-Disposition": content_disposition,
"Cache-Control": "public, max-age=3600",
"ETag": f'"{object_name}"',
}
)

except FileTooLargeException as e:
logger.warning(f"[preview_file] File too large: object_name={object_name}, error={str(e)}")
raise HTTPException(
status_code=HTTPStatus.REQUEST_ENTITY_TOO_LARGE,
detail=str(e)
)
except NotFoundException as e:
logger.error(f"[preview_file] File not found: object_name={object_name}, error={str(e)}")
raise HTTPException(
status_code=HTTPStatus.NOT_FOUND,
detail=f"File not found: {object_name}"
)
except UnsupportedFileTypeException as e:
logger.error(f"[preview_file] Unsupported file type: object_name={object_name}, error={str(e)}")
raise HTTPException(
status_code=HTTPStatus.BAD_REQUEST,
detail=f"File format not supported for preview: {str(e)}"
)
except OfficeConversionException as e:
logger.error(f"[preview_file] Conversion failed: object_name={object_name}, error={str(e)}")
raise HTTPException(
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
detail=f"Failed to preview file: {str(e)}"
)
except Exception as e:
logger.error(f"[preview_file] Unexpected error: object_name={object_name}, error={str(e)}")
raise HTTPException(
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
detail=f"Failed to preview file: {str(e)}"
)
109 changes: 109 additions & 0 deletions backend/apps/idata_app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
"""
iData App Layer
FastAPI endpoints for iData knowledge space operations.

This module provides API endpoints to interact with iData's API,
including fetching knowledge spaces and transforming responses to a format
compatible with the frontend.
"""
import logging
from http import HTTPStatus

from fastapi import APIRouter, Query
from fastapi.responses import JSONResponse

from consts.error_code import ErrorCode
from consts.exceptions import AppException
from services.idata_service import (
fetch_idata_knowledge_spaces_impl,
fetch_idata_datasets_impl,
)

router = APIRouter(prefix="/idata")
logger = logging.getLogger("idata_app")


@router.get("/knowledge-space")
async def fetch_idata_knowledge_spaces_api(
idata_api_base: str = Query(..., description="iData API base URL"),
api_key: str = Query(..., description="iData API key"),
user_id: str = Query(..., description="iData user ID"),
):
"""
Fetch knowledge spaces from iData API.

Returns knowledge spaces in a format with id and name for frontend compatibility.
"""
try:
# Normalize URL by removing trailing slash
idata_api_base = idata_api_base.rstrip('/')
except Exception as e:
logger.error(f"Invalid iData configuration: {e}")
raise AppException(
ErrorCode.IDATA_CONFIG_INVALID,
f"Invalid URL format: {str(e)}"
)

try:
result = fetch_idata_knowledge_spaces_impl(
idata_api_base=idata_api_base,
api_key=api_key,
user_id=user_id,
)
return JSONResponse(
status_code=HTTPStatus.OK,
content=result
)
except AppException:
# Re-raise AppException to be handled by global middleware
raise
except Exception as e:
logger.error(f"Failed to fetch iData knowledge spaces: {e}")
raise AppException(
ErrorCode.IDATA_SERVICE_ERROR,
f"Failed to fetch iData knowledge spaces: {str(e)}"
)


@router.get("/datasets")
async def fetch_idata_datasets_api(
idata_api_base: str = Query(..., description="iData API base URL"),
api_key: str = Query(..., description="iData API key"),
user_id: str = Query(..., description="iData user ID"),
knowledge_space_id: str = Query(..., description="Knowledge space ID"),
):
"""
Fetch datasets (knowledge bases) from iData API.

Returns knowledge bases in a format consistent with DataMate for frontend compatibility.
"""
try:
# Normalize URL by removing trailing slash
idata_api_base = idata_api_base.rstrip('/')
except Exception as e:
logger.error(f"Invalid iData configuration: {e}")
raise AppException(
ErrorCode.IDATA_CONFIG_INVALID,
f"Invalid URL format: {str(e)}"
)

try:
result = fetch_idata_datasets_impl(
idata_api_base=idata_api_base,
api_key=api_key,
user_id=user_id,
knowledge_space_id=knowledge_space_id,
)
return JSONResponse(
status_code=HTTPStatus.OK,
content=result
)
except AppException:
# Re-raise AppException to be handled by global middleware
raise
except Exception as e:
logger.error(f"Failed to fetch iData datasets: {e}")
raise AppException(
ErrorCode.IDATA_SERVICE_ERROR,
f"Failed to fetch iData datasets: {str(e)}"
)
Loading
Loading