access.ts 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. import {
  2. ApiPath,
  3. DEFAULT_API_HOST,
  4. ServiceProvider,
  5. StoreKey,
  6. } from "../constant";
  7. import { getHeaders } from "../client/api";
  8. import { getClientConfig } from "../config/client";
  9. import { createPersistStore } from "../utils/store";
  10. import { ensure } from "../utils/clone";
  11. import { DEFAULT_CONFIG } from "./config";
  12. let fetchState = 0; // 0 not fetch, 1 fetching, 2 done
  13. const DEFAULT_OPENAI_URL =
  14. getClientConfig()?.buildMode === "export"
  15. ? DEFAULT_API_HOST + "/api/proxy/openai"
  16. : ApiPath.OpenAI;
  17. const DEFAULT_ACCESS_STATE = {
  18. accessCode: "",
  19. useCustomConfig: false,
  20. provider: ServiceProvider.OpenAI,
  21. // openai
  22. openaiUrl: DEFAULT_OPENAI_URL,
  23. openaiApiKey: "",
  24. // azure
  25. azureUrl: "",
  26. azureApiKey: "",
  27. azureApiVersion: "2023-08-01-preview",
  28. // google ai studio
  29. googleUrl: "",
  30. googleApiKey: "",
  31. googleApiVersion: "v1",
  32. // anthropic
  33. anthropicApiKey: "",
  34. anthropicApiVersion: "2023-06-01",
  35. anthropicUrl: "",
  36. // server config
  37. needCode: true,
  38. hideUserApiKey: false,
  39. hideBalanceQuery: false,
  40. disableGPT4: false,
  41. disableFastLink: false,
  42. customModels: "",
  43. defaultModel: "",
  44. };
  45. export const useAccessStore = createPersistStore(
  46. { ...DEFAULT_ACCESS_STATE },
  47. (set, get) => ({
  48. enabledAccessControl() {
  49. this.fetch();
  50. return get().needCode;
  51. },
  52. isValidOpenAI() {
  53. return ensure(get(), ["openaiApiKey"]);
  54. },
  55. isValidAzure() {
  56. return ensure(get(), ["azureUrl", "azureApiKey", "azureApiVersion"]);
  57. },
  58. isValidGoogle() {
  59. return ensure(get(), ["googleApiKey"]);
  60. },
  61. isValidAnthropic() {
  62. return ensure(get(), ["anthropicApiKey"]);
  63. },
  64. isAuthorized() {
  65. this.fetch();
  66. // has token or has code or disabled access control
  67. return (
  68. this.isValidOpenAI() ||
  69. this.isValidAzure() ||
  70. this.isValidGoogle() ||
  71. this.isValidAnthropic() ||
  72. !this.enabledAccessControl() ||
  73. (this.enabledAccessControl() && ensure(get(), ["accessCode"]))
  74. );
  75. },
  76. fetch() {
  77. if (fetchState > 0 || getClientConfig()?.buildMode === "export") return;
  78. fetchState = 1;
  79. fetch("/api/config", {
  80. method: "post",
  81. body: null,
  82. headers: {
  83. ...getHeaders(),
  84. },
  85. })
  86. .then((res) => res.json())
  87. .then((res) => {
  88. // Set default model from env request
  89. let defaultModel = res.defaultModel ?? "";
  90. DEFAULT_CONFIG.modelConfig.model =
  91. defaultModel !== "" ? defaultModel : "gpt-3.5-turbo";
  92. return res;
  93. })
  94. .then((res: DangerConfig) => {
  95. console.log("[Config] got config from server", res);
  96. set(() => ({ ...res }));
  97. })
  98. .catch(() => {
  99. console.error("[Config] failed to fetch config");
  100. })
  101. .finally(() => {
  102. fetchState = 2;
  103. });
  104. },
  105. }),
  106. {
  107. name: StoreKey.Access,
  108. version: 2,
  109. migrate(persistedState, version) {
  110. if (version < 2) {
  111. const state = persistedState as {
  112. token: string;
  113. openaiApiKey: string;
  114. azureApiVersion: string;
  115. googleApiKey: string;
  116. };
  117. state.openaiApiKey = state.token;
  118. state.azureApiVersion = "2023-08-01-preview";
  119. }
  120. return persistedState as any;
  121. },
  122. },
  123. );