Unverified Commit 8e112003 authored by Joel's avatar Joel Committed by GitHub

feat: frontend support claude (#573)

Co-authored-by: 's avatarStyleZhang <jasonapring2015@outlook.com>
parent 7599f79a
...@@ -9,15 +9,16 @@ import ParamItem from './param-item' ...@@ -9,15 +9,16 @@ import ParamItem from './param-item'
import Radio from '@/app/components/base/radio' import Radio from '@/app/components/base/radio'
import Panel from '@/app/components/base/panel' import Panel from '@/app/components/base/panel'
import type { CompletionParams } from '@/models/debug' import type { CompletionParams } from '@/models/debug'
import { AppType } from '@/types/app' import { AppType, ProviderType } from '@/types/app'
import { TONE_LIST } from '@/config' import { TONE_LIST } from '@/config'
import Toast from '@/app/components/base/toast' import Toast from '@/app/components/base/toast'
import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback' import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback'
import { formatNumber } from '@/utils/format'
export type IConifgModelProps = { export type IConifgModelProps = {
mode: string mode: string
modelId: string modelId: string
setModelId: (id: string) => void setModelId: (id: string, provider: ProviderType) => void
completionParams: CompletionParams completionParams: CompletionParams
onCompletionParamsChange: (newParams: CompletionParams) => void onCompletionParamsChange: (newParams: CompletionParams) => void
disabled: boolean disabled: boolean
...@@ -29,18 +30,49 @@ const options = [ ...@@ -29,18 +30,49 @@ const options = [
{ id: 'gpt-3.5-turbo', name: 'gpt-3.5-turbo', type: AppType.chat }, { id: 'gpt-3.5-turbo', name: 'gpt-3.5-turbo', type: AppType.chat },
{ id: 'gpt-3.5-turbo-16k', name: 'gpt-3.5-turbo-16k', type: AppType.chat }, { id: 'gpt-3.5-turbo-16k', name: 'gpt-3.5-turbo-16k', type: AppType.chat },
{ id: 'gpt-4', name: 'gpt-4', type: AppType.chat }, // 8k version { id: 'gpt-4', name: 'gpt-4', type: AppType.chat }, // 8k version
{ id: 'claude-instant-1', name: 'claude-instant-1', type: AppType.chat, provider: ProviderType.anthropic }, // set 30k
{ id: 'claude-2', name: 'claude-2', type: AppType.chat, provider: ProviderType.anthropic }, // set 30k
{ id: 'gpt-3.5-turbo', name: 'gpt-3.5-turbo', type: AppType.completion }, { id: 'gpt-3.5-turbo', name: 'gpt-3.5-turbo', type: AppType.completion },
{ id: 'gpt-3.5-turbo-16k', name: 'gpt-3.5-turbo-16k', type: AppType.completion }, { id: 'gpt-3.5-turbo-16k', name: 'gpt-3.5-turbo-16k', type: AppType.completion },
{ id: 'text-davinci-003', name: 'text-davinci-003', type: AppType.completion }, { id: 'text-davinci-003', name: 'text-davinci-003', type: AppType.completion },
{ id: 'gpt-4', name: 'gpt-4', type: AppType.completion }, // 8k version { id: 'gpt-4', name: 'gpt-4', type: AppType.completion }, // 8k version
{ id: 'claude-instant-1', name: 'claude-instant-1', type: AppType.completion, provider: ProviderType.anthropic }, // set 30k
{ id: 'claude-2', name: 'claude-2', type: AppType.completion, provider: ProviderType.anthropic }, // set 30k
] ]
const ModelIcon = ({ className }: { className?: string }) => ( const getMaxToken = (modelId: string) => {
<svg className={`w-4 h-4 ${className}`} width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> if (['claude-instant-1', 'claude-2'].includes(modelId))
<rect width="20" height="20" rx="6" fill="black" /> return 30 * 1000
<path d="M16.5963 9.65729C16.748 9.99569 16.8443 10.3574 16.8836 10.7265C16.9216 11.0955 16.9026 11.4689 16.8238 11.8321C16.7465 12.1953 16.6123 12.5439 16.4256 12.8648C16.3031 13.0793 16.1587 13.2805 15.9924 13.4658C15.8276 13.6496 15.6438 13.8159 15.444 13.9617C15.2427 14.1076 15.0283 14.2301 14.8007 14.3308C14.5746 14.4299 14.3383 14.5058 14.0962 14.5554C13.9824 14.9084 13.8132 15.2424 13.5944 15.5429C13.3771 15.8434 13.1131 16.1074 12.8126 16.3247C12.5121 16.5435 12.1795 16.7127 11.8266 16.8265C11.4736 16.9417 11.1045 16.9986 10.7326 16.9986C10.4861 17.0001 10.2381 16.9738 9.99596 16.9242C9.75529 16.8732 9.51899 16.7959 9.2929 16.6952C9.06681 16.5946 8.85239 16.4691 8.65256 16.3233C8.45418 16.1774 8.2704 16.0097 8.10703 15.8244C7.74237 15.9032 7.36896 15.9221 6.99992 15.8842C6.63089 15.8448 6.26914 15.7486 5.92928 15.5969C5.59088 15.4466 5.27727 15.2424 5.00159 14.993C4.72591 14.7436 4.49107 14.4518 4.30582 14.1309C4.18184 13.9165 4.07973 13.6904 4.00242 13.4556C3.92511 13.2207 3.87406 12.9786 3.84781 12.7321C3.82155 12.487 3.82301 12.2391 3.84927 11.9926C3.87552 11.7475 3.92949 11.5054 4.0068 11.2705C3.75883 10.9949 3.55462 10.6813 3.40292 10.3428C3.25268 10.003 3.15495 9.6427 3.11703 9.27367C3.07765 8.90463 3.09807 8.53122 3.17538 8.16802C3.25268 7.80482 3.38688 7.4562 3.57358 7.1353C3.69611 6.92088 3.84051 6.71813 4.00534 6.53434C4.17017 6.35056 4.35541 6.18427 4.55525 6.03841C4.75508 5.89254 4.97096 5.76856 5.19705 5.66937C5.42459 5.56873 5.66089 5.49434 5.90303 5.44474C6.0168 5.09029 6.186 4.75772 6.40334 4.45725C6.62213 4.15677 6.88615 3.89275 7.18663 3.67396C7.48711 3.45662 7.81968 3.28742 8.17267 3.17219C8.52566 3.05841 8.89469 3.00007 9.26664 3.00153C9.51315 3.00007 9.76112 3.02486 10.0033 3.07592C10.2454 3.12697 10.4817 3.20282 10.7078 3.30346C10.9339 3.40557 11.1483 3.52955 11.3481 3.67542C11.548 3.82274 11.7317 3.98902 11.8951 4.17427C12.2583 4.09696 12.6317 4.078 13.0008 4.11592C13.3698 4.15385 13.7301 4.25158 14.0699 4.40182C14.4083 4.55352 14.7219 4.75627 14.9976 5.00569C15.2733 5.25366 15.5082 5.54393 15.6934 5.86629C15.8174 6.07925 15.9195 6.30534 15.9968 6.54164C16.0741 6.77648 16.1266 7.01861 16.1514 7.26512C16.1777 7.51163 16.1777 7.7596 16.15 8.00611C16.1237 8.25262 16.0697 8.49475 15.9924 8.72959C16.2418 9.00528 16.4446 9.31742 16.5963 9.65729ZM11.7361 15.8842C12.0541 15.7529 12.3429 15.5589 12.5865 15.3153C12.8301 15.0717 13.0241 14.7829 13.1554 14.4635C13.2866 14.1455 13.3552 13.8042 13.3552 13.46V10.2072C13.3542 10.2043 13.3533 10.2009 13.3523 10.197C13.3513 10.1941 13.3499 10.1911 13.3479 10.1882C13.346 10.1853 13.3435 10.1829 13.3406 10.1809C13.3377 10.178 13.3348 10.1761 13.3319 10.1751L12.1547 9.49538V13.4249C12.1547 13.4643 12.1489 13.5052 12.1387 13.5431C12.1285 13.5825 12.1139 13.6189 12.0935 13.654C12.0731 13.689 12.0497 13.7211 12.0206 13.7488C11.9922 13.777 11.9603 13.8015 11.9257 13.8217L9.13828 15.4306C9.11495 15.4452 9.07556 15.4656 9.05514 15.4772C9.17037 15.575 9.29582 15.661 9.42709 15.7369C9.55983 15.8127 9.69694 15.8769 9.83989 15.9294C9.98284 15.9805 10.1302 16.0199 10.2789 16.0461C10.4292 16.0724 10.5809 16.0855 10.7326 16.0855C11.0768 16.0855 11.4181 16.0169 11.7361 15.8842ZM5.09786 13.6758C5.27144 13.9749 5.50044 14.2345 5.77321 14.4445C6.04743 14.6546 6.35812 14.8077 6.69069 14.8967C7.02326 14.9857 7.37042 15.009 7.71174 14.9638C8.05306 14.9186 8.38125 14.8077 8.68027 14.6356L11.4984 13.0092L11.5057 13.0019C11.5076 13 11.5091 12.9971 11.51 12.9932C11.512 12.9903 11.5134 12.9874 11.5144 12.9844V11.6133L8.11286 13.581C8.07786 13.6014 8.04139 13.616 8.00346 13.6277C7.96408 13.6379 7.9247 13.6423 7.88386 13.6423C7.84447 13.6423 7.80509 13.6379 7.76571 13.6277C7.72778 13.616 7.68986 13.6014 7.65485 13.581L4.86739 11.9707C4.8426 11.9561 4.80613 11.9342 4.78571 11.9211C4.75946 12.0713 4.74633 12.223 4.74633 12.3747C4.74633 12.5264 4.76091 12.6781 4.78717 12.8284C4.81342 12.9771 4.85427 13.1245 4.90532 13.2674C4.95783 13.4104 5.02201 13.5475 5.09786 13.6788V13.6758ZM4.36562 7.59332C4.1935 7.89234 4.08265 8.22199 4.03743 8.56331C3.99221 8.90463 4.01555 9.25033 4.10453 9.58436C4.1935 9.91692 4.34666 10.2276 4.5567 10.5018C4.76675 10.7746 5.02784 11.0036 5.32541 11.1757L8.14204 12.8036C8.14495 12.8045 8.14836 12.8055 8.15225 12.8065H8.16246C8.16635 12.8065 8.16975 12.8055 8.17267 12.8036C8.17558 12.8026 8.1785 12.8011 8.18142 12.7992L9.36291 12.1165L5.96137 10.1532C5.92782 10.1328 5.89573 10.108 5.86656 10.0803C5.8383 10.0519 5.81379 10.0201 5.79363 9.98548C5.77467 9.95047 5.75862 9.91401 5.74841 9.87462C5.7382 9.8367 5.73237 9.79732 5.73383 9.75647V6.44391C5.59088 6.49642 5.45231 6.5606 5.32103 6.63645C5.18975 6.71376 5.06577 6.80128 4.94908 6.899C4.83385 6.99673 4.72591 7.10467 4.62818 7.22136C4.53045 7.3366 4.44439 7.46204 4.36854 7.59332H4.36562ZM14.0408 9.84545C14.0758 9.86587 14.1079 9.88921 14.137 9.91838C14.1647 9.9461 14.1895 9.97819 14.21 10.0132C14.2289 10.0482 14.245 10.0861 14.2552 10.1241C14.2639 10.1634 14.2698 10.2028 14.2683 10.2437V13.5562C14.7365 13.3841 15.145 13.0822 15.4469 12.6854C15.7503 12.2887 15.9326 11.8146 15.9749 11.3187C16.0172 10.8227 15.918 10.3239 15.6876 9.88192C15.4571 9.43995 15.1056 9.07237 14.6738 8.82441L11.8572 7.19657C11.8543 7.19559 11.8509 7.19462 11.847 7.19365H11.8368C11.8338 7.19462 11.8304 7.19559 11.8266 7.19657C11.8236 7.19754 11.8207 7.199 11.8178 7.20094L10.6421 7.88067L14.0437 9.84545H14.0408ZM15.215 8.0805H15.2135V8.08196L15.215 8.0805ZM15.2135 8.07904C15.2981 7.58894 15.2412 7.08425 15.0487 6.62478C14.8576 6.16531 14.5382 5.77002 14.1297 5.48413C13.7213 5.19969 13.24 5.03632 12.7426 5.01445C12.2437 4.99402 11.7507 5.11509 11.3189 5.36306L8.50232 6.98944C8.4994 6.99138 8.49697 6.99382 8.49503 6.99673L8.48919 7.00549C8.48822 7.0084 8.48725 7.01181 8.48627 7.0157C8.4853 7.01861 8.48482 7.02202 8.48482 7.02591V8.38536L11.8864 6.42057C11.9214 6.40015 11.9593 6.38556 11.9972 6.37389C12.0366 6.36368 12.076 6.35931 12.1154 6.35931C12.1562 6.35931 12.1956 6.36368 12.235 6.37389C12.2729 6.38556 12.3094 6.40015 12.3444 6.42057L15.1318 8.03091C15.1566 8.04549 15.1931 8.06591 15.2135 8.07904ZM7.84301 6.57373C7.84301 6.53434 7.84885 6.49496 7.85906 6.45558C7.86927 6.41765 7.88386 6.37973 7.90428 6.34472C7.9247 6.31117 7.94804 6.27908 7.97721 6.24991C8.00492 6.2222 8.03701 6.1974 8.07202 6.17844L10.8595 4.56956C10.8857 4.55352 10.9222 4.53309 10.9426 4.52288C10.5605 4.20344 10.0937 3.99923 9.59921 3.93651C9.10474 3.87233 8.60296 3.9511 8.15225 4.1626C7.70007 4.3741 7.3179 4.71105 7.05097 5.13114C6.78404 5.55268 6.64256 6.03987 6.64256 6.53872V9.79148C6.64353 9.79537 6.6445 9.79878 6.64547 9.80169C6.64645 9.80461 6.6479 9.80753 6.64985 9.81044C6.65179 9.81336 6.65422 9.81628 6.65714 9.8192C6.65909 9.82114 6.662 9.82309 6.66589 9.82503L7.84301 10.5048V6.57373ZM8.4819 10.8723L9.99742 11.7475L11.5129 10.8723V9.12343L9.99888 8.24824L8.48336 9.12343L8.4819 10.8723Z" fill="white" />
</svg> if (['gpt-4', 'gpt-3.5-turbo-16k'].includes(modelId))
) return 8000
return 4000
}
const ModelIcon = ({ provider, className }: { provider?: ProviderType; className?: string }) => {
if (provider === ProviderType.anthropic) {
return (
<svg className={`w-4 h-4 ${className}`} width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="24" height="24" rx="6" fill="#CA9F7B"/>
<g clip-path="url(#clip0_3907_39360)">
<path d="M14.9613 7.13043H12.8476L16.7022 16.8696H18.8159L14.9613 7.13043ZM8.85457 7.13043L5 16.8696H7.15539L7.94365 14.8243H11.9763L12.7645 16.8696H14.9199L11.0653 7.13043H8.85457ZM8.64091 13.0156L9.95996 9.59291L11.279 13.0156H8.64091Z" fill="#191918"/>
</g>
<defs>
<clipPath id="clip0_3907_39360">
<rect width="14" height="9.73913" fill="white" transform="translate(5 7.13043)"/>
</clipPath>
</defs>
</svg>
)
}
return (
<svg className={`w-4 h-4 ${className}`} width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="20" height="20" rx="6" fill="black" />
<path d="M16.5963 9.65729C16.748 9.99569 16.8443 10.3574 16.8836 10.7265C16.9216 11.0955 16.9026 11.4689 16.8238 11.8321C16.7465 12.1953 16.6123 12.5439 16.4256 12.8648C16.3031 13.0793 16.1587 13.2805 15.9924 13.4658C15.8276 13.6496 15.6438 13.8159 15.444 13.9617C15.2427 14.1076 15.0283 14.2301 14.8007 14.3308C14.5746 14.4299 14.3383 14.5058 14.0962 14.5554C13.9824 14.9084 13.8132 15.2424 13.5944 15.5429C13.3771 15.8434 13.1131 16.1074 12.8126 16.3247C12.5121 16.5435 12.1795 16.7127 11.8266 16.8265C11.4736 16.9417 11.1045 16.9986 10.7326 16.9986C10.4861 17.0001 10.2381 16.9738 9.99596 16.9242C9.75529 16.8732 9.51899 16.7959 9.2929 16.6952C9.06681 16.5946 8.85239 16.4691 8.65256 16.3233C8.45418 16.1774 8.2704 16.0097 8.10703 15.8244C7.74237 15.9032 7.36896 15.9221 6.99992 15.8842C6.63089 15.8448 6.26914 15.7486 5.92928 15.5969C5.59088 15.4466 5.27727 15.2424 5.00159 14.993C4.72591 14.7436 4.49107 14.4518 4.30582 14.1309C4.18184 13.9165 4.07973 13.6904 4.00242 13.4556C3.92511 13.2207 3.87406 12.9786 3.84781 12.7321C3.82155 12.487 3.82301 12.2391 3.84927 11.9926C3.87552 11.7475 3.92949 11.5054 4.0068 11.2705C3.75883 10.9949 3.55462 10.6813 3.40292 10.3428C3.25268 10.003 3.15495 9.6427 3.11703 9.27367C3.07765 8.90463 3.09807 8.53122 3.17538 8.16802C3.25268 7.80482 3.38688 7.4562 3.57358 7.1353C3.69611 6.92088 3.84051 6.71813 4.00534 6.53434C4.17017 6.35056 4.35541 6.18427 4.55525 6.03841C4.75508 5.89254 4.97096 5.76856 5.19705 5.66937C5.42459 5.56873 5.66089 5.49434 5.90303 5.44474C6.0168 5.09029 6.186 4.75772 6.40334 4.45725C6.62213 4.15677 6.88615 3.89275 7.18663 3.67396C7.48711 3.45662 7.81968 3.28742 8.17267 3.17219C8.52566 3.05841 8.89469 3.00007 9.26664 3.00153C9.51315 3.00007 9.76112 3.02486 10.0033 3.07592C10.2454 3.12697 10.4817 3.20282 10.7078 3.30346C10.9339 3.40557 11.1483 3.52955 11.3481 3.67542C11.548 3.82274 11.7317 3.98902 11.8951 4.17427C12.2583 4.09696 12.6317 4.078 13.0008 4.11592C13.3698 4.15385 13.7301 4.25158 14.0699 4.40182C14.4083 4.55352 14.7219 4.75627 14.9976 5.00569C15.2733 5.25366 15.5082 5.54393 15.6934 5.86629C15.8174 6.07925 15.9195 6.30534 15.9968 6.54164C16.0741 6.77648 16.1266 7.01861 16.1514 7.26512C16.1777 7.51163 16.1777 7.7596 16.15 8.00611C16.1237 8.25262 16.0697 8.49475 15.9924 8.72959C16.2418 9.00528 16.4446 9.31742 16.5963 9.65729ZM11.7361 15.8842C12.0541 15.7529 12.3429 15.5589 12.5865 15.3153C12.8301 15.0717 13.0241 14.7829 13.1554 14.4635C13.2866 14.1455 13.3552 13.8042 13.3552 13.46V10.2072C13.3542 10.2043 13.3533 10.2009 13.3523 10.197C13.3513 10.1941 13.3499 10.1911 13.3479 10.1882C13.346 10.1853 13.3435 10.1829 13.3406 10.1809C13.3377 10.178 13.3348 10.1761 13.3319 10.1751L12.1547 9.49538V13.4249C12.1547 13.4643 12.1489 13.5052 12.1387 13.5431C12.1285 13.5825 12.1139 13.6189 12.0935 13.654C12.0731 13.689 12.0497 13.7211 12.0206 13.7488C11.9922 13.777 11.9603 13.8015 11.9257 13.8217L9.13828 15.4306C9.11495 15.4452 9.07556 15.4656 9.05514 15.4772C9.17037 15.575 9.29582 15.661 9.42709 15.7369C9.55983 15.8127 9.69694 15.8769 9.83989 15.9294C9.98284 15.9805 10.1302 16.0199 10.2789 16.0461C10.4292 16.0724 10.5809 16.0855 10.7326 16.0855C11.0768 16.0855 11.4181 16.0169 11.7361 15.8842ZM5.09786 13.6758C5.27144 13.9749 5.50044 14.2345 5.77321 14.4445C6.04743 14.6546 6.35812 14.8077 6.69069 14.8967C7.02326 14.9857 7.37042 15.009 7.71174 14.9638C8.05306 14.9186 8.38125 14.8077 8.68027 14.6356L11.4984 13.0092L11.5057 13.0019C11.5076 13 11.5091 12.9971 11.51 12.9932C11.512 12.9903 11.5134 12.9874 11.5144 12.9844V11.6133L8.11286 13.581C8.07786 13.6014 8.04139 13.616 8.00346 13.6277C7.96408 13.6379 7.9247 13.6423 7.88386 13.6423C7.84447 13.6423 7.80509 13.6379 7.76571 13.6277C7.72778 13.616 7.68986 13.6014 7.65485 13.581L4.86739 11.9707C4.8426 11.9561 4.80613 11.9342 4.78571 11.9211C4.75946 12.0713 4.74633 12.223 4.74633 12.3747C4.74633 12.5264 4.76091 12.6781 4.78717 12.8284C4.81342 12.9771 4.85427 13.1245 4.90532 13.2674C4.95783 13.4104 5.02201 13.5475 5.09786 13.6788V13.6758ZM4.36562 7.59332C4.1935 7.89234 4.08265 8.22199 4.03743 8.56331C3.99221 8.90463 4.01555 9.25033 4.10453 9.58436C4.1935 9.91692 4.34666 10.2276 4.5567 10.5018C4.76675 10.7746 5.02784 11.0036 5.32541 11.1757L8.14204 12.8036C8.14495 12.8045 8.14836 12.8055 8.15225 12.8065H8.16246C8.16635 12.8065 8.16975 12.8055 8.17267 12.8036C8.17558 12.8026 8.1785 12.8011 8.18142 12.7992L9.36291 12.1165L5.96137 10.1532C5.92782 10.1328 5.89573 10.108 5.86656 10.0803C5.8383 10.0519 5.81379 10.0201 5.79363 9.98548C5.77467 9.95047 5.75862 9.91401 5.74841 9.87462C5.7382 9.8367 5.73237 9.79732 5.73383 9.75647V6.44391C5.59088 6.49642 5.45231 6.5606 5.32103 6.63645C5.18975 6.71376 5.06577 6.80128 4.94908 6.899C4.83385 6.99673 4.72591 7.10467 4.62818 7.22136C4.53045 7.3366 4.44439 7.46204 4.36854 7.59332H4.36562ZM14.0408 9.84545C14.0758 9.86587 14.1079 9.88921 14.137 9.91838C14.1647 9.9461 14.1895 9.97819 14.21 10.0132C14.2289 10.0482 14.245 10.0861 14.2552 10.1241C14.2639 10.1634 14.2698 10.2028 14.2683 10.2437V13.5562C14.7365 13.3841 15.145 13.0822 15.4469 12.6854C15.7503 12.2887 15.9326 11.8146 15.9749 11.3187C16.0172 10.8227 15.918 10.3239 15.6876 9.88192C15.4571 9.43995 15.1056 9.07237 14.6738 8.82441L11.8572 7.19657C11.8543 7.19559 11.8509 7.19462 11.847 7.19365H11.8368C11.8338 7.19462 11.8304 7.19559 11.8266 7.19657C11.8236 7.19754 11.8207 7.199 11.8178 7.20094L10.6421 7.88067L14.0437 9.84545H14.0408ZM15.215 8.0805H15.2135V8.08196L15.215 8.0805ZM15.2135 8.07904C15.2981 7.58894 15.2412 7.08425 15.0487 6.62478C14.8576 6.16531 14.5382 5.77002 14.1297 5.48413C13.7213 5.19969 13.24 5.03632 12.7426 5.01445C12.2437 4.99402 11.7507 5.11509 11.3189 5.36306L8.50232 6.98944C8.4994 6.99138 8.49697 6.99382 8.49503 6.99673L8.48919 7.00549C8.48822 7.0084 8.48725 7.01181 8.48627 7.0157C8.4853 7.01861 8.48482 7.02202 8.48482 7.02591V8.38536L11.8864 6.42057C11.9214 6.40015 11.9593 6.38556 11.9972 6.37389C12.0366 6.36368 12.076 6.35931 12.1154 6.35931C12.1562 6.35931 12.1956 6.36368 12.235 6.37389C12.2729 6.38556 12.3094 6.40015 12.3444 6.42057L15.1318 8.03091C15.1566 8.04549 15.1931 8.06591 15.2135 8.07904ZM7.84301 6.57373C7.84301 6.53434 7.84885 6.49496 7.85906 6.45558C7.86927 6.41765 7.88386 6.37973 7.90428 6.34472C7.9247 6.31117 7.94804 6.27908 7.97721 6.24991C8.00492 6.2222 8.03701 6.1974 8.07202 6.17844L10.8595 4.56956C10.8857 4.55352 10.9222 4.53309 10.9426 4.52288C10.5605 4.20344 10.0937 3.99923 9.59921 3.93651C9.10474 3.87233 8.60296 3.9511 8.15225 4.1626C7.70007 4.3741 7.3179 4.71105 7.05097 5.13114C6.78404 5.55268 6.64256 6.03987 6.64256 6.53872V9.79148C6.64353 9.79537 6.6445 9.79878 6.64547 9.80169C6.64645 9.80461 6.6479 9.80753 6.64985 9.81044C6.65179 9.81336 6.65422 9.81628 6.65714 9.8192C6.65909 9.82114 6.662 9.82309 6.66589 9.82503L7.84301 10.5048V6.57373ZM8.4819 10.8723L9.99742 11.7475L11.5129 10.8723V9.12343L9.99888 8.24824L8.48336 9.12343L8.4819 10.8723Z" fill="white" />
</svg>
)
}
const ConifgModel: FC<IConifgModelProps> = ({ const ConifgModel: FC<IConifgModelProps> = ({
mode, mode,
...@@ -58,6 +90,7 @@ const ConifgModel: FC<IConifgModelProps> = ({ ...@@ -58,6 +90,7 @@ const ConifgModel: FC<IConifgModelProps> = ({
const [isShowConfig, { setFalse: hideConfig, toggle: toogleShowConfig }] = useBoolean(false) const [isShowConfig, { setFalse: hideConfig, toggle: toogleShowConfig }] = useBoolean(false)
const [maxTokenSettingTipVisible, setMaxTokenSettingTipVisible] = useState(false) const [maxTokenSettingTipVisible, setMaxTokenSettingTipVisible] = useState(false)
const configContentRef = React.useRef(null) const configContentRef = React.useRef(null)
const currModel = options.find(item => item.id === modelId)
useClickAway(() => { useClickAway(() => {
hideConfig() hideConfig()
}, configContentRef) }, configContentRef)
...@@ -99,7 +132,7 @@ const ConifgModel: FC<IConifgModelProps> = ({ ...@@ -99,7 +132,7 @@ const ConifgModel: FC<IConifgModelProps> = ({
key: 'max_tokens', key: 'max_tokens',
tip: t('common.model.params.maxTokenTip'), tip: t('common.model.params.maxTokenTip'),
step: 100, step: 100,
max: (modelId === 'gpt-4' || modelId === 'gpt-3.5-turbo-16k') ? 8000 : 4000, max: getMaxToken(modelId),
}, },
] ]
...@@ -112,7 +145,7 @@ const ConifgModel: FC<IConifgModelProps> = ({ ...@@ -112,7 +145,7 @@ const ConifgModel: FC<IConifgModelProps> = ({
hideOption() hideOption()
}, triggerRef) }, triggerRef)
const handleSelectModel = (id: string) => { const handleSelectModel = (id: string, provider = ProviderType.openai) => {
return () => { return () => {
if (id === 'gpt-4' && !canUseGPT4) { if (id === 'gpt-4' && !canUseGPT4) {
hideConfig() hideConfig()
...@@ -120,17 +153,18 @@ const ConifgModel: FC<IConifgModelProps> = ({ ...@@ -120,17 +153,18 @@ const ConifgModel: FC<IConifgModelProps> = ({
onShowUseGPT4Confirm() onShowUseGPT4Confirm()
return return
} }
if (id !== 'gpt-4' && completionParams.max_tokens > 4000) { const nextSelectModelMaxToken = getMaxToken(id)
if (completionParams.max_tokens > nextSelectModelMaxToken) {
Toast.notify({ Toast.notify({
type: 'warning', type: 'warning',
message: t('common.model.params.setToCurrentModelMaxTokenTip'), message: t('common.model.params.setToCurrentModelMaxTokenTip', { maxToken: formatNumber(nextSelectModelMaxToken) }),
}) })
onCompletionParamsChange({ onCompletionParamsChange({
...completionParams, ...completionParams,
max_tokens: 4000, max_tokens: nextSelectModelMaxToken,
}) })
} }
setModelId(id) setModelId(id, provider)
} }
} }
...@@ -181,7 +215,7 @@ const ConifgModel: FC<IConifgModelProps> = ({ ...@@ -181,7 +215,7 @@ const ConifgModel: FC<IConifgModelProps> = ({
useEffect(() => { useEffect(() => {
const max = params[4].max const max = params[4].max
if (completionParams.max_tokens > max * 2 / 3) if (currModel?.provider !== ProviderType.anthropic && completionParams.max_tokens > max * 2 / 3)
setMaxTokenSettingTipVisible(true) setMaxTokenSettingTipVisible(true)
else else
setMaxTokenSettingTipVisible(false) setMaxTokenSettingTipVisible(false)
...@@ -193,7 +227,7 @@ const ConifgModel: FC<IConifgModelProps> = ({ ...@@ -193,7 +227,7 @@ const ConifgModel: FC<IConifgModelProps> = ({
className={cn('flex items-center border h-8 px-2.5 space-x-2 rounded-lg', disabled ? diabledStyle : ableStyle)} className={cn('flex items-center border h-8 px-2.5 space-x-2 rounded-lg', disabled ? diabledStyle : ableStyle)}
onClick={() => !disabled && toogleShowConfig()} onClick={() => !disabled && toogleShowConfig()}
> >
<ModelIcon /> <ModelIcon provider={currModel?.provider} />
<div className='text-[13px] text-gray-900 font-medium'>{selectedModel.name}</div> <div className='text-[13px] text-gray-900 font-medium'>{selectedModel.name}</div>
{disabled ? <InformationCircleIcon className='w-3.5 h-3.5 text-[#F79009]' /> : <Cog8ToothIcon className='w-3.5 h-3.5 text-gray-500' />} {disabled ? <InformationCircleIcon className='w-3.5 h-3.5 text-[#F79009]' /> : <Cog8ToothIcon className='w-3.5 h-3.5 text-gray-500' />}
</div> </div>
...@@ -220,15 +254,15 @@ const ConifgModel: FC<IConifgModelProps> = ({ ...@@ -220,15 +254,15 @@ const ConifgModel: FC<IConifgModelProps> = ({
{/* model selector */} {/* model selector */}
<div className="relative" style={{ zIndex: 30 }}> <div className="relative" style={{ zIndex: 30 }}>
<div ref={triggerRef} onClick={() => !selectModelDisabled && toogleOption()} className={cn(selectModelDisabled ? 'cursor-not-allowed' : 'cursor-pointer', 'flex items-center h-9 px-3 space-x-2 rounded-lg bg-gray-50 ')}> <div ref={triggerRef} onClick={() => !selectModelDisabled && toogleOption()} className={cn(selectModelDisabled ? 'cursor-not-allowed' : 'cursor-pointer', 'flex items-center h-9 px-3 space-x-2 rounded-lg bg-gray-50 ')}>
<ModelIcon /> <ModelIcon provider={currModel?.provider} />
<div className="text-sm gray-900">{selectedModel?.name}</div> <div className="text-sm gray-900">{selectedModel?.name}</div>
{!selectModelDisabled && <ChevronDownIcon className={cn(isShowOption && 'rotate-180', 'w-[14px] h-[14px] text-gray-500')} />} {!selectModelDisabled && <ChevronDownIcon className={cn(isShowOption && 'rotate-180', 'w-[14px] h-[14px] text-gray-500')} />}
</div> </div>
{isShowOption && ( {isShowOption && (
<div className={cn(isChatApp ? 'min-w-[159px]' : 'w-[179px]', 'absolute right-0 bg-gray-50 rounded-lg shadow')}> <div className={cn(isChatApp ? 'min-w-[159px]' : 'w-[179px]', 'absolute right-0 bg-gray-50 rounded-lg shadow')}>
{availableModels.map(item => ( {availableModels.map(item => (
<div key={item.id} onClick={handleSelectModel(item.id)} className="flex items-center h-9 px-3 rounded-lg cursor-pointer hover:bg-gray-100"> <div key={item.id} onClick={handleSelectModel(item.id, item.provider)} className="flex items-center h-9 px-3 rounded-lg cursor-pointer hover:bg-gray-100">
<ModelIcon className='shrink-0 mr-2' /> <ModelIcon className='shrink-0 mr-2' provider={item?.provider} />
<div className="text-sm gray-900 whitespace-nowrap">{item.name}</div> <div className="text-sm gray-900 whitespace-nowrap">{item.name}</div>
</div> </div>
))} ))}
......
...@@ -372,7 +372,7 @@ const Debug: FC<IDebug> = ({ ...@@ -372,7 +372,7 @@ const Debug: FC<IDebug> = ({
{/* Chat */} {/* Chat */}
{mode === AppType.chat && ( {mode === AppType.chat && (
<div className="mt-[34px] h-full flex flex-col"> <div className="mt-[34px] h-full flex flex-col">
<div className={cn(doShowSuggestion ? 'pb-[140px]' : (isResponsing ? 'pb-[113px]' : 'pb-[66px]'), 'relative mt-1.5 grow h-[200px] overflow-hidden')}> <div className={cn(doShowSuggestion ? 'pb-[140px]' : (isResponsing ? 'pb-[113px]' : 'pb-[76px]'), 'relative mt-1.5 grow h-[200px] overflow-hidden')}>
<div className="h-full overflow-y-auto overflow-x-hidden" ref={chatListDomRef}> <div className="h-full overflow-y-auto overflow-x-hidden" ref={chatListDomRef}>
<Chat <Chat
chatList={chatList} chatList={chatList}
......
...@@ -16,6 +16,7 @@ import ConfigModel from '@/app/components/app/configuration/config-model' ...@@ -16,6 +16,7 @@ import ConfigModel from '@/app/components/app/configuration/config-model'
import Config from '@/app/components/app/configuration/config' import Config from '@/app/components/app/configuration/config'
import Debug from '@/app/components/app/configuration/debug' import Debug from '@/app/components/app/configuration/debug'
import Confirm from '@/app/components/base/confirm' import Confirm from '@/app/components/base/confirm'
import { ProviderType } from '@/types/app'
import type { AppDetailResponse } from '@/models/app' import type { AppDetailResponse } from '@/models/app'
import { ToastContext } from '@/app/components/base/toast' import { ToastContext } from '@/app/components/base/toast'
import { fetchTenantInfo } from '@/service/common' import { fetchTenantInfo } from '@/service/common'
...@@ -67,7 +68,7 @@ const Configuration: FC = () => { ...@@ -67,7 +68,7 @@ const Configuration: FC = () => {
frequency_penalty: 1, // -2-2 frequency_penalty: 1, // -2-2
}) })
const [modelConfig, doSetModelConfig] = useState<ModelConfig>({ const [modelConfig, doSetModelConfig] = useState<ModelConfig>({
provider: 'openai', provider: ProviderType.openai,
model_id: 'gpt-3.5-turbo', model_id: 'gpt-3.5-turbo',
configs: { configs: {
prompt_template: '', prompt_template: '',
...@@ -84,8 +85,9 @@ const Configuration: FC = () => { ...@@ -84,8 +85,9 @@ const Configuration: FC = () => {
doSetModelConfig(newModelConfig) doSetModelConfig(newModelConfig)
} }
const setModelId = (modelId: string) => { const setModelId = (modelId: string, provider: ProviderType) => {
const newModelConfig = produce(modelConfig, (draft: any) => { const newModelConfig = produce(modelConfig, (draft: any) => {
draft.provider = provider
draft.model_id = modelId draft.model_id = modelId
}) })
setModelConfig(newModelConfig) setModelConfig(newModelConfig)
......
...@@ -19,6 +19,7 @@ const AutoHeightTextarea = forwardRef( ...@@ -19,6 +19,7 @@ const AutoHeightTextarea = forwardRef(
{ value, onChange, placeholder, className, minHeight = 36, maxHeight = 96, autoFocus, controlFocus, onKeyDown, onKeyUp }: IProps, { value, onChange, placeholder, className, minHeight = 36, maxHeight = 96, autoFocus, controlFocus, onKeyDown, onKeyUp }: IProps,
outerRef: any, outerRef: any,
) => { ) => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const ref = outerRef || useRef<HTMLTextAreaElement>(null) const ref = outerRef || useRef<HTMLTextAreaElement>(null)
const doFocus = () => { const doFocus = () => {
...@@ -54,13 +55,20 @@ const AutoHeightTextarea = forwardRef( ...@@ -54,13 +55,20 @@ const AutoHeightTextarea = forwardRef(
return ( return (
<div className='relative'> <div className='relative'>
<div className={cn(className, 'invisible whitespace-pre-wrap break-all overflow-y-auto')} style={{ minHeight, maxHeight }}> <div className={cn(className, 'invisible whitespace-pre-wrap break-all overflow-y-auto')} style={{
minHeight,
maxHeight,
paddingRight: (value && value.trim().length > 10000) ? 140 : 130,
}}>
{!value ? placeholder : value.replace(/\n$/, '\n ')} {!value ? placeholder : value.replace(/\n$/, '\n ')}
</div> </div>
<textarea <textarea
ref={ref} ref={ref}
autoFocus={autoFocus} autoFocus={autoFocus}
className={cn(className, 'absolute inset-0 resize-none overflow-hidden')} className={cn(className, 'absolute inset-0 resize-none overflow-auto')}
style={{
paddingRight: (value && value.trim().length > 10000) ? 140 : 130,
}}
placeholder={placeholder} placeholder={placeholder}
onChange={onChange} onChange={onChange}
onKeyDown={onKeyDown} onKeyDown={onKeyDown}
......
.icon {
width: 24px;
height: 24px;
margin-right: 12px;
background: url(../../../assets/anthropic.svg) center center no-repeat;
background-size: contain;
}
.bar {
background: linear-gradient(90deg, rgba(41, 112, 255, 0.9) 0%, rgba(21, 94, 239, 0.9) 100%);
}
.bar-error {
background: linear-gradient(90deg, rgba(240, 68, 56, 0.72) 0%, rgba(217, 45, 32, 0.9) 100%);
}
.bar-item {
width: 10%;
border-right: 1px solid rgba(255, 255, 255, 0.5);
}
.bar-item:last-of-type {
border-right: 0;
}
\ No newline at end of file
import { useTranslation } from 'react-i18next'
import cn from 'classnames'
import s from './index.module.css'
import type { ProviderHosted } from '@/models/common'
type AnthropicHostedProviderProps = {
provider: ProviderHosted
}
const AnthropicHostedProvider = ({
provider,
}: AnthropicHostedProviderProps) => {
const { t } = useTranslation()
const exhausted = provider.quota_used > provider.quota_limit
return (
<div className={`
border-[0.5px] border-gray-200 rounded-xl
${exhausted ? 'bg-[#FFFBFA]' : 'bg-gray-50'}
`}>
<div className='pt-4 px-4 pb-3'>
<div className='flex items-center mb-3'>
<div className={s.icon} />
<div className='grow text-sm font-medium text-gray-800'>
{t('common.provider.anthropicHosted.anthropicHosted')}
</div>
<div className={`
px-2 h-[22px] flex items-center rounded-md border
text-xs font-semibold
${exhausted ? 'border-[#D92D20] text-[#D92D20]' : 'border-primary-600 text-primary-600'}
`}>
{exhausted ? t('common.provider.anthropicHosted.exhausted') : t('common.provider.anthropicHosted.onTrial')}
</div>
</div>
<div className='text-[13px] text-gray-500'>{t('common.provider.anthropicHosted.desc')}</div>
</div>
<div className='flex items-center h-[42px] px-4 border-t-[0.5px] border-t-[rgba(0, 0, 0, 0.05)]'>
<div className='text-[13px] text-gray-700'>{t('common.provider.anthropicHosted.callTimes')}</div>
<div className='relative grow h-2 flex bg-gray-200 rounded-md mx-2 overflow-hidden'>
<div
className={cn(s.bar, exhausted && s['bar-error'], 'absolute top-0 left-0 right-0 bottom-0')}
style={{ width: `${(provider.quota_used / provider.quota_limit * 100).toFixed(2)}%` }}
/>
{Array(10).fill(0).map((i, k) => (
<div key={k} className={s['bar-item']} />
))}
</div>
<div className={`
text-[13px] font-medium ${exhausted ? 'text-[#D92D20]' : 'text-gray-700'}
`}>{provider.quota_used}/{provider.quota_limit}</div>
</div>
{
exhausted && (
<div className='
px-4 py-3 leading-[18px] flex items-center text-[13px] text-gray-700 font-medium
bg-[#FFFAEB] border-t border-t-[rgba(0, 0, 0, 0.05)] rounded-b-xl
'>
{t('common.provider.anthropicHosted.usedUp')}
</div>
)
}
</div>
)
}
export default AnthropicHostedProvider
import { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import Link from 'next/link'
import { ArrowTopRightOnSquareIcon } from '@heroicons/react/24/outline'
import ProviderInput from '../provider-input'
import type { ValidatedStatusState } from '../provider-input/useValidateToken'
import useValidateToken, { ValidatedStatus } from '../provider-input/useValidateToken'
import {
ValidatedErrorIcon,
ValidatedErrorOnOpenaiTip,
ValidatedSuccessIcon,
ValidatingTip,
} from '../provider-input/Validate'
import type { Provider, ProviderAnthropicToken } from '@/models/common'
type AnthropicProviderProps = {
provider: Provider
onValidatedStatus: (status?: ValidatedStatusState) => void
onTokenChange: (token: ProviderAnthropicToken) => void
}
const AnthropicProvider = ({
provider,
onValidatedStatus,
onTokenChange,
}: AnthropicProviderProps) => {
const { t } = useTranslation()
const [token, setToken] = useState<ProviderAnthropicToken>((provider.token as ProviderAnthropicToken) || { anthropic_api_key: '' })
const [validating, validatedStatus, setValidatedStatus, validate] = useValidateToken(provider.provider_name)
const handleFocus = () => {
if (token.anthropic_api_key === (provider.token as ProviderAnthropicToken).anthropic_api_key) {
setToken({ anthropic_api_key: '' })
onTokenChange({ anthropic_api_key: '' })
setValidatedStatus({})
}
}
const handleChange = (v: string) => {
const apiKey = { anthropic_api_key: v }
setToken(apiKey)
onTokenChange(apiKey)
validate(apiKey, {
beforeValidating: () => {
if (!v) {
setValidatedStatus({})
return false
}
return true
},
})
}
useEffect(() => {
if (typeof onValidatedStatus === 'function')
onValidatedStatus(validatedStatus)
}, [validatedStatus])
const getValidatedIcon = () => {
if (validatedStatus?.status === ValidatedStatus.Error || validatedStatus.status === ValidatedStatus.Exceed)
return <ValidatedErrorIcon />
if (validatedStatus.status === ValidatedStatus.Success)
return <ValidatedSuccessIcon />
}
const getValidatedTip = () => {
if (validating)
return <ValidatingTip />
if (validatedStatus?.status === ValidatedStatus.Error)
return <ValidatedErrorOnOpenaiTip errorMessage={validatedStatus.message ?? ''} />
}
return (
<div className='px-4 pt-3 pb-4'>
<ProviderInput
value={token.anthropic_api_key}
name={t('common.provider.apiKey')}
placeholder={t('common.provider.enterYourKey')}
onChange={handleChange}
onFocus={handleFocus}
validatedIcon={getValidatedIcon()}
validatedTip={getValidatedTip()}
/>
<Link className="inline-flex items-center mt-3 text-xs font-normal cursor-pointer text-primary-600 w-fit" href="https://docs.anthropic.com/claude/reference/getting-started-with-the-api" target={'_blank'}>
{t('common.provider.anthropic.keyFrom')}
<ArrowTopRightOnSquareIcon className='w-3 h-3 ml-1 text-primary-600' aria-hidden="true" />
</Link>
</div>
)
}
export default AnthropicProvider
...@@ -5,6 +5,7 @@ import { useTranslation } from 'react-i18next' ...@@ -5,6 +5,7 @@ import { useTranslation } from 'react-i18next'
import Link from 'next/link' import Link from 'next/link'
import ProviderItem from './provider-item' import ProviderItem from './provider-item'
import OpenaiHostedProvider from './openai-hosted-provider' import OpenaiHostedProvider from './openai-hosted-provider'
import AnthropicHostedProvider from './anthropic-hosted-provider'
import type { ProviderHosted } from '@/models/common' import type { ProviderHosted } from '@/models/common'
import { fetchProviders } from '@/service/common' import { fetchProviders } from '@/service/common'
import { IS_CE_EDITION } from '@/config' import { IS_CE_EDITION } from '@/config'
...@@ -18,6 +19,10 @@ const providersMap: { [k: string]: any } = { ...@@ -18,6 +19,10 @@ const providersMap: { [k: string]: any } = {
icon: 'azure', icon: 'azure',
name: 'Azure OpenAI Service', name: 'Azure OpenAI Service',
}, },
'anthropic-custom': {
icon: 'anthropic',
name: 'Anthropic',
},
} }
// const providersList = [ // const providersList = [
...@@ -65,6 +70,8 @@ const ProviderPage = () => { ...@@ -65,6 +70,8 @@ const ProviderPage = () => {
} }
}) })
const providerHosted = data?.filter(provider => provider.provider_name === 'openai' && provider.provider_type === 'system')?.[0] const providerHosted = data?.filter(provider => provider.provider_name === 'openai' && provider.provider_type === 'system')?.[0]
const anthropicHosted = data?.filter(provider => provider.provider_name === 'anthropic' && provider.provider_type === 'system')?.[0]
const providedOpenaiProvider = data?.find(provider => provider.is_enabled && (provider.provider_name === 'openai' || provider.provider_name === 'azure_openai'))
return ( return (
<div className='pb-7'> <div className='pb-7'>
...@@ -78,6 +85,16 @@ const ProviderPage = () => { ...@@ -78,6 +85,16 @@ const ProviderPage = () => {
</> </>
) )
} }
{
anthropicHosted && !IS_CE_EDITION && (
<>
<div>
<AnthropicHostedProvider provider={anthropicHosted as ProviderHosted} />
</div>
<div className='my-5 w-full h-0 border-[0.5px] border-gray-100' />
</>
)
}
<div> <div>
{ {
providers?.map(providerItem => ( providers?.map(providerItem => (
...@@ -89,6 +106,7 @@ const ProviderPage = () => { ...@@ -89,6 +106,7 @@ const ProviderPage = () => {
activeId={activeProviderId} activeId={activeProviderId}
onActive={aid => setActiveProviderId(aid)} onActive={aid => setActiveProviderId(aid)}
onSave={() => mutate()} onSave={() => mutate()}
providedOpenaiProvider={providedOpenaiProvider}
/> />
)) ))
} }
......
...@@ -5,14 +5,20 @@ import { useTranslation } from 'react-i18next' ...@@ -5,14 +5,20 @@ import { useTranslation } from 'react-i18next'
import Indicator from '../../../indicator' import Indicator from '../../../indicator'
import OpenaiProvider from '../openai-provider' import OpenaiProvider from '../openai-provider'
import AzureProvider from '../azure-provider' import AzureProvider from '../azure-provider'
import AnthropicProvider from '../anthropic-provider'
import type { ValidatedStatusState } from '../provider-input/useValidateToken' import type { ValidatedStatusState } from '../provider-input/useValidateToken'
import { ValidatedStatus } from '../provider-input/useValidateToken' import { ValidatedStatus } from '../provider-input/useValidateToken'
import s from './index.module.css' import s from './index.module.css'
import type { Provider, ProviderAzureToken } from '@/models/common' import type { Provider, ProviderAnthropicToken, ProviderAzureToken } from '@/models/common'
import { ProviderName } from '@/models/common' import { ProviderName } from '@/models/common'
import { updateProviderAIKey } from '@/service/common' import { updateProviderAIKey } from '@/service/common'
import { ToastContext } from '@/app/components/base/toast' import { ToastContext } from '@/app/components/base/toast'
import Tooltip from '@/app/components/base/tooltip'
const providerNameMap: Record<string, string> = {
openai: 'OpenAI',
azure_openai: 'Azure OpenAI Service',
}
type IProviderItemProps = { type IProviderItemProps = {
icon: string icon: string
name: string name: string
...@@ -20,6 +26,7 @@ type IProviderItemProps = { ...@@ -20,6 +26,7 @@ type IProviderItemProps = {
activeId: string activeId: string
onActive: (v: string) => void onActive: (v: string) => void
onSave: () => void onSave: () => void
providedOpenaiProvider?: Provider
} }
const ProviderItem = ({ const ProviderItem = ({
activeId, activeId,
...@@ -28,15 +35,18 @@ const ProviderItem = ({ ...@@ -28,15 +35,18 @@ const ProviderItem = ({
provider, provider,
onActive, onActive,
onSave, onSave,
providedOpenaiProvider,
}: IProviderItemProps) => { }: IProviderItemProps) => {
const { t } = useTranslation() const { t } = useTranslation()
const [validatedStatus, setValidatedStatus] = useState<ValidatedStatusState>() const [validatedStatus, setValidatedStatus] = useState<ValidatedStatusState>()
const [loading, setLoading] = useState(false) const [loading, setLoading] = useState(false)
const { notify } = useContext(ToastContext) const { notify } = useContext(ToastContext)
const [token, setToken] = useState<ProviderAzureToken | string>( const [token, setToken] = useState<ProviderAzureToken | string | ProviderAnthropicToken>(
provider.provider_name === 'azure_openai' provider.provider_name === 'azure_openai'
? { openai_api_base: '', openai_api_key: '' } ? { openai_api_base: '', openai_api_key: '' }
: '', : provider.provider_name === 'anthropic'
? { anthropic_api_key: '' }
: '',
) )
const id = `${provider.provider_name}-${provider.provider_type}` const id = `${provider.provider_name}-${provider.provider_type}`
const isOpen = id === activeId const isOpen = id === activeId
...@@ -54,6 +64,8 @@ const ProviderItem = ({ ...@@ -54,6 +64,8 @@ const ProviderItem = ({
} }
if (provider.provider_name === ProviderName.OPENAI) if (provider.provider_name === ProviderName.OPENAI)
return provider.token return provider.token
if (provider.provider_name === ProviderName.ANTHROPIC)
return provider.token?.anthropic_api_key
} }
const handleUpdateToken = async () => { const handleUpdateToken = async () => {
if (loading) if (loading)
...@@ -81,7 +93,7 @@ const ProviderItem = ({ ...@@ -81,7 +93,7 @@ const ProviderItem = ({
<div className={cn(s[`icon-${icon}`], 'mr-3 w-6 h-6 rounded-md')} /> <div className={cn(s[`icon-${icon}`], 'mr-3 w-6 h-6 rounded-md')} />
<div className='grow text-sm font-medium text-gray-800'>{name}</div> <div className='grow text-sm font-medium text-gray-800'>{name}</div>
{ {
providerTokenHasSetted() && !comingSoon && !isOpen && ( providerTokenHasSetted() && !comingSoon && !isOpen && provider.provider_name !== ProviderName.ANTHROPIC && (
<div className='flex items-center mr-4'> <div className='flex items-center mr-4'>
{!isValid && <div className='text-xs text-[#D92D20]'>{t('common.provider.invalidApiKey')}</div>} {!isValid && <div className='text-xs text-[#D92D20]'>{t('common.provider.invalidApiKey')}</div>}
<Indicator color={!isValid ? 'red' : 'green'} className='ml-2' /> <Indicator color={!isValid ? 'red' : 'green'} className='ml-2' />
...@@ -89,7 +101,27 @@ const ProviderItem = ({ ...@@ -89,7 +101,27 @@ const ProviderItem = ({
) )
} }
{ {
!comingSoon && !isOpen && ( (providerTokenHasSetted() && !comingSoon && !isOpen && provider.provider_name === ProviderName.ANTHROPIC) && (
<div className='flex items-center mr-4'>
{
providedOpenaiProvider?.is_valid
? !isValid
? <div className='text-xs text-[#D92D20]'>{t('common.provider.invalidApiKey')}</div>
: null
: <div className='text-xs text-[#DC6803]'>{t('common.provider.anthropic.notEnabled')}</div>
}
<Indicator color={
providedOpenaiProvider?.is_valid
? isValid
? 'green'
: 'red'
: 'yellow'
} className='ml-2' />
</div>
)
}
{
!comingSoon && !isOpen && provider.provider_name !== ProviderName.ANTHROPIC && (
<div className=' <div className='
px-3 h-[28px] bg-white border border-gray-200 rounded-md cursor-pointer px-3 h-[28px] bg-white border border-gray-200 rounded-md cursor-pointer
text-xs font-medium text-gray-700 flex items-center text-xs font-medium text-gray-700 flex items-center
...@@ -98,6 +130,34 @@ const ProviderItem = ({ ...@@ -98,6 +130,34 @@ const ProviderItem = ({
</div> </div>
) )
} }
{
(!comingSoon && !isOpen && provider.provider_name === ProviderName.ANTHROPIC)
? providedOpenaiProvider?.is_enabled
? (
<div className='
px-3 h-[28px] bg-white border border-gray-200 rounded-md cursor-pointer
text-xs font-medium text-gray-700 flex items-center
' onClick={() => providedOpenaiProvider.is_valid && onActive(id)}>
{providerTokenHasSetted() ? t('common.provider.editKey') : t('common.provider.addKey')}
</div>
)
: (
<Tooltip
htmlContent={<div className='w-[320px]'>
{t('common.provider.anthropic.enableTip')}
</div>}
position='bottom'
selector='anthropic-provider-enable-top-tooltip'>
<div className='
px-3 h-[28px] bg-white border border-gray-200 rounded-md cursor-not-allowed
text-xs font-medium text-gray-700 flex items-center opacity-50
'>
{t('common.provider.addKey')}
</div>
</Tooltip>
)
: null
}
{ {
comingSoon && !isOpen && ( comingSoon && !isOpen && (
<div className=' <div className='
...@@ -147,6 +207,29 @@ const ProviderItem = ({ ...@@ -147,6 +207,29 @@ const ProviderItem = ({
/> />
) )
} }
{
provider.provider_name === ProviderName.ANTHROPIC && isOpen && (
<AnthropicProvider
provider={provider}
onValidatedStatus={v => setValidatedStatus(v)}
onTokenChange={v => setToken(v)}
/>
)
}
{
provider.provider_name === ProviderName.ANTHROPIC && !isOpen && providerTokenHasSetted() && providedOpenaiProvider?.is_valid && (
<div className='px-4 py-3 text-[13px] font-medium text-gray-700'>
{t('common.provider.anthropic.using')} {providerNameMap[providedOpenaiProvider.provider_name as string]}
</div>
)
}
{
provider.provider_name === ProviderName.ANTHROPIC && !isOpen && providerTokenHasSetted() && !providedOpenaiProvider?.is_valid && (
<div className='px-4 py-3 bg-[#FFFAEB] text-[13px] font-medium text-gray-700'>
{t('common.provider.anthropic.enableTip')}
</div>
)
}
</div> </div>
) )
} }
......
...@@ -620,7 +620,7 @@ const Main: FC<IMainProps> = ({ ...@@ -620,7 +620,7 @@ const Main: FC<IMainProps> = ({
{ {
hasSetInputs && ( hasSetInputs && (
<div className={cn(doShowSuggestion ? 'pb-[140px]' : (isResponsing ? 'pb-[113px]' : 'pb-[66px]'), 'relative grow h-[200px] pc:w-[794px] max-w-full mobile:w-full mx-auto mb-3.5 overflow-hidden')}> <div className={cn(doShowSuggestion ? 'pb-[140px]' : (isResponsing ? 'pb-[113px]' : 'pb-[76px]'), 'relative grow h-[200px] pc:w-[794px] max-w-full mobile:w-full mx-auto mb-3.5 overflow-hidden')}>
<div className='h-full overflow-y-auto' ref={chatListDomRef}> <div className='h-full overflow-y-auto' ref={chatListDomRef}>
<Chat <Chat
chatList={chatList} chatList={chatList}
......
...@@ -609,7 +609,7 @@ const Main: FC<IMainProps> = ({ ...@@ -609,7 +609,7 @@ const Main: FC<IMainProps> = ({
{ {
hasSetInputs && ( hasSetInputs && (
<div className={cn(doShowSuggestion ? 'pb-[140px]' : (isResponsing ? 'pb-[113px]' : 'pb-[66px]'), 'relative grow h-[200px] pc:w-[794px] max-w-full mobile:w-full mx-auto mb-3.5 overflow-hidden')}> <div className={cn(doShowSuggestion ? 'pb-[140px]' : (isResponsing ? 'pb-[113px]' : 'pb-[76px]'), 'relative grow h-[200px] pc:w-[794px] max-w-full mobile:w-full mx-auto mb-3.5 overflow-hidden')}>
<div className='h-full overflow-y-auto' ref={chatListDomRef}> <div className='h-full overflow-y-auto' ref={chatListDomRef}>
<Chat <Chat
chatList={chatList} chatList={chatList}
......
...@@ -54,7 +54,7 @@ const translation = { ...@@ -54,7 +54,7 @@ const translation = {
maxTokenTip: maxTokenTip:
'Max tokens depending on the model. Prompt and completion share this limit. One token is roughly 1 English character.', 'Max tokens depending on the model. Prompt and completion share this limit. One token is roughly 1 English character.',
maxTokenSettingTip: 'Your max token setting is high, potentially limiting space for prompts, queries, and data. Consider setting it below 2/3.', maxTokenSettingTip: 'Your max token setting is high, potentially limiting space for prompts, queries, and data. Consider setting it below 2/3.',
setToCurrentModelMaxTokenTip: 'Max token is updated to the maximum token of the current model 4,000.', setToCurrentModelMaxTokenTip: 'Max token is updated to the maximum token of the current model {{maxToken}}.',
}, },
tone: { tone: {
Creative: 'Creative', Creative: 'Creative',
...@@ -180,6 +180,22 @@ const translation = { ...@@ -180,6 +180,22 @@ const translation = {
useYourModel: 'Currently using own Model Provider.', useYourModel: 'Currently using own Model Provider.',
close: 'Close', close: 'Close',
}, },
anthropicHosted: {
anthropicHosted: 'Anthropic Claude',
onTrial: 'ON TRIAL',
exhausted: 'QUOTA EXHAUSTED',
desc: 'Powerful model, which excels at a wide range of tasks from sophisticated dialogue and creative content generation to detailed instruction.',
callTimes: 'Call times',
usedUp: 'Trial quota used up. Add own Model Provider.',
useYourModel: 'Currently using own Model Provider.',
close: 'Close',
},
anthropic: {
using: 'The embedding capability is using',
enableTip: 'To enable the Anthropic model, you need to bind to OpenAI or Azure OpenAI Service first.',
notEnabled: 'Not enabled',
keyFrom: 'Get your API key from Anthropic',
},
encrypted: { encrypted: {
front: 'Your API KEY will be encrypted and stored using', front: 'Your API KEY will be encrypted and stored using',
back: ' technology.', back: ' technology.',
......
...@@ -54,7 +54,7 @@ const translation = { ...@@ -54,7 +54,7 @@ const translation = {
maxTokenTip: maxTokenTip:
'生成的最大令牌数取决于模型。提示和完成共享令牌数限制。一个令牌约等于 1 个英文或 半个中文字符。', '生成的最大令牌数取决于模型。提示和完成共享令牌数限制。一个令牌约等于 1 个英文或 半个中文字符。',
maxTokenSettingTip: '您设置的最大 tokens 数较大,可能会导致 prompt、用户问题、数据集内容没有 token 空间进行处理,建议设置到 2/3 以下。', maxTokenSettingTip: '您设置的最大 tokens 数较大,可能会导致 prompt、用户问题、数据集内容没有 token 空间进行处理,建议设置到 2/3 以下。',
setToCurrentModelMaxTokenTip: '最大令牌数更新为当前模型最大的令牌数 4,000。', setToCurrentModelMaxTokenTip: '最大令牌数更新为当前模型最大的令牌数 {{maxToken}}。',
}, },
tone: { tone: {
Creative: '创意', Creative: '创意',
...@@ -180,6 +180,22 @@ const translation = { ...@@ -180,6 +180,22 @@ const translation = {
useYourModel: '当前正在使用你自己的模型供应商。', useYourModel: '当前正在使用你自己的模型供应商。',
close: '关闭', close: '关闭',
}, },
anthropicHosted: {
anthropicHosted: 'Anthropic Claude',
onTrial: '体验',
exhausted: '超出限额',
desc: '功能强大的模型,擅长执行从复杂对话和创意内容生成到详细指导的各种任务。',
callTimes: '调用次数',
usedUp: '试用额度已用完,请在下方添加自己的模型供应商',
useYourModel: '当前正在使用你自己的模型供应商。',
close: '关闭',
},
anthropic: {
using: '嵌入能力正在使用',
enableTip: '要启用 Anthropic 模型,您需要先绑定 OpenAI 或 Azure OpenAI 服务。',
notEnabled: '未启用',
keyFrom: '从 Anthropic 获取您的 API 密钥',
},
encrypted: { encrypted: {
front: '密钥将使用 ', front: '密钥将使用 ',
back: ' 技术进行加密和存储。', back: ' 技术进行加密和存储。',
......
...@@ -59,14 +59,19 @@ export type Member = Pick<UserProfileResponse, 'id' | 'name' | 'email' | 'last_l ...@@ -59,14 +59,19 @@ export type Member = Pick<UserProfileResponse, 'id' | 'name' | 'email' | 'last_l
export enum ProviderName { export enum ProviderName {
OPENAI = 'openai', OPENAI = 'openai',
AZURE_OPENAI = 'azure_openai', AZURE_OPENAI = 'azure_openai',
ANTHROPIC = 'anthropic',
} }
export type ProviderAzureToken = { export type ProviderAzureToken = {
openai_api_base?: string openai_api_base?: string
openai_api_key?: string openai_api_key?: string
} }
export type ProviderAnthropicToken = {
anthropic_api_key?: string
}
export type ProviderTokenType = { export type ProviderTokenType = {
[ProviderName.OPENAI]: string [ProviderName.OPENAI]: string
[ProviderName.AZURE_OPENAI]: ProviderAzureToken [ProviderName.AZURE_OPENAI]: ProviderAzureToken
[ProviderName.ANTHROPIC]: ProviderAnthropicToken
} }
export type Provider = { export type Provider = {
[Name in ProviderName]: { [Name in ProviderName]: {
......
...@@ -3,7 +3,7 @@ import { del, get, patch, post, put } from './base' ...@@ -3,7 +3,7 @@ import { del, get, patch, post, put } from './base'
import type { import type {
AccountIntegrate, CommonResponse, DataSourceNotion, AccountIntegrate, CommonResponse, DataSourceNotion,
IWorkspace, LangGeniusVersionResponse, Member, IWorkspace, LangGeniusVersionResponse, Member,
OauthResponse, Provider, ProviderAzureToken, TenantInfoResponse, OauthResponse, Provider, ProviderAnthropicToken, ProviderAzureToken, TenantInfoResponse,
UserProfileOriginResponse, UserProfileOriginResponse,
} from '@/models/common' } from '@/models/common'
import type { import type {
...@@ -58,7 +58,7 @@ export const fetchProviders: Fetcher<Provider[] | null, { url: string; params: R ...@@ -58,7 +58,7 @@ export const fetchProviders: Fetcher<Provider[] | null, { url: string; params: R
export const validateProviderKey: Fetcher<ValidateOpenAIKeyResponse, { url: string; body: { token: string } }> = ({ url, body }) => { export const validateProviderKey: Fetcher<ValidateOpenAIKeyResponse, { url: string; body: { token: string } }> = ({ url, body }) => {
return post(url, { body }) as Promise<ValidateOpenAIKeyResponse> return post(url, { body }) as Promise<ValidateOpenAIKeyResponse>
} }
export const updateProviderAIKey: Fetcher<UpdateOpenAIKeyResponse, { url: string; body: { token: string | ProviderAzureToken } }> = ({ url, body }) => { export const updateProviderAIKey: Fetcher<UpdateOpenAIKeyResponse, { url: string; body: { token: string | ProviderAzureToken | ProviderAnthropicToken } }> = ({ url, body }) => {
return post(url, { body }) as Promise<UpdateOpenAIKeyResponse> return post(url, { body }) as Promise<UpdateOpenAIKeyResponse>
} }
......
export enum ProviderType {
openai = 'openai',
anthropic = 'anthropic',
}
export enum AppType { export enum AppType {
'chat' = 'chat', 'chat' = 'chat',
'completion' = 'completion', 'completion' = 'completion',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment