@lobehub/chat 0.128.10 → 0.129.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/locales/ar/chat.json +1 -0
  3. package/locales/ar/common.json +2 -1
  4. package/locales/ar/error.json +6 -0
  5. package/locales/ar/setting.json +9 -1
  6. package/locales/de-DE/chat.json +1 -0
  7. package/locales/de-DE/common.json +1 -0
  8. package/locales/de-DE/error.json +6 -0
  9. package/locales/de-DE/setting.json +9 -1
  10. package/locales/en-US/chat.json +1 -0
  11. package/locales/en-US/common.json +1 -0
  12. package/locales/en-US/error.json +6 -0
  13. package/locales/en-US/setting.json +8 -0
  14. package/locales/es-ES/chat.json +1 -0
  15. package/locales/es-ES/common.json +1 -0
  16. package/locales/es-ES/error.json +6 -0
  17. package/locales/es-ES/setting.json +9 -1
  18. package/locales/fr-FR/chat.json +1 -0
  19. package/locales/fr-FR/common.json +1 -0
  20. package/locales/fr-FR/error.json +6 -0
  21. package/locales/fr-FR/setting.json +8 -0
  22. package/locales/it-IT/chat.json +1 -0
  23. package/locales/it-IT/common.json +1 -0
  24. package/locales/it-IT/error.json +6 -0
  25. package/locales/it-IT/setting.json +8 -0
  26. package/locales/ja-JP/chat.json +1 -0
  27. package/locales/ja-JP/common.json +1 -0
  28. package/locales/ja-JP/error.json +6 -0
  29. package/locales/ja-JP/setting.json +8 -0
  30. package/locales/ko-KR/chat.json +1 -0
  31. package/locales/ko-KR/common.json +1 -0
  32. package/locales/ko-KR/error.json +6 -0
  33. package/locales/ko-KR/setting.json +8 -0
  34. package/locales/nl-NL/chat.json +1 -0
  35. package/locales/nl-NL/common.json +2 -1
  36. package/locales/nl-NL/error.json +6 -0
  37. package/locales/nl-NL/setting.json +8 -0
  38. package/locales/pl-PL/chat.json +1 -0
  39. package/locales/pl-PL/common.json +2 -1
  40. package/locales/pl-PL/error.json +6 -0
  41. package/locales/pl-PL/setting.json +8 -0
  42. package/locales/pt-BR/chat.json +1 -0
  43. package/locales/pt-BR/common.json +1 -0
  44. package/locales/pt-BR/error.json +6 -0
  45. package/locales/pt-BR/setting.json +9 -1
  46. package/locales/ru-RU/chat.json +1 -0
  47. package/locales/ru-RU/common.json +1 -0
  48. package/locales/ru-RU/error.json +6 -0
  49. package/locales/ru-RU/setting.json +9 -1
  50. package/locales/tr-TR/chat.json +1 -0
  51. package/locales/tr-TR/common.json +1 -0
  52. package/locales/tr-TR/error.json +6 -0
  53. package/locales/tr-TR/setting.json +9 -1
  54. package/locales/vi-VN/chat.json +1 -0
  55. package/locales/vi-VN/common.json +1 -0
  56. package/locales/vi-VN/error.json +6 -0
  57. package/locales/vi-VN/setting.json +9 -1
  58. package/locales/zh-CN/chat.json +1 -0
  59. package/locales/zh-CN/common.json +1 -0
  60. package/locales/zh-CN/error.json +6 -0
  61. package/locales/zh-CN/setting.json +8 -0
  62. package/locales/zh-TW/chat.json +1 -0
  63. package/locales/zh-TW/common.json +1 -0
  64. package/locales/zh-TW/error.json +6 -0
  65. package/locales/zh-TW/setting.json +8 -0
  66. package/package.json +3 -3
  67. package/public/images/logo.png +0 -0
  68. package/src/app/api/chat/[provider]/agentRuntime.ts +13 -0
  69. package/src/app/api/config/route.ts +2 -0
  70. package/src/app/api/errorResponse.ts +3 -0
  71. package/src/app/chat/(desktop)/features/ChatInput/Footer/index.tsx +1 -0
  72. package/src/app/layout.tsx +18 -12
  73. package/src/app/settings/llm/Perplexity/index.tsx +52 -0
  74. package/src/app/settings/llm/index.tsx +2 -0
  75. package/src/app/settings/tts/page.tsx +1 -1
  76. package/src/components/ModelIcon/index.tsx +3 -1
  77. package/src/components/ModelProviderIcon/index.tsx +19 -1
  78. package/src/components/ModelTag/ModelIcon.tsx +3 -1
  79. package/src/config/modelProviders/index.ts +3 -0
  80. package/src/config/modelProviders/perplexity.ts +44 -0
  81. package/src/config/server/provider.ts +8 -0
  82. package/src/const/settings.ts +4 -0
  83. package/src/features/AvatarWithUpload/index.tsx +7 -6
  84. package/src/features/Conversation/Error/APIKeyForm/Perplexity.tsx +60 -0
  85. package/src/features/Conversation/Error/APIKeyForm/index.tsx +5 -0
  86. package/src/features/Conversation/Error/index.tsx +1 -0
  87. package/src/features/SideBar/BottomActions.tsx +5 -8
  88. package/src/features/SideBar/TopActions.tsx +2 -1
  89. package/src/libs/agent-runtime/error.ts +3 -0
  90. package/src/libs/agent-runtime/index.ts +1 -0
  91. package/src/libs/agent-runtime/perplexity/index.ts +86 -0
  92. package/src/libs/agent-runtime/types/type.ts +1 -0
  93. package/src/locales/default/chat.ts +1 -0
  94. package/src/locales/default/common.ts +1 -0
  95. package/src/locales/default/error.ts +7 -0
  96. package/src/locales/default/setting.ts +8 -0
  97. package/src/services/_auth.ts +4 -0
  98. package/src/store/global/slices/settings/selectors/modelProvider.ts +9 -0
  99. package/src/types/settings/modelProvider.ts +7 -0
@@ -0,0 +1,52 @@
1
+ import { Perplexity } from '@lobehub/icons';
2
+ import { Input } from 'antd';
3
+ import { useTheme } from 'antd-style';
4
+ import { memo } from 'react';
5
+ import { useTranslation } from 'react-i18next';
6
+
7
+ import { ModelProvider } from '@/libs/agent-runtime';
8
+
9
+ import Checker from '../components/Checker';
10
+ import ProviderConfig from '../components/ProviderConfig';
11
+ import { LLMProviderApiTokenKey, LLMProviderConfigKey } from '../const';
12
+
13
+ const providerKey = 'perplexity';
14
+
15
+ const PerplexityProvider = memo(() => {
16
+ const { t } = useTranslation('setting');
17
+
18
+ const theme = useTheme();
19
+
20
+ return (
21
+ <ProviderConfig
22
+ configItems={[
23
+ {
24
+ children: (
25
+ <Input.Password
26
+ autoComplete={'new-password'}
27
+ placeholder={t('llm.Perplexity.token.placeholder')}
28
+ />
29
+ ),
30
+ desc: t('llm.Perplexity.token.desc'),
31
+ label: t('llm.Perplexity.token.title'),
32
+ name: [LLMProviderConfigKey, providerKey, LLMProviderApiTokenKey],
33
+ },
34
+ {
35
+ children: <Checker model={'pplx-7b-chat'} provider={ModelProvider.Perplexity} />,
36
+ desc: t('llm.checker.desc'),
37
+ label: t('llm.checker.title'),
38
+ minWidth: '100%',
39
+ },
40
+ ]}
41
+ provider={providerKey}
42
+ title={
43
+ <Perplexity.Combine
44
+ color={theme.isDarkMode ? theme.colorText : Perplexity.colorPrimary}
45
+ size={24}
46
+ />
47
+ }
48
+ />
49
+ );
50
+ });
51
+
52
+ export default PerplexityProvider;
@@ -13,6 +13,7 @@ import Google from './Google';
13
13
  import Moonshot from './Moonshot';
14
14
  import Ollama from './Ollama';
15
15
  import OpenAI from './OpenAI';
16
+ import Perplexity from './Perplexity';
16
17
  import Zhipu from './Zhipu';
17
18
 
18
19
  export default memo<{ showOllama: boolean }>(({ showOllama }) => {
@@ -27,6 +28,7 @@ export default memo<{ showOllama: boolean }>(({ showOllama }) => {
27
28
  <Moonshot />
28
29
  <Google />
29
30
  <Bedrock />
31
+ <Perplexity />
30
32
  {showOllama && <Ollama />}
31
33
  <Footer>
32
34
  <Trans i18nKey="llm.waitingForMore" ns={'setting'}>
@@ -11,7 +11,7 @@ export default memo(() => {
11
11
  const { t } = useTranslation('setting');
12
12
  return (
13
13
  <>
14
- <PageTitle title={t('tab.llm')} />
14
+ <PageTitle title={t('tab.tts')} />
15
15
  <TTS />
16
16
  </>
17
17
  );
@@ -9,6 +9,7 @@ import {
9
9
  Mistral,
10
10
  Moonshot,
11
11
  OpenAI,
12
+ Perplexity,
12
13
  Tongyi,
13
14
  } from '@lobehub/icons';
14
15
  import { memo } from 'react';
@@ -33,7 +34,8 @@ const ModelIcon = memo<ModelProviderIconProps>(({ model, size = 12 }) => {
33
34
  if (model.includes('moonshot')) return <Moonshot.Avatar size={size} />;
34
35
  if (model.includes('baichuan'))
35
36
  return <Baichuan.Avatar background={Baichuan.colorPrimary} size={size} />;
36
- if (model.includes('mistral')) return <Mistral.Avatar size={size} />;
37
+ if (model.includes('mistral') || model.includes('mixtral')) return <Mistral.Avatar size={size} />;
38
+ if (model.includes('pplx')) return <Perplexity.Avatar size={size} />;
37
39
  });
38
40
 
39
41
  export default ModelIcon;
@@ -1,4 +1,14 @@
1
- import { Azure, Bedrock, Google, Moonshot, Ollama, OpenAI, Zhipu } from '@lobehub/icons';
1
+ import {
2
+ Azure,
3
+ Bedrock,
4
+ Google,
5
+ Mistral,
6
+ Moonshot,
7
+ Ollama,
8
+ OpenAI,
9
+ Perplexity,
10
+ Zhipu,
11
+ } from '@lobehub/icons';
2
12
  import { memo } from 'react';
3
13
  import { Center } from 'react-layout-kit';
4
14
 
@@ -46,6 +56,14 @@ const ModelProviderIcon = memo<ModelProviderIconProps>(({ provider }) => {
46
56
  return <Ollama size={20} />;
47
57
  }
48
58
 
59
+ case ModelProvider.Perplexity: {
60
+ return <Perplexity size={20} />;
61
+ }
62
+
63
+ case ModelProvider.Mistral: {
64
+ return <Mistral size={20} />;
65
+ }
66
+
49
67
  default: {
50
68
  return null;
51
69
  }
@@ -9,6 +9,7 @@ import {
9
9
  Mistral,
10
10
  Moonshot,
11
11
  OpenAI,
12
+ Perplexity,
12
13
  Tongyi,
13
14
  } from '@lobehub/icons';
14
15
  import { memo } from 'react';
@@ -31,7 +32,8 @@ const ModelIcon = memo<ModelIconProps>(({ model, size = 12 }) => {
31
32
  if (model.includes('qwen')) return <Tongyi size={size} />;
32
33
  if (model.includes('minmax')) return <Minimax size={size} />;
33
34
  if (model.includes('baichuan')) return <Baichuan size={size} />;
34
- if (model.includes('mistral')) return <Mistral size={size} />;
35
+ if (model.includes('mistral') || model.includes('mixtral')) return <Mistral size={size} />;
36
+ if (model.includes('pplx')) return <Perplexity size={size} />;
35
37
  });
36
38
 
37
39
  export default ModelIcon;
@@ -5,6 +5,7 @@ import GoogleProvider from './google';
5
5
  import MoonshotProvider from './moonshot';
6
6
  import OllamaProvider from './ollama';
7
7
  import OpenAIProvider from './openai';
8
+ import PerplexityProvider from './perplexity';
8
9
  import ZhiPuProvider from './zhipu';
9
10
 
10
11
  export const LOBE_DEFAULT_MODEL_LIST: ChatModelCard[] = [
@@ -14,6 +15,7 @@ export const LOBE_DEFAULT_MODEL_LIST: ChatModelCard[] = [
14
15
  GoogleProvider.chatModels,
15
16
  MoonshotProvider.chatModels,
16
17
  OllamaProvider.chatModels,
18
+ PerplexityProvider.chatModels,
17
19
  ].flat();
18
20
 
19
21
  export { default as BedrockProvider } from './bedrock';
@@ -21,4 +23,5 @@ export { default as GoogleProvider } from './google';
21
23
  export { default as MoonshotProvider } from './moonshot';
22
24
  export { default as OllamaProvider } from './ollama';
23
25
  export { default as OpenAIProvider } from './openai';
26
+ export { default as PerplexityProvider } from './perplexity';
24
27
  export { default as ZhiPuProvider } from './zhipu';
@@ -0,0 +1,44 @@
1
+ import { ModelProviderCard } from '@/types/llm';
2
+
3
+ const Perplexity: ModelProviderCard = {
4
+ chatModels: [
5
+ {
6
+ displayName: 'Perplexity 7B Chat',
7
+ id: 'pplx-7b-chat',
8
+ tokens: 8192,
9
+ },
10
+ {
11
+ displayName: 'Perplexity 70B Chat',
12
+ id: 'pplx-70b-chat',
13
+ tokens: 8192,
14
+ },
15
+ {
16
+ displayName: 'Perplexity 7B Online',
17
+ id: 'pplx-7b-online',
18
+ tokens: 8192,
19
+ },
20
+ {
21
+ displayName: 'Perplexity 70B Online',
22
+ id: 'pplx-70b-online',
23
+ tokens: 8192,
24
+ },
25
+ {
26
+ displayName: 'Codellama 34B Instruct',
27
+ id: 'codellama-34b-instruct',
28
+ tokens: 16_384,
29
+ },
30
+ {
31
+ displayName: 'Codellama 70B Instruct',
32
+ id: 'codellama-70b-instruct',
33
+ tokens: 16_384,
34
+ },
35
+ {
36
+ displayName: 'Mixtral 8x7B Instruct',
37
+ id: 'mixtral-8x7b-instruct',
38
+ tokens: 8192,
39
+ },
40
+ ],
41
+ id: 'perplexity',
42
+ };
43
+
44
+ export default Perplexity;
@@ -28,6 +28,9 @@ declare global {
28
28
  MOONSHOT_API_KEY?: string;
29
29
  MOONSHOT_PROXY_URL?: string;
30
30
 
31
+ // Perplexity Provider
32
+ PERPLEXITY_API_KEY?: string;
33
+
31
34
  // AWS Credentials
32
35
  AWS_REGION?: string;
33
36
  AWS_ACCESS_KEY_ID?: string;
@@ -53,6 +56,8 @@ export const getProviderConfig = () => {
53
56
 
54
57
  const MOONSHOT_API_KEY = process.env.MOONSHOT_API_KEY || '';
55
58
 
59
+ const PERPLEXITY_API_KEY = process.env.PERPLEXITY_API_KEY || '';
60
+
56
61
  // region format: iad1,sfo1
57
62
  let regions: string[] = [];
58
63
  if (process.env.OPENAI_FUNCTION_REGIONS) {
@@ -72,6 +77,9 @@ export const getProviderConfig = () => {
72
77
  ENABLED_GOOGLE: !!GOOGLE_API_KEY,
73
78
  GOOGLE_API_KEY,
74
79
 
80
+ ENABLED_PERPLEXITY: !!PERPLEXITY_API_KEY,
81
+ PERPLEXITY_API_KEY,
82
+
75
83
  ENABLED_MOONSHOT: !!MOONSHOT_API_KEY,
76
84
  MOONSHOT_API_KEY,
77
85
  MOONSHOT_PROXY_URL: process.env.MOONSHOT_PROXY_URL,
@@ -75,6 +75,10 @@ export const DEFAULT_LLM_CONFIG: GlobalLLMConfig = {
75
75
  enabled: true,
76
76
  models: [],
77
77
  },
78
+ perplexity: {
79
+ apiKey: '',
80
+ enabled: false,
81
+ },
78
82
  zhipu: {
79
83
  apiKey: '',
80
84
  enabled: false,
@@ -1,9 +1,9 @@
1
- import { Logo } from '@lobehub/ui';
2
1
  import { Upload } from 'antd';
3
2
  import { createStyles } from 'antd-style';
4
3
  import Avatar from 'next/image';
5
4
  import { CSSProperties, memo } from 'react';
6
5
 
6
+ import { imageUrl } from '@/const/url';
7
7
  import { useGlobalStore } from '@/store/global';
8
8
  import { commonSelectors } from '@/store/global/selectors';
9
9
  import { imageToBase64 } from '@/utils/imageToBase64';
@@ -55,11 +55,12 @@ const AvatarWithUpload = memo<AvatarWithUploadProps>(
55
55
  return (
56
56
  <div className={styles} id={id} style={{ maxHeight: size, maxWidth: size, ...style }}>
57
57
  <Upload beforeUpload={handleUploadAvatar} itemRender={() => void 0} maxCount={1}>
58
- {avatar ? (
59
- <Avatar alt={'avatar'} height={size} src={avatar} width={size} />
60
- ) : (
61
- <Logo size={size} />
62
- )}
58
+ <Avatar
59
+ alt={avatar ? 'userAvatar' : 'LobeChat'}
60
+ height={size}
61
+ src={!!avatar ? avatar : imageUrl('logo.png')}
62
+ width={size}
63
+ />
63
64
  </Upload>
64
65
  </div>
65
66
  );
@@ -0,0 +1,60 @@
1
+ import { Perplexity } from '@lobehub/icons';
2
+ import { Input } from 'antd';
3
+ import { memo } from 'react';
4
+ import { useTranslation } from 'react-i18next';
5
+
6
+ import { ModelProvider } from '@/libs/agent-runtime';
7
+ import { useGlobalStore } from '@/store/global';
8
+ import { modelProviderSelectors } from '@/store/global/selectors';
9
+
10
+ import { FormAction } from '../style';
11
+
12
+ const PerplexityForm = memo(() => {
13
+ const { t } = useTranslation('error');
14
+ // const [showProxy, setShow] = useState(false);
15
+
16
+ const [apiKey, setConfig] = useGlobalStore((s) => [
17
+ modelProviderSelectors.perplexityAPIKey(s),
18
+ s.setModelProviderConfig,
19
+ ]);
20
+
21
+ return (
22
+ <FormAction
23
+ avatar={<Perplexity size={56} />}
24
+ description={t('unlock.apikey.Perplexity.description')}
25
+ title={t('unlock.apikey.Perplexity.title')}
26
+ >
27
+ <Input.Password
28
+ autoComplete={'new-password'}
29
+ onChange={(e) => {
30
+ setConfig(ModelProvider.Perplexity, { apiKey: e.target.value });
31
+ }}
32
+ placeholder={'*********************************'}
33
+ type={'block'}
34
+ value={apiKey}
35
+ />
36
+ {/*{showProxy ? (*/}
37
+ {/* <Input*/}
38
+ {/* onChange={(e) => {*/}
39
+ {/* setConfig({ endpoint: e.target.value });*/}
40
+ {/* }}*/}
41
+ {/* placeholder={'https://api.openai.com/v1'}*/}
42
+ {/* type={'block'}*/}
43
+ {/* value={proxyUrl}*/}
44
+ {/* />*/}
45
+ {/*) : (*/}
46
+ {/* <Button*/}
47
+ {/* icon={<Icon icon={Network} />}*/}
48
+ {/* onClick={() => {*/}
49
+ {/* setShow(true);*/}
50
+ {/* }}*/}
51
+ {/* type={'text'}*/}
52
+ {/* >*/}
53
+ {/* {t('unlock.apikey.addProxyUrl')}*/}
54
+ {/* </Button>*/}
55
+ {/*)}*/}
56
+ </FormAction>
57
+ );
58
+ });
59
+
60
+ export default PerplexityForm;
@@ -10,6 +10,7 @@ import BedrockForm from './Bedrock';
10
10
  import GoogleForm from './Google';
11
11
  import MoonshotForm from './Moonshot';
12
12
  import OpenAIForm from './OpenAI';
13
+ import PerplexityForm from './Perplexity';
13
14
  import ZhipuForm from './Zhipu';
14
15
 
15
16
  interface APIKeyFormProps {
@@ -40,6 +41,10 @@ const APIKeyForm = memo<APIKeyFormProps>(({ id, provider }) => {
40
41
  return <MoonshotForm />;
41
42
  }
42
43
 
44
+ case ModelProvider.Perplexity: {
45
+ return <PerplexityForm />;
46
+ }
47
+
43
48
  default:
44
49
  case ModelProvider.OpenAI: {
45
50
  return <OpenAIForm />;
@@ -66,6 +66,7 @@ const ErrorMessageExtra = memo<{ data: ChatMessage }>(({ data }) => {
66
66
  case AgentRuntimeErrorType.InvalidZhipuAPIKey:
67
67
  case AgentRuntimeErrorType.InvalidMoonshotAPIKey:
68
68
  case AgentRuntimeErrorType.InvalidGoogleAPIKey:
69
+ case AgentRuntimeErrorType.InvalidPerplexityAPIKey:
69
70
  case AgentRuntimeErrorType.NoOpenAIAPIKey: {
70
71
  return <InvalidAPIKey id={data.id} provider={data.error?.body?.provider} />;
71
72
  }
@@ -17,7 +17,7 @@ import { memo } from 'react';
17
17
  import { useTranslation } from 'react-i18next';
18
18
  import { Flexbox } from 'react-layout-kit';
19
19
 
20
- import { ABOUT, CHANGELOG, DISCORD, DOCUMENTS, FEEDBACK, GITHUB } from '@/const/url';
20
+ import { ABOUT, CHANGELOG, DISCORD, DOCUMENTS, FEEDBACK } from '@/const/url';
21
21
  import DataImporter from '@/features/DataImporter';
22
22
  import { configService } from '@/services/config';
23
23
  import { GlobalStore, useGlobalStore } from '@/store/global';
@@ -120,13 +120,10 @@ const BottomActions = memo<BottomActionProps>(({ tab }) => {
120
120
 
121
121
  return (
122
122
  <>
123
- <ActionIcon
124
- icon={Github}
125
- onClick={() => window.open(GITHUB)}
126
- placement={'right'}
127
- title={'GitHub'}
128
- />
129
- <Link href={DOCUMENTS} target={'_blank'}>
123
+ <Link aria-label={'GitHub'} href={DOCUMENTS} target={'_blank'}>
124
+ <ActionIcon icon={Github} placement={'right'} title={'GitHub'} />
125
+ </Link>
126
+ <Link aria-label={t('document')} href={DOCUMENTS} target={'_blank'}>
130
127
  <ActionIcon icon={Book} placement={'right'} title={t('document')} />
131
128
  </Link>
132
129
  <Dropdown arrow={false} menu={{ items }} trigger={['click']}>
@@ -19,6 +19,7 @@ const TopActions = memo<TopActionProps>(({ tab }) => {
19
19
  return (
20
20
  <>
21
21
  <Link
22
+ aria-label={t('tab.chat')}
22
23
  href={'/chat'}
23
24
  onClick={(e) => {
24
25
  e.preventDefault();
@@ -33,7 +34,7 @@ const TopActions = memo<TopActionProps>(({ tab }) => {
33
34
  title={t('tab.chat')}
34
35
  />
35
36
  </Link>
36
- <Link href={'/market'}>
37
+ <Link aria-label={t('tab.market')} href={'/market'}>
37
38
  <ActionIcon
38
39
  active={tab === SidebarTabKey.Market}
39
40
  icon={Compass}
@@ -25,6 +25,9 @@ export const AgentRuntimeErrorType = {
25
25
 
26
26
  InvalidOllamaArgs: 'InvalidOllamaArgs',
27
27
  OllamaBizError: 'OllamaBizError',
28
+
29
+ InvalidPerplexityAPIKey: 'InvalidPerplexityAPIKey',
30
+ PerplexityBizError: 'PerplexityBizError',
28
31
  } as const;
29
32
 
30
33
  export type ILobeAgentRuntimeErrorType =
@@ -6,6 +6,7 @@ export { LobeGoogleAI } from './google';
6
6
  export { LobeMoonshotAI } from './moonshot';
7
7
  export { LobeOllamaAI } from './ollama';
8
8
  export { LobeOpenAI } from './openai';
9
+ export { LobePerplexityAI } from './perplexity';
9
10
  export * from './types';
10
11
  export { AgentRuntimeError } from './utils/createError';
11
12
  export { LobeZhipuAI } from './zhipu';
@@ -0,0 +1,86 @@
1
+ import { OpenAIStream, StreamingTextResponse } from 'ai';
2
+ import OpenAI from 'openai';
3
+
4
+ import { LobeRuntimeAI } from '../BaseAI';
5
+ import { AgentRuntimeErrorType } from '../error';
6
+ import { ChatStreamPayload, ModelProvider } from '../types';
7
+ import { AgentRuntimeError } from '../utils/createError';
8
+ import { debugStream } from '../utils/debugStream';
9
+ import { desensitizeUrl } from '../utils/desensitizeUrl';
10
+ import { DEBUG_CHAT_COMPLETION } from '../utils/env';
11
+ import { handleOpenAIError } from '../utils/handleOpenAIError';
12
+
13
+ const DEFAULT_BASE_URL = 'https://api.perplexity.ai';
14
+
15
+ export class LobePerplexityAI implements LobeRuntimeAI {
16
+ private _llm: OpenAI;
17
+
18
+ baseURL: string;
19
+
20
+ constructor(apiKey?: string, baseURL: string = DEFAULT_BASE_URL) {
21
+ if (!apiKey) throw AgentRuntimeError.createError(AgentRuntimeErrorType.InvalidPerplexityAPIKey);
22
+
23
+ this._llm = new OpenAI({ apiKey, baseURL });
24
+ this.baseURL = this._llm.baseURL;
25
+ }
26
+
27
+ async chat(payload: ChatStreamPayload) {
28
+ try {
29
+ // Set a default frequency penalty value greater than 0
30
+ const defaultFrequencyPenalty = 0.1;
31
+ const chatPayload = {
32
+ ...payload,
33
+ frequency_penalty: payload.frequency_penalty || defaultFrequencyPenalty,
34
+ };
35
+ const response = await this._llm.chat.completions.create(
36
+ chatPayload as unknown as OpenAI.ChatCompletionCreateParamsStreaming,
37
+ );
38
+
39
+ const stream = OpenAIStream(response);
40
+
41
+ const [debug, returnStream] = stream.tee();
42
+
43
+ if (DEBUG_CHAT_COMPLETION) {
44
+ debugStream(debug).catch(console.error);
45
+ }
46
+
47
+ return new StreamingTextResponse(returnStream);
48
+ } catch (error) {
49
+ let desensitizedEndpoint = this.baseURL;
50
+
51
+ if (this.baseURL !== DEFAULT_BASE_URL) {
52
+ desensitizedEndpoint = desensitizeUrl(this.baseURL);
53
+ }
54
+
55
+ if ('status' in (error as any)) {
56
+ switch ((error as Response).status) {
57
+ case 401: {
58
+ throw AgentRuntimeError.chat({
59
+ endpoint: desensitizedEndpoint,
60
+ error: error as any,
61
+ errorType: AgentRuntimeErrorType.InvalidPerplexityAPIKey,
62
+ provider: ModelProvider.Perplexity,
63
+ });
64
+ }
65
+
66
+ default: {
67
+ break;
68
+ }
69
+ }
70
+ }
71
+
72
+ const { errorResult, RuntimeError } = handleOpenAIError(error);
73
+
74
+ const errorType = RuntimeError || AgentRuntimeErrorType.PerplexityBizError;
75
+
76
+ throw AgentRuntimeError.chat({
77
+ endpoint: desensitizedEndpoint,
78
+ error: errorResult,
79
+ errorType,
80
+ provider: ModelProvider.Perplexity,
81
+ });
82
+ }
83
+ }
84
+ }
85
+
86
+ export default LobePerplexityAI;
@@ -31,6 +31,7 @@ export enum ModelProvider {
31
31
  Moonshot = 'moonshot',
32
32
  Ollama = 'ollama',
33
33
  OpenAI = 'openai',
34
+ Perplexity = 'perplexity',
34
35
  Tongyi = 'tongyi',
35
36
  ZhiPu = 'zhipu',
36
37
  }
@@ -21,6 +21,7 @@ export default {
21
21
  title: '随便聊聊',
22
22
  },
23
23
  input: {
24
+ more: '更多',
24
25
  onlyAdd: '仅添加消息',
25
26
  send: '发送',
26
27
  sendWithCmdEnter: '按 {{meta}} + Enter 键发送',
@@ -107,6 +107,7 @@ export default {
107
107
  ollama: 'Ollama',
108
108
  oneapi: 'One API',
109
109
  openai: 'OpenAI',
110
+ perplexity: 'Perplexity',
110
111
  zhipu: '智谱AI',
111
112
  },
112
113
  noDescription: '暂无描述',
@@ -73,6 +73,9 @@ export default {
73
73
  InvalidAzureAPIKey: 'Azure API Key 不正确或为空,请检查 Azure API Key 后重试',
74
74
  AzureBizError: '请求 Azure AI 服务出错,请根据以下信息排查或重试',
75
75
 
76
+ InvalidPerplexityAPIKey: 'Perplexity API Key 不正确或为空,请检查 Perplexity API Key 后重试',
77
+ PerplexityBizError: '请求 Perplexity AI 服务出错,请根据以下信息排查或重试',
78
+
76
79
  InvalidOllamaArgs: 'Ollama 配置不正确,请检查 Ollama 配置后重试',
77
80
  OllamaBizError: '请求 Ollama 服务出错,请根据以下信息排查或重试',
78
81
 
@@ -106,6 +109,10 @@ export default {
106
109
  description: '输入你的 OpenAI API Key 即可开始会话。应用不会记录你的 API Key',
107
110
  title: '使用自定义 OpenAI API Key',
108
111
  },
112
+ Perplexity: {
113
+ description: '输入你的 Perplexity API Key 即可开始会话。应用不会记录你的 API Key',
114
+ title: '使用自定义 Perplexity API Key',
115
+ },
109
116
  Zhipu: {
110
117
  description: '输入你的 Zhipu API Key 即可开始会话。应用不会记录你的 API Key',
111
118
  title: '使用自定义 Zhipu API Key',
@@ -139,6 +139,14 @@ export default {
139
139
  title: 'Azure OpenAI',
140
140
  },
141
141
  },
142
+ Perplexity: {
143
+ title: 'Perplexity',
144
+ token: {
145
+ desc: '填入来自 Perplexity AI 的 API Key',
146
+ placeholder: 'Perplexity AI API Key',
147
+ title: 'API Key',
148
+ },
149
+ },
142
150
  Zhipu: {
143
151
  title: '智谱',
144
152
  token: {
@@ -48,6 +48,10 @@ export const getProviderAuthPayload = (provider: string) => {
48
48
  };
49
49
  }
50
50
 
51
+ case ModelProvider.Perplexity: {
52
+ return { apiKey: modelProviderSelectors.perplexityAPIKey(useGlobalStore.getState()) };
53
+ }
54
+
51
55
  default:
52
56
  case ModelProvider.OpenAI: {
53
57
  const openai = modelProviderSelectors.openAIConfig(useGlobalStore.getState());
@@ -7,6 +7,7 @@ import {
7
7
  MoonshotProvider,
8
8
  OllamaProvider,
9
9
  OpenAIProvider,
10
+ PerplexityProvider,
10
11
  ZhiPuProvider,
11
12
  } from '@/config/modelProviders';
12
13
  import { ChatModelCard, ModelProviderCard } from '@/types/llm';
@@ -48,6 +49,9 @@ const enableOllamaConfigInSettings = (s: GlobalStore) =>
48
49
  const enableOllama = (s: GlobalStore) => modelProvider(s).ollama.enabled;
49
50
  const ollamaProxyUrl = (s: GlobalStore) => modelProvider(s).ollama.endpoint;
50
51
 
52
+ const enablePerplexity = (s: GlobalStore) => modelProvider(s).perplexity.enabled;
53
+ const perplexityAPIKey = (s: GlobalStore) => modelProvider(s).perplexity.apiKey;
54
+
51
55
  // const azureModelList = (s: GlobalStore): ModelProviderCard => {
52
56
  // const azure = azureConfig(s);
53
57
  // return {
@@ -133,6 +137,7 @@ const modelSelectList = (s: GlobalStore): ModelProviderCard[] => {
133
137
  { ...GoogleProvider, enabled: enableGoogle(s) },
134
138
  { ...BedrockProvider, enabled: enableBedrock(s) },
135
139
  { ...OllamaProvider, chatModels: ollamaChatModels, enabled: enableOllama(s) },
140
+ { ...PerplexityProvider, enabled: enablePerplexity(s) },
136
141
  ];
137
142
  };
138
143
 
@@ -203,4 +208,8 @@ export const modelProviderSelectors = {
203
208
  enableOllamaConfigInSettings,
204
209
  enableOllama,
205
210
  ollamaProxyUrl,
211
+
212
+ // Perplexity
213
+ enablePerplexity,
214
+ perplexityAPIKey,
206
215
  };
@@ -54,6 +54,12 @@ export interface OllamaConfig {
54
54
  endpoint?: string;
55
55
  }
56
56
 
57
+ export interface PerplexityConfig {
58
+ apiKey?: string;
59
+ enabled: boolean;
60
+ endpoint?: string;
61
+ }
62
+
57
63
  export interface GlobalLLMConfig {
58
64
  azure: AzureOpenAIConfig;
59
65
  bedrock: AWSBedrockConfig;
@@ -61,6 +67,7 @@ export interface GlobalLLMConfig {
61
67
  moonshot: MoonshotConfig;
62
68
  ollama: OllamaConfig;
63
69
  openAI: OpenAIConfig;
70
+ perplexity: PerplexityConfig;
64
71
  zhipu: ZhiPuConfig;
65
72
  }
66
73