Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 42 additions & 64 deletions apps/stage-tamagotchi/src/pages/settings/providers/anthropic.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,99 +2,60 @@
import type { RemovableRef } from '@vueuse/core'

import {
Alert,
ProviderAdvancedSettings,
ProviderApiKeyInput,
ProviderBaseUrlInput,
ProviderBasicSettings,
ProviderSettingsContainer,
ProviderSettingsLayout,
} from '@proj-airi/stage-ui/components'
import { useProviderValidation } from '@proj-airi/stage-ui/composables/useProviderValidation'
import { useProvidersStore } from '@proj-airi/stage-ui/stores/providers'
import { storeToRefs } from 'pinia'
import { computed, onMounted, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRouter } from 'vue-router'
import { computed } from 'vue'

const { t } = useI18n()
const router = useRouter()
const providerId = 'anthropic'
const providersStore = useProvidersStore()
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }

// Get provider metadata
const providerId = 'anthropic'
const providerMetadata = computed(() => providersStore.getProviderMetadata(providerId))

// Use computed properties for settings
// Define computed properties for credentials
const apiKey = computed({
get: () => providers.value[providerId]?.apiKey || '',
set: (value) => {
if (!providers.value[providerId])
providers.value[providerId] = {}

providers.value[providerId].apiKey = value
},
})

const baseUrl = computed({
get: () => providers.value[providerId]?.baseUrl || 'https://api.anthropic.com/v1/',
get: () => providers.value[providerId]?.baseUrl || '',
set: (value) => {
if (!providers.value[providerId])
providers.value[providerId] = {}

providers.value[providerId].baseUrl = value
},
})

onMounted(() => {
// Initialize provider if it doesn't exist
if (!providers.value[providerId]) {
providers.value[providerId] = {
baseUrl: 'https://api.anthropic.com/v1/',
}
}

// Initialize refs with current values
apiKey.value = providers.value[providerId]?.apiKey || ''
baseUrl.value = providers.value[providerId]?.baseUrl || 'https://api.anthropic.com/v1/'
})

// Watch settings and update the provider configuration
watch([apiKey, baseUrl], () => {
providers.value[providerId] = {
...providers.value[providerId],
apiKey: apiKey.value,
baseUrl: baseUrl.value || 'https://api.anthropic.com/v1/',
}
})

function handleResetSettings() {
providers.value[providerId] = {
baseUrl: 'https://api.anthropic.com/v1/',
}
}
// Use the composable to get validation logic and state
const {
t,
router,
providerMetadata,
isValidating,
isValid,
validationMessage,
handleResetSettings,
} = useProviderValidation(providerId)
</script>

<template>
<ProviderSettingsLayout
:provider-name="providerMetadata?.localizedName || 'Anthropic | Claude'"
:provider-icon="providerMetadata?.icon"
:provider-name="providerMetadata?.localizedName"
:provider-icon-color="providerMetadata?.iconColor"
:on-back="() => router.back()"
>
<div bg="orange-50 dark:orange-900/20" rounded-xl p-4 flex="~ col gap-3">
<h2 text-xl font-normal text="orange-700 dark:orange-500">
Before you start
</h2>
<p>
While Anthropic recently did announce that they are having a beta support for
OpenAI SDK compatibility <a underline href="https://docs.anthropic.com/en/api/openai-sdk">(you can read more here)</a>,
but due to the implementation details comes with <a underline href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS">CORS</a>
restrictions which not aligned with the OpenAI SDK, it's currently not possible to use this provider in the browser.
</p>
<p>
If you do need to use this provider, you will need a dedicated proxy backend like a Serverless Function running on
<a underline href="https://workers.cloudflare.com/">Cloudflare Workers</a> or some CORS bypassing services to bypass the CORS restrictions.
</p>
</div>
<ProviderSettingsContainer>
<ProviderBasicSettings
:title="t('settings.pages.providers.common.section.basic.title')"
Expand All @@ -103,8 +64,8 @@ function handleResetSettings() {
>
<ProviderApiKeyInput
v-model="apiKey"
:provider-name="providerMetadata?.localizedName || 'Anthropic'"
placeholder="sk-..."
:provider-name="providerMetadata?.localizedName"
placeholder="sk-ant-..."
/>
</ProviderBasicSettings>

Expand All @@ -114,13 +75,30 @@ function handleResetSettings() {
placeholder="https://api.anthropic.com/v1/"
/>
</ProviderAdvancedSettings>

<!-- Validation Status -->
<Alert v-if="!isValid && isValidating === 0 && validationMessage" type="error">
<template #title>
{{ t('settings.dialogs.onboarding.validationFailed') }}
</template>
<template v-if="validationMessage" #content>
<div class="whitespace-pre-wrap break-all">
{{ validationMessage }}
</div>
</template>
</Alert>
<Alert v-if="isValid && isValidating === 0" type="success">
<template #title>
{{ t('settings.dialogs.onboarding.validationSuccess') }}
</template>
</Alert>
</ProviderSettingsContainer>
</ProviderSettingsLayout>
</template>

<route lang="yaml">
meta:
layout: settings
stageTransition:
name: slide
</route>
meta:
layout: settings
stageTransition:
name: slide
</route>
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
<script setup lang="ts">
import type { RemovableRef } from '@vueuse/core'

import {
Alert,
ProviderAccountIdInput,
ProviderAdvancedSettings,
ProviderApiKeyInput,
ProviderBasicSettings,
ProviderSettingsContainer,
ProviderSettingsLayout,
} from '@proj-airi/stage-ui/components'
import { useProviderValidation } from '@proj-airi/stage-ui/composables/useProviderValidation'
import { useProvidersStore } from '@proj-airi/stage-ui/stores/providers'
import { storeToRefs } from 'pinia'
import { computed } from 'vue'

const providerId = 'azure-ai-foundry'
const providersStore = useProvidersStore()
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }

// Define computed properties for credentials
const apiKey = computed({
get: () => providers.value[providerId]?.apiKey || '',
set: (value) => {
if (!providers.value[providerId])
providers.value[providerId] = {}
providers.value[providerId].apiKey = value
},
})

const resourceName = computed({
get: () => providers.value[providerId]?.resourceName || '',
set: (value) => {
if (!providers.value[providerId])
providers.value[providerId] = {}
providers.value[providerId].resourceName = value
},
})

const apiVersion = computed({
get: () => providers.value[providerId]?.apiVersion || '',
set: (value) => {
if (!providers.value[providerId])
providers.value[providerId] = {}
providers.value[providerId].apiVersion = value
},
})

const modelId = computed({
get: () => providers.value[providerId]?.modelId || '',
set: (value) => {
if (!providers.value[providerId])
providers.value[providerId] = {}
providers.value[providerId].modelId = value
},
})

// Use the composable to get validation logic and state
const {
t,
router,
providerMetadata,
isValidating,
isValid,
validationMessage,
handleResetSettings,
} = useProviderValidation(providerId)
</script>

<template>
<ProviderSettingsLayout
:provider-name="providerMetadata?.localizedName"
:provider-icon-color="providerMetadata?.iconColor"
:on-back="() => router.back()"
>
<ProviderSettingsContainer>
<ProviderBasicSettings
:title="t('settings.pages.providers.common.section.basic.title')"
:description="t('settings.pages.providers.common.section.basic.description')"
:on-reset="handleResetSettings"
>
<ProviderApiKeyInput
v-model="apiKey"
:provider-name="providerMetadata?.localizedName"
placeholder="..."
required
/>
<ProviderAccountIdInput
v-model="resourceName"
label="Resouce name"
placeholder="..."
description="Prefix used in https://<prefix>.services.ai.azure.com"
required
/>
<ProviderAccountIdInput
v-model="modelId"
label="Model id"
placeholder="..."
description="Model ID on Azure AI Foundry"
required
/>
</ProviderBasicSettings>

<ProviderAdvancedSettings :title="t('settings.pages.providers.common.section.advanced.title')">
<ProviderAccountIdInput
v-model="apiVersion"
label="API version"
placeholder="e.g. 2025-04-01-preview"
description="API version for snapshot of the models"
/>
</ProviderAdvancedSettings>

<!-- Validation Status -->
<Alert v-if="!isValid && isValidating === 0 && validationMessage" type="error">
<template #title>
{{ t('settings.dialogs.onboarding.validationFailed') }}
</template>
<template v-if="validationMessage" #content>
<div class="whitespace-pre-wrap break-all">
{{ validationMessage }}
</div>
</template>
</Alert>
<Alert v-if="isValid && isValidating === 0" type="success">
<template #title>
{{ t('settings.dialogs.onboarding.validationSuccess') }}
</template>
</Alert>
</ProviderSettingsContainer>
</ProviderSettingsLayout>
</template>

<route lang="yaml">
meta:
layout: settings
stageTransition:
name: slide
</route>
Loading