Skip to content

Commit 5471404

Browse files
committed
fix check_json_error
1 parent 89e4dba commit 5471404

File tree

6 files changed

+230
-54
lines changed

6 files changed

+230
-54
lines changed

frontend/public/locales/en/translation.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@
9393
"concurrentUsers": "Concurrent Users",
9494
"testDuration": "Test Duration",
9595
"builtInDataset": "Built-in Dataset",
96-
"customDataset": "Custom Dataset 🆕",
96+
"customDataset": "Custom Dataset",
9797
"textOnlyConversations": "Text-Only Conversations",
9898
"multimodalTextImage": "Multimodal (Text + Image)",
9999
"noValidResults": "No valid test results found",
@@ -417,7 +417,6 @@
417417
"create": "Create",
418418
"basicRequest": "Basic & Request",
419419
"dataLoad": "Data & Load",
420-
"fieldMapping": "Field Mapping",
421420
"apiTest": "API Test",
422421
"statusCode": "Status Code",
423422
"responseData": "Response Data",
@@ -437,6 +436,8 @@
437436
"taskTemplateCopied": "Task template copied. Please note: Advanced settings need to be re-filled or uploaded.",
438437
"pleaseEnterTaskName": "Please enter task name",
439438
"pleaseEnterApiUrl": "Please enter API URL",
439+
"invalidUrlFormat": "Please enter a valid URL format (starting with http:// or https://)",
440+
"urlCannotContainSpaces": "URL cannot contain spaces",
440441
"pleaseEnterApiPath": "Please enter API path",
441442
"pleaseEnterModelName": "Please enter model name",
442443
"pleaseSelectResponseMode": "Please select response mode",

frontend/public/locales/zh/translation.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,8 @@
436436
"taskTemplateCopied": "任务模板已复制。请注意:鉴权信息和上传文件需要重新填写或上传。",
437437
"pleaseEnterTaskName": "请输入任务名称",
438438
"pleaseEnterApiUrl": "请输入API URL",
439+
"invalidUrlFormat": "请输入正确的URL格式(http://或https://开头)",
440+
"urlCannotContainSpaces": "URL不能包含空格",
439441
"pleaseEnterApiPath": "请输入API路径",
440442
"pleaseEnterModelName": "请输入模型名称",
441443
"pleaseSelectResponseMode": "请选择响应模式",

frontend/src/components/CreateJobForm.tsx

Lines changed: 69 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,6 +1118,7 @@ const CreateJobFormContent: React.FC<CreateJobFormProps> = ({
11181118
message: t('components.createJobForm.pleaseEnterTaskName'),
11191119
},
11201120
]}
1121+
normalize={value => value?.trim() || ''}
11211122
>
11221123
<Input
11231124
placeholder={t('components.createJobForm.taskNamePlaceholder')}
@@ -1151,7 +1152,55 @@ const CreateJobFormContent: React.FC<CreateJobFormProps> = ({
11511152
required: true,
11521153
message: t('components.createJobForm.pleaseEnterApiUrl'),
11531154
},
1155+
{
1156+
validator: (_, value) => {
1157+
if (!value?.trim()) return Promise.resolve();
1158+
1159+
const trimmedValue = value.trim();
1160+
1161+
// Check for spaces in URL
1162+
if (trimmedValue.includes(' ')) {
1163+
return Promise.reject(
1164+
new Error(
1165+
t('components.createJobForm.urlCannotContainSpaces')
1166+
)
1167+
);
1168+
}
1169+
1170+
// Check for proper protocol
1171+
if (
1172+
!trimmedValue.startsWith('http://') &&
1173+
!trimmedValue.startsWith('https://')
1174+
) {
1175+
return Promise.reject(
1176+
new Error(
1177+
t('components.createJobForm.invalidUrlFormat')
1178+
)
1179+
);
1180+
}
1181+
1182+
try {
1183+
const url = new URL(trimmedValue);
1184+
// Additional validation: ensure hostname is present
1185+
if (!url.hostname || url.hostname.length === 0) {
1186+
return Promise.reject(
1187+
new Error(
1188+
t('components.createJobForm.invalidUrlFormat')
1189+
)
1190+
);
1191+
}
1192+
return Promise.resolve();
1193+
} catch (error) {
1194+
return Promise.reject(
1195+
new Error(
1196+
t('components.createJobForm.invalidUrlFormat')
1197+
)
1198+
);
1199+
}
1200+
},
1201+
},
11541202
]}
1203+
normalize={value => value?.trim() || ''}
11551204
>
11561205
<Input
11571206
style={{ width: '70%' }}
@@ -1167,6 +1216,7 @@ const CreateJobFormContent: React.FC<CreateJobFormProps> = ({
11671216
message: t('components.createJobForm.pleaseEnterApiPath'),
11681217
},
11691218
]}
1219+
normalize={value => value?.trim() || ''}
11701220
>
11711221
<Input
11721222
style={{ width: '30%' }}
@@ -1196,6 +1246,7 @@ const CreateJobFormContent: React.FC<CreateJobFormProps> = ({
11961246
message: t('components.createJobForm.pleaseEnterModelName'),
11971247
},
11981248
]}
1249+
normalize={value => value?.trim() || ''}
11991250
>
12001251
<Input placeholder='e.g. gpt-4, claude-3, internlm3-latest' />
12011252
</Form.Item>
@@ -1974,47 +2025,46 @@ const CreateJobFormContent: React.FC<CreateJobFormProps> = ({
19742025

19752026
<Col span={8}>
19762027
<Form.Item
1977-
name={['field_mapping', 'stop_flag']}
2028+
name={['field_mapping', 'end_condition']}
19782029
label={
19792030
<span>
1980-
{t('components.createJobForm.stopSignal')}
2031+
{t('components.createJobForm.endFieldPath')}
19812032
<Tooltip
1982-
title={t('components.createJobForm.stopSignalTooltip')}
2033+
title={t(
2034+
'components.createJobForm.endFieldPathTooltip'
2035+
)}
19832036
>
19842037
<InfoCircleOutlined style={{ marginLeft: 5 }} />
19852038
</Tooltip>
19862039
</span>
19872040
}
1988-
rules={[
1989-
{
1990-
required: true,
1991-
message: t(
1992-
'components.createJobForm.pleaseSpecifyStopSignal'
1993-
),
1994-
},
1995-
]}
19962041
>
1997-
<Input placeholder='[DONE]' />
2042+
<Input placeholder='choices.0.finish_reason' />
19982043
</Form.Item>
19992044
</Col>
2000-
20012045
<Col span={8}>
20022046
<Form.Item
2003-
name={['field_mapping', 'end_condition']}
2047+
name={['field_mapping', 'stop_flag']}
20042048
label={
20052049
<span>
2006-
{t('components.createJobForm.endFieldPath')}
2050+
{t('components.createJobForm.stopSignal')}
20072051
<Tooltip
2008-
title={t(
2009-
'components.createJobForm.endFieldPathTooltip'
2010-
)}
2052+
title={t('components.createJobForm.stopSignalTooltip')}
20112053
>
20122054
<InfoCircleOutlined style={{ marginLeft: 5 }} />
20132055
</Tooltip>
20142056
</span>
20152057
}
2058+
rules={[
2059+
{
2060+
required: true,
2061+
message: t(
2062+
'components.createJobForm.pleaseSpecifyStopSignal'
2063+
),
2064+
},
2065+
]}
20162066
>
2017-
<Input placeholder='choices.0.finish_reason' />
2067+
<Input placeholder='[DONE]' />
20182068
</Form.Item>
20192069
</Col>
20202070
</Row>

frontend/src/utils/validation.ts

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,47 @@ export const validateJson = (value: string): string | undefined => {
2626
/**
2727
* Validate URL format
2828
* @param value - URL string to validate
29+
* @param t - Translation function (optional, for i18n)
2930
* @returns Error message or undefined if valid
3031
*/
31-
export const validateUrl = (value: string): string | undefined => {
32+
export const validateUrl = (
33+
value: string,
34+
t?: (key: string) => string
35+
): string | undefined => {
3236
if (!value?.trim()) return undefined;
3337

38+
const trimmedValue = value.trim();
39+
40+
// Check for spaces in URL
41+
if (trimmedValue.includes(' ')) {
42+
return t
43+
? t('components.createJobForm.urlCannotContainSpaces')
44+
: 'URL cannot contain spaces';
45+
}
46+
47+
// Check for proper protocol
48+
if (
49+
!trimmedValue.startsWith('http://') &&
50+
!trimmedValue.startsWith('https://')
51+
) {
52+
return t
53+
? t('components.createJobForm.invalidUrlFormat')
54+
: 'Please enter a valid URL format (starting with http:// or https://)';
55+
}
56+
3457
try {
35-
const url = new URL(value);
36-
// Use url to avoid unused variable warning
37-
return url ? undefined : 'Please enter a valid URL';
58+
const url = new URL(trimmedValue);
59+
// Additional validation: ensure hostname is present
60+
if (!url.hostname || url.hostname.length === 0) {
61+
return t
62+
? t('components.createJobForm.invalidUrlFormat')
63+
: 'Please enter a valid URL format (starting with http:// or https://)';
64+
}
65+
return undefined;
3866
} catch (error) {
39-
return 'Please enter a valid URL';
67+
return t
68+
? t('components.createJobForm.invalidUrlFormat')
69+
: 'Please enter a valid URL format (starting with http:// or https://)';
4070
}
4171
};
4272

@@ -105,11 +135,11 @@ export const VALIDATION_RULES = {
105135
}),
106136

107137
// URL validation
108-
url: (required: boolean = false): Rule => ({
138+
url: (required: boolean = false, t?: (key: string) => string): Rule => ({
109139
required,
110140
validator: (_, value) => {
111141
if (!required && !value) return Promise.resolve();
112-
const error = validateUrl(value);
142+
const error = validateUrl(value, t);
113143
return error ? Promise.reject(new Error(error)) : Promise.resolve();
114144
},
115145
}),
@@ -212,6 +242,27 @@ export const isFormValidForTest = (values: Record<string, any>): boolean => {
212242
});
213243
};
214244

245+
/**
246+
* Trim whitespace from input value
247+
* @param value - Input value
248+
* @returns Trimmed value
249+
*/
250+
export const trimValue = (value: string | undefined | null): string => {
251+
return value?.trim() || '';
252+
};
253+
254+
/**
255+
* Create a validator that automatically trims the value
256+
* @param validator - Original validator function
257+
* @returns Validator that trims before validating
258+
*/
259+
export const withTrim = (validator: (value: string) => string | undefined) => {
260+
return (value: string | undefined | null) => {
261+
const trimmedValue = trimValue(value);
262+
return validator(trimmedValue);
263+
};
264+
};
265+
215266
/**
216267
* Sanitize input value
217268
* @param value - Input value

st_engine/engine/core.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import json
99
import ssl
1010
from dataclasses import dataclass, field
11-
from typing import Dict, Optional, Tuple, Union
11+
from typing import Any, Dict, Optional, Tuple, Union
1212

1313
from gevent import queue
1414
from gevent.lock import Semaphore
@@ -26,8 +26,8 @@ class StreamMetrics:
2626
first_thinking_received: bool = False
2727
reasoning_is_active: bool = False
2828
reasoning_ended: bool = False
29-
first_output_token_time: float = 0.0
30-
first_thinking_token_time: float = 0.0
29+
first_output_token_time: Optional[float] = None
30+
first_thinking_token_time: Optional[float] = None
3131
model_output: str = ""
3232
reasoning_content: str = ""
3333

@@ -77,7 +77,7 @@ class GlobalStateManager:
7777
_global_task_queue: Optional[Dict[str, queue.Queue]] = None
7878
_start_time: Optional[float] = None
7979
_lock: Semaphore = Semaphore()
80-
_logger_cache: Dict[str, any] = {}
80+
_logger_cache: Dict[str, Any] = {}
8181
_ssl_context: Optional[ssl.SSLContext] = None
8282

8383
@classmethod

0 commit comments

Comments
 (0)