feat: manually mirror opencoze's code from bytedance

Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
fanlv
2025-07-20 17:36:12 +08:00
commit 890153324f
14811 changed files with 1923430 additions and 0 deletions

View File

@@ -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}`;
};