Skip to content

Commit da5fdae

Browse files
committed
feat: ⚡ 会话保持时间配置
1 parent fbeba04 commit da5fdae

File tree

9 files changed

+57
-4
lines changed

9 files changed

+57
-4
lines changed

internal/model/group.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ type GroupUpdateRequest struct {
3535
Mode *GroupMode `json:"mode,omitempty"` // 仅在模式变更时发送
3636
MatchRegex *string `json:"match_regex,omitempty"` // 仅在匹配正则变更时发送
3737
FirstTokenTimeOut *int `json:"first_token_time_out,omitempty"` // 仅在超时变更时发送(秒)
38+
SessionKeepTime *int `json:"session_keep_time,omitempty"` // 仅在会话保持时间变更时发送(秒)
3839
ItemsToAdd []GroupItemAddRequest `json:"items_to_add,omitempty"` // 新增的 items
3940
ItemsToUpdate []GroupItemUpdateRequest `json:"items_to_update,omitempty"` // 更新的 items (priority 变更)
4041
ItemsToDelete []int `json:"items_to_delete,omitempty"` // 删除的 item IDs

internal/op/group.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ func GroupUpdate(req *model.GroupUpdateRequest, ctx context.Context) (*model.Gro
8888
selectFields = append(selectFields, "first_token_time_out")
8989
updates.FirstTokenTimeOut = *req.FirstTokenTimeOut
9090
}
91+
if req.SessionKeepTime != nil {
92+
selectFields = append(selectFields, "session_keep_time")
93+
updates.SessionKeepTime = *req.SessionKeepTime
94+
}
9195

9296
if len(selectFields) > 0 {
9397
if err := tx.Model(&model.Group{}).Where("id = ?", req.ID).Select(selectFields).Updates(&updates).Error; err != nil {

web/public/locale/en.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,8 @@
316316
"matchRegexInvalid": "Invalid regex",
317317
"firstTokenTimeOut": "First Token Timeout",
318318
"firstTokenTimeOutHint": "Unit: seconds, only effective for streaming response, 0 = no limit",
319+
"sessionKeepTime": "Session Keep Time",
320+
"sessionKeepTimeHint": "Unit: seconds, keeps using the same channel within a session, 0 = disabled",
319321
"items": "Selected Models",
320322
"addItem": "Add Model",
321323
"autoAdd": "Auto Add",

web/public/locale/zh_hans.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,8 @@
316316
"matchRegexInvalid": "正则无效",
317317
"firstTokenTimeOut": "首字超时",
318318
"firstTokenTimeOutHint": "单位秒,仅流式响应起效,0 表示不限制",
319+
"sessionKeepTime": "会话保持",
320+
"sessionKeepTimeHint": "单位秒,会话期间保持使用同一渠道,0 表示禁用",
319321
"items": "已选模型",
320322
"addItem": "添加模型",
321323
"autoAdd": "自动添加",

web/public/locale/zh_hant.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,8 @@
316316
"matchRegexInvalid": "正規無效",
317317
"firstTokenTimeOut": "首字逾時",
318318
"firstTokenTimeOutHint": "單位秒,僅串流響應起效,0 表示不限制",
319+
"sessionKeepTime": "會話保持",
320+
"sessionKeepTimeHint": "單位秒,會話期間保持使用同一供應源,0 表示停用",
319321
"items": "已選模型",
320322
"addItem": "新增模型",
321323
"autoAdd": "自動新增",

web/src/api/endpoints/group.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export interface Group {
3333
mode: GroupMode;
3434
match_regex: string;
3535
first_token_time_out?: number;
36+
session_keep_time?: number;
3637
items?: GroupItem[];
3738
}
3839

@@ -64,6 +65,7 @@ export interface GroupUpdateRequest {
6465
mode?: GroupMode; // 仅在模式变更时发送
6566
match_regex?: string; // 仅在匹配正则变更时发送
6667
first_token_time_out?: number; // 仅在超时变更时发送
68+
session_keep_time?: number; // 仅在会话保持时间变更时发送
6769
items_to_add?: GroupItemAddRequest[]; // 新增的 items
6870
items_to_update?: GroupItemUpdateRequest[]; // 更新的 items (priority 变更)
6971
items_to_delete?: number[]; // 删除的 item IDs

web/src/components/modules/group/Card.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ function EditDialogContent({ group, displayMembers, isSubmitting, onSubmit }: Ed
5454
match_regex: group.match_regex ?? '',
5555
mode: group.mode,
5656
first_token_time_out: group.first_token_time_out ?? 0,
57+
session_keep_time: group.session_keep_time ?? 0,
5758
members: displayMembers,
5859
}}
5960
submitText={t('detail.actions.save')}
@@ -214,11 +215,13 @@ export function GroupCard({ group }: { group: Group }) {
214215
const nextName = values.name.trim();
215216
const nextRegex = (values.match_regex ?? '').trim();
216217
const nextFirstTokenTimeOut = values.first_token_time_out ?? 0;
218+
const nextSessionKeepTime = values.session_keep_time ?? 0;
217219

218220
if (nextName && nextName !== group.name) payload.name = nextName;
219221
if (values.mode !== group.mode) payload.mode = values.mode;
220222
if (nextRegex !== (group.match_regex ?? '')) payload.match_regex = nextRegex;
221223
if (nextFirstTokenTimeOut !== (group.first_token_time_out ?? 0)) payload.first_token_time_out = nextFirstTokenTimeOut;
224+
if (nextSessionKeepTime !== (group.session_keep_time ?? 0)) payload.session_keep_time = nextSessionKeepTime;
222225
if (items_to_add.length) payload.items_to_add = items_to_add;
223226
if (items_to_update.length) payload.items_to_update = items_to_update;
224227
if (items_to_delete.length) payload.items_to_delete = items_to_delete;
@@ -235,7 +238,7 @@ export function GroupCard({ group }: { group: Group }) {
235238
},
236239
onError,
237240
});
238-
}, [group.first_token_time_out, group.id, group.items, group.match_regex, group.mode, group.name, onSuccess, onError, updateGroup]);
241+
}, [group.first_token_time_out, group.session_keep_time, group.id, group.items, group.match_regex, group.mode, group.name, onSuccess, onError, updateGroup]);
239242

240243
return (
241244
<article className="flex flex-col rounded-3xl border border-border bg-card text-card-foreground p-4 custom-shadow">

web/src/components/modules/group/Create.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export function CreateDialogContent() {
3939
submitText={t('create.submit')}
4040
submittingText={t('create.submitting')}
4141
isSubmitting={createGroup.isPending}
42-
onSubmit={({ name, match_regex, mode, first_token_time_out, members }) => {
42+
onSubmit={({ name, match_regex, mode, first_token_time_out, session_keep_time, members }) => {
4343
const items: GroupItem[] = members.map((member, index) => ({
4444
channel_id: member.channel_id,
4545
model_name: member.name,
@@ -48,7 +48,7 @@ export function CreateDialogContent() {
4848
}));
4949

5050
createGroup.mutate(
51-
{ name, mode, match_regex: match_regex ?? '', first_token_time_out: first_token_time_out ?? 0, items },
51+
{ name, mode, match_regex: match_regex ?? '', first_token_time_out: first_token_time_out ?? 0, session_keep_time: session_keep_time ?? 0, items },
5252
{
5353
onSuccess: () => setIsOpen(false),
5454
onError: (error) => toast.error(t('toast.createFailed'), { description: error.message }),

web/src/components/modules/group/Editor.tsx

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export type GroupEditorValues = {
2525
match_regex: string;
2626
mode: GroupMode;
2727
first_token_time_out: number;
28+
session_keep_time: number;
2829
members: SelectedMember[];
2930
};
3031

@@ -232,6 +233,7 @@ export function GroupEditor({
232233
const [matchRegex, setMatchRegex] = useState(initial?.match_regex ?? '');
233234
const [mode, setMode] = useState<GroupMode>((initial?.mode ?? 1) as GroupMode);
234235
const [firstTokenTimeOut, setFirstTokenTimeOut] = useState<number>(initial?.first_token_time_out ?? 0);
236+
const [sessionKeepTime, setSessionKeepTime] = useState<number>(initial?.session_keep_time ?? 0);
235237
const [selectedMembers, setSelectedMembers] = useState<SelectedMember[]>(initial?.members ?? []);
236238
const [removingIds, setRemovingIds] = useState<Set<string>>(new Set());
237239

@@ -314,6 +316,7 @@ export function GroupEditor({
314316
match_regex: regexKey,
315317
mode,
316318
first_token_time_out: firstTokenTimeOut,
319+
session_keep_time: sessionKeepTime,
317320
members: selectedMembers,
318321
});
319322
};
@@ -323,7 +326,7 @@ export function GroupEditor({
323326
<form onSubmit={handleSubmit} className="flex flex-col h-full min-h-0 ">
324327
<div className="flex-1 min-h-0 overflow-hidden pr-1">
325328
<FieldGroup className="gap-4 flex flex-col min-h-0 h-full">
326-
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
329+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
327330
<Field>
328331
<FieldLabel htmlFor="group-name">{t('form.name')}</FieldLabel>
329332
<Input
@@ -382,6 +385,40 @@ export function GroupEditor({
382385
className="rounded-xl"
383386
/>
384387
</Field>
388+
389+
<Field>
390+
<FieldLabel htmlFor="group-session-keep-time">
391+
{t('form.sessionKeepTime')}
392+
<TooltipProvider>
393+
<Tooltip>
394+
<TooltipTrigger asChild>
395+
<HelpCircle className="size-4 text-muted-foreground cursor-help" />
396+
</TooltipTrigger>
397+
<TooltipContent>
398+
{t('form.sessionKeepTimeHint')}
399+
</TooltipContent>
400+
</Tooltip>
401+
</TooltipProvider>
402+
</FieldLabel>
403+
<Input
404+
id="group-session-keep-time"
405+
type="number"
406+
inputMode="numeric"
407+
min={0}
408+
step={1}
409+
value={String(sessionKeepTime)}
410+
onChange={(e) => {
411+
const raw = e.target.value;
412+
if (raw.trim() === '') {
413+
setSessionKeepTime(0);
414+
return;
415+
}
416+
const n = Number.parseInt(raw, 10);
417+
setSessionKeepTime(Number.isFinite(n) && n > 0 ? n : 0);
418+
}}
419+
className="rounded-xl"
420+
/>
421+
</Field>
385422
</div>
386423

387424
{/* Mode */}

0 commit comments

Comments
 (0)