Skip to content

Commit

Permalink
fix: Fix some bugs in AI gateway management (higress-group#443)
Browse files Browse the repository at this point in the history
  • Loading branch information
CH3CHO authored Mar 3, 2025
1 parent d343d96 commit 184af31
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,7 @@ public class LlmProviderServiceImpl implements LlmProviderService {
private static final Map<String, LlmProviderHandler> PROVIDER_HANDLERS;

static {
PROVIDER_HANDLERS = Stream.of(
new OpenaiLlmProviderHandler(),
PROVIDER_HANDLERS = Stream.of(new OpenaiLlmProviderHandler(),
new DefaultLlmProviderHandler(LlmProviderType.MOONSHOT, "api.moonshot.cn", 443, V1McpBridge.PROTOCOL_HTTPS),
new DefaultLlmProviderHandler(LlmProviderType.QWEN, "dashscope.aliyuncs.com", 443,
V1McpBridge.PROTOCOL_HTTPS),
Expand All @@ -69,7 +68,8 @@ public class LlmProviderServiceImpl implements LlmProviderService {
new DefaultLlmProviderHandler(LlmProviderType.ZHIPUAI, "open.bigmodel.cn", 443, V1McpBridge.PROTOCOL_HTTPS),
new OllamaLlmProviderHandler(),
new DefaultLlmProviderHandler(LlmProviderType.CLAUDE, "api.anthropic.com", 443, V1McpBridge.PROTOCOL_HTTPS),
new DefaultLlmProviderHandler(LlmProviderType.BAIDU, "qianfan.baidubce.com", 443, V1McpBridge.PROTOCOL_HTTPS),
new DefaultLlmProviderHandler(LlmProviderType.BAIDU, "qianfan.baidubce.com", 443,
V1McpBridge.PROTOCOL_HTTPS),
new DefaultLlmProviderHandler(LlmProviderType.STEPFUN, "api.stepfun.com", 443, V1McpBridge.PROTOCOL_HTTPS),
new DefaultLlmProviderHandler(LlmProviderType.MINIMAX, "api.minimax.chat", 443, V1McpBridge.PROTOCOL_HTTPS),
new DefaultLlmProviderHandler(LlmProviderType.GEMINI, "generativelanguage.googleapis.com", 443,
Expand Down Expand Up @@ -125,26 +125,27 @@ public LlmProvider addOrUpdate(LlmProvider provider) {
configurations.put(PROVIDERS, providersObj);
}

Map<String, Object> providerConfig =
provider.getRawConfigs() != null ? new HashMap<>(provider.getRawConfigs()) : new HashMap<>();
handler.saveConfig(provider, providerConfig);

boolean found = false;
List<Object> providers = (List<Object>)providersObj;
Map<String, Object> providerConfig = null;
for (Object providerObj : providers) {
for (int i = 0; i < providers.size(); i++) {
Object providerObj = providers.get(i);
if (!(providerObj instanceof Map<?, ?>)) {
continue;
}
Map<String, Object> providerMap = (Map<String, Object>)providerObj;
if (provider.getName().equals(providerMap.get(PROVIDER_ID))) {
providerConfig = providerMap;
providers.set(i, providerConfig);
found = true;
break;
}
}
if (providerConfig == null) {
providerConfig = new HashMap<>();
if (!found) {
providers.add(providerConfig);
}
if (MapUtils.isNotEmpty(provider.getRawConfigs())) {
providerConfig.putAll(provider.getRawConfigs());
}
handler.saveConfig(provider, providerConfig);
wasmPluginInstanceService.addOrUpdate(instance);

ServiceSource serviceSource = handler.buildServiceSource(provider.getName(), providerConfig);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ private static URI getCustomUri(Map<String, Object> providerConfig) {
}
Object customUrlObject = providerConfig.get(CUSTOM_URL_KEY);
if (!(customUrlObject instanceof String customUrl)) {
throw new ValidationException(CUSTOM_URL_KEY + " must be a string.");
return null;
}
if (StringUtils.isEmpty(customUrl)) {
throw new ValidationException(CUSTOM_URL_KEY + " cannot be empty.");
Expand Down
21 changes: 16 additions & 5 deletions frontend/src/pages/ai/components/ProviderForm/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ const ProviderForm: React.FC = forwardRef((props: { value: any }, ref) => {
name,
type,
protocol,
tokens,
tokens: tokens && tokens.length && tokens || [""],
failoverEnabled: localFailoverEnabled,
failureThreshold: failureThreshold || 1,
successThreshold: successThreshold || 1,
Expand Down Expand Up @@ -77,7 +77,7 @@ const ProviderForm: React.FC = forwardRef((props: { value: any }, ref) => {
const result = {
type: values.type,
name: values.name,
tokens: values.tokens,
tokens: values.tokens.filter(v => v),
version: 0,
protocol: values.protocol,
tokenFailoverConfig: {
Expand Down Expand Up @@ -205,9 +205,20 @@ const ProviderForm: React.FC = forwardRef((props: { value: any }, ref) => {
validateTrigger={['onChange', 'onBlur']}
rules={[
{
required: !providerConfig || providerConfig.tokenRequired !== false,
whitespace: false,
message: t('llmProvider.providerForm.rules.tokenRequired'),
validator(rule, value) {
if (value) {
return Promise.resolve();
}
if (providerConfig) {
if (providerConfig.tokenRequired === false) {
return Promise.resolve();
}
if (typeof providerConfig.isTokenRequired === 'function' && !providerConfig.isTokenRequired(form.getFieldsValue())) {
return Promise.resolve();
}
}
return Promise.reject(t('llmProvider.providerForm.rules.tokenRequired'));
},
},
]}
noStyle
Expand Down
14 changes: 10 additions & 4 deletions frontend/src/pages/ai/configs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,17 @@ export const aiModelProviders = [
value: 'gpt-4o-mini',
},
],
getProviderEndpoints: (record) => {
if (!record.rawConfigs) {
return null;
isTokenRequired: record => {
if (record.openaiServerType) {
// For form validation
return record.openaiServerType === 'official';
}
return [record.rawConfigs['openaiCustomUrl']];
// For generic logic
return !record.rawConfigs || !record.rawConfigs.openaiCustomUrl;
},
getProviderEndpoints: (record) => {
const customUrl = record.rawConfigs && record.rawConfigs.openaiCustomUrl;
return customUrl && [customUrl] || null;
},
},
{
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/pages/plugin/components/PluginList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ const PluginList = forwardRef((props: Props, ref) => {
let plugins = result || [];
const hiddenPlugins = HIDDEN_PLUGINS_BY_QUERY_TYPE[type];
if (Array.isArray(hiddenPlugins)) {
plugins = plugins.filter(p => p.builtIn && hiddenPlugins.indexOf(p.name) === -1);
plugins = plugins.filter(p => !p.builtIn || hiddenPlugins.indexOf(p.name) === -1);
}
if (type === QueryType.ROUTE) {
const routeName = searchParams.get('name');
Expand Down

0 comments on commit 184af31

Please sign in to comment.