Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 5 additions & 1 deletion backend/services/model_management_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,11 @@ async def list_provider_models_for_tenant(tenant_id: str, provider: str, model_t
model_list = get_models_by_tenant_factory_type(
tenant_id, provider, model_type)
for model in model_list:
model["id"] = model["model_repo"] + "/" + model["model_name"]
# Use add_repo_to_name for consistent format with /model/list API
model["id"] = add_repo_to_name(
model_repo=model["model_repo"],
model_name=model["model_name"],
)

logging.debug(f"Provider model {provider} created successfully")
return model_list
Expand Down
54 changes: 41 additions & 13 deletions frontend/app/[locale]/models/components/model/ModelAddDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1300,19 +1300,47 @@ export const ModelAddDialog = ({
</a>
</Tooltip>
{form.isBatchImport && (
<Tooltip title="SiliconFlow">
<a
href={PROVIDER_LINKS.siliconflow}
target="_blank"
rel="noopener noreferrer"
>
<img
src="/siliconflow.png"
alt="SiliconFlow"
className="h-4 ml-1.5 cursor-pointer"
/>
</a>
</Tooltip>
<>
<Tooltip title="SiliconFlow">
<a
href={PROVIDER_LINKS.siliconflow}
target="_blank"
rel="noopener noreferrer"
>
<img
src="/siliconflow.png"
alt="SiliconFlow"
className="h-4 ml-1.5 cursor-pointer"
/>
</a>
</Tooltip>
<Tooltip title={t("model.provider.dashscope")}>
<a
href={PROVIDER_LINKS.dashscope}
target="_blank"
rel="noopener noreferrer"
>
<img
src="/aliyuncs.png"
alt="DashScope"
className="h-4 ml-1.5 cursor-pointer"
/>
</a>
</Tooltip>
<Tooltip title={t("model.provider.tokenpony")}>
<a
href={PROVIDER_LINKS.tokenpony}
target="_blank"
rel="noopener noreferrer"
>
<img
src="/tokenpony.png"
alt="TokenPony"
className="h-4 ml-1.5 cursor-pointer"
/>
</a>
</Tooltip>
</>
)}
{form.type === "llm" && !form.isBatchImport && (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1252,7 +1252,9 @@ export const ModelDeleteDialog = ({
</div>

{(selectedSource === MODEL_SOURCES.SILICON ||
selectedSource === MODEL_SOURCES.MODELENGINE) &&
selectedSource === MODEL_SOURCES.MODELENGINE ||
selectedSource === MODEL_SOURCES.DASHSCOPE ||
selectedSource === MODEL_SOURCES.TOKENPONY) &&
providerModels.length > 0 ? (
<div className="max-h-60 overflow-y-auto border border-gray-200 rounded-md divide-y divide-gray-200">
{providerModels.length > 0 && (
Expand Down
4 changes: 3 additions & 1 deletion frontend/const/modelConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,9 @@ export const PROVIDER_LINKS: Record<string, string> = {
deepseek: "https://platform.deepseek.com/",
qwen: "https://bailian.console.aliyun.com/",
jina: "https://jina.ai/",
baai: "https://www.baai.ac.cn/"
baai: "https://www.baai.ac.cn/",
dashscope: "https://dashscope.aliyun.com/",
tokenpony: "https://www.tokenpony.cn/"
};

// User role constants
Expand Down
Binary file added sdk/nexent/assets/git-flow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
49 changes: 42 additions & 7 deletions sdk/nexent/core/models/openai_vlm.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import asyncio
import base64
import logging
import os
from typing import List, Dict, Any, Union, BinaryIO

Expand All @@ -7,6 +9,8 @@
from ..models import OpenAIModel
from ..utils.observer import MessageObserver

logger = logging.getLogger(__name__)


class OpenAIVLModel(OpenAIModel):
def __init__(
Expand All @@ -32,17 +36,48 @@ def __init__(

async def check_connectivity(self) -> bool:
"""
Check the connectivity of the VLM model.
Check the connectivity of the VLM model by sending a test request with
a text prompt and an image. VLM APIs (especially DashScope qwen-vl)
require specific format: content as a list with 'type': 'image' and
'type': 'text' objects.

Returns:
bool: Returns True if the model can respond normally, otherwise returns False.
bool: True if the model responds successfully, otherwise False.
"""
# Use local test image from images folder - use absolute path based on module location
module_dir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
test_image_path = os.path.join(module_dir, "assets", "git-flow.png")
if os.path.exists(test_image_path):
base64_image = self.encode_image(test_image_path)
# Detect image format for proper MIME type
_, ext = os.path.splitext(test_image_path)
image_format = ext.lower()[1:] if ext else "png"
if image_format == "jpg":
image_format = "jpeg"

content_parts: List[Dict[str, Any]] = [
{"type": "image_url", "image_url": {"url": f"data:image/{image_format};base64,{base64_image}"}},
{"type": "text", "text": "Hello"},
]
else:
# Fallback to remote URL if local image not found
test_image_url = "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20250925/thtclx/input1.png"
content_parts = [
{"type": "image_url", "image_url": {"url": test_image_url}},
{"type": "text", "text": "Hello"},
]

try:
# Directly reuse the parent class's check_connectivity method
return await super().check_connectivity()
await asyncio.to_thread(
self.client.chat.completions.create,
model=self.model_id,
messages=[{"role": "user", "content": content_parts}],
max_tokens=5,
stream=False,
)
return True
except Exception as e:
import logging
logging.error(f"VLM connectivity check failed: {str(e)}")
logger.error("VLM connectivity check failed: %s", e)
return False

def encode_image(self, image_input: Union[str, BinaryIO]) -> str:
Expand Down Expand Up @@ -87,7 +122,7 @@ def prepare_image_message(self, image_input: Union[str, BinaryIO], system_prompt

messages = [{"role": "system", "content": [{"text": system_prompt, "type": "text"}]}, {"role": "user",
"content": [{"type": "image_url",
"image_url": {"url": f"data:image/jpeg;base64,{base64_image}", "detail": "auto"}}]}]
"image_url": {"url": f"data:image/{image_format};base64,{base64_image}", "detail": "auto"}}]}]

return messages

Expand Down
Loading
Loading