Skip to content

Commit 1ce994e

Browse files
authored
feat: 勾选高级设置-启用图片时 进行图片输入检查 (#79)
1 parent 6cb5c78 commit 1ce994e

File tree

10 files changed

+490
-314
lines changed

10 files changed

+490
-314
lines changed

consts/consts.go

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

domain/domain.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,14 @@ type ModelListItem struct {
3232
}
3333

3434
type CheckModelReq struct {
35-
Provider string `json:"provider" query:"provider" validate:"required,oneof=OpenAI Ollama DeepSeek SiliconFlow Moonshot Other AzureOpenAI BaiZhiCloud Hunyuan BaiLian Volcengine Gemini ZhiPu AiHubMix"`
36-
Model string `json:"model" query:"model_name" validate:"required"`
37-
BaseURL string `json:"base_url" query:"base_url" validate:"required"`
38-
APIKey string `json:"api_key" query:"api_key"`
39-
APIHeader string `json:"api_header" query:"api_header"`
40-
APIVersion string `json:"api_version" query:"api_version"` // for azure openai
41-
Type string `json:"type" query:"model_type" validate:"required,oneof=chat embedding rerank llm"`
35+
Provider string `json:"provider" query:"provider" validate:"required,oneof=OpenAI Ollama DeepSeek SiliconFlow Moonshot Other AzureOpenAI BaiZhiCloud Hunyuan BaiLian Volcengine Gemini ZhiPu AiHubMix"`
36+
Model string `json:"model" query:"model_name" validate:"required"`
37+
BaseURL string `json:"base_url" query:"base_url" validate:"required"`
38+
APIKey string `json:"api_key" query:"api_key"`
39+
APIHeader string `json:"api_header" query:"api_header"`
40+
APIVersion string `json:"api_version" query:"api_version"` // for azure openai
41+
Type string `json:"type" query:"model_type" validate:"required,oneof=chat embedding rerank llm"`
42+
Param *ModelParam `json:"param" query:"param"`
4243
}
4344

4445
type CheckModelResp struct {

domain/model.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@ import (
55
"github.com/cloudwego/eino-ext/libs/acl/openai"
66
)
77

8+
type ModelParam struct {
9+
ContextWindow int `json:"context_window"`
10+
MaxTokens int `json:"max_tokens"`
11+
R1Enabled bool `json:"r1_enabled"`
12+
SupportComputerUse bool `json:"support_computer_use"`
13+
SupportImages bool `json:"support_images"`
14+
SupportPromptCache bool `json:"support_prompt_cache"`
15+
Temperature *float32 `json:"temperature"`
16+
}
17+
818
type ModelMetadata struct {
919
// 基础参数
1020
ModelName string `json:"id"` // 模型的名字

test/backend/main.go

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package main
22

33
import (
4+
"encoding/json"
45
"fmt"
56
"log/slog"
67
"net/http"
@@ -65,11 +66,54 @@ func (p *ModelKitHandler) GetModelList(c echo.Context) error {
6566
}
6667

6768
func (p *ModelKitHandler) CheckModel(c echo.Context) error {
69+
// 手动绑定参数,避免 param 字段的 JSON 解析问题
6870
var req domain.CheckModelReq
69-
if err := c.Bind(&req); err != nil {
71+
72+
// 绑定基本字段
73+
req.Provider = c.QueryParam("provider")
74+
req.Model = c.QueryParam("model_name")
75+
req.BaseURL = c.QueryParam("base_url")
76+
req.APIKey = c.QueryParam("api_key")
77+
req.APIHeader = c.QueryParam("api_header")
78+
req.APIVersion = c.QueryParam("api_version")
79+
req.Type = c.QueryParam("model_type")
80+
81+
// 单独处理 param 字段
82+
paramStr := c.QueryParam("param")
83+
if paramStr != "" {
84+
var param domain.ModelParam
85+
if err := json.Unmarshal([]byte(paramStr), &param); err != nil {
86+
return c.JSON(http.StatusBadRequest, domain.Response{
87+
Success: false,
88+
Message: "param 参数解析失败: " + err.Error(),
89+
})
90+
}
91+
req.Param = &param
92+
}
93+
94+
// 验证必需参数
95+
if req.Provider == "" {
7096
return c.JSON(http.StatusBadRequest, domain.Response{
7197
Success: false,
72-
Message: "参数绑定失败: " + err.Error(),
98+
Message: "provider 参数是必需的",
99+
})
100+
}
101+
if req.Model == "" {
102+
return c.JSON(http.StatusBadRequest, domain.Response{
103+
Success: false,
104+
Message: "model_name 参数是必需的",
105+
})
106+
}
107+
if req.BaseURL == "" {
108+
return c.JSON(http.StatusBadRequest, domain.Response{
109+
Success: false,
110+
Message: "base_url 参数是必需的",
111+
})
112+
}
113+
if req.Type == "" {
114+
return c.JSON(http.StatusBadRequest, domain.Response{
115+
Success: false,
116+
Message: "model_type 参数是必需的",
73117
})
74118
}
75119

test/ui_example/src/localService.ts

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -90,20 +90,22 @@ export class LocalModelService implements ModelService {
9090
return { models: response.models, error: response.error };
9191
}
9292

93-
async checkModel(data: CheckModelReq): Promise<{ model: Model; error?: string }> {
94-
const queryParams = new URLSearchParams();
95-
if (data.provider) queryParams.append('provider', data.provider);
96-
if (data.model_name) queryParams.append('model_name', data.model_name);
97-
if (data.base_url) queryParams.append('base_url', data.base_url);
98-
if (data.api_key) queryParams.append('api_key', data.api_key);
99-
if (data.api_header) queryParams.append('api_header', data.api_header);
100-
if (data.model_type) queryParams.append('model_type', data.model_type);
101-
const url = `/checkmodel${queryParams.toString() ? '?' + queryParams.toString() : ''}`;
102-
const response = await this.request<CheckModelResponse>(url, {
103-
method: 'GET',
104-
});
105-
return { model: response.model, error: response.error };
106-
}
93+
async checkModel(data: CheckModelReq): Promise<{ model: Model; error?: string }> {
94+
const queryParams = new URLSearchParams();
95+
if (data.provider) queryParams.append('provider', data.provider);
96+
if (data.model_name) queryParams.append('model_name', data.model_name);
97+
if (data.base_url) queryParams.append('base_url', data.base_url);
98+
if (data.api_key) queryParams.append('api_key', data.api_key);
99+
if (data.api_header) queryParams.append('api_header', data.api_header);
100+
if (data.model_type) queryParams.append('model_type', data.model_type);
101+
if (data.param) queryParams.append('param', JSON.stringify(data.param));
102+
103+
const url = `/checkmodel${queryParams.toString() ? '?' + queryParams.toString() : ''}`;
104+
const response = await this.request<CheckModelResponse>(url, {
105+
method: 'GET',
106+
});
107+
return { model: response.model, error: response.error };
108+
}
107109

108110
async updateModel(data: UpdateModelReq): Promise<{ model: Model }> {
109111
const requestData = {

ui/ModelModal/src/ModelModal.tsx

Lines changed: 80 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,14 @@ export const ModelModal: React.FC<ModelModalProps> = ({
219219
api_version: value.api_version,
220220
provider: value.provider,
221221
api_header: value.api_header || header,
222+
param: {
223+
context_window: value.context_window_size,
224+
max_tokens: value.max_output_tokens,
225+
r1_enabled: value.enable_r1_params,
226+
support_images: value.support_image,
227+
support_computer_use: value.support_compute,
228+
support_prompt_cache: value.support_prompt_caching,
229+
},
222230
})
223231
.then((res) => {
224232
// 错误处理
@@ -1047,7 +1055,6 @@ export const ModelModal: React.FC<ModelModalProps> = ({
10471055
},
10481056
'& .MuiAccordionDetails-root': {
10491057
padding: 0,
1050-
paddingTop: 1.5,
10511058
},
10521059
}}
10531060
expanded={expandAdvanced}
@@ -1070,7 +1077,77 @@ export const ModelModal: React.FC<ModelModalProps> = ({
10701077
高级设置
10711078
</AccordionSummary>
10721079
<AccordionDetails>
1073-
<Stack spacing={2}>
1080+
<Stack spacing={0}>
1081+
{/* 复选框组 - 使用更紧凑的布局 */}
1082+
<Stack spacing={0} sx={{ ml: -1.2 }}>
1083+
<Controller
1084+
control={control}
1085+
name='support_image'
1086+
render={({ field }) => (
1087+
<FormControlLabel
1088+
control={
1089+
<Checkbox
1090+
checked={field.value}
1091+
onChange={(e) =>
1092+
field.onChange(e.target.checked)
1093+
}
1094+
size='small'
1095+
/>
1096+
}
1097+
label={
1098+
<Box sx={{ fontSize: 12 }}>
1099+
启用图片
1100+
<Box
1101+
component='span'
1102+
sx={{
1103+
ml: 1,
1104+
color: 'text.secondary',
1105+
fontSize: 11,
1106+
}}
1107+
>
1108+
(支持图片输入的模型可以启用此选项)
1109+
</Box>
1110+
</Box>
1111+
}
1112+
sx={{ margin: 0 }}
1113+
/>
1114+
)}
1115+
/>
1116+
<Controller
1117+
control={control}
1118+
name='enable_r1_params'
1119+
render={({ field }) => (
1120+
<FormControlLabel
1121+
control={
1122+
<Checkbox
1123+
checked={field.value}
1124+
onChange={(e) =>
1125+
field.onChange(e.target.checked)
1126+
}
1127+
size='small'
1128+
/>
1129+
}
1130+
label={
1131+
<Box sx={{ fontSize: 12 }}>
1132+
启用 R1 模型参数
1133+
<Box
1134+
component='span'
1135+
sx={{
1136+
ml: 1,
1137+
color: 'text.secondary',
1138+
fontSize: 11,
1139+
}}
1140+
>
1141+
(使用 QWQ 等 R1
1142+
系列模型时必须启用,避免出现 400 错误)
1143+
</Box>
1144+
</Box>
1145+
}
1146+
sx={{ margin: 0 }}
1147+
/>
1148+
)}
1149+
/>
1150+
</Stack>
10741151
<Box>
10751152
<Box sx={{ fontSize: 14, lineHeight: '32px' }}>
10761153
上下文窗口大小
@@ -1150,76 +1227,7 @@ export const ModelModal: React.FC<ModelModalProps> = ({
11501227
/>
11511228
</Box>
11521229

1153-
{/* 复选框组 - 使用更紧凑的布局 */}
1154-
<Stack spacing={0}>
1155-
<Controller
1156-
control={control}
1157-
name='enable_r1_params'
1158-
render={({ field }) => (
1159-
<FormControlLabel
1160-
control={
1161-
<Checkbox
1162-
checked={field.value}
1163-
onChange={(e) =>
1164-
field.onChange(e.target.checked)
1165-
}
1166-
size='small'
1167-
/>
1168-
}
1169-
label={
1170-
<Box sx={{ fontSize: 12 }}>
1171-
启用 R1 模型参数
1172-
<Box
1173-
component='span'
1174-
sx={{
1175-
ml: 1,
1176-
color: 'text.secondary',
1177-
fontSize: 11,
1178-
}}
1179-
>
1180-
(使用 QWQ 等 R1
1181-
系列模型时必须启用,避免出现 400 错误)
1182-
</Box>
1183-
</Box>
1184-
}
1185-
sx={{ margin: 0 }}
1186-
/>
1187-
)}
1188-
/>
1189-
<Controller
1190-
control={control}
1191-
name='support_image'
1192-
render={({ field }) => (
1193-
<FormControlLabel
1194-
control={
1195-
<Checkbox
1196-
checked={field.value}
1197-
onChange={(e) =>
1198-
field.onChange(e.target.checked)
1199-
}
1200-
size='small'
1201-
/>
1202-
}
1203-
label={
1204-
<Box sx={{ fontSize: 12 }}>
1205-
启用图片
1206-
<Box
1207-
component='span'
1208-
sx={{
1209-
ml: 1,
1210-
color: 'text.secondary',
1211-
fontSize: 11,
1212-
}}
1213-
>
1214-
(支持图片输入的模型可以启用此选项)
1215-
</Box>
1216-
</Box>
1217-
}
1218-
sx={{ margin: 0 }}
1219-
/>
1220-
)}
1221-
/>
1222-
</Stack>
1230+
12231231
</Stack>
12241232
</AccordionDetails>
12251233
</Accordion>

ui/ModelModal/src/types/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ export interface CheckModelReq {
9696
model_name?: string;
9797
provider?: string;
9898
model_type?: string;
99+
param?: ModelParam;
99100
}
100101

101102
// 更新模型数据

usecase/assets/image.png

49.7 KB
Loading

0 commit comments

Comments
 (0)