Browse Source

feat(ai): Add an AI tool management page

pull/1457/head
colin 6 months ago
parent
commit
b799a15c29
  1. 3
      apps/vben5/apps/app-antd/src/locales/langs/en-US/abp.json
  2. 3
      apps/vben5/apps/app-antd/src/locales/langs/zh-CN/abp.json
  3. 15
      apps/vben5/apps/app-antd/src/views/ai-management/tools/index.vue
  4. 2
      apps/vben5/packages/@abp/ai-management/package.json
  5. 1
      apps/vben5/packages/@abp/ai-management/src/api/index.ts
  6. 114
      apps/vben5/packages/@abp/ai-management/src/api/useAIToolsApi.ts
  7. 2
      apps/vben5/packages/@abp/ai-management/src/api/useWorkspaceDefinitionsApi.ts
  8. 1
      apps/vben5/packages/@abp/ai-management/src/components/index.ts
  9. 321
      apps/vben5/packages/@abp/ai-management/src/components/tools/AIToolDefinitionModal.vue
  10. 236
      apps/vben5/packages/@abp/ai-management/src/components/tools/AIToolDefinitionTable.vue
  11. 54
      apps/vben5/packages/@abp/ai-management/src/components/workspaces/WorkspaceDefinitionModal.vue
  12. 7
      apps/vben5/packages/@abp/ai-management/src/constants/permissions.ts
  13. 1
      apps/vben5/packages/@abp/ai-management/src/types/index.ts
  14. 61
      apps/vben5/packages/@abp/ai-management/src/types/tools.ts
  15. 2
      apps/vben5/packages/@abp/ai-management/src/types/workspaces.ts
  16. 8
      apps/vben5/packages/@abp/ui/src/components/properties/PropertyTable.vue
  17. 3
      apps/vben5/packages/@abp/ui/src/components/properties/types.ts
  18. 2
      apps/vben5/packages/@abp/webhooks/src/components/subscriptions/WebhookSubscriptionTable.vue
  19. 9
      apps/vben5/packages/@abp/webhooks/src/types/subscriptions.ts

3
apps/vben5/apps/app-antd/src/locales/langs/en-US/abp.json

@ -153,6 +153,7 @@
"ai": {
"title": "Artificial Intelligence",
"workspaces": "Workspaces",
"conversations": "Conversations"
"conversations": "Conversations",
"tools": "AI Tools"
}
}

3
apps/vben5/apps/app-antd/src/locales/langs/zh-CN/abp.json

@ -153,6 +153,7 @@
"ai": {
"title": "人工智能",
"workspaces": "工作区管理",
"conversations": "会话管理"
"conversations": "会话管理",
"tools": "工具管理"
}
}

15
apps/vben5/apps/app-antd/src/views/ai-management/tools/index.vue

@ -0,0 +1,15 @@
<script lang="ts" setup>
import { Page } from '@vben/common-ui';
import { AIToolDefinitionTable } from '@abp/ai-management';
defineOptions({
name: 'Vben5AIToolDefinitions',
});
</script>
<template>
<Page>
<AIToolDefinitionTable />
</Page>
</template>

2
apps/vben5/packages/@abp/ai-management/package.json

@ -37,10 +37,12 @@
"ant-design-vue": "catalog:",
"ant-design-x-vue": "catalog:",
"dayjs": "catalog:",
"lodash.debounce": "catalog:",
"markdown-it": "catalog:",
"vue": "catalog:"
},
"devDependencies": {
"@types/lodash.debounce": "catalog:",
"@types/markdown-it": "catalog:"
}
}

1
apps/vben5/packages/@abp/ai-management/src/api/index.ts

@ -1,3 +1,4 @@
export { useAIToolsApi } from './useAIToolsApi';
export { useChatsApi } from './useChatsApi';
export { useConversationsApi } from './useConversationsApi';
export { useWorkspaceDefinitionsApi } from './useWorkspaceDefinitionsApi';

114
apps/vben5/packages/@abp/ai-management/src/api/useAIToolsApi.ts

@ -0,0 +1,114 @@
import type { ListResultDto, PagedResultDto } from '@abp/core';
import type {
AIToolDefinitionRecordCreateDto,
AIToolDefinitionRecordDto,
AIToolDefinitionRecordGetPagedListInput,
AIToolDefinitionRecordUpdateDto,
AIToolProviderDto,
} from '../types/tools';
import { useRequest } from '@abp/request';
export function useAIToolsApi() {
const { cancel, request } = useRequest();
/**
* 获取AI工具详情
* @param id AI工具id
* @returns AI工具详情
*/
function getApi(id: string): Promise<AIToolDefinitionRecordDto> {
return request<AIToolDefinitionRecordDto>(
`/api/ai-management/tools/${id}`,
{
method: 'GET',
},
);
}
/**
* 获取AI工具分页列表
* @param input 查询过滤参数
* @returns AI工具分页列表
*/
function getPagedListApi(
input?: AIToolDefinitionRecordGetPagedListInput,
): Promise<PagedResultDto<AIToolDefinitionRecordDto>> {
return request<PagedResultDto<AIToolDefinitionRecordDto>>(
'/api/ai-management/tools',
{
method: 'GET',
params: input,
},
);
}
/**
* 获取可用AI工具提供者列表
* @returns AI工具提供者列表
*/
function getAvailableProviderListApi(): Promise<
ListResultDto<AIToolProviderDto>
> {
return request<ListResultDto<AIToolProviderDto>>(
'/api/ai-management/tools/available-providers',
{
method: 'GET',
},
);
}
/**
* 删除AI工具
* @param id AI工具id
*/
function deleteApi(id: string): Promise<void> {
return request(`/api/ai-management/tools/${id}`, {
method: 'DELETE',
});
}
/**
* 新增AI工具
* @param input 参数
* @returns AI工具详情
*/
function createApi(
input: AIToolDefinitionRecordCreateDto,
): Promise<AIToolDefinitionRecordDto> {
return request<AIToolDefinitionRecordDto>(`/api/ai-management/tools`, {
data: input,
method: 'POST',
});
}
/**
* 编辑AI工具
* @param id AI工具id
* @param input 参数
* @returns AI工具详情
*/
function updateApi(
id: string,
input: AIToolDefinitionRecordUpdateDto,
): Promise<AIToolDefinitionRecordDto> {
return request<AIToolDefinitionRecordDto>(
`/api/ai-management/tools/${id}`,
{
data: input,
method: 'PUT',
},
);
}
return {
cancel,
createApi,
deleteApi,
getApi,
getAvailableProviderListApi,
getPagedListApi,
updateApi,
};
}

2
apps/vben5/packages/@abp/ai-management/src/api/useWorkspaceDefinitionsApi.ts

@ -87,7 +87,7 @@ export function useWorkspaceDefinitionsApi() {
}
/**
* 新增工作区
* 编辑工作区
* @param id 工作区id
* @param input 参数
* @returns 工作区详情

1
apps/vben5/packages/@abp/ai-management/src/components/index.ts

@ -1,2 +1,3 @@
export { default as Conversations } from './conversations/index.vue';
export { default as AIToolDefinitionTable } from './tools/AIToolDefinitionTable.vue';
export { default as WorkspaceDefinitionTable } from './workspaces/WorkspaceDefinitionTable.vue';

321
apps/vben5/packages/@abp/ai-management/src/components/tools/AIToolDefinitionModal.vue

@ -0,0 +1,321 @@
<script setup lang="ts">
import type { PropertyInfo } from '@abp/ui';
import type { FormInstance } from 'ant-design-vue/lib/form';
import type {
DefaultOptionType,
SelectProps,
SelectValue,
} from 'ant-design-vue/lib/select';
import type {
AIToolDefinitionRecordDto,
AIToolProviderDto,
} from '../../types/tools';
import { computed, nextTick, ref, useTemplateRef, watch } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { $t } from '@vben/locales';
import { useAuthorization } from '@abp/core';
import { LocalizableInput, PropertyTable, useMessage } from '@abp/ui';
import {
Checkbox,
Form,
FormItemRest,
Input,
InputNumber,
Select,
Tabs,
} from 'ant-design-vue';
import { useAIToolsApi } from '../../api/useAIToolsApi';
import { AIToolDefinitionPermissions } from '../../constants/permissions';
const emit = defineEmits<{
(event: 'change', data: AIToolDefinitionVto): void;
}>();
const FormItem = Form.Item;
const TabPane = Tabs.TabPane;
type AIToolDefinitionVto = Omit<AIToolDefinitionRecordDto, 'creationTime'> & {
apiKey?: string;
};
// 默认表单数据
const defaultModel: AIToolDefinitionVto = {
id: '',
name: '',
isEnabled: true,
isGlobal: false,
isSystem: false,
provider: '',
extraProperties: {},
};
const message = useMessage();
const { isGranted } = useAuthorization();
const { createApi, updateApi, getApi, getAvailableProviderListApi } =
useAIToolsApi();
// 表单
const form = useTemplateRef<FormInstance>('formEl');
// 表单数据
const formModel = ref<AIToolDefinitionVto>({ ...defaultModel });
// 工具提供者选项
const aiToolProviders = ref<AIToolProviderDto[]>([]);
const currentAIToolProvider = ref<AIToolProviderDto>();
const getAIToolOptions = computed<NonNullable<SelectProps['options']>>(() => {
return aiToolProviders.value.map((provider) => {
return {
label: provider.name,
value: provider.name,
properties: provider.properties,
};
});
});
// 表单允许编辑
const getIsAllowUpdate = computed<boolean>(() => {
if (formModel.value.id) {
if (formModel.value.isSystem) {
return false;
}
return isGranted(AIToolDefinitionPermissions.Update);
}
return isGranted(AIToolDefinitionPermissions.Create);
});
watch(
() => getIsAllowUpdate.value,
(allowUpdate) => {
nextTick(() => {
modalApi.setState({ showConfirmButton: allowUpdate });
});
},
);
// 工作区编辑模态框
const [Modal, modalApi] = useVbenModal({
title: $t('AIManagement.Tools:New'),
class: 'w-1/2',
closeOnClickModal: false,
closeOnPressEscape: false,
fullscreenButton: false,
onConfirm: onSubmit,
async onOpenChange(isOpen) {
isOpen && (await onInit());
},
});
/** 初始化工作区数据 */
async function onInit() {
try {
modalApi.setState({
loading: true,
title: $t('AIManagement.Tools:New'),
});
await onInitProviderOptions();
const { id } = modalApi.getData<AIToolDefinitionVto>();
if (!id) {
formModel.value = { ...defaultModel };
currentAIToolProvider.value = undefined;
return;
}
const dto = await getApi(id);
formModel.value = dto;
currentAIToolProvider.value = aiToolProviders.value.find(
(p) => p.name === dto.provider,
);
modalApi.setState({
title: $t('AIManagement.Tools:Edit'),
});
} finally {
modalApi.setState({
loading: false,
});
}
}
/** 初始化模型选项 */
async function onInitProviderOptions() {
const { items } = await getAvailableProviderListApi();
aiToolProviders.value = items;
}
function onProviderChange(_: SelectValue, option: DefaultOptionType) {
const provider = option as AIToolProviderDto;
currentAIToolProvider.value = provider;
if (provider) {
const propertites: Record<string, any> = {};
provider.properties.forEach((prop) => {
propertites[prop.name] = '';
});
formModel.value.extraProperties ??= {};
formModel.value.extraProperties = propertites;
}
}
function onPropChange(key: string, prop: PropertyInfo) {
const propertites = formModel.value.extraProperties ?? {};
propertites[key] = {};
propertites[key][prop.key] = prop.value;
formModel.value.extraProperties = propertites;
}
function onPropDelete(key: string, prop: PropertyInfo) {
const propertites = formModel.value.extraProperties ?? {};
propertites[key] = {};
delete propertites[key][prop.key];
formModel.value.extraProperties = propertites;
}
/** 提交表单 */
async function onSubmit() {
await form.value?.validate();
try {
modalApi.setState({ submitting: true });
const vto = await (formModel.value.id
? updateApi(formModel.value.id, formModel.value)
: createApi(formModel.value));
formModel.value = vto;
message.success($t('AbpUi.SavedSuccessfully'));
emit('change', vto);
modalApi.close();
} finally {
modalApi.setState({ submitting: false });
}
}
</script>
<template>
<Modal>
<Form
:model="formModel"
ref="formEl"
:label-col="{ span: 6 }"
:wrapper-col="{ span: 18 }"
:disabled="!getIsAllowUpdate"
scroll-to-first-error
>
<Tabs>
<TabPane key="basic" :tab="$t('AIManagement.BasicInfo')" force-render>
<FormItem
:label="$t('AIManagement.DisplayName:IsEnabled')"
name="isEnabled"
>
<Checkbox v-model:checked="formModel.isEnabled">
{{ $t('AIManagement.DisplayName:IsEnabled') }}
</Checkbox>
</FormItem>
<FormItem
:label="$t('AIManagement.DisplayName:IsGlobal')"
name="isEnabled"
>
<Checkbox v-model:checked="formModel.isGlobal">
{{ $t('AIManagement.DisplayName:IsGlobal') }}
</Checkbox>
</FormItem>
<FormItem
:label="$t('AIManagement.DisplayName:ToolProvider')"
name="provider"
required
>
<Select
:options="getAIToolOptions"
v-model:value="formModel.provider"
@change="onProviderChange"
/>
</FormItem>
<FormItem
:label="$t('AIManagement.DisplayName:Name')"
name="name"
required
>
<Input v-model:value="formModel.name" />
</FormItem>
<FormItem
:label="$t('AIManagement.DisplayName:Description')"
name="description"
>
<LocalizableInput v-model:value="formModel.description" />
</FormItem>
</TabPane>
<TabPane
v-if="currentAIToolProvider"
key="propertites"
:tab="$t('AIManagement.Propertites')"
force-render
>
<div class="h-[500px] overflow-y-auto rounded bg-gray-50 p-4">
<template
v-for="prop in currentAIToolProvider.properties"
:key="prop.name"
>
<FormItem
v-if="prop.valueType === 'String'"
:extra="prop.description"
:label="prop.displayName"
:name="['extraProperties', prop.name]"
:required="prop.required"
>
<Input v-model:value="formModel.extraProperties[prop.name]" />
</FormItem>
<FormItem
v-if="prop.valueType === 'Number'"
:extra="prop.description"
:label="prop.displayName"
:name="['extraProperties', prop.name]"
:required="prop.required"
>
<InputNumber
class="w-full"
:min="0"
v-model:value="formModel.extraProperties[prop.name]"
/>
</FormItem>
<FormItem
v-else-if="prop.valueType === 'Boolean'"
:extra="prop.description"
:label="prop.displayName"
:name="['extraProperties', prop.name]"
:required="prop.required"
>
<Checkbox
v-model:checked="formModel.extraProperties[prop.name]"
>
{{ prop.displayName }}
</Checkbox>
</FormItem>
<FormItem
v-else-if="prop.valueType === 'Select'"
:extra="prop.description"
:label="prop.displayName"
:name="['extraProperties', prop.name]"
:required="prop.required"
>
<Select
class="w-full"
:options="prop.options"
:field-names="{ label: 'name', value: 'value' }"
v-model:value="formModel.extraProperties[prop.name]"
/>
</FormItem>
<FormItem
v-else-if="prop.valueType === 'Dictionary'"
:extra="prop.description"
:label="prop.displayName"
:name="['extraProperties', prop.name]"
>
<FormItemRest>
<PropertyTable
:data="formModel.extraProperties[prop.name]"
@change="(data) => onPropChange(prop.name, data)"
@delete="(data) => onPropDelete(prop.name, data)"
/>
</FormItemRest>
</FormItem>
</template>
</div>
</TabPane>
</Tabs>
</Form>
</Modal>
</template>
<style scoped></style>

236
apps/vben5/packages/@abp/ai-management/src/components/tools/AIToolDefinitionTable.vue

@ -0,0 +1,236 @@
<script setup lang="ts">
import type { VxeGridProps } from '@abp/ui';
import type { VbenFormProps } from '@vben/common-ui';
import type { AIToolDefinitionRecordDto } from '../../types/tools';
import { defineAsyncComponent, h } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { $t } from '@vben/locales';
import {
useAuthorization,
useLocalization,
useLocalizationSerializer,
} from '@abp/core';
import { useVbenVxeGrid } from '@abp/ui';
import {
CheckOutlined,
CloseOutlined,
DeleteOutlined,
EditOutlined,
PlusOutlined,
} from '@ant-design/icons-vue';
import { Button, message, Modal } from 'ant-design-vue';
import { useAIToolsApi } from '../../api/useAIToolsApi';
import { AIToolDefinitionPermissions } from '../../constants/permissions';
defineOptions({
name: 'WorkspaceDefinitionTable',
});
const { deleteApi, getPagedListApi } = useAIToolsApi();
const { isGranted } = useAuthorization();
const { Lr } = useLocalization();
const { deserialize: deserializeLocalizableString } =
useLocalizationSerializer();
const formOptions: VbenFormProps = {
// 默认展开
collapsed: true,
collapsedRows: 2,
schema: [
{
component: 'Input',
fieldName: 'filter',
formItemClass: 'col-span-2 items-baseline',
label: $t('AbpUi.Search'),
},
],
// 控制表单是否显示折叠按钮
showCollapseButton: true,
// 按下回车时是否提交表单
submitOnEnter: true,
wrapperClass: 'grid-cols-4',
};
const gridOptions: VxeGridProps<AIToolDefinitionRecordDto> = {
columns: [
{
align: 'left',
field: 'name',
sortable: true,
title: $t('AIManagement.DisplayName:Name'),
},
{
align: 'left',
field: 'provider',
sortable: true,
title: $t('AIManagement.DisplayName:ToolProvider'),
width: 150,
},
{
align: 'left',
field: 'description',
formatter: ({ row }) => {
if (!row.description) {
return '';
}
const localizableString = deserializeLocalizableString(row.description);
return Lr(localizableString.resourceName, localizableString.name);
},
sortable: true,
title: $t('AIManagement.DisplayName:Description'),
width: 180,
},
{
align: 'left',
field: 'isEnabled',
slots: { default: 'isEnabled' },
sortable: true,
title: $t('AIManagement.DisplayName:IsEnabled'),
width: 150,
},
{
align: 'left',
field: 'isGlobal',
slots: { default: 'isGlobal' },
sortable: true,
title: $t('AIManagement.DisplayName:IsGlobal'),
width: 150,
},
{
field: 'actions',
fixed: 'right',
slots: { default: 'actions' },
title: $t('AbpUi.Actions'),
width: 220,
visible: isGranted([
AIToolDefinitionPermissions.Default,
AIToolDefinitionPermissions.Delete,
]),
},
],
exportConfig: {},
keepSource: true,
proxyConfig: {
ajax: {
query: async ({ page, sort }, formValues) => {
const sorting = sort.order ? `${sort.field} ${sort.order}` : undefined;
return await getPagedListApi({
sorting,
maxResultCount: page.pageSize,
skipCount: (page.currentPage - 1) * page.pageSize,
...formValues,
});
},
},
response: {
total: 'totalCount',
list: 'items',
},
},
sortConfig: {
remote: true,
allowBtn: true,
},
toolbarConfig: {
custom: true,
export: true,
// import: true,
refresh: {
code: 'query',
},
zoom: true,
},
};
const [Grid, gridApi] = useVbenVxeGrid<AIToolDefinitionRecordDto>({
formOptions,
gridOptions,
});
const [AIToolDefinitionModal, modalApi] = useVbenModal({
connectedComponent: defineAsyncComponent(
() => import('./AIToolDefinitionModal.vue'),
),
});
function onCreate() {
modalApi.setData({});
modalApi.open();
}
function onUpdate(row: AIToolDefinitionRecordDto) {
modalApi.setData(row);
modalApi.open();
}
async function onDelete(row: AIToolDefinitionRecordDto) {
Modal.confirm({
centered: true,
content: $t('AbpUi.ItemWillBeDeletedMessage'),
onOk: async () => {
await deleteApi(row.id);
message.success($t('AbpUi.DeletedSuccessfully'));
gridApi.query();
},
title: $t('AbpUi.AreYouSure'),
});
}
</script>
<template>
<Grid :table-title="$t('AIManagement.Tools')">
<template #toolbar-tools>
<Button
v-access:code="[AIToolDefinitionPermissions.Create]"
:icon="h(PlusOutlined)"
type="primary"
@click="onCreate"
>
{{ $t('AIManagement.Tools:New') }}
</Button>
</template>
<template #isEnabled="{ row }">
<div class="flex flex-row justify-center">
<CheckOutlined v-if="row.isEnabled" class="text-green-500" />
<CloseOutlined v-else class="text-red-500" />
</div>
</template>
<template #isGlobal="{ row }">
<div class="flex flex-row justify-center">
<CheckOutlined v-if="row.isGlobal" class="text-green-500" />
<CloseOutlined v-else class="text-red-500" />
</div>
</template>
<template #actions="{ row }">
<div class="flex flex-row">
<Button
v-access:code="[AIToolDefinitionPermissions.Default]"
:icon="h(EditOutlined)"
block
type="link"
@click="onUpdate(row)"
>
{{ $t('AbpUi.Edit') }}
</Button>
<Button
v-access:code="[AIToolDefinitionPermissions.Delete]"
:icon="h(DeleteOutlined)"
block
danger
type="link"
@click="onDelete(row)"
>
{{ $t('AbpUi.Delete') }}
</Button>
</div>
</template>
</Grid>
<AIToolDefinitionModal @change="() => gridApi.query()" />
</template>
<style lang="scss" scoped></style>

54
apps/vben5/packages/@abp/ai-management/src/components/workspaces/WorkspaceDefinitionModal.vue

@ -13,7 +13,11 @@ import { ref, useTemplateRef } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { $t } from '@vben/locales';
import { useAuthorization } from '@abp/core';
import {
useAuthorization,
useLocalization,
useLocalizationSerializer,
} from '@abp/core';
import { useMessage } from '@abp/ui';
import {
AutoComplete,
@ -25,7 +29,9 @@ import {
Tabs,
Textarea,
} from 'ant-design-vue';
import debounce from 'lodash.debounce';
import { useAIToolsApi } from '../../api/useAIToolsApi';
import { useWorkspaceDefinitionsApi } from '../../api/useWorkspaceDefinitionsApi';
import { WorkspaceDefinitionPermissions } from '../../constants/permissions';
@ -53,6 +59,10 @@ const defaultModel: WorkspaceDefinitionVto = {
const message = useMessage();
const { isGranted } = useAuthorization();
const { Lr } = useLocalization();
const { deserialize: deserializeLocalizableString } =
useLocalizationSerializer();
const { getPagedListApi: getAIToolPagedListApi } = useAIToolsApi();
const { createApi, updateApi, getApi, getAvailableProviderListApi } =
useWorkspaceDefinitionsApi();
// 表单允许编辑
@ -65,6 +75,8 @@ const formModel = ref<WorkspaceDefinitionVto>({ ...defaultModel });
const providerOptions = ref<NonNullable<SelectProps['options']>>([]);
// 模型选项
const modelOptions = ref<NonNullable<SelectProps['options']>>([]);
// AI工具
const aiToolOptions = ref<NonNullable<SelectProps['options']>>([]);
// 工作区编辑模态框
const [Modal, modalApi] = useVbenModal({
@ -85,7 +97,7 @@ async function onInit() {
loading: true,
title: $t('AIManagement.Workspaces:New'),
});
await onInitProviderOptions();
await Promise.all([onSearchAIToolOptions(), onInitProviderOptions()]);
const { id } = modalApi.getData<WorkspaceDefinitionVto>();
if (!id) {
isAllowUpdate.value = isGranted(WorkspaceDefinitionPermissions.Create);
@ -123,6 +135,27 @@ async function onInitProviderOptions() {
});
}
/** 初始化AI工具选项 */
const onSearchAIToolOptions = debounce((filter?: string) => {
getAIToolPagedListApi({ isEnabled: true, filter }).then((res) => {
aiToolOptions.value = res.items.map((item) => {
let description = item.description;
if (description) {
const localizableString = deserializeLocalizableString(description);
description = Lr(
localizableString.resourceName,
localizableString.name,
);
}
return {
label: item.name,
value: item.name,
description,
};
});
});
}, 500);
function onProviderChange(_: SelectValue, option: DefaultOptionType) {
modelOptions.value = option.models;
}
@ -188,6 +221,21 @@ async function onSubmit() {
:auto-size="{ minRows: 3 }"
/>
</FormItem>
<FormItem :label="$t('AIManagement.DisplayName:Tools')" name="tools">
<Select
:allow-clear="true"
:show-search="true"
:filter-option="false"
:options="aiToolOptions"
v-model:value="formModel.tools"
mode="multiple"
@search="onSearchAIToolOptions"
>
<template #option="{ label, description }">
{{ label }} ({{ description }})
</template>
</Select>
</FormItem>
</TabPane>
<TabPane key="model" :tab="$t('AIManagement.ModelInfo')" force-render>
<div class="h-[500px] overflow-y-auto rounded bg-gray-50 p-4">
@ -254,7 +302,7 @@ async function onSubmit() {
>
<InputNumber
v-model:value="formModel.temperature"
:max="1.0"
:max="2.0"
:min="0.0"
:step="0.1"
class="w-full"

7
apps/vben5/packages/@abp/ai-management/src/constants/permissions.ts

@ -16,3 +16,10 @@ export const ChatPermissions = {
Default: 'AIManagement.Chats',
SendMessage: 'AIManagement.Chats.SendMessage',
};
export const AIToolDefinitionPermissions = {
Default: 'AIManagement.AIToolDefinitions',
Create: 'AIManagement.AIToolDefinitions.Create',
Update: 'AIManagement.AIToolDefinitions.Update',
Delete: 'AIManagement.AIToolDefinitions.Delete',
};

1
apps/vben5/packages/@abp/ai-management/src/types/index.ts

@ -1,3 +1,4 @@
export * from './chats';
export * from './conversations';
export * from './tools';
export * from './workspaces';

61
apps/vben5/packages/@abp/ai-management/src/types/tools.ts

@ -0,0 +1,61 @@
import type {
ExtensibleAuditedEntityDto,
ExtensibleObject,
IHasConcurrencyStamp,
NameValue,
PagedAndSortedResultRequestDto,
} from '@abp/core';
interface AIToolDefinitionRecordDto
extends ExtensibleAuditedEntityDto<string>, IHasConcurrencyStamp {
description?: string;
isEnabled: boolean;
isGlobal: boolean;
isSystem: boolean;
name: string;
provider: string;
stateCheckers?: string;
}
interface AIToolDefinitionRecordCreateOrUpdateDto extends ExtensibleObject {
description?: string;
isEnabled: boolean;
isGlobal: boolean;
provider: string;
stateCheckers?: string;
}
interface AIToolDefinitionRecordCreateDto extends AIToolDefinitionRecordCreateOrUpdateDto {
name: string;
}
interface AIToolDefinitionRecordUpdateDto
extends AIToolDefinitionRecordCreateOrUpdateDto, IHasConcurrencyStamp {}
interface AIToolDefinitionRecordGetPagedListInput extends PagedAndSortedResultRequestDto {
filter?: string;
isEnabled?: boolean;
provider?: string;
}
interface AIToolPropertyDescriptorDto {
description?: string;
displayName: string;
name: string;
options: NameValue<any>[];
required: boolean;
valueType: string;
}
interface AIToolProviderDto {
name: string;
properties: AIToolPropertyDescriptorDto[];
}
export type {
AIToolDefinitionRecordCreateDto,
AIToolDefinitionRecordDto,
AIToolDefinitionRecordGetPagedListInput,
AIToolDefinitionRecordUpdateDto,
AIToolProviderDto,
};

2
apps/vben5/packages/@abp/ai-management/src/types/workspaces.ts

@ -21,6 +21,7 @@ interface WorkspaceDefinitionRecordDto
stateCheckers?: string;
systemPrompt?: string;
temperature?: number;
tools?: string[];
}
interface WorkspaceDefinitionRecordCreateOrUpdateDto extends ExtensibleObject {
@ -38,6 +39,7 @@ interface WorkspaceDefinitionRecordCreateOrUpdateDto extends ExtensibleObject {
stateCheckers?: string;
systemPrompt?: string;
temperature?: number;
tools?: string[];
}
interface WorkspaceDefinitionRecordCreateDto extends WorkspaceDefinitionRecordCreateOrUpdateDto {

8
apps/vben5/packages/@abp/ui/src/components/properties/PropertyTable.vue

@ -8,6 +8,7 @@ import { computed, defineAsyncComponent } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { createIconifyIcon } from '@vben/icons';
import { $t } from '@vben/locales';
import { isFunction } from '@vben/utils';
import { Button, Popconfirm, Table } from 'ant-design-vue';
@ -46,8 +47,13 @@ const getTableColumns = computed((): TableColumnsType<PropertyInfo> => {
align: 'left',
dataIndex: 'key',
fixed: 'left',
minWidth: 100,
width: 100,
title: $t('component.extra_property_dictionary.key'),
customRender: (opt) => {
if (props.renderKey && isFunction(props.renderKey)) {
return props.renderKey(opt.record.key);
}
},
},
{
align: 'left',

3
apps/vben5/packages/@abp/ui/src/components/properties/types.ts

@ -1,5 +1,7 @@
import type { Dictionary } from '@abp/core';
import type { VNode } from 'vue';
interface PropertyInfo {
key: string;
value: string;
@ -9,6 +11,7 @@ interface PropertyProps {
allowEdit?: boolean;
data?: Dictionary<string, string>;
disabled?: boolean;
renderKey?: (key: string) => string | VNode;
}
export type { PropertyInfo, PropertyProps };

2
apps/vben5/packages/@abp/webhooks/src/components/subscriptions/WebhookSubscriptionTable.vue

@ -273,7 +273,7 @@ function onUpdate(row: WebhookSubscriptionDto) {
function onDelete(row: WebhookSubscriptionDto) {
Modal.confirm({
centered: true,
content: $t('AbpUi.ItemWillBeDeletedMessageWithFormat', [row.title]),
content: $t('AbpUi.ItemWillBeDeletedMessageWithFormat', [row.description]),
onCancel: () => {
cancel();
},

9
apps/vben5/packages/@abp/webhooks/src/types/subscriptions.ts

@ -5,8 +5,7 @@ import type {
} from '@abp/core';
interface WebhookSubscriptionDto
extends CreationAuditedEntityDto<string>,
IHasConcurrencyStamp {
extends CreationAuditedEntityDto<string>, IHasConcurrencyStamp {
description?: string;
headers?: Record<string, string>;
isActive: boolean;
@ -31,15 +30,13 @@ interface WebhookSubscriptionCreateOrUpdateDto {
type WebhookSubscriptionCreateDto = WebhookSubscriptionCreateOrUpdateDto;
interface WebhookSubscriptionUpdateDto
extends IHasConcurrencyStamp,
WebhookSubscriptionCreateOrUpdateDto {}
extends IHasConcurrencyStamp, WebhookSubscriptionCreateOrUpdateDto {}
interface WebhookSubscriptionDeleteManyInput {
recordIds: string[];
}
interface WebhookSubscriptionGetListInput
extends PagedAndSortedResultRequestDto {
interface WebhookSubscriptionGetListInput extends PagedAndSortedResultRequestDto {
beginCreationTime?: Date;
endCreationTime?: Date;
filter?: string;

Loading…
Cancel
Save