feat: manually mirror opencoze's code from bytedance
Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
@@ -0,0 +1,330 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import qs from 'qs';
|
||||
import { useSpaceStore } from '@coze-foundation/space-store';
|
||||
import {
|
||||
type Int64,
|
||||
ProductEntityType,
|
||||
type ProductInfo,
|
||||
type public_api,
|
||||
ProductListSource,
|
||||
type CommercialSetting,
|
||||
} from '@coze-arch/bot-api/product_api';
|
||||
import {
|
||||
type PluginInfoForPlayground,
|
||||
PluginType,
|
||||
} from '@coze-arch/bot-api/plugin_develop';
|
||||
// import { type PluginInfoForPlayground } from '@coze-arch/bot-api/developer_api';
|
||||
import { ProductApi, PluginDevelopApi } from '@coze-arch/bot-api';
|
||||
|
||||
import { type RequestServiceResp } from '../types/plugin-modal-types';
|
||||
import { type AuthMode } from '../types/auth-mode';
|
||||
import { DEFAULT_PAGE_SIZE } from '../constants/plugin-modal-constants';
|
||||
|
||||
type ProductMetaInfo = public_api.ProductMetaInfo;
|
||||
type PluginExtraInfo = public_api.PluginExtraInfo;
|
||||
|
||||
export type SimplifyProductInfo = Pick<
|
||||
ProductMetaInfo,
|
||||
| 'id'
|
||||
| 'category'
|
||||
| 'entity_type'
|
||||
| 'favorite_count'
|
||||
| 'heat'
|
||||
| 'is_favorited'
|
||||
| 'is_free'
|
||||
| 'status'
|
||||
| 'listed_at'
|
||||
| 'user_info'
|
||||
> & { favorite_time: string; version_name?: string } & PluginExtraInfo &
|
||||
AuthMode;
|
||||
|
||||
export interface PluginContentListItem {
|
||||
productInfo?: SimplifyProductInfo;
|
||||
pluginInfo: PluginInfoForPlayground;
|
||||
belong_page?: number;
|
||||
isFromMarket?: boolean; //数据是从哪里获取的
|
||||
commercial_setting?: CommercialSetting;
|
||||
}
|
||||
|
||||
const filterProductListParams = (key: string, value: unknown) => {
|
||||
const keyMap: {
|
||||
[K in keyof Pick<
|
||||
Required<public_api.GetProductListRequest>,
|
||||
'current_entity_id' | 'current_entity_version'
|
||||
>]: K;
|
||||
} = {
|
||||
current_entity_id: 'current_entity_id',
|
||||
current_entity_version: 'current_entity_version',
|
||||
};
|
||||
if (!(key in keyMap)) {
|
||||
return value;
|
||||
}
|
||||
// keyMap 键对应 value 为 stringifyNumber 过滤掉非法值 ''
|
||||
if (value === '') {
|
||||
return;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
function formatPluginApiProductInfo(productInfo: ProductInfo) {
|
||||
const name = productInfo?.meta_info?.name;
|
||||
const pluginId = `${productInfo?.meta_info?.entity_id || ''}`;
|
||||
const apiList = productInfo?.plugin_extra?.tools;
|
||||
return apiList?.map(item => ({
|
||||
api_id: `${item?.id || ''}`,
|
||||
desc: item?.description,
|
||||
name: item?.name,
|
||||
plugin_id: pluginId,
|
||||
plugin_name: name,
|
||||
record_id: '',
|
||||
// 插件预设卡片信息
|
||||
card_binding_info: {
|
||||
thumbnail: item?.card_info?.card_url,
|
||||
},
|
||||
parameters: item?.parameters?.map(param => ({
|
||||
name: param?.name,
|
||||
desc: param?.description,
|
||||
required: param?.required,
|
||||
type: param?.type,
|
||||
sub_params: param?.sub_params,
|
||||
})),
|
||||
debug_example: item?.example,
|
||||
}));
|
||||
}
|
||||
|
||||
function formatPluginProductInfo(
|
||||
item: ProductInfo,
|
||||
currentPage: number,
|
||||
favoriteTime: Int64 = '',
|
||||
): PluginContentListItem {
|
||||
return {
|
||||
productInfo: {
|
||||
id: String(item?.meta_info?.id),
|
||||
category: item?.meta_info?.category,
|
||||
entity_type: item?.meta_info?.entity_type,
|
||||
favorite_count: item?.meta_info?.favorite_count,
|
||||
heat: item?.meta_info?.heat,
|
||||
is_favorited: item?.meta_info?.is_favorited,
|
||||
is_free: item?.meta_info?.is_free,
|
||||
favorite_time: String(favoriteTime || ''),
|
||||
status: item?.meta_info?.status,
|
||||
listed_at: item?.meta_info?.listed_at,
|
||||
user_info: item.meta_info.user_info,
|
||||
...item.plugin_extra,
|
||||
},
|
||||
pluginInfo: {
|
||||
name: item?.meta_info?.name,
|
||||
plugin_apis: formatPluginApiProductInfo(item),
|
||||
id: `${item?.meta_info?.entity_id || ''}`,
|
||||
plugin_icon: item?.meta_info?.icon_url,
|
||||
desc_for_human: item?.meta_info?.description,
|
||||
creator: {
|
||||
id: `${item?.meta_info?.user_info?.user_id || ''}`,
|
||||
name: item?.meta_info?.user_info?.name,
|
||||
avatar_url: item?.meta_info?.user_info?.avatar_url,
|
||||
},
|
||||
statistic_data: {
|
||||
bot_quote: item?.plugin_extra?.bots_use_count || 0,
|
||||
},
|
||||
tag: item?.meta_info?.category?.id,
|
||||
},
|
||||
isFromMarket: true,
|
||||
belong_page: currentPage,
|
||||
|
||||
commercial_setting: item.commercial_setting,
|
||||
};
|
||||
}
|
||||
|
||||
// 拉取 插件市场的 插件商品列表
|
||||
async function getPluginFromMarket(
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
queryParams,
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
commParams,
|
||||
): Promise<RequestServiceResp<PluginContentListItem> | undefined> {
|
||||
const { nextPage } = commParams;
|
||||
|
||||
const {
|
||||
search,
|
||||
type,
|
||||
orderByPublic,
|
||||
botInfo = {},
|
||||
isOfficial,
|
||||
pluginType,
|
||||
} = queryParams;
|
||||
|
||||
const res = await ProductApi.PublicGetProductList(
|
||||
{
|
||||
entity_type: ProductEntityType.Plugin,
|
||||
category_id: type === 'recommend' || IS_OPEN_SOURCE ? undefined : type,
|
||||
sort_type: orderByPublic,
|
||||
page_num: nextPage,
|
||||
page_size: 20,
|
||||
keyword: search,
|
||||
source:
|
||||
type === 'recommend'
|
||||
? ProductListSource.CustomizedRecommend
|
||||
: undefined,
|
||||
is_official: isOfficial,
|
||||
plugin_type: pluginType,
|
||||
...botInfo,
|
||||
},
|
||||
{
|
||||
paramsSerializer: p =>
|
||||
qs.stringify(p, {
|
||||
filter: filterProductListParams,
|
||||
}),
|
||||
},
|
||||
);
|
||||
const list = (res?.data?.products || []).map(item =>
|
||||
formatPluginProductInfo(item, nextPage),
|
||||
);
|
||||
const hasMore = (list.length > 0 && res?.data?.has_more) || false;
|
||||
return {
|
||||
list,
|
||||
total: -1,
|
||||
hasMore,
|
||||
};
|
||||
}
|
||||
|
||||
async function getPluginFromFavorite(
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
queryParams,
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
commParams,
|
||||
): Promise<RequestServiceResp<PluginContentListItem> | undefined> {
|
||||
const { nextPage } = commParams;
|
||||
|
||||
const { search, orderByFavorite } = queryParams;
|
||||
const res = await ProductApi.PublicGetUserFavoriteList({
|
||||
entity_type: ProductEntityType.Plugin,
|
||||
sort_type: orderByFavorite,
|
||||
page_num: nextPage,
|
||||
page_size: 20,
|
||||
key_wrod: search,
|
||||
});
|
||||
const list = (res?.data?.favorite_products || [])?.map(item =>
|
||||
formatPluginProductInfo(
|
||||
item.product,
|
||||
nextPage,
|
||||
`${item?.created_at || ''}`,
|
||||
),
|
||||
);
|
||||
const hasMore = (list.length > 0 && res?.data?.has_more) || false;
|
||||
return {
|
||||
list,
|
||||
total: -1,
|
||||
hasMore,
|
||||
};
|
||||
}
|
||||
function getPluginFromMinOrTeam(
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
queryParams,
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
commParams,
|
||||
): Promise<RequestServiceResp<PluginContentListItem> | undefined> {
|
||||
const { isMine, isTeam, isCreatorMine, isTemplate, nextPage } = commParams;
|
||||
const pluginTypes = [PluginType.PLUGIN, PluginType.APP, PluginType.LOCAL];
|
||||
|
||||
const { search, orderByPublic, orderBy } = queryParams;
|
||||
const params = {
|
||||
page: nextPage || 1,
|
||||
size: DEFAULT_PAGE_SIZE,
|
||||
name: search || void 0,
|
||||
self_created: isMine || (isTeam && isCreatorMine) ? true : undefined,
|
||||
order_by: isTemplate ? orderByPublic : orderBy,
|
||||
plugin_types: pluginTypes,
|
||||
space_id: useSpaceStore.getState().getSpaceId(),
|
||||
channel_id: 1,
|
||||
};
|
||||
|
||||
return PluginDevelopApi.GetPlaygroundPluginList(params).then(res => {
|
||||
const list =
|
||||
res.data?.plugin_list?.map(item => ({
|
||||
pluginInfo: item,
|
||||
isFromMarket: false,
|
||||
// 当前数据属于第几页的数据,用于page数据替换
|
||||
// 如果后面用id + count代替page + size,可以把这个逻辑去掉
|
||||
belong_page: nextPage,
|
||||
})) || [];
|
||||
const hasMore =
|
||||
list.length > 0 && nextPage * DEFAULT_PAGE_SIZE < Number(res.data?.total);
|
||||
return {
|
||||
list,
|
||||
total: -1,
|
||||
hasMore,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
async function getPluginFromProject(
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
queryParams,
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
commParams,
|
||||
): Promise<RequestServiceResp<PluginContentListItem> | undefined> {
|
||||
const { nextPage } = commParams;
|
||||
const { search, projectId, devId, orderBy } = queryParams;
|
||||
const res = await PluginDevelopApi.GetDevPluginList({
|
||||
page: nextPage,
|
||||
size: DEFAULT_PAGE_SIZE,
|
||||
space_id: useSpaceStore.getState().getSpaceId(),
|
||||
name: search,
|
||||
dev_id: devId,
|
||||
project_id: projectId,
|
||||
order_by: orderBy,
|
||||
});
|
||||
const list = (res?.plugin_list || [])?.map(item => ({
|
||||
pluginInfo: item,
|
||||
isFromMarket: false,
|
||||
belong_page: nextPage,
|
||||
}));
|
||||
const hasMore =
|
||||
list.length > 0 && nextPage * DEFAULT_PAGE_SIZE < Number(res?.total);
|
||||
return {
|
||||
list,
|
||||
total: -1,
|
||||
hasMore,
|
||||
};
|
||||
}
|
||||
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
export const fetchPlugin = (queryParams, commParams) => {
|
||||
const { isMine, isTeam, isFavorite, isProject } = commParams;
|
||||
console.log('[div] params:', queryParams, commParams);
|
||||
if (isMine || isTeam) {
|
||||
return getPluginFromMinOrTeam(queryParams, commParams);
|
||||
} else if (isFavorite) {
|
||||
return getPluginFromFavorite(queryParams, commParams);
|
||||
} else if (isProject) {
|
||||
return getPluginFromProject(queryParams, commParams);
|
||||
}
|
||||
return getPluginFromMarket(queryParams, commParams);
|
||||
};
|
||||
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
export const formatCacheKey = ({ query, isSearching, isTemplate, page }) => {
|
||||
const { orderBy, orderByPublic, type, mineActive } = query;
|
||||
if (isSearching) {
|
||||
return;
|
||||
}
|
||||
if (isTemplate) {
|
||||
return `plugin-${type}-${page}-${orderByPublic}`;
|
||||
}
|
||||
return `plugin-${type}-${page}-${orderBy}-${mineActive}`;
|
||||
};
|
||||
Reference in New Issue
Block a user