Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ feat: support configuring multiple agent index urls #1648

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/self-hosting/environment-variables/basic.mdx
Expand Up @@ -173,7 +173,7 @@ Further reading:
### `PLUGINS_INDEX_URL`

- Type: Optional
- Description: Index address of the LobeChat plugin market. If you have deployed the plugin market service on your own, you can use this variable to override the default plugin market address.
- Description: Index address of the LobeChat plugin market. If you have deployed the plugin market service on your own, you can use this variable to override the default plugin market address, it supports comma-separated values to configure multiple index addresses.
- Default: `https://chat-plugins.lobehub.com`

### `PLUGIN_SETTINGS`
Expand Down Expand Up @@ -202,7 +202,7 @@ The above example sets the `SERPAPI_API_KEY` of the `search-engine` plugin to `x
### `AGENTS_INDEX_URL`

- Type: Optional
- Description: Index address of the LobeChat assistant market. If you have deployed the assistant market service on your own, you can use this variable to override the default market address.
- Description: Index address of the LobeChat assistant market. If you have deployed the assistant market service on your own, you can use this variable to override the default market address, it supports comma-separated values to configure multiple index addresses.
- Default: `https://chat-agents.lobehub.com`

[auth0-client-page]: https://manage.auth0.com/dashboard
4 changes: 2 additions & 2 deletions docs/self-hosting/environment-variables/basic.zh-CN.mdx
Expand Up @@ -172,7 +172,7 @@ LobeChat 在部署时提供了一些额外的配置项,你可以使用环境
### `PLUGINS_INDEX_URL`

- 类型:可选
- 描述:LobeChat 插件市场的索引地址,如果你自行部署了插件市场的服务,可以使用该变量来覆盖默认的插件市场地址
- 描述:LobeChat 插件市场的索引地址,如果你自行部署了插件市场的服务,可以使用该变量来覆盖默认的插件市场地址, 支持用逗号分隔以配置多个索引地址.
- 默认值:`https://chat-plugins.lobehub.com`

### `PLUGIN_SETTINGS`
Expand Down Expand Up @@ -201,7 +201,7 @@ LobeChat 在部署时提供了一些额外的配置项,你可以使用环境
### `AGENTS_INDEX_URL`

- 类型:可选
- 描述:LobeChat 助手市场的索引地址,如果你自行部署了助手市场的服务,可以使用该变量来覆盖默认的市场地址
- 描述:LobeChat 助手市场的索引地址,如果你自行部署了助手市场的服务,可以使用该变量来覆盖默认的市场地址, 支持用逗号分隔以配置多个索引地址.
- 默认值:`https://chat-agents.lobehub.com`

[auth0-client-page]: https://manage.auth0.com/dashboard
15 changes: 13 additions & 2 deletions src/app/api/market/[id]/route.ts
@@ -1,4 +1,8 @@
import { NextResponse } from 'next/server';

import { getServerConfig } from '@/config/server';
import { DEFAULT_LANG } from '@/const/locale';
import { AgentsMarketItem } from '@/types/market';

import { AgentMarket } from '../AgentMarket';

Expand All @@ -8,8 +12,10 @@ export const GET = async (req: Request, { params }: { params: { id: string } })
const { searchParams } = new URL(req.url);

const locale = searchParams.get('locale');
const marketId = Number(searchParams.get('marketId')) || 0; // Convert marketId to number
const marketBaseUrls = getServerConfig().AGENTS_INDEX_URL.split(',');

const market = new AgentMarket();
const market = new AgentMarket(marketBaseUrls[marketId]);

let res: Response;

Expand All @@ -18,5 +24,10 @@ export const GET = async (req: Request, { params }: { params: { id: string } })
res = await fetch(market.getAgentUrl(params.id, DEFAULT_LANG));
}

return res;
if (res.status !== 200) {
return res;
}
const data: AgentsMarketItem = await res.json();
data.marketId = marketId;
return NextResponse.json(data);
};
40 changes: 31 additions & 9 deletions src/app/api/market/route.ts
@@ -1,4 +1,8 @@
import { NextResponse } from 'next/server';

import { getServerConfig } from '@/config/server';
import { DEFAULT_LANG } from '@/const/locale';
import { LobeChatAgentsMarketIndex } from '@/types/market';

import { AgentMarket } from './AgentMarket';

Expand All @@ -7,15 +11,33 @@ export const runtime = 'edge';
export const GET = async (req: Request) => {
const locale = new URL(req.url).searchParams.get('locale');

const market = new AgentMarket();

let res: Response;

res = await fetch(market.getAgentIndexUrl(locale as any));

if (res.status === 404) {
res = await fetch(market.getAgentIndexUrl(DEFAULT_LANG));
const marketBaseUrls = getServerConfig().AGENTS_INDEX_URL.split(',');

let marketIndex: LobeChatAgentsMarketIndex = {
agents: [],
schemaVersion: 1,
tags: [],
};
for (const [index, baseUrl] of marketBaseUrls.entries()) {
const market = new AgentMarket(baseUrl);
let res: Response;
res = await fetch(market.getAgentIndexUrl(locale as any));

if (res.status === 404) {
res = await fetch(market.getAgentIndexUrl(DEFAULT_LANG));
}

if (res.status !== 200) {
continue;
}

const data: LobeChatAgentsMarketIndex = await res.json();
marketIndex.tags = marketIndex.tags.concat(data.tags);
for (const agent of data.agents) {
agent.marketId = index;
marketIndex.agents.push(agent);
}
}

return res;
return NextResponse.json(marketIndex);
};
34 changes: 25 additions & 9 deletions src/app/api/plugin/store/route.ts
@@ -1,3 +1,7 @@
import { LobeChatPluginsMarketIndex } from '@lobehub/chat-plugin-sdk';
import { NextResponse } from 'next/server';

import { getServerConfig } from '@/config/server';
import { DEFAULT_LANG } from '@/const/locale';

import { PluginStore } from './Store';
Expand All @@ -7,15 +11,27 @@ export const runtime = 'edge';
export const GET = async (req: Request) => {
const locale = new URL(req.url).searchParams.get('locale');

const pluginStore = new PluginStore();

let res: Response;

res = await fetch(pluginStore.getPluginIndexUrl(locale as any), { next: { revalidate: 3600 } });

if (res.status === 404) {
res = await fetch(pluginStore.getPluginIndexUrl(DEFAULT_LANG));
const pluginBaseUrls = getServerConfig().PLUGINS_INDEX_URL.split(',');
let pluginIndex: LobeChatPluginsMarketIndex = {
plugins: [],
schemaVersion: 1,
};
for (const baseUrl of pluginBaseUrls) {
const pluginStore = new PluginStore(baseUrl);
let res: Response;
res = await fetch(pluginStore.getPluginIndexUrl(locale as any));

if (res.status === 404) {
res = await fetch(pluginStore.getPluginIndexUrl(DEFAULT_LANG));
}

if (res.status !== 200) {
continue;
}

const data: LobeChatPluginsMarketIndex = await res.json();
pluginIndex.plugins = pluginIndex.plugins.concat(data.plugins);
}

return res;
return NextResponse.json(pluginIndex);
};
2 changes: 1 addition & 1 deletion src/app/market/_layout/Desktop/AgentDetail.tsx
Expand Up @@ -38,7 +38,7 @@ const SideBar = memo(() => {
setTempId(useMarketStore.getState().currentIdentifier);
deactivateAgent();
} else if (tempId) {
activateAgent(tempId);
activateAgent(tempId, useMarketStore.getState().currentMarketId);
}
},
[deactivateAgent, activateAgent, tempId],
Expand Down
7 changes: 5 additions & 2 deletions src/app/market/features/AgentCard/AgentCardItem.tsx
Expand Up @@ -14,7 +14,7 @@ import { useStyles } from './style';

const { Paragraph } = Typography;

const AgentCardItem = memo<AgentsMarketIndexItem>(({ meta, identifier }) => {
const AgentCardItem = memo<AgentsMarketIndexItem>(({ meta, identifier, marketId }) => {
const ref = useRef(null);
const isHovering = useHover(ref);
const onAgentCardClick = useMarketStore((s) => s.activateAgent);
Expand All @@ -24,7 +24,10 @@ const AgentCardItem = memo<AgentsMarketIndexItem>(({ meta, identifier }) => {
const { avatar, title, description, tags, backgroundColor } = meta;

return (
<Flexbox className={styles.container} onClick={() => onAgentCardClick(identifier)}>
<Flexbox
className={styles.container}
onClick={() => onAgentCardClick(identifier, marketId || 0)}
>
<AgentCardBanner meta={meta} style={{ opacity: isDarkMode ? 0.9 : 0.4 }} />
<Flexbox className={styles.inner} gap={8} ref={ref}>
<Avatar
Expand Down
Expand Up @@ -18,13 +18,14 @@ enum InfoTabs {
}

const AgentModalInner = memo(() => {
const [useFetchAgent, currentIdentifier] = useMarketStore((s) => [
const [useFetchAgent, currentIdentifier, currentMarketId] = useMarketStore((s) => [
s.useFetchAgent,
s.currentIdentifier,
s.currentMarketId,
]);
const { t } = useTranslation('market');
const [tab, setTab] = useState<string>(InfoTabs.prompt);
const { data, isLoading } = useFetchAgent(currentIdentifier);
const { data, isLoading } = useFetchAgent(currentIdentifier, currentMarketId);
const { styles } = useStyles();

if (isLoading || !data?.meta) return <Loading />;
Expand Down
6 changes: 4 additions & 2 deletions src/services/market.ts
Expand Up @@ -12,9 +12,11 @@ class MarketService {
/**
* 请求助手 manifest
*/
getAgentManifest = async (identifier: string, locale: string) => {
getAgentManifest = async (identifier: string, locale: string, marketId: number = 0) => {
if (!identifier) return;
const res = await fetch(`${API_ENDPOINTS.marketItem(identifier)}?locale=${locale}`);
const res = await fetch(
`${API_ENDPOINTS.marketItem(identifier)}?locale=${locale}&marketId=${marketId}`,
);

return res.json();
};
Expand Down
10 changes: 6 additions & 4 deletions src/store/market/action.ts
Expand Up @@ -10,11 +10,11 @@ import { AgentsMarketItem, LobeChatAgentsMarketIndex } from '@/types/market';
import type { Store } from './store';

export interface StoreAction {
activateAgent: (identifier: string) => void;
activateAgent: (identifier: string, marketId: number) => void;
deactivateAgent: () => void;
setSearchKeywords: (keywords: string) => void;
updateAgentMap: (key: string, value: AgentsMarketItem) => void;
useFetchAgent: (identifier: string) => SWRResponse<AgentsMarketItem>;
useFetchAgent: (identifier: string, marketId: number) => SWRResponse<AgentsMarketItem>;
useFetchAgentList: () => SWRResponse<LobeChatAgentsMarketIndex>;
}

Expand All @@ -24,8 +24,9 @@ export const createMarketAction: StateCreator<
[],
StoreAction
> = (set, get) => ({
activateAgent: (identifier) => {
activateAgent: (identifier, marketId) => {
set({ currentIdentifier: identifier });
set({ currentMarketId: marketId });
},
deactivateAgent: () => {
set({ currentIdentifier: undefined }, false, 'deactivateAgent');
Expand All @@ -47,7 +48,8 @@ export const createMarketAction: StateCreator<
useFetchAgent: (identifier) =>
useSWR<AgentsMarketItem>(
[identifier, globalHelpers.getCurrentLanguage()],
([id, locale]) => marketService.getAgentManifest(id, locale as string),
([id, locale, marketId]) =>
marketService.getAgentManifest(id, locale as string, marketId as number),
{
onError: () => {
get().deactivateAgent();
Expand Down
2 changes: 2 additions & 0 deletions src/store/market/initialState.ts
Expand Up @@ -6,6 +6,7 @@ export interface StoreState {
agentList: AgentsMarketIndexItem[];
agentMap: MarketAgentMap;
currentIdentifier: string;
currentMarketId: number;
searchKeywords: string;
tagList: string[];
}
Expand All @@ -14,6 +15,7 @@ export const initialState: StoreState = {
agentList: [],
agentMap: {},
currentIdentifier: '',
currentMarketId: 0,
searchKeywords: '',
tagList: [],
};
2 changes: 1 addition & 1 deletion src/store/market/store.ts
Expand Up @@ -27,7 +27,7 @@ const persistOptions: PersistOptions<Store> = {
mode: 'search',
selectors: [
// map state key to storage key
{ currentIdentifier: 'agent' },
{ currentIdentifier: 'agent', currentMarketId: 'market' },
],
},
}),
Expand Down
1 change: 1 addition & 0 deletions src/types/market.ts
Expand Up @@ -7,6 +7,7 @@ export interface AgentsMarketIndexItem {
homepage: string;
identifier: string;
manifest: string;
marketId?: number;
meta: MetaData;
schemaVersion: 1;
}
Expand Down