refactor(core): 重构业务模块代码格式并清理冗余空行
统一前后端业务模块(热词组、提示词模板等)的代码换行符与导入语句格式,移除 Java 实体、DTO、VO 及 Service 实现类中的冗余空行,优化前端组件及 API 文件的 import 结构。dev_na
parent
49eaea32b2
commit
a53d85bbec
|
|
@ -16,9 +16,6 @@ public class HotWordGroupDTO {
|
|||
@Schema(description = "热词组名称")
|
||||
private String groupName;
|
||||
|
||||
@Schema(description = "排序值,越小越靠前")
|
||||
private Integer sortOrder;
|
||||
|
||||
@Schema(description = "状态:1-启用,0-禁用")
|
||||
private Integer status;
|
||||
|
||||
|
|
|
|||
|
|
@ -24,9 +24,6 @@ public class HotWordGroupVO {
|
|||
@Schema(description = "状态:1-启用,0-禁用")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "排序值,越小越靠前")
|
||||
private Integer sortOrder;
|
||||
|
||||
@Schema(description = "组内热词数量")
|
||||
private Long hotWordCount;
|
||||
|
||||
|
|
|
|||
|
|
@ -31,9 +31,6 @@ public class PromptTemplateDTO {
|
|||
@Schema(description = "绑定热词组 ID")
|
||||
private Long hotWordGroupId;
|
||||
|
||||
@Schema(description = "鎺掑簭鍊硷紝瓒婂皬瓒婇潬鍓?")
|
||||
private Integer sortOrder;
|
||||
|
||||
@Schema(description = "模板内容")
|
||||
private String promptContent;
|
||||
|
||||
|
|
|
|||
|
|
@ -30,8 +30,6 @@ public class PromptTemplateVO {
|
|||
private String hotWordGroupName;
|
||||
@Schema(description = "绑定热词列表")
|
||||
private List<String> hotWords;
|
||||
@Schema(description = "排序字段")
|
||||
private Integer sortOrder;
|
||||
@Schema(description = "使用次数")
|
||||
private Integer usageCount;
|
||||
@Schema(description = "提示词正文")
|
||||
|
|
|
|||
|
|
@ -24,9 +24,6 @@ public class HotWordGroup extends BaseEntity {
|
|||
@Schema(description = "创建者ID")
|
||||
private Long creatorId;
|
||||
|
||||
@Schema(description = "排序值,越小越靠前")
|
||||
private Integer sortOrder;
|
||||
|
||||
@Schema(description = "备注")
|
||||
private String remark;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,9 +39,6 @@ public class PromptTemplate extends BaseEntity {
|
|||
@Schema(description = "绑定热词组 ID")
|
||||
private Long hotWordGroupId;
|
||||
|
||||
@Schema(description = "鎺掑簭鍊硷紝瓒婂皬瓒婇潬鍓?")
|
||||
private Integer sortOrder;
|
||||
|
||||
@Schema(description = "使用次数")
|
||||
private Integer usageCount;
|
||||
|
||||
|
|
|
|||
|
|
@ -27,8 +27,6 @@ import java.util.stream.Collectors;
|
|||
@RequiredArgsConstructor
|
||||
public class HotWordGroupServiceImpl extends ServiceImpl<HotWordGroupMapper, HotWordGroup> implements HotWordGroupService {
|
||||
|
||||
private static final int DEFAULT_SORT_ORDER = 0;
|
||||
|
||||
private final HotWordMapper hotWordMapper;
|
||||
private final PromptTemplateMapper promptTemplateMapper;
|
||||
|
||||
|
|
@ -86,7 +84,6 @@ public class HotWordGroupServiceImpl extends ServiceImpl<HotWordGroupMapper, Hot
|
|||
LambdaQueryWrapper<HotWordGroup> wrapper = new LambdaQueryWrapper<HotWordGroup>()
|
||||
.like(name != null && !name.isBlank(), HotWordGroup::getGroupName, name)
|
||||
.eq(status != null, HotWordGroup::getStatus, status)
|
||||
.orderByAsc(HotWordGroup::getSortOrder)
|
||||
.orderByDesc(HotWordGroup::getCreatedAt);
|
||||
wrapper.eq(tenantId != null, HotWordGroup::getTenantId, tenantId);
|
||||
Page<HotWordGroup> page = this.page(new Page<>(current, size), wrapper);
|
||||
|
|
@ -104,7 +101,6 @@ public class HotWordGroupServiceImpl extends ServiceImpl<HotWordGroupMapper, Hot
|
|||
public List<HotWordGroupVO> listVisibleOptions(Long tenantId) {
|
||||
LambdaQueryWrapper<HotWordGroup> wrapper = new LambdaQueryWrapper<HotWordGroup>()
|
||||
.eq(HotWordGroup::getStatus, 1)
|
||||
.orderByAsc(HotWordGroup::getSortOrder)
|
||||
.orderByDesc(HotWordGroup::getCreatedAt);
|
||||
wrapper.eq(tenantId != null, HotWordGroup::getTenantId, tenantId);
|
||||
List<HotWordGroup> groups = this.list(wrapper);
|
||||
|
|
@ -133,7 +129,6 @@ public class HotWordGroupServiceImpl extends ServiceImpl<HotWordGroupMapper, Hot
|
|||
|
||||
private void copyProperties(HotWordGroupDTO dto, HotWordGroup entity) {
|
||||
entity.setGroupName(dto.getGroupName());
|
||||
entity.setSortOrder(normalizeSortOrder(dto.getSortOrder()));
|
||||
entity.setStatus(dto.getStatus());
|
||||
entity.setRemark(dto.getRemark());
|
||||
}
|
||||
|
|
@ -145,7 +140,6 @@ public class HotWordGroupServiceImpl extends ServiceImpl<HotWordGroupMapper, Hot
|
|||
vo.setGroupName(entity.getGroupName());
|
||||
vo.setCreatorId(entity.getCreatorId());
|
||||
vo.setStatus(entity.getStatus());
|
||||
vo.setSortOrder(normalizeSortOrder(entity.getSortOrder()));
|
||||
vo.setHotWordCount(hotWordCount);
|
||||
vo.setRemark(entity.getRemark());
|
||||
vo.setCreatedAt(entity.getCreatedAt());
|
||||
|
|
@ -153,7 +147,4 @@ public class HotWordGroupServiceImpl extends ServiceImpl<HotWordGroupMapper, Hot
|
|||
return vo;
|
||||
}
|
||||
|
||||
private Integer normalizeSortOrder(Integer sortOrder) {
|
||||
return sortOrder == null ? DEFAULT_SORT_ORDER : sortOrder;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -209,7 +209,6 @@ public class MeetingRuntimeProfileResolverImpl implements MeetingRuntimeProfileR
|
|||
.eq(PromptTemplate::getIsSystem, 1)
|
||||
.and(wrapper -> wrapper.eq(PromptTemplate::getTenantId, tenantId).or().eq(PromptTemplate::getTenantId, 0L))
|
||||
.orderByDesc(PromptTemplate::getTenantId)
|
||||
.orderByAsc(PromptTemplate::getSortOrder)
|
||||
.orderByDesc(PromptTemplate::getCreatedAt)
|
||||
.last("LIMIT 1"));
|
||||
if (template != null) {
|
||||
|
|
@ -221,7 +220,6 @@ public class MeetingRuntimeProfileResolverImpl implements MeetingRuntimeProfileR
|
|||
.and(wrapper -> wrapper.eq(PromptTemplate::getTenantId, tenantId).or().eq(PromptTemplate::getTenantId, 0L))
|
||||
.orderByDesc(PromptTemplate::getTenantId)
|
||||
.orderByDesc(PromptTemplate::getIsSystem)
|
||||
.orderByAsc(PromptTemplate::getSortOrder)
|
||||
.orderByDesc(PromptTemplate::getCreatedAt)
|
||||
.last("LIMIT 1"));
|
||||
if (template == null) {
|
||||
|
|
|
|||
|
|
@ -29,8 +29,6 @@ import java.util.stream.Collectors;
|
|||
@RequiredArgsConstructor
|
||||
public class PromptTemplateServiceImpl extends ServiceImpl<PromptTemplateMapper, PromptTemplate> implements PromptTemplateService {
|
||||
|
||||
private static final int DEFAULT_SORT_ORDER = 0;
|
||||
|
||||
private final PromptTemplateUserConfigMapper userConfigMapper;
|
||||
private final HotWordGroupMapper hotWordGroupMapper;
|
||||
private final HotWordService hotWordService;
|
||||
|
|
@ -72,8 +70,8 @@ public class PromptTemplateServiceImpl extends ServiceImpl<PromptTemplateMapper,
|
|||
LambdaQueryWrapper<PromptTemplate> wrapper = buildVisibilityWrapper(tenantId, userId, isPlatformAdmin, isTenantAdmin);
|
||||
wrapper.like(name != null && !name.isEmpty(), PromptTemplate::getTemplateName, name)
|
||||
.eq(category != null && !category.isEmpty(), PromptTemplate::getCategory, category)
|
||||
.orderByDesc(PromptTemplate::getIsSystem)
|
||||
.orderByAsc(PromptTemplate::getSortOrder)
|
||||
.orderByAsc(PromptTemplate::getIsSystem)
|
||||
.orderByDesc(PromptTemplate::getTenantId)
|
||||
.orderByDesc(PromptTemplate::getCreatedAt);
|
||||
|
||||
Page<PromptTemplate> page = this.page(new Page<>(current, size), wrapper);
|
||||
|
|
@ -259,16 +257,11 @@ public class PromptTemplateServiceImpl extends ServiceImpl<PromptTemplateMapper,
|
|||
entity.setTenantId(dto.getTenantId());
|
||||
entity.setTags(dto.getTags());
|
||||
entity.setHotWordGroupId(dto.getHotWordGroupId());
|
||||
entity.setSortOrder(normalizeSortOrder(dto.getSortOrder()));
|
||||
entity.setPromptContent(dto.getPromptContent());
|
||||
entity.setStatus(dto.getStatus());
|
||||
entity.setRemark(dto.getRemark());
|
||||
}
|
||||
|
||||
private Integer normalizeSortOrder(Integer sortOrder) {
|
||||
return sortOrder == null ? DEFAULT_SORT_ORDER : sortOrder;
|
||||
}
|
||||
|
||||
private PromptTemplateVO toVO(PromptTemplate entity, Integer status, Map<Long, HotWordGroup> hotWordGroupMap) {
|
||||
PromptTemplateVO vo = new PromptTemplateVO();
|
||||
vo.setId(entity.getId());
|
||||
|
|
@ -283,7 +276,6 @@ public class PromptTemplateServiceImpl extends ServiceImpl<PromptTemplateMapper,
|
|||
vo.setHotWordGroupId(hotWordGroupId);
|
||||
HotWordGroup group = hotWordGroupId == null ? null : hotWordGroupMap.get(hotWordGroupId);
|
||||
vo.setHotWordGroupName(group == null ? null : group.getGroupName());
|
||||
vo.setSortOrder(normalizeSortOrder(entity.getSortOrder()));
|
||||
vo.setUsageCount(entity.getUsageCount());
|
||||
vo.setPromptContent(entity.getPromptContent());
|
||||
vo.setStatus(status);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ export interface HotWordGroupVO {
|
|||
groupName: string;
|
||||
creatorId: number;
|
||||
status: number;
|
||||
sortOrder?: number;
|
||||
hotWordCount: number;
|
||||
remark?: string;
|
||||
createdAt: string;
|
||||
|
|
@ -16,7 +15,6 @@ export interface HotWordGroupVO {
|
|||
export interface HotWordGroupDTO {
|
||||
id?: number;
|
||||
groupName: string;
|
||||
sortOrder?: number;
|
||||
status: number;
|
||||
remark?: string;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ export interface PromptTemplateVO {
|
|||
hotWordGroupId?: number;
|
||||
hotWordGroupName?: string;
|
||||
hotWords?: string[];
|
||||
sortOrder?: number;
|
||||
usageCount: number;
|
||||
promptContent: string;
|
||||
status: number;
|
||||
|
|
@ -29,7 +28,6 @@ export interface PromptTemplateDTO {
|
|||
isSystem: number;
|
||||
tags?: string[];
|
||||
hotWordGroupId?: number;
|
||||
sortOrder?: number;
|
||||
promptContent: string;
|
||||
status: number;
|
||||
remark?: string;
|
||||
|
|
|
|||
|
|
@ -238,7 +238,7 @@ const AiModels: React.FC = () => {
|
|||
|
||||
const values = form.getFieldsValue(["provider", "baseUrl", "apiKey"]);
|
||||
if (!values.provider || !values.baseUrl) {
|
||||
message.warning("璇峰厛濉啓鎻愪緵鍟嗗拰 Base URL");
|
||||
message.warning("请先填写提供商和 Base URL");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -248,7 +248,7 @@ const AiModels: React.FC = () => {
|
|||
const rawModels = (res as any)?.data?.data ?? (Array.isArray(res) ? res : []);
|
||||
const models = Array.isArray(rawModels) ? rawModels : [];
|
||||
setRemoteModels(models);
|
||||
message.success(`鑾峰彇鍒?${models.length} 涓ā鍨媊);
|
||||
message.success(`已获取 ${models.length} 个模型`);
|
||||
} finally {
|
||||
setFetchLoading(false);
|
||||
}
|
||||
|
|
@ -292,7 +292,7 @@ const AiModels: React.FC = () => {
|
|||
const handleSubmit = async () => {
|
||||
const values = await form.validateFields();
|
||||
if (values.isDefaultChecked && !values.statusChecked) {
|
||||
message.warning("????????????");
|
||||
message.warning("默认模型必须保持启用状态");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -334,10 +334,10 @@ const AiModels: React.FC = () => {
|
|||
try {
|
||||
if (editingId) {
|
||||
await updateAiModel(payload);
|
||||
message.success("鏇存柊鎴愬姛");
|
||||
message.success("更新成功");
|
||||
} else {
|
||||
await saveAiModel(payload);
|
||||
message.success("鏂板鎴愬姛");
|
||||
message.success("新增成功");
|
||||
}
|
||||
setDrawerVisible(false);
|
||||
void fetchData();
|
||||
|
|
@ -363,7 +363,7 @@ const AiModels: React.FC = () => {
|
|||
max_tokens: extraValues.max_tokens,
|
||||
testMessage: DEFAULT_LLM_TEST_MESSAGE,
|
||||
});
|
||||
message.success("LLM ???????");
|
||||
message.success("LLM 连通性测试成功");
|
||||
} finally {
|
||||
setConnectivityLoading(false);
|
||||
}
|
||||
|
|
@ -372,7 +372,7 @@ const AiModels: React.FC = () => {
|
|||
|
||||
const values = await form.validateFields(["provider", "baseUrl"]);
|
||||
if (String(values.provider || "").toLowerCase() !== "local") {
|
||||
message.warning("???? ASR ????????");
|
||||
message.warning("仅本地 ASR 模型支持连通性测试");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -385,7 +385,7 @@ const AiModels: React.FC = () => {
|
|||
});
|
||||
const profile = (res as any)?.data?.data ?? (res as any)?.data ?? (res as any);
|
||||
applyLocalProfile(profile as AiLocalProfileVO, values.baseUrl);
|
||||
message.success("???????????");
|
||||
message.success("本地模型连通性测试成功");
|
||||
} finally {
|
||||
setConnectivityLoading(false);
|
||||
}
|
||||
|
|
@ -393,65 +393,63 @@ const AiModels: React.FC = () => {
|
|||
|
||||
const handleDelete = async (record: AiModelVO) => {
|
||||
await deleteAiModelByType(record.id, record.modelType);
|
||||
message.success("鍒犻櫎鎴愬姛");
|
||||
message.success("删除成功");
|
||||
void fetchData();
|
||||
};
|
||||
|
||||
const handleTenantToggle = async (record: AiModelVO, checked: boolean) => {
|
||||
if (checked) {
|
||||
await tenantEnableModel(record.id, activeType);
|
||||
message.success(activeType === "ASR" ? "宸插垏鎹㈠綋鍓?ASR" : "宸插惎鐢ㄥ綋鍓?LLM");
|
||||
message.success(activeType === "ASR" ? "已启用当前 ASR 模型" : "已启用当前 LLM 模型");
|
||||
} else {
|
||||
await tenantDisableModel(record.id, activeType);
|
||||
message.success(activeType === "ASR" ? "宸插叧闂綋鍓?ASR" : "宸插叧闂綋鍓?LLM");
|
||||
message.success(activeType === "ASR" ? "已停用当前 ASR 模型" : "已停用当前 LLM 模型");
|
||||
}
|
||||
await fetchData();
|
||||
};
|
||||
|
||||
const handlePlatformStatusToggle = async (record: AiModelVO, checked: boolean) => {
|
||||
await updatePlatformModelStatus(record.id, activeType, checked ? 1 : 0);
|
||||
message.success(checked ? `骞冲彴绾?${activeType} 宸插惎鐢╜ : `骞冲彴绾 ? ${activeType}
|
||||
宸茬鐢╜)
|
||||
;
|
||||
message.success(checked ? `平台级 ${activeType} 已启用` : `平台级 ${activeType} 已禁用`);
|
||||
await fetchData();
|
||||
};
|
||||
|
||||
const handleSyncCurrentAsr = async () => {
|
||||
await syncCurrentAsrSpeakers();
|
||||
message.success("?????????");
|
||||
message.success("当前 ASR 声纹已同步");
|
||||
};
|
||||
|
||||
const handleSetTenantDefault = async (record: AiModelVO) => {
|
||||
await setTenantDefaultModel(record.id, "LLM");
|
||||
message.success("宸茶缃负榛樿 LLM");
|
||||
message.success("已设置为默认 LLM");
|
||||
await fetchData();
|
||||
};
|
||||
|
||||
const resolvedTableColumns = [
|
||||
{
|
||||
title: "妯″瀷鍚嶇О",
|
||||
title: "模型名称",
|
||||
dataIndex: "modelName",
|
||||
key: "modelName",
|
||||
render: (text: string, record: AiModelVO) => (
|
||||
<Space>
|
||||
{text}
|
||||
{record.isDefault === 1 && <Tag color="gold">绯荤粺榛樿</Tag>}
|
||||
{record.tenantDefault === 1 && <Tag color="blue">绉熸埛榛樿</Tag>}
|
||||
{record.isDefault === 1 && <Tag color="gold">系统默认</Tag>}
|
||||
{record.tenantDefault === 1 && <Tag color="blue">租户默认</Tag>}
|
||||
{record.tenantId === 0 && (
|
||||
<Tooltip title="骞冲彴閫忎紶妯″瀷">
|
||||
<Tooltip title="平台透传模型">
|
||||
<SafetyCertificateOutlined style={{ color: "#52c41a" }} />
|
||||
</Tooltip>
|
||||
)}
|
||||
{record.scope && (
|
||||
<Tag bordered={false} color={record.scope === "PLATFORM" ? "geekblue" : "default"}>
|
||||
{record.scope === "PLATFORM" ? "骞冲彴绾? : "绉熸埛绾 ?}
|
||||
{record.scope === "PLATFORM" ? "平台级" : "租户级"}
|
||||
</Tag>
|
||||
)}
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "???",
|
||||
title: "提供商",
|
||||
dataIndex: "provider",
|
||||
key: "provider",
|
||||
render: (value: string) => {
|
||||
|
|
@ -460,18 +458,18 @@ const AiModels: React.FC = () => {
|
|||
},
|
||||
},
|
||||
{
|
||||
title: "妯″瀷缂栫爜",
|
||||
title: "模型编码",
|
||||
dataIndex: "modelCode",
|
||||
key: "modelCode",
|
||||
},
|
||||
{
|
||||
title: "鎺掑簭",
|
||||
title: "排序",
|
||||
dataIndex: "sortOrder",
|
||||
key: "sortOrder",
|
||||
render: (value: number | undefined) => value ?? 0,
|
||||
},
|
||||
{
|
||||
title: "??",
|
||||
title: "状态",
|
||||
dataIndex: "status",
|
||||
key: "status",
|
||||
render: (status: number, record: AiModelVO) => {
|
||||
|
|
@ -479,8 +477,8 @@ const AiModels: React.FC = () => {
|
|||
return (
|
||||
<Switch
|
||||
checked={status === 1}
|
||||
checkedChildren="鍚敤"
|
||||
unCheckedChildren="绂佺敤"
|
||||
checkedChildren="启用"
|
||||
unCheckedChildren="禁用"
|
||||
onChange={(checked) => void handlePlatformStatusToggle(record, checked)}
|
||||
/>
|
||||
);
|
||||
|
|
@ -488,8 +486,8 @@ const AiModels: React.FC = () => {
|
|||
return (
|
||||
<Switch
|
||||
checked={record.tenantEnabled === 1}
|
||||
checkedChildren={activeType === "ASR" ? "????" : "???"}
|
||||
unCheckedChildren={activeType === "ASR" ? "鏈惎鐢? : "宸插叧闂 ?}
|
||||
checkedChildren={activeType === "ASR" ? "已启用" : "已启用"}
|
||||
unCheckedChildren={activeType === "ASR" ? "未启用" : "已停用"}
|
||||
disabled={status !== 1}
|
||||
onChange={(checked) => void handleTenantToggle(record, checked)}
|
||||
/>
|
||||
|
|
@ -497,7 +495,7 @@ const AiModels: React.FC = () => {
|
|||
},
|
||||
},
|
||||
{
|
||||
title: "鎿嶄綔",
|
||||
title: "操作",
|
||||
key: "action",
|
||||
render: (_: unknown, record: AiModelVO) => {
|
||||
const canEdit = record.canEditConfig ?? (record.tenantId !== 0 || isPlatformAdmin);
|
||||
|
|
@ -506,18 +504,18 @@ const AiModels: React.FC = () => {
|
|||
<Space>
|
||||
{canSetDefault && (
|
||||
<Button type="link" onClick={() => void handleSetTenantDefault(record)}>
|
||||
{record.tenantDefault === 1 ? "榛樿 LLM" : "璁句负榛樿"}
|
||||
{record.tenantDefault === 1 ? "默认 LLM" : "设为默认"}
|
||||
</Button>
|
||||
)}
|
||||
{canEdit && (
|
||||
<Button type="link" icon={<EditOutlined />} onClick={() => openDrawer(record)}>
|
||||
缂栬緫
|
||||
编辑
|
||||
</Button>
|
||||
)}
|
||||
{canEdit && (
|
||||
<Popconfirm title="纭畾鍒犻櫎鍚楋紵" onConfirm={() => handleDelete(record)}>
|
||||
<Popconfirm title="确认删除吗?" onConfirm={() => handleDelete(record)}>
|
||||
<Button type="link" danger icon={<DeleteOutlined />}>
|
||||
鍒犻櫎
|
||||
删除
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
)}
|
||||
|
|
@ -530,11 +528,11 @@ const AiModels: React.FC = () => {
|
|||
const leftActions = (
|
||||
<Space wrap>
|
||||
<Button type="primary" icon={<PlusOutlined/>} onClick={() => openDrawer()}>
|
||||
鏂板妯″瀷
|
||||
新增模型
|
||||
</Button>
|
||||
{activeType === "ASR" && (
|
||||
<Button icon={<SyncOutlined/>} onClick={() => void handleSyncCurrentAsr()}>
|
||||
鍚屾褰撳墠 ASR 澹扮汗
|
||||
同步当前 ASR 声纹
|
||||
</Button>
|
||||
)}
|
||||
</Space>
|
||||
|
|
@ -543,8 +541,8 @@ const AiModels: React.FC = () => {
|
|||
return (
|
||||
<PageContainer title={null} className="ai-models-page">
|
||||
<SectionCard
|
||||
title="AI 妯″瀷閰嶇疆"
|
||||
description="?? ASR ????? LLM ??????"
|
||||
title="AI 模型配置"
|
||||
description="管理 ASR 语音识别模型和 LLM 大语言模型"
|
||||
tabs={
|
||||
<Tabs
|
||||
activeKey={activeType}
|
||||
|
|
@ -553,8 +551,8 @@ const AiModels: React.FC = () => {
|
|||
setCurrent(1);
|
||||
}}
|
||||
items={[
|
||||
{key: "ASR", label: "ASR 妯″瀷"},
|
||||
{key: "LLM", label: "LLM 妯″瀷"},
|
||||
{key: "ASR", label: "ASR 模型"},
|
||||
{key: "LLM", label: "LLM 模型"},
|
||||
]}
|
||||
size="middle"
|
||||
type="card"
|
||||
|
|
@ -568,7 +566,7 @@ const AiModels: React.FC = () => {
|
|||
rightActions={
|
||||
<Input.Search
|
||||
allowClear
|
||||
placeholder="鎼滅储妯″瀷鍚嶇О"
|
||||
placeholder="搜索模型名称"
|
||||
prefix={<SearchOutlined />}
|
||||
className="ai-models-search"
|
||||
onSearch={(value) => {
|
||||
|
|
@ -605,13 +603,13 @@ const AiModels: React.FC = () => {
|
|||
width={600}
|
||||
open={drawerVisible}
|
||||
onClose={() => setDrawerVisible(false)}
|
||||
title={<Title level={4} style={{margin: 0}}>{editingId ? "缂栬緫妯″瀷" : "鏂板妯″瀷"}</Title>}
|
||||
title={<Title level={4} style={{margin: 0}}>{editingId ? "编辑模型" : "新增模型"}</Title>}
|
||||
forceRender
|
||||
extra={
|
||||
<Space>
|
||||
<Button onClick={() => setDrawerVisible(false)}>鍙栨秷</Button>
|
||||
<Button onClick={() => setDrawerVisible(false)}>取消</Button>
|
||||
<Button type="primary" icon={<SaveOutlined />} loading={submitLoading} onClick={handleSubmit}>
|
||||
淇濆瓨
|
||||
保存
|
||||
</Button>
|
||||
</Space>
|
||||
}
|
||||
|
|
@ -621,9 +619,9 @@ const AiModels: React.FC = () => {
|
|||
<Input />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="妯″瀷绫诲瀷">
|
||||
<Form.Item label="模型类型">
|
||||
<Tag color={activeType === "ASR" ? "blue" : "purple"}>
|
||||
{activeType === "ASR" ? "璇煶璇嗗埆 (ASR)" : "澶ц瑷€妯″瀷 (LLM)"}
|
||||
{activeType === "ASR" ? "语音识别 (ASR)" : "大语言模型 (LLM)"}
|
||||
</Tag>
|
||||
</Form.Item>
|
||||
|
||||
|
|
@ -631,7 +629,7 @@ const AiModels: React.FC = () => {
|
|||
<Col xs={24} md={12}>
|
||||
<Form.Item
|
||||
name="modelName"
|
||||
label="鏄剧ず鍚嶇О"
|
||||
label="模型名称"
|
||||
rules={[{required: true, message: "请输入显示名称"}, {max: 15, message: "模型名称不能超过15个字符"}]}
|
||||
>
|
||||
<Input onChange={() => {
|
||||
|
|
@ -642,10 +640,10 @@ const AiModels: React.FC = () => {
|
|||
<Col xs={24} md={12}>
|
||||
<Form.Item
|
||||
name="provider"
|
||||
label="???"
|
||||
rules={[{required: true, message: "??????"}]}
|
||||
label="提供商"
|
||||
rules={[{required: true, message: "请选择提供商"}]}
|
||||
>
|
||||
<Select allowClear placeholder="璇烽€夋嫨">
|
||||
<Select allowClear placeholder="请选择">
|
||||
{providers.map((item) => (
|
||||
<Option key={item.itemValue} value={item.itemValue}>
|
||||
{item.itemLabel}
|
||||
|
|
@ -658,7 +656,7 @@ const AiModels: React.FC = () => {
|
|||
|
||||
<Row gutter={16} className="app-responsive-form-row">
|
||||
<Col xs={24} md={12}>
|
||||
<Form.Item name="sortOrder" label="???">
|
||||
<Form.Item name="sortOrder" label="排序">
|
||||
<InputNumber min={0} style={{ width: "100%" }} />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
|
|
@ -666,7 +664,7 @@ const AiModels: React.FC = () => {
|
|||
|
||||
{!isTencentProvider && (
|
||||
<>
|
||||
<Form.Item name="baseUrl" label="Base URL" rules={[{required: true, message: "璇疯緭鍏?Base URL"}]}>
|
||||
<Form.Item name="baseUrl" label="Base URL" rules={[{required: true, message: "请输入 Base URL"}]}>
|
||||
<Input placeholder="https://api.example.com"/>
|
||||
</Form.Item>
|
||||
<Form.Item name="apiKey" label="API Key">
|
||||
|
|
@ -676,28 +674,28 @@ const AiModels: React.FC = () => {
|
|||
)}
|
||||
|
||||
{(activeType === "LLM" || isLocalProvider) && (
|
||||
<Form.Item label="?????">
|
||||
<Form.Item label="连通性测试">
|
||||
<Button icon={<WifiOutlined />} loading={connectivityLoading} onClick={handleTestConnectivity}>
|
||||
娴嬭瘯杩炴帴
|
||||
测试连接
|
||||
</Button>
|
||||
</Form.Item>
|
||||
)}
|
||||
|
||||
<Divider orientation="left" style={{ fontSize: 14, color: "#999" }}>
|
||||
妯″瀷鍙傛暟
|
||||
模型参数
|
||||
</Divider>
|
||||
|
||||
<Form.Item
|
||||
label="妯″瀷缂栫爜"
|
||||
label="模型编码"
|
||||
required={activeType === "LLM"}
|
||||
hidden={activeType === "ASR" && isTencentProvider}
|
||||
tooltip="鍙粠杩滅▼鍒楄〃閫夋嫨锛屼篃鍙墜鍔ㄨ緭鍏ワ紱璇ュ€间細浣滀负妯″瀷缂栫爜浼犵粰鍚庣"
|
||||
tooltip="可从远程列表选择,也可手动输入;该值会作为模型编码传给后端"
|
||||
>
|
||||
<Space.Compact style={{ width: "100%" }}>
|
||||
<Form.Item
|
||||
name="modelCode"
|
||||
noStyle
|
||||
rules={activeType === "LLM" ? [{required: true, message: "璇疯緭鍏ユ垨閫夋嫨妯″瀷缂栫爜"}] : []}
|
||||
rules={activeType === "LLM" ? [{required: true, message: "请输入或选择模型编码"}] : []}
|
||||
>
|
||||
<AutoComplete
|
||||
style={{ width: "calc(100% - 100px)" }}
|
||||
|
|
@ -711,18 +709,18 @@ const AiModels: React.FC = () => {
|
|||
isLocalProvider || String(option?.value || "").toLowerCase().includes(inputValue.toLowerCase())
|
||||
}
|
||||
>
|
||||
<Input allowClear placeholder="????????????"/>
|
||||
<Input allowClear placeholder="请输入或选择模型编码"/>
|
||||
</AutoComplete>
|
||||
</Form.Item>
|
||||
{!isTencentProvider && (
|
||||
<Button icon={<SyncOutlined spin={fetchLoading}/>} onClick={handleFetchRemote} style={{width: 100}}>
|
||||
鍒锋柊
|
||||
刷新
|
||||
</Button>
|
||||
)}
|
||||
</Space.Compact>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item name="wsUrl" label="WebSocket 鍦板潃"
|
||||
<Form.Item name="wsUrl" label="WebSocket 地址"
|
||||
hidden={!(activeType === "ASR" && createConfig.realtimeEnabled)}>
|
||||
<Input placeholder="wss://api.example.com/v1/ws" />
|
||||
</Form.Item>
|
||||
|
|
@ -730,7 +728,7 @@ const AiModels: React.FC = () => {
|
|||
{activeType === "ASR" && isLocalProvider && (
|
||||
<Row gutter={16} hidden className="app-responsive-form-row">
|
||||
<Col xs={24} md={12}>
|
||||
<Form.Item name="svThreshold" label="????">
|
||||
<Form.Item name="svThreshold" label="声纹阈值">
|
||||
<InputNumber min={0} max={1} step={0.01} style={{ width: "100%" }} />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
|
|
@ -740,32 +738,32 @@ const AiModels: React.FC = () => {
|
|||
{activeType === "ASR" && isTencentProvider && (
|
||||
<Row gutter={16} className="app-responsive-form-row">
|
||||
<Col xs={24} md={12}>
|
||||
<Form.Item name="tencentAppId" label="App ID" rules={[{required: true, message: "璇疯緭鍏?App ID"}]}>
|
||||
<Form.Item name="tencentAppId" label="App ID" rules={[{required: true, message: "请输入 App ID"}]}>
|
||||
<Input/>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col xs={24} md={12}>
|
||||
<Form.Item name="tencentSecretId" label="Secret ID"
|
||||
rules={[{required: true, message: "璇疯緭鍏?Secret ID"}]}>
|
||||
rules={[{required: true, message: "请输入 Secret ID"}]}>
|
||||
<Input/>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
<Form.Item name="tencentSecretKey" label="Secret Key"
|
||||
rules={[{required: true, message: "璇疯緭鍏?Secret Key"}]}>
|
||||
rules={[{required: true, message: "请输入 Secret Key"}]}>
|
||||
<Input.Password/>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col xs={24} md={12}>
|
||||
<Form.Item name="tencentOfflineModelCode" label="绂荤嚎璇嗗埆妯″瀷"
|
||||
rules={[{required: true, message: "?????????"}]}>
|
||||
<Input placeholder="渚嬪锛?6k_zh"/>
|
||||
<Form.Item name="tencentOfflineModelCode" label="离线识别模型"
|
||||
rules={[{required: true, message: "请输入离线识别模型"}]}>
|
||||
<Input placeholder="例如:16k_zh"/>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col xs={24} md={12}>
|
||||
<Form.Item name="tencentRealtimeModelCode" label="瀹炴椂璇嗗埆妯″瀷"
|
||||
rules={[{required: true, message: "?????????"}]}>
|
||||
<Input placeholder="渚嬪锛?6k_zh_realtime"/>
|
||||
<Form.Item name="tencentRealtimeModelCode" label="实时识别模型"
|
||||
rules={[{required: true, message: "请输入实时识别模型"}]}>
|
||||
<Input placeholder="例如:16k_zh_realtime"/>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
|
|
@ -773,7 +771,7 @@ const AiModels: React.FC = () => {
|
|||
|
||||
{activeType === "LLM" && (
|
||||
<>
|
||||
<Form.Item name="apiPath" label="API 璺緞" initialValue="/v1/chat/completions">
|
||||
<Form.Item name="apiPath" label="API 路径" initialValue="/v1/chat/completions">
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Row gutter={16} className="app-responsive-form-row">
|
||||
|
|
@ -792,7 +790,7 @@ const AiModels: React.FC = () => {
|
|||
name="max_tokens"
|
||||
label="max_tokens"
|
||||
rules={[
|
||||
{required: true, message: "璇疯緭鍏?max_tokens"},
|
||||
{required: true, message: "请输入 max_tokens"},
|
||||
{
|
||||
validator: (_, value) => {
|
||||
if (value === undefined || value === null || value === "") {
|
||||
|
|
@ -801,7 +799,7 @@ const AiModels: React.FC = () => {
|
|||
if (Number.isInteger(value) && value > 0) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return Promise.reject(new Error("max_tokens 蹇呴』涓烘鏁存暟"));
|
||||
return Promise.reject(new Error("max_tokens 必须为正整数"));
|
||||
},
|
||||
},
|
||||
]}
|
||||
|
|
@ -815,10 +813,10 @@ const AiModels: React.FC = () => {
|
|||
|
||||
<Row gutter={16} className="app-responsive-form-row">
|
||||
<Col xs={24} md={8}>
|
||||
<Form.Item name="isDefaultChecked" label="璁句负榛樿" valuePropName="checked">
|
||||
<Form.Item name="isDefaultChecked" label="设为默认" valuePropName="checked">
|
||||
<Switch
|
||||
checkedChildren="?"
|
||||
unCheckedChildren="?"
|
||||
checkedChildren="是"
|
||||
unCheckedChildren="否"
|
||||
onChange={(checked) => {
|
||||
if (checked) {
|
||||
form.setFieldValue("statusChecked", true);
|
||||
|
|
@ -828,13 +826,13 @@ const AiModels: React.FC = () => {
|
|||
</Form.Item>
|
||||
</Col>
|
||||
<Col xs={24} md={8}>
|
||||
<Form.Item name="statusChecked" label="??" valuePropName="checked">
|
||||
<Switch checkedChildren="鍚敤" unCheckedChildren="绂佺敤" disabled={Boolean(isDefaultChecked)}/>
|
||||
<Form.Item name="statusChecked" label="状态" valuePropName="checked">
|
||||
<Switch checkedChildren="启用" unCheckedChildren="禁用" disabled={Boolean(isDefaultChecked)}/>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Form.Item name="remark" label="澶囨敞">
|
||||
<Form.Item name="remark" label="备注">
|
||||
<Input.TextArea rows={2} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
|
|
|
|||
|
|
@ -812,9 +812,6 @@ const HotWords: React.FC = () => {
|
|||
}]}>
|
||||
<Input placeholder="例如:项目术语、客户名单" maxLength={15} showCount/>
|
||||
</Form.Item>
|
||||
<Form.Item name="sortOrder" label="排序">
|
||||
<InputNumber min={0} precision={0} className="hotwords-weight-input"/>
|
||||
</Form.Item>
|
||||
<Form.Item name="status" label="状态">
|
||||
<Select>
|
||||
<Option value={1}>启用</Option>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import {
|
|||
Empty,
|
||||
Form,
|
||||
Input,
|
||||
InputNumber,
|
||||
Popconfirm,
|
||||
Row,
|
||||
Select,
|
||||
|
|
@ -133,7 +132,7 @@ const PromptTemplates: React.FC = () => {
|
|||
setDrawerInitialValues({
|
||||
...record,
|
||||
tags: normalizePromptTags(record.tags),
|
||||
templateName: `${record.templateName} (鍓湰)`,
|
||||
templateName: `${record.templateName} (副本)`,
|
||||
isSystem: 0,
|
||||
id: undefined,
|
||||
tenantId: undefined,
|
||||
|
|
@ -172,7 +171,6 @@ const PromptTemplates: React.FC = () => {
|
|||
setDrawerInitialValues({
|
||||
status: 1,
|
||||
isSystem: defaultLevel,
|
||||
sortOrder: 0,
|
||||
});
|
||||
setTemplateLevel(defaultLevel);
|
||||
setSelectedHotWordGroupId(undefined);
|
||||
|
|
@ -199,8 +197,8 @@ const PromptTemplates: React.FC = () => {
|
|||
) : null}
|
||||
<div className="prompt-template-detail__section">
|
||||
<Space wrap>
|
||||
{detail.hotWordGroupName ? <Tag color="blue">鐑瘝缁勶細{detail.hotWordGroupName}</Tag> :
|
||||
<Tag>鏈粦瀹氱儹璇嶇粍</Tag>}
|
||||
{detail.hotWordGroupName ? <Tag color="blue">热词组:{detail.hotWordGroupName}</Tag> :
|
||||
<Tag>未绑定热词组</Tag>}
|
||||
{normalizePromptTags(detail.tags).map((tag) => {
|
||||
const dictItem = dictTags.find((item) => item.itemValue === tag);
|
||||
return <Tag key={tag}>{dictItem ? dictItem.itemLabel : tag}</Tag>;
|
||||
|
|
@ -209,20 +207,20 @@ const PromptTemplates: React.FC = () => {
|
|||
</div>
|
||||
{detail.hotWords && detail.hotWords.length > 0 ? (
|
||||
<div className="prompt-template-detail__section">
|
||||
<div className="prompt-template-detail__section-title">缁戝畾鐑瘝</div>
|
||||
<div className="prompt-template-detail__section-title">绑定热词</div>
|
||||
<Space wrap>
|
||||
{detail.hotWords.map((word) => <Tag key={word}>{word}</Tag>)}
|
||||
</Space>
|
||||
</div>
|
||||
) : detail.hotWordGroupId ? (
|
||||
<div className="prompt-template-detail__section">
|
||||
<Text type="secondary">璇ョ儹璇嶇粍褰撳墠娌℃湁鐑瘝</Text>
|
||||
<Text type="secondary">该热词组当前没有热词</Text>
|
||||
</div>
|
||||
) : null}
|
||||
<ReactMarkdown remarkPlugins={[remarkGfm]}>{detail.promptContent}</ReactMarkdown>
|
||||
</div>
|
||||
),
|
||||
okText: '鍏抽棴',
|
||||
okText: '关闭',
|
||||
maskClosable: true,
|
||||
});
|
||||
})();
|
||||
|
|
@ -236,7 +234,7 @@ const PromptTemplates: React.FC = () => {
|
|||
}
|
||||
if (editingId) {
|
||||
await updatePromptTemplate({ ...values, id: editingId });
|
||||
message.success('鏇存柊鎴愬姛');
|
||||
message.success('更新成功');
|
||||
} else {
|
||||
await savePromptTemplate(values);
|
||||
message.success("模板创建成功");
|
||||
|
|
@ -292,28 +290,25 @@ const PromptTemplates: React.FC = () => {
|
|||
|
||||
const tableColumns: ColumnsType<PromptTemplateVO> = [
|
||||
{
|
||||
title: '妯℃澘鍚嶇О',
|
||||
title: '模板名称',
|
||||
dataIndex: 'templateName',
|
||||
width: 280,
|
||||
render: (_: unknown, item: PromptTemplateVO) => (
|
||||
<div className="prompt-template-name-cell">
|
||||
<Text strong ellipsis={{ tooltip: item.templateName }}>{item.templateName}</Text>
|
||||
{item.description ? (
|
||||
<Text type="secondary" className="prompt-template-description" ellipsis={{ tooltip: item.description }}>
|
||||
{item.description}
|
||||
</Text>
|
||||
) : null}
|
||||
{item.description ? <Text type="secondary" className="prompt-template-description"
|
||||
ellipsis={{tooltip: item.description}}>{item.description}</Text> : null}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '鍒嗙被',
|
||||
title: '分类',
|
||||
dataIndex: 'category',
|
||||
width: 140,
|
||||
render: (category: string) => categories.find((c) => c.itemValue === category)?.itemLabel || category || '-',
|
||||
},
|
||||
{
|
||||
title: '灞傜骇',
|
||||
title: '层级',
|
||||
dataIndex: 'isSystem',
|
||||
width: 110,
|
||||
render: (_: unknown, item: PromptTemplateVO) => {
|
||||
|
|
@ -322,36 +317,29 @@ const PromptTemplates: React.FC = () => {
|
|||
},
|
||||
},
|
||||
{
|
||||
title: "业务标签",
|
||||
dataIndex: "tags",
|
||||
minWidth: 220,
|
||||
render: (tags: unknown) => {
|
||||
title: '业务标签',
|
||||
dataIndex: 'tags',
|
||||
width: 220,
|
||||
render: (tags: unknown) => {
|
||||
const tagList = normalizePromptTags(tags);
|
||||
if (!tagList.length) {
|
||||
return <Text type="secondary">未配置</Text>;
|
||||
}
|
||||
return (
|
||||
<Space size={[4, 4]} wrap className="prompt-template-tags-cell">
|
||||
{tagList.slice(0, 3).map((tag) => {
|
||||
const dictItem = dictTags.find((dt) => dt.itemValue === tag);
|
||||
return <Tag key={tag}>{dictItem ? dictItem.itemLabel : tag}</Tag>;
|
||||
})}
|
||||
{tagList.length > 3 ? <Tag>+{tagList.length - 3}</Tag> : null}
|
||||
</Space>
|
||||
);
|
||||
if (!tagList.length) return <Text type="secondary">未配置</Text>;
|
||||
return <Space size={[4, 4]} wrap className="prompt-template-tags-cell">
|
||||
{tagList.slice(0, 3).map((tag) => <Tag
|
||||
key={tag}>{dictTags.find((item) => item.itemValue === tag)?.itemLabel || tag}</Tag>)}
|
||||
{tagList.length > 3 ? <Tag>+{tagList.length - 3}</Tag> : null}
|
||||
</Space>;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "状态",
|
||||
dataIndex: "status",
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
width: 90,
|
||||
render: (_: unknown, item: PromptTemplateVO) => (
|
||||
/>
|
||||
),
|
||||
render: (_: unknown, item: PromptTemplateVO) => <Switch checked={item.status === 1}
|
||||
onChange={(checked) => void handleStatusChange(item.id, checked)}
|
||||
onClick={(_, event) => event.stopPropagation()}/>,
|
||||
},
|
||||
{
|
||||
title: '鎿嶄綔',
|
||||
title: '操作',
|
||||
key: 'actions',
|
||||
width: 150,
|
||||
fixed: 'right' as const,
|
||||
|
|
@ -359,29 +347,29 @@ const PromptTemplates: React.FC = () => {
|
|||
const canEdit = canManageTemplate(item);
|
||||
return (
|
||||
<Space size={2} onClick={(e) => e.stopPropagation()}>
|
||||
<Tooltip title="鏌ョ湅">
|
||||
<Tooltip title="查看">
|
||||
<Button type="text" size="small" icon={<EyeOutlined/>} onClick={() => showDetail(item)}
|
||||
aria-label="鏌ョ湅妯℃澘"/>
|
||||
aria-label="查看模板"/>
|
||||
</Tooltip>
|
||||
{canEdit && (
|
||||
<Tooltip title="缂栬緫">
|
||||
<Tooltip title="编辑">
|
||||
<Button type="text" size="small" icon={<EditOutlined/>} onClick={() => handleOpenDrawer(item)}
|
||||
aria-label="缂栬緫妯℃澘"/>
|
||||
aria-label="编辑模板"/>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Tooltip title="浠ユ鍒涘缓">
|
||||
<Tooltip title="以此创建">
|
||||
<Button type="text" size="small" icon={<CopyOutlined/>} onClick={() => handleOpenDrawer(item, true)}
|
||||
aria-label="浠ユ鍒涘缓妯℃澘"/>
|
||||
aria-label="以此创建模板"/>
|
||||
</Tooltip>
|
||||
{canEdit && (
|
||||
<Popconfirm
|
||||
title="?????"
|
||||
title="确认删除该模板吗?"
|
||||
onConfirm={() => deletePromptTemplate(item.id).then(() => fetchData())}
|
||||
okText={t('common.confirm')}
|
||||
cancelText={t('common.cancel')}
|
||||
>
|
||||
<Tooltip title="鍒犻櫎">
|
||||
<Button type="text" size="small" danger icon={<DeleteOutlined/>} aria-label="鍒犻櫎妯℃澘"/>
|
||||
<Tooltip title="删除">
|
||||
<Button type="text" size="small" danger icon={<DeleteOutlined/>} aria-label="删除模板"/>
|
||||
</Tooltip>
|
||||
</Popconfirm>
|
||||
)}
|
||||
|
|
@ -391,43 +379,32 @@ const PromptTemplates: React.FC = () => {
|
|||
},
|
||||
];
|
||||
|
||||
const promptTableColumnsWithSort: ColumnsType<PromptTemplateVO> = [
|
||||
...tableColumns.slice(0, 4),
|
||||
{
|
||||
title: '鎺掑簭',
|
||||
dataIndex: 'sortOrder',
|
||||
width: 100,
|
||||
render: (value?: number) => value ?? 0,
|
||||
},
|
||||
...tableColumns.slice(4),
|
||||
];
|
||||
|
||||
return (
|
||||
<PageContainer title={null} className="prompt-templates-page">
|
||||
<SectionCard
|
||||
title="?????"
|
||||
description="?? AI ????????????"
|
||||
title="提示词模板"
|
||||
description="配置 AI 任务所需的提示词模板"
|
||||
>
|
||||
<DataListPanel
|
||||
className="prompt-templates-list-panel"
|
||||
leftActions={
|
||||
<Button type="primary" icon={<PlusOutlined />} onClick={() => handleOpenDrawer()}>
|
||||
鏂板妯℃澘
|
||||
新增模板
|
||||
</Button>
|
||||
}
|
||||
rightActions={
|
||||
<Form layout="inline" onFinish={handleSearch} className="prompt-templates-search">
|
||||
<Form.Item label="妯℃澘鍚嶇О">
|
||||
<Form.Item label="模板名称">
|
||||
<Input
|
||||
placeholder="璇疯緭鍏?.."
|
||||
placeholder="请输入模板名称"
|
||||
className="prompt-templates-search__name"
|
||||
value={queryDraft.name}
|
||||
onChange={(event) => setQueryDraft((currentDraft) => ({ ...currentDraft, name: event.target.value }))}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item label="鍒嗙被">
|
||||
<Form.Item label="分类">
|
||||
<Select
|
||||
placeholder="閫夋嫨鍒嗙被"
|
||||
placeholder="选择分类"
|
||||
className="prompt-templates-search__category"
|
||||
allowClear
|
||||
value={queryDraft.category}
|
||||
|
|
@ -438,8 +415,8 @@ const PromptTemplates: React.FC = () => {
|
|||
</Form.Item>
|
||||
<Form.Item>
|
||||
<Space>
|
||||
<Button type="primary" htmlType="submit">鏌ヨ</Button>
|
||||
<Button onClick={handleResetSearch}>閲嶇疆</Button>
|
||||
<Button type="primary" htmlType="submit">查询</Button>
|
||||
<Button onClick={handleResetSearch}>重置</Button>
|
||||
</Space>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
|
|
@ -458,14 +435,14 @@ const PromptTemplates: React.FC = () => {
|
|||
>
|
||||
<Table<PromptTemplateVO>
|
||||
className="prompt-templates-table"
|
||||
columns={promptTableColumnsWithSort}
|
||||
columns={tableColumns}
|
||||
dataSource={data}
|
||||
rowKey="id"
|
||||
loading={loading}
|
||||
pagination={false}
|
||||
scroll={{ x: "max(100%, 1400px)", y: "100%" }}
|
||||
onRow={(record) => ({ onClick: () => showDetail(record) })}
|
||||
locale={{emptyText: <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description="鏆傛棤鍙敤妯℃澘"/>}}
|
||||
locale={{emptyText: <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description="暂无可用模板"/>}}
|
||||
/>
|
||||
</DataListPanel>
|
||||
</SectionCard>
|
||||
|
|
@ -506,14 +483,14 @@ const PromptTemplates: React.FC = () => {
|
|||
</Col>
|
||||
{(isPlatformAdmin || isTenantAdmin) && (
|
||||
<Col xs={24} md={12} xl={6}>
|
||||
<Form.Item name="isSystem" label="????" rules={[{required: true}]}>
|
||||
<Select placeholder="????">
|
||||
<Form.Item name="isSystem" label="模板层级" rules={[{required: true}]}>
|
||||
<Select placeholder="请选择模板层级">
|
||||
{promptLevels.length > 0 ? (
|
||||
promptLevels.map((i) => <Option key={i.itemValue} value={Number(i.itemValue)}>{i.itemLabel}</Option>)
|
||||
) : (
|
||||
<>
|
||||
<Option value={1}>{isPlatformAdmin ? '绯荤粺棰勭疆 (鍏ㄥ眬)' : '绉熸埛棰勭疆 (鍏ㄥ憳)'}</Option>
|
||||
<Option value={0}>涓汉妯℃澘</Option>
|
||||
<Option value={1}>{isPlatformAdmin ? '系统预置(全局)' : '租户预置(全员)'}</Option>
|
||||
<Option value={0}>个人模板</Option>
|
||||
</>
|
||||
)}
|
||||
</Select>
|
||||
|
|
@ -521,35 +498,35 @@ const PromptTemplates: React.FC = () => {
|
|||
</Col>
|
||||
)}
|
||||
<Col xs={24} md={12} xl={6}>
|
||||
<Form.Item name="category" label="鍒嗙被" rules={[{required: true}]}>
|
||||
<Form.Item name="category" label="分类" rules={[{required: true}]}>
|
||||
<Select loading={dictLoading}>
|
||||
{categories.map((i) => <Option key={i.itemValue} value={i.itemValue}>{i.itemLabel}</Option>)}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col xs={24} md={12} xl={6}>
|
||||
<Form.Item name="status" label="??">
|
||||
<Form.Item name="status" label="状态">
|
||||
<Select>
|
||||
<Option value={1}>鍚敤</Option>
|
||||
<Option value={0}>绂佺敤</Option>
|
||||
<Option value={1}>启用</Option>
|
||||
<Option value={0}>禁用</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Form.Item name="description" label="妯℃澘鎻忚堪">
|
||||
<Form.Item name="description" label="模板描述">
|
||||
<Input.TextArea
|
||||
maxLength={255}
|
||||
showCount
|
||||
autoSize={{ minRows: 2, maxRows: 4 }}
|
||||
placeholder="???????"
|
||||
placeholder="请输入模板描述"
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Row gutter={24}>
|
||||
<Col xs={24} xl={12}>
|
||||
<Form.Item name="tags" label="????" tooltip="??????????????????????">
|
||||
<Select mode="tags" placeholder="閫夋嫨鎴栬緭鍏ユ柊鏍囩" allowClear tokenSeparators={[',', ' ', ';']}>
|
||||
<Form.Item name="tags" label="业务标签" tooltip="可选择已有标签,也可直接输入新标签">
|
||||
<Select mode="tags" placeholder="选择或输入新标签" allowClear tokenSeparators={[',', ' ', ';']}>
|
||||
{dictTags.map((item) => <Option key={item.itemValue} value={item.itemValue}>{item.itemLabel}</Option>)}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
|
@ -557,11 +534,11 @@ const PromptTemplates: React.FC = () => {
|
|||
<Col xs={24} xl={12}>
|
||||
<Form.Item
|
||||
name="hotWordGroupId"
|
||||
label="?????"
|
||||
tooltip="鍙€夛紝鏈粦瀹氬垯淇濇寔鍏煎"
|
||||
label="热词组"
|
||||
tooltip="可选,未绑定则保持兼容"
|
||||
>
|
||||
<Select
|
||||
placeholder="?????"
|
||||
placeholder="请选择热词组"
|
||||
allowClear
|
||||
options={groupOptions.map((item) => ({ label: `${item.groupName} (${item.hotWordCount}/200)`, value: item.id }))}
|
||||
/>
|
||||
|
|
@ -569,29 +546,21 @@ const PromptTemplates: React.FC = () => {
|
|||
</Col>
|
||||
</Row>
|
||||
|
||||
<Row gutter={24}>
|
||||
<Col xs={24} md={12}>
|
||||
<Form.Item name="sortOrder" label="鎺掑簭">
|
||||
<InputNumber min={0} precision={0} style={{width: '100%'}}/>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Row gutter={[12, 16]} className="prompt-template-editor-header">
|
||||
<Col xs={24} xl={12} className="prompt-template-editor-header__col">
|
||||
<div className="prompt-template-editor-title">
|
||||
鎻愮ず璇嶇紪杈戝櫒 (Markdown 瀹炴椂棰勮)
|
||||
提示词编辑器(Markdown 实时预览)
|
||||
</div>
|
||||
</Col>
|
||||
<Col xs={24} xl={12} className="prompt-template-editor-header__col">
|
||||
<div className="prompt-template-editor__preview-meta">
|
||||
{selectedHotWordGroupId ? (
|
||||
<Tag color="blue">
|
||||
缁戝畾鐑瘝缁勶細
|
||||
{groupOptions.find((item) => item.id === selectedHotWordGroupId)?.groupName || '宸查€夋嫨'}
|
||||
绑定热词组:
|
||||
{groupOptions.find((item) => item.id === selectedHotWordGroupId)?.groupName || '已选择'}
|
||||
</Tag>
|
||||
) : (
|
||||
<Tag>鏈粦瀹氱儹璇嶇粍</Tag>
|
||||
<Tag>未绑定热词组</Tag>
|
||||
)}
|
||||
</div>
|
||||
</Col>
|
||||
|
|
@ -602,7 +571,7 @@ const PromptTemplates: React.FC = () => {
|
|||
<Input.TextArea
|
||||
onChange={(e) => setPreviewContent(e.target.value)}
|
||||
className="prompt-template-editor__input"
|
||||
placeholder="鍦ㄦ杈撳叆 Markdown 鎸囦护..."
|
||||
placeholder="在此输入 Markdown 提示词..."
|
||||
/>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
|
|
|
|||
Loading…
Reference in New Issue