mirror of
https://github.com/enricoros/big-AGI.git
synced 2026-05-10 21:50:14 -07:00
Show when there's server-side key support
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import { shallow } from 'zustand/shallow';
|
||||
|
||||
import { Box, Button, IconButton, ListItemDecorator, MenuItem, Option, Select, Typography } from '@mui/joy';
|
||||
import { Badge, Box, Button, IconButton, ListItemDecorator, MenuItem, Option, Select, Typography } from '@mui/joy';
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
import CloudDoneOutlinedIcon from '@mui/icons-material/CloudDoneOutlined';
|
||||
import CloudOutlinedIcon from '@mui/icons-material/CloudOutlined';
|
||||
@@ -10,8 +10,8 @@ import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';
|
||||
|
||||
import { DModelSourceId, useModelsStore } from '~/modules/llms/store-llms';
|
||||
import { IModelVendor, ModelVendorId } from '~/modules/llms/vendors/IModelVendor';
|
||||
import { ModelVendorOpenAI } from '~/modules/llms/vendors/openai/openai.vendor';
|
||||
import { createModelSourceForVendor, findAllVendors, findVendorById } from '~/modules/llms/vendors/vendor.registry';
|
||||
import { hasServerKeyOpenAI } from '~/modules/llms/vendors/openai/openai.vendor';
|
||||
|
||||
import { CloseableMenu } from '~/common/components/CloseableMenu';
|
||||
import { ConfirmationModal } from '~/common/components/ConfirmationModal';
|
||||
@@ -19,14 +19,16 @@ import { hideOnDesktop, hideOnMobile } from '~/common/theme';
|
||||
|
||||
|
||||
function locationIcon(vendor?: IModelVendor | null) {
|
||||
if (vendor && vendor.id === 'openai' && hasServerKeyOpenAI)
|
||||
if (vendor && vendor.id === 'openai' && ModelVendorOpenAI.hasServerKey)
|
||||
return <CloudDoneOutlinedIcon />;
|
||||
return !vendor ? null : vendor.location === 'local' ? <ComputerIcon /> : <CloudOutlinedIcon />;
|
||||
}
|
||||
|
||||
function vendorIcon(vendor?: IModelVendor | null) {
|
||||
function vendorIcon(vendor: IModelVendor | null, greenMark: boolean) {
|
||||
const Icon = !vendor ? null : vendor.Icon;
|
||||
return Icon ? <Icon /> : null;
|
||||
return (greenMark && Icon)
|
||||
? <Badge color='primary' size='sm' badgeContent=''><Icon /></Badge>
|
||||
: Icon ? <Icon /> : null;
|
||||
}
|
||||
|
||||
|
||||
@@ -73,23 +75,26 @@ export function ModelsSourceSelector(props: {
|
||||
|
||||
|
||||
// vendor list items
|
||||
const vendorItems = React.useMemo(() => findAllVendors().filter(v => !!v.instanceLimit).map(vendor => {
|
||||
const sourceCount = modelSources.filter(source => source.vId === vendor.id).length;
|
||||
const enabled = vendor.instanceLimit > sourceCount;
|
||||
return {
|
||||
vendor,
|
||||
enabled,
|
||||
sourceCount,
|
||||
component: (
|
||||
<MenuItem key={vendor.id} disabled={!enabled} onClick={() => handleAddSourceFromVendor(vendor.id)}>
|
||||
<ListItemDecorator>
|
||||
{vendorIcon(vendor)}
|
||||
</ListItemDecorator>
|
||||
{vendor.name}{/*{sourceCount > 0 && ` (added)`}*/}
|
||||
</MenuItem>
|
||||
),
|
||||
};
|
||||
}), [handleAddSourceFromVendor, modelSources]);
|
||||
const vendorItems = React.useMemo(() => findAllVendors()
|
||||
.filter(v => !!v.instanceLimit)
|
||||
.map(vendor => {
|
||||
const sourceCount = modelSources.filter(source => source.vId === vendor.id).length;
|
||||
const enabled = vendor.instanceLimit > sourceCount;
|
||||
return {
|
||||
vendor,
|
||||
enabled,
|
||||
sourceCount,
|
||||
component: (
|
||||
<MenuItem key={vendor.id} disabled={!enabled} onClick={() => handleAddSourceFromVendor(vendor.id)}>
|
||||
<ListItemDecorator>
|
||||
{vendorIcon(vendor, !!vendor.hasServerKey)}
|
||||
</ListItemDecorator>
|
||||
{vendor.name}{/*{sourceCount > 0 && ` (added)`}*/}
|
||||
</MenuItem>
|
||||
),
|
||||
};
|
||||
},
|
||||
), [handleAddSourceFromVendor, modelSources]);
|
||||
|
||||
|
||||
// source items
|
||||
|
||||
+1
@@ -13,6 +13,7 @@ export interface IModelVendor<TSourceSetup = unknown, TLLMOptions = unknown, TAc
|
||||
readonly rank: number;
|
||||
readonly location: 'local' | 'cloud';
|
||||
readonly instanceLimit: number;
|
||||
readonly hasServerKey?: boolean;
|
||||
|
||||
// components
|
||||
readonly Icon: React.ComponentType;
|
||||
|
||||
@@ -13,7 +13,7 @@ import { settingsGap } from '~/common/theme';
|
||||
import { DModelSourceId, useModelsStore, useSourceSetup } from '../../store-llms';
|
||||
import { modelDescriptionToDLLM } from '../openai/OpenAISourceSetup';
|
||||
|
||||
import { hasServerKeyAnthropic, isValidAnthropicApiKey, ModelVendorAnthropic } from './anthropic.vendor';
|
||||
import { isValidAnthropicApiKey, ModelVendorAnthropic } from './anthropic.vendor';
|
||||
|
||||
|
||||
export function AnthropicSourceSetup(props: { sourceId: DModelSourceId }) {
|
||||
@@ -25,7 +25,7 @@ export function AnthropicSourceSetup(props: { sourceId: DModelSourceId }) {
|
||||
// derived state
|
||||
const { anthropicKey } = access;
|
||||
|
||||
const needsUserKey = !hasServerKeyAnthropic;
|
||||
const needsUserKey = !ModelVendorAnthropic.hasServerKey;
|
||||
const keyValid = isValidAnthropicApiKey(anthropicKey);
|
||||
const keyError = (/*needsUserKey ||*/ !!anthropicKey) && !keyValid;
|
||||
const shallFetchSucceed = anthropicKey ? keyValid : !needsUserKey;
|
||||
|
||||
+1
-1
@@ -13,7 +13,6 @@ import { AnthropicSourceSetup } from './AnthropicSourceSetup';
|
||||
|
||||
|
||||
// special symbols
|
||||
export const hasServerKeyAnthropic = !!process.env.HAS_SERVER_KEY_ANTHROPIC;
|
||||
export const isValidAnthropicApiKey = (apiKey?: string) => !!apiKey && apiKey.startsWith('sk-') && apiKey.length > 40;
|
||||
|
||||
export interface SourceSetupAnthropic {
|
||||
@@ -27,6 +26,7 @@ export const ModelVendorAnthropic: IModelVendor<SourceSetupAnthropic, LLMOptions
|
||||
rank: 13,
|
||||
location: 'cloud',
|
||||
instanceLimit: 1,
|
||||
hasServerKey: !!process.env.HAS_SERVER_KEY_ANTHROPIC,
|
||||
|
||||
// components
|
||||
Icon: AnthropicIcon,
|
||||
|
||||
+2
-2
@@ -13,7 +13,7 @@ import { settingsGap } from '~/common/theme';
|
||||
import { DModelSourceId, useModelsStore, useSourceSetup } from '../../store-llms';
|
||||
import { modelDescriptionToDLLM } from '../openai/OpenAISourceSetup';
|
||||
|
||||
import { hasServerKeyAzure, isValidAzureApiKey, ModelVendorAzure } from './azure.vendor';
|
||||
import { isValidAzureApiKey, ModelVendorAzure } from './azure.vendor';
|
||||
|
||||
|
||||
export function AzureSourceSetup(props: { sourceId: DModelSourceId }) {
|
||||
@@ -25,7 +25,7 @@ export function AzureSourceSetup(props: { sourceId: DModelSourceId }) {
|
||||
// derived state
|
||||
const { oaiKey: azureKey, oaiHost: azureEndpoint } = access;
|
||||
|
||||
const needsUserKey = !hasServerKeyAzure;
|
||||
const needsUserKey = !ModelVendorAzure.hasServerKey;
|
||||
const keyValid = isValidAzureApiKey(azureKey);
|
||||
const keyError = (/*needsUserKey ||*/ !!azureKey) && !keyValid;
|
||||
const hostValid = !!asValidURL(azureEndpoint);
|
||||
|
||||
+2
-2
@@ -11,7 +11,6 @@ import { AzureSourceSetup } from './AzureSourceSetup';
|
||||
|
||||
|
||||
// special symbols
|
||||
export const hasServerKeyAzure = !!process.env.HAS_SERVER_KEY_AZURE_OPENAI;
|
||||
export const isValidAzureApiKey = (apiKey?: string) => !!apiKey && apiKey.length >= 32;
|
||||
|
||||
export interface SourceSetupAzure {
|
||||
@@ -40,7 +39,8 @@ export const ModelVendorAzure: IModelVendor<SourceSetupAzure, LLMOptionsOpenAI,
|
||||
name: 'Azure',
|
||||
rank: 14,
|
||||
location: 'cloud',
|
||||
instanceLimit: 0,
|
||||
instanceLimit: 2,
|
||||
hasServerKey: !!process.env.HAS_SERVER_KEY_AZURE_OPENAI,
|
||||
|
||||
// components
|
||||
Icon: AzureIcon,
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ export interface SourceSetupOobabooga {
|
||||
export const ModelVendorOoobabooga: IModelVendor<SourceSetupOobabooga, LLMOptionsOpenAI, OpenAIAccessSchema> = {
|
||||
id: 'oobabooga',
|
||||
name: 'Oobabooga',
|
||||
rank: 15,
|
||||
rank: 25,
|
||||
location: 'local',
|
||||
instanceLimit: 1,
|
||||
|
||||
|
||||
+2
-2
@@ -14,7 +14,7 @@ import { settingsCol1Width, settingsGap } from '~/common/theme';
|
||||
import type { ModelDescriptionSchema } from '../../transports/server/server.common';
|
||||
import { DLLM, DModelSource, DModelSourceId, useModelsStore, useSourceSetup } from '../../store-llms';
|
||||
|
||||
import { hasServerKeyOpenAI, isValidOpenAIApiKey, LLMOptionsOpenAI, ModelVendorOpenAI, SourceSetupOpenAI } from './openai.vendor';
|
||||
import { isValidOpenAIApiKey, LLMOptionsOpenAI, ModelVendorOpenAI, SourceSetupOpenAI } from './openai.vendor';
|
||||
import { openAIModelToModelDescription } from './openai.data';
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ export function OpenAISourceSetup(props: { sourceId: DModelSourceId }) {
|
||||
// derived state
|
||||
const { oaiKey, oaiOrg, oaiHost, heliKey, moderationCheck } = access;
|
||||
|
||||
const needsUserKey = !hasServerKeyOpenAI;
|
||||
const needsUserKey = !ModelVendorOpenAI.hasServerKey;
|
||||
const keyValid = isValidOpenAIApiKey(oaiKey);
|
||||
const keyError = (/*needsUserKey ||*/ !!oaiKey) && !keyValid;
|
||||
const shallFetchSucceed = oaiKey ? keyValid : !needsUserKey;
|
||||
|
||||
+1
-1
@@ -11,7 +11,6 @@ import { OpenAISourceSetup } from './OpenAISourceSetup';
|
||||
|
||||
|
||||
// special symbols
|
||||
export const hasServerKeyOpenAI = !!process.env.HAS_SERVER_KEY_OPENAI;
|
||||
export const isValidOpenAIApiKey = (apiKey?: string) => !!apiKey && apiKey.startsWith('sk-') && apiKey.length > 40;
|
||||
|
||||
export interface SourceSetupOpenAI {
|
||||
@@ -34,6 +33,7 @@ export const ModelVendorOpenAI: IModelVendor<SourceSetupOpenAI, LLMOptionsOpenAI
|
||||
rank: 10,
|
||||
location: 'cloud',
|
||||
instanceLimit: 1,
|
||||
hasServerKey: !!process.env.HAS_SERVER_KEY_OPENAI,
|
||||
|
||||
// components
|
||||
Icon: OpenAIIcon,
|
||||
|
||||
@@ -13,7 +13,7 @@ import { settingsGap } from '~/common/theme';
|
||||
import { LLMOptionsOpenAI } from '../openai/openai.vendor';
|
||||
import { DLLM, DModelSource, DModelSourceId, useModelsStore, useSourceSetup } from '../../store-llms';
|
||||
|
||||
import { hasServerKeyOpenRouter, isValidOpenRouterKey, ModelVendorOpenRouter, SourceSetupOpenRouter } from './openrouter.vendor';
|
||||
import { isValidOpenRouterKey, ModelVendorOpenRouter, SourceSetupOpenRouter } from './openrouter.vendor';
|
||||
|
||||
|
||||
export function OpenRouterSourceSetup(props: { sourceId: DModelSourceId }) {
|
||||
@@ -26,7 +26,7 @@ export function OpenRouterSourceSetup(props: { sourceId: DModelSourceId }) {
|
||||
// derived state
|
||||
const { oaiKey } = access;
|
||||
|
||||
const needsUserKey = !hasServerKeyOpenRouter;
|
||||
const needsUserKey = !ModelVendorOpenRouter.hasServerKey;
|
||||
const keyValid = isValidOpenRouterKey(oaiKey);
|
||||
const keyError = (/*needsUserKey ||*/ !!oaiKey) && !keyValid;
|
||||
const shallFetchSucceed = oaiKey ? keyValid : !needsUserKey;
|
||||
|
||||
@@ -11,7 +11,6 @@ import { OpenRouterSourceSetup } from './OpenRouterSourceSetup';
|
||||
|
||||
|
||||
// special symbols
|
||||
export const hasServerKeyOpenRouter = !!process.env.HAS_SERVER_KEY_OPENROUTER;
|
||||
export const isValidOpenRouterKey = (apiKey?: string) => !!apiKey && apiKey.startsWith('sk-or-') && apiKey.length > 40;
|
||||
|
||||
// use OpenAI-compatible host and key
|
||||
@@ -34,9 +33,10 @@ export interface SourceSetupOpenRouter {
|
||||
export const ModelVendorOpenRouter: IModelVendor<SourceSetupOpenRouter, LLMOptionsOpenAI, OpenAIAccessSchema> = {
|
||||
id: 'openrouter',
|
||||
name: 'OpenRouter',
|
||||
rank: 25,
|
||||
rank: 12,
|
||||
location: 'cloud',
|
||||
instanceLimit: 1,
|
||||
hasServerKey: !!process.env.HAS_SERVER_KEY_OPENAI,
|
||||
|
||||
// components
|
||||
Icon: OpenRouterIcon,
|
||||
|
||||
Reference in New Issue
Block a user