feat(stage-web|stage-tamagotchi): i18n
This commit is contained in:
@@ -43,26 +43,12 @@ prompt:
|
||||
|
||||
And the last, do what ever you want!
|
||||
settings:
|
||||
elevenlabs-api-key:
|
||||
label: ElevenLabs API Key
|
||||
placeholder: Input your ElevenLabs API key
|
||||
placeholder_mobile: Elevenlabs API Key
|
||||
language:
|
||||
chinese: 简体中文
|
||||
english: English
|
||||
title: Language
|
||||
microphone: Microphone
|
||||
models: Model
|
||||
openai-api-key:
|
||||
label: OpenAI API Key
|
||||
placeholder: Input your API key
|
||||
placeholder_mobile: OpenAI API Key
|
||||
openai-base-url:
|
||||
label: OpenAI API BaseURL
|
||||
placeholder: Input your API base URL
|
||||
placeholder_mobile: OpenAI API BaseURL
|
||||
title: Settings
|
||||
voices: Voice
|
||||
quit: Quit
|
||||
viewer: Viewer
|
||||
shortcuts:
|
||||
@@ -73,6 +59,210 @@ settings:
|
||||
debug: Toggle developer tools
|
||||
press_keys: Press keys...
|
||||
other: Other
|
||||
pages:
|
||||
models:
|
||||
description: Live2D, VRM, etc.
|
||||
title: Models
|
||||
modules:
|
||||
consciousness:
|
||||
description: Personality, desired model, etc.
|
||||
sections:
|
||||
section:
|
||||
provider-model-selection:
|
||||
title: Model
|
||||
description: Select the suitable LLM provider for consciousness
|
||||
collapse: Collapse
|
||||
custom_model_placeholder: Enter custom model name...
|
||||
error: Error loading models
|
||||
expand: Expand
|
||||
loading: Loading available models...
|
||||
manual_model_name: Model Name
|
||||
manual_model_placeholder: Enter the model name to use with this provider
|
||||
no_models: No models available
|
||||
no_models_description: No models were found for this provider
|
||||
no_search_results: No matching models
|
||||
no_search_results_description: No models match '{query}'. Try a different search term.
|
||||
not_supported: Model listing not supported
|
||||
not_supported_description: This provider doesn't support model listing functionality
|
||||
search_placeholder: Search models...
|
||||
search_results: Found {count} of {total} models
|
||||
show_less: Show less
|
||||
show_more: Show more
|
||||
subtitle: Select a model from the provider
|
||||
title: Consciousness
|
||||
description: Thinking, vision, speech synthesis, gaming, etc.
|
||||
gaming-factorio:
|
||||
description: Playing Factorio!
|
||||
title: Factorio
|
||||
gaming-minecraft:
|
||||
description: Playing Minecraft!
|
||||
title: Minecraft
|
||||
hearing:
|
||||
description: Configure how speech recognition works
|
||||
title: Hearing
|
||||
memory-long-term:
|
||||
description: Long-term memory specific settings and management
|
||||
title: Long-Term Memory
|
||||
memory-short-term:
|
||||
description: Short-term memory specific settings and management
|
||||
title: Short-Term Memory
|
||||
messaging-discord:
|
||||
description: Chat & voice chat over Discord
|
||||
title: Discord
|
||||
speech:
|
||||
description: Speech synthesis
|
||||
title: Speech
|
||||
title: Modules
|
||||
vision:
|
||||
description: Vision
|
||||
title: Vision
|
||||
providers:
|
||||
common:
|
||||
section:
|
||||
advanced:
|
||||
fields:
|
||||
field:
|
||||
headers:
|
||||
description: Add custom HTTP headers
|
||||
key:
|
||||
placeholder: Key
|
||||
label: HTTP Headers
|
||||
value:
|
||||
placeholder: Value
|
||||
title: Advanced
|
||||
basic:
|
||||
description: Essential settings
|
||||
title: Basic
|
||||
voice:
|
||||
title: Voice Settings
|
||||
description: LLMs, speech providers, etc.
|
||||
provider:
|
||||
cloudflare-workers-ai:
|
||||
description: cloudflare.com
|
||||
fields:
|
||||
field:
|
||||
account-id:
|
||||
description: Cloudflare Account ID
|
||||
label: Account ID
|
||||
placeholder: Your Cloudflare Account ID
|
||||
api-key:
|
||||
placeholder: Input Cloudflare Account ID
|
||||
title: Cloudflare Workers AI
|
||||
deepseek:
|
||||
description: deepseek.com
|
||||
title: DeepSeek
|
||||
elevenlabs:
|
||||
description: elevenlabs.io
|
||||
fields:
|
||||
field:
|
||||
simularity-boost:
|
||||
description: Voice similarity adherence
|
||||
label: Similarity Boost
|
||||
speaker-boost:
|
||||
description: Enhance speaker similarity
|
||||
label: Speaker Boost
|
||||
speed:
|
||||
description: Speech generation speed
|
||||
label: Speed
|
||||
stability:
|
||||
description: Voice stability and randomness
|
||||
label: Stability
|
||||
style:
|
||||
description: Voice style exaggeration
|
||||
label: Style
|
||||
playground:
|
||||
buttons:
|
||||
button:
|
||||
test-voice:
|
||||
generating: Generating...
|
||||
label: Test Voice
|
||||
fields:
|
||||
field:
|
||||
input:
|
||||
placeholder: Enter text to test the voice...
|
||||
language:
|
||||
description: Select voice language
|
||||
label: Language
|
||||
voice:
|
||||
description: Select preferred voice
|
||||
label: Voice
|
||||
title: Voice Playground
|
||||
validation:
|
||||
error-missing-api-key: Please enter an API key to test the voice.
|
||||
title: ElevenLabs
|
||||
fireworks:
|
||||
description: fireworks.ai
|
||||
title: Fireworks.ai
|
||||
mistral:
|
||||
description: mistral.ai
|
||||
title: Mistral
|
||||
moonshot:
|
||||
description: moonshot.ai
|
||||
title: Moonshot AI
|
||||
novita:
|
||||
description: novita.ai
|
||||
title: Novita
|
||||
ollama:
|
||||
description: ollama.ai
|
||||
title: Ollama
|
||||
openai:
|
||||
description: openai.com
|
||||
title: OpenAI
|
||||
openrouter:
|
||||
description: openrouter.ai
|
||||
title: OpenRouter
|
||||
together:
|
||||
description: together.ai
|
||||
title: Together.ai
|
||||
vllm:
|
||||
description: vllm.ai
|
||||
title: vLLM
|
||||
xai:
|
||||
description: x.ai
|
||||
title: xAI
|
||||
title: Providers
|
||||
themes:
|
||||
description: Customize your stage!
|
||||
sections:
|
||||
section:
|
||||
custom-color:
|
||||
fields:
|
||||
field:
|
||||
primary-color:
|
||||
label: Primary color
|
||||
reset:
|
||||
label: Reset to Default
|
||||
rgb-on:
|
||||
title: I Want It Dynamic!
|
||||
title: Custom Colors
|
||||
theme-presets:
|
||||
preset:
|
||||
chinese:
|
||||
description: >-
|
||||
Traditional Chinese colors, derived from ancient textiles,
|
||||
porcelain and paintings
|
||||
title: Chinese Traditional Colors
|
||||
japanese:
|
||||
description: Traditional Japanese color palette
|
||||
title: Japanese Colors
|
||||
monet:
|
||||
description: Impressionist palette inspired by Claude Monet\'s works
|
||||
title: Monet Colors
|
||||
morandi:
|
||||
description: Soft, muted tones inspired by Giorgio Morandi\'s paintings
|
||||
title: Morandi Colors
|
||||
nordic:
|
||||
description: Scandinavian minimalist color scheme
|
||||
title: Nordic Colors
|
||||
title: Theme Presets
|
||||
title: Themes
|
||||
sections:
|
||||
section:
|
||||
general:
|
||||
title: General
|
||||
theme: Theme
|
||||
title: Settings
|
||||
voices: Voice
|
||||
stage:
|
||||
chat:
|
||||
message:
|
||||
|
||||
@@ -31,25 +31,11 @@ prompt:
|
||||
|
||||
最后,做任何你想做的事!
|
||||
settings:
|
||||
elevenlabs-api-key:
|
||||
label: ElevenLabs API 密钥
|
||||
placeholder: 输入您的 ElevenLabs API 密钥
|
||||
placeholder_mobile: ElevenLabs API Key
|
||||
language:
|
||||
chinese: 简体中文
|
||||
english: English
|
||||
title: 语言
|
||||
models: 模型
|
||||
openai-api-key:
|
||||
label: OpenAI API 密钥
|
||||
placeholder: 输入您的 API 密钥
|
||||
placeholder_mobile: OpenAI API Key
|
||||
openai-base-url:
|
||||
label: OpenAI API BaseURL
|
||||
placeholder: 输入您的 API BaseURL
|
||||
placeholder_mobile: OpenAI BaseURL
|
||||
title: 设置
|
||||
voices: 声线
|
||||
quit: 退出
|
||||
viewer: 查看器
|
||||
shortcuts:
|
||||
@@ -60,6 +46,203 @@ settings:
|
||||
debug: 切换开发者模式
|
||||
press_keys: 按下快捷键...
|
||||
other: 其他
|
||||
pages:
|
||||
models:
|
||||
description: 切换角色的 Live2D,VRM 模型
|
||||
title: 角色模型
|
||||
modules:
|
||||
consciousness:
|
||||
description: 人格设定、使用的模型等配置
|
||||
title: 意识
|
||||
sections:
|
||||
section:
|
||||
provider-model-selection:
|
||||
title: 模型
|
||||
description: 为意识选择合适的 LLM 提供商
|
||||
collapse: 折叠
|
||||
custom_model_placeholder: 输入自订模型名字
|
||||
error: 获取出错啦
|
||||
expand: 展开
|
||||
loading: 获取模型中...
|
||||
manual_model_name: 模型名字
|
||||
manual_model_placeholder: 输入与该提供商一起使用的模型名字
|
||||
no_models: 没有任何可用的模型
|
||||
no_models_description: 该提供商的模型列表没有返回任何的数据
|
||||
no_search_results: 没有匹配的模型
|
||||
no_search_results_description: 没有模型匹配 '{query}' 关键字,请尝试一下别的关键词呢
|
||||
not_supported: 无法列出模型
|
||||
not_supported_description: 此提供商不支持列出模型的功能
|
||||
search_placeholder: 搜索模型...
|
||||
search_results: 找到 {count} / {total} 个模型
|
||||
show_less: 显示更多
|
||||
show_more: 收起
|
||||
subtitle: 选择一个模型
|
||||
description: 思维,视觉,言语综合,游戏等
|
||||
gaming-factorio:
|
||||
description: 一起玩 Factorio!
|
||||
title: 异星工厂 Factorio
|
||||
gaming-minecraft:
|
||||
description: 一起 Minecraft!
|
||||
title: 我的世界 Minecraft
|
||||
hearing:
|
||||
description: 语音识别
|
||||
title: 听觉
|
||||
memory-long-term:
|
||||
description: 长期记忆
|
||||
title: 长期记忆
|
||||
memory-short-term:
|
||||
description: 短期记忆
|
||||
title: 短期记忆
|
||||
messaging-discord:
|
||||
description: Discord 发消息和语音聊天
|
||||
title: Discord
|
||||
speech:
|
||||
description: 语音合成
|
||||
title: 发声
|
||||
title: 机体模块
|
||||
vision:
|
||||
description: 视觉
|
||||
title: 视觉
|
||||
providers:
|
||||
common:
|
||||
section:
|
||||
advanced:
|
||||
fields:
|
||||
field:
|
||||
headers:
|
||||
description: 添加自定义HTTP标头
|
||||
key:
|
||||
placeholder: 请求头名字
|
||||
label: HTTP 请求头
|
||||
value:
|
||||
placeholder: 请求头数值
|
||||
title: 高级配置
|
||||
basic:
|
||||
description: 基本设置
|
||||
title: 基础配置
|
||||
voice:
|
||||
title: 声音配置
|
||||
description: LLM,演讲提供商等
|
||||
provider:
|
||||
cloudflare-workers-ai:
|
||||
description: Cloudflare.com
|
||||
fields:
|
||||
field:
|
||||
account-id:
|
||||
description: Cloudflare帐户ID
|
||||
label: Cloudflare Account ID
|
||||
placeholder: 请输入 Cloudflare Account ID
|
||||
api-key:
|
||||
placeholder: 请输入 Cloudflare Workers AI 的 API Key
|
||||
title: Workers AI
|
||||
deepseek:
|
||||
description: DeepSeek.com
|
||||
title: 深度求索 DeepSeek
|
||||
elevenlabs:
|
||||
description: Elevenlabs.io
|
||||
fields:
|
||||
field:
|
||||
simularity-boost:
|
||||
description: 声音相似性依从性
|
||||
label: 相似度修正
|
||||
speaker-boost:
|
||||
description: 增强说话者的相似性
|
||||
label: 扬声器增强
|
||||
speed:
|
||||
description: 语音生成速度
|
||||
label: 语速
|
||||
stability:
|
||||
description: 语音稳定性和随机性
|
||||
label: 稳定性
|
||||
style:
|
||||
description: 语音风格夸张
|
||||
label: 风格
|
||||
playground:
|
||||
buttons:
|
||||
button:
|
||||
test-voice:
|
||||
generating: 生成中...
|
||||
label: 测试声音
|
||||
fields:
|
||||
field:
|
||||
input:
|
||||
placeholder: 输入用于测试发音的文本
|
||||
language:
|
||||
description: 选择语音语言
|
||||
label: 语言
|
||||
voice:
|
||||
description: 选择首选语音
|
||||
label: 声线
|
||||
title: 调试场地
|
||||
validation:
|
||||
error-missing-api-key: 需要填写 API Key 才能用哦!
|
||||
title: ElevenLabs (11labs)
|
||||
fireworks:
|
||||
description: Fireworks.ai
|
||||
title: Fireworks.ai
|
||||
mistral:
|
||||
description: mistral.ai
|
||||
title: Mistral
|
||||
moonshot:
|
||||
description: Moonshot.ai
|
||||
title: 月之暗面
|
||||
novita:
|
||||
description: novita.ai
|
||||
title: Novita
|
||||
ollama:
|
||||
description: ollama.ai
|
||||
title: Ollama
|
||||
openai:
|
||||
description: OpenAi.com
|
||||
title: OpenAI
|
||||
openrouter:
|
||||
description: OpenRouter.ai
|
||||
title: OpenRouter
|
||||
together:
|
||||
description: 一起
|
||||
title: Together.ai
|
||||
vllm:
|
||||
description: vllm.ai
|
||||
title: vLLM
|
||||
xai:
|
||||
description: X.AI
|
||||
title: xAI
|
||||
title: 提供商
|
||||
themes:
|
||||
description: 自定义你的舞台外观!
|
||||
sections:
|
||||
section:
|
||||
custom-color:
|
||||
fields:
|
||||
field:
|
||||
primary-color:
|
||||
label: 主题色
|
||||
reset:
|
||||
label: 重设为默认主题色
|
||||
rgb-on:
|
||||
title: RGB ON
|
||||
title: 自定义主题色
|
||||
theme-presets:
|
||||
preset:
|
||||
chinese:
|
||||
title: 中国传统颜色
|
||||
japanese:
|
||||
title: 日本颜色
|
||||
monet:
|
||||
title: 莫奈颜色
|
||||
morandi:
|
||||
title: Morandi颜色
|
||||
nordic:
|
||||
title: 北欧颜色
|
||||
title: 主题预设
|
||||
title: 舞台主题
|
||||
sections:
|
||||
section:
|
||||
general:
|
||||
title: 通用
|
||||
theme: 主题颜色
|
||||
title: 设置
|
||||
voices: 声线
|
||||
stage:
|
||||
message: 消息
|
||||
select-a-audio-input: 选择一个音频输入设备
|
||||
|
||||
@@ -4,9 +4,11 @@ import { useChatStore } from '@proj-airi/stage-ui/stores'
|
||||
import { useElementBounding, useScroll } from '@vueuse/core'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { nextTick, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const chatHistoryRef = ref<HTMLDivElement>()
|
||||
|
||||
const { t } = useI18n()
|
||||
const { messages, sending } = storeToRefs(useChatStore())
|
||||
const bounding = useElementBounding(chatHistoryRef, { immediate: true, windowScroll: true, windowResize: true })
|
||||
const { y: chatHistoryContainerY } = useScroll(chatHistoryRef)
|
||||
@@ -48,7 +50,7 @@ onTokenLiteral(async () => {
|
||||
<div flex="~ row" gap-2>
|
||||
<div flex-1>
|
||||
<span text-xs text="violet-400/90 dark:violet-600/90" font-semibold class="inline <sm:hidden">{{
|
||||
$t('stage.chat.message.character-name.core-system') }}</span>
|
||||
t('stage.chat.message.character-name.core-system') }}</span>
|
||||
</div>
|
||||
<div i-solar:danger-triangle-bold-duotone text-violet-500 />
|
||||
</div>
|
||||
|
||||
@@ -30,7 +30,7 @@ function handleLanguageChange(event: Event) {
|
||||
<div i-solar:alt-arrow-left-line-duotone text-2xl />
|
||||
</button>
|
||||
<h1 text-3xl>
|
||||
Settings
|
||||
{{ t('settings.title') }}
|
||||
</h1>
|
||||
</div>
|
||||
<div flex="~ col gap-4">
|
||||
@@ -40,8 +40,8 @@ function handleLanguageChange(event: Event) {
|
||||
:initial="{ opacity: 0, y: 10 }"
|
||||
:enter="{ opacity: 1, y: 0 }"
|
||||
:duration="250"
|
||||
title="Modules"
|
||||
description="Thinking, vision, speech synthesis, gaming, etc."
|
||||
:title="t('settings.pages.modules.title')"
|
||||
:description="t('settings.pages.modules.description')"
|
||||
icon="i-lucide:blocks"
|
||||
to="/settings/modules"
|
||||
/>
|
||||
@@ -51,8 +51,8 @@ function handleLanguageChange(event: Event) {
|
||||
:enter="{ opacity: 1, y: 0 }"
|
||||
:duration="250"
|
||||
:delay="50"
|
||||
title="Models"
|
||||
description="Live2D, VRM, etc."
|
||||
:title="t('settings.pages.models.title')"
|
||||
:description="t('settings.pages.models.description')"
|
||||
icon="i-lucide:person-standing"
|
||||
to="/settings/models"
|
||||
/>
|
||||
@@ -62,8 +62,8 @@ function handleLanguageChange(event: Event) {
|
||||
:enter="{ opacity: 1, y: 0 }"
|
||||
:duration="250"
|
||||
:delay="100"
|
||||
title="Providers"
|
||||
description="LLMs, speech providers, etc."
|
||||
:title="t('settings.pages.providers.title')"
|
||||
:description="t('settings.pages.providers.description')"
|
||||
icon="i-lucide:brain"
|
||||
to="/settings/providers"
|
||||
/>
|
||||
@@ -73,8 +73,8 @@ function handleLanguageChange(event: Event) {
|
||||
:enter="{ opacity: 1, y: 0 }"
|
||||
:duration="250"
|
||||
:delay="150"
|
||||
title="Themes"
|
||||
description="Customize your stage!"
|
||||
:title="t('settings.pages.themes.title')"
|
||||
:description="t('settings.pages.themes.description')"
|
||||
icon="i-lucide:paintbrush"
|
||||
to="/settings/themes"
|
||||
/>
|
||||
@@ -87,7 +87,7 @@ function handleLanguageChange(event: Event) {
|
||||
:delay="150"
|
||||
>
|
||||
<h2 text-2xl>
|
||||
General
|
||||
{{ t('settings.sections.section.general.title') }}
|
||||
</h2>
|
||||
</div>
|
||||
<div flex="~ col gap-4">
|
||||
@@ -188,7 +188,7 @@ function handleLanguageChange(event: Event) {
|
||||
>
|
||||
<div flex="~ row" w-full items-center gap-1.5>
|
||||
<div text="sm" w-full flex-1>
|
||||
<span>Disable Transitions (for debugging)</span>
|
||||
<span>{{ t('settings.animations.stage-transitions.title') }}</span>
|
||||
</div>
|
||||
<div select-none>
|
||||
<Transition name="slide-away" mode="out-in">
|
||||
|
||||
@@ -2,14 +2,39 @@
|
||||
import Live2DCanvas from '@proj-airi/stage-ui/components/Live2D/Canvas.vue'
|
||||
import Live2DModel from '@proj-airi/stage-ui/components/Live2D/Model.vue'
|
||||
import { useElementBounding } from '@vueuse/core'
|
||||
import { Vibrant } from 'node-vibrant/browser'
|
||||
import { ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
import Live2DSettings from '../../../components/Widgets/Live2DSettings.vue'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const live2dContainerRef = ref<HTMLDivElement>()
|
||||
const live2dCanvasRef = ref<InstanceType<typeof Live2DCanvas>>()
|
||||
const { width, height } = useElementBounding(live2dContainerRef)
|
||||
|
||||
const palette = ref<string[]>([])
|
||||
|
||||
async function extractColorsFromModel() {
|
||||
if (!live2dCanvasRef.value)
|
||||
return
|
||||
|
||||
const frame = await live2dCanvasRef.value.captureFrame()
|
||||
if (!frame) {
|
||||
console.error('No frame captured')
|
||||
return
|
||||
}
|
||||
|
||||
const frameUrl = URL.createObjectURL(frame)
|
||||
const vibrant = new Vibrant(frameUrl)
|
||||
|
||||
const paletteFromVibrant = await vibrant.getPalette()
|
||||
palette.value = Object.values(paletteFromVibrant).map(color => color?.hex).filter(it => typeof it === 'string')
|
||||
|
||||
URL.revokeObjectURL(frameUrl)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -26,20 +51,20 @@ const { width, height } = useElementBounding(live2dContainerRef)
|
||||
</button>
|
||||
<h1 relative>
|
||||
<div absolute left-0 top-0 translate-y="[-80%]">
|
||||
<span text="neutral-300 dark:neutral-500">Settings</span>
|
||||
<span text="neutral-300 dark:neutral-500">{{ t('settings.title') }}</span>
|
||||
</div>
|
||||
<div text-3xl font-semibold>
|
||||
Models
|
||||
{{ t('settings.pages.models.title') }}
|
||||
</div>
|
||||
</h1>
|
||||
</div>
|
||||
<div flex>
|
||||
<div ref="live2dContainerRef" w="50%" h="80vh">
|
||||
<Live2DCanvas v-slot="{ app }" :width="width" :height="height">
|
||||
<Live2DCanvas v-slot="{ app }" ref="live2dCanvasRef" :width="width" :height="height">
|
||||
<Live2DModel :app="app" :mouth-open-size="0" :width="width" :height="height" :paused="false" />
|
||||
</Live2DCanvas>
|
||||
</div>
|
||||
<Live2DSettings w="50%" h="80vh" />
|
||||
<Live2DSettings w="50%" h="80vh" :palette="palette" @extract-colors-from-model="extractColorsFromModel" />
|
||||
</div>
|
||||
|
||||
<div text="neutral-100/50 dark:neutral-500/20" pointer-events-none fixed bottom-0 right-0 translate-x-10 translate-y-10>
|
||||
|
||||
@@ -3,6 +3,7 @@ import { RadioCardDetailManySelect, RadioCardSimple } from '@proj-airi/stage-ui/
|
||||
import { useConsciousnessStore, useProvidersStore } from '@proj-airi/stage-ui/stores'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { onMounted } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { RouterLink, useRouter } from 'vue-router'
|
||||
|
||||
const providersStore = useProvidersStore()
|
||||
@@ -19,6 +20,7 @@ const {
|
||||
activeProviderModelError,
|
||||
} = storeToRefs(consciousnessStore)
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
|
||||
onMounted(async () => {
|
||||
@@ -44,10 +46,10 @@ function updateCustomModelName(value: string) {
|
||||
</button>
|
||||
<h1 relative>
|
||||
<div absolute left-0 top-0 translate-y="[-80%]">
|
||||
<span text="neutral-300 dark:neutral-500">Modules</span>
|
||||
<span text="neutral-300 dark:neutral-500">{{ t('settings.pages.modules.title') }}</span>
|
||||
</div>
|
||||
<div text-3xl font-semibold>
|
||||
Consciousness
|
||||
{{ t('settings.pages.modules.consciousness.title') }}
|
||||
</div>
|
||||
</h1>
|
||||
</div>
|
||||
@@ -56,10 +58,10 @@ function updateCustomModelName(value: string) {
|
||||
<div flex="~ col gap-4">
|
||||
<div>
|
||||
<h2 class="text-lg text-neutral-500 md:text-2xl dark:text-neutral-500">
|
||||
Provider
|
||||
{{ t('settings.pages.providers.title') }}
|
||||
</h2>
|
||||
<div text="neutral-400 dark:neutral-400">
|
||||
<span>Select the suitable LLM provider for consciousness</span>
|
||||
<span>{{ t('settings.pages.modules.consciousness.sections.section.provider-model-selection.description') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div max-w-full>
|
||||
@@ -112,10 +114,10 @@ function updateCustomModelName(value: string) {
|
||||
<div flex="~ col gap-4">
|
||||
<div>
|
||||
<h2 class="text-lg md:text-2xl">
|
||||
{{ $t('settings.modules.consciousness.provider-model-selection.title') }}
|
||||
{{ t('settings.pages.modules.consciousness.sections.section.provider-model-selection.title') }}
|
||||
</h2>
|
||||
<div text="neutral-400 dark:neutral-400">
|
||||
<span>{{ $t('settings.modules.consciousness.provider-model-selection.subtitle') }}</span>
|
||||
<span>{{ t('settings.pages.modules.consciousness.sections.section.provider-model-selection.subtitle') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -124,7 +126,7 @@ function updateCustomModelName(value: string) {
|
||||
<div class="mr-2 animate-spin">
|
||||
<div i-solar:spinner-line-duotone text-xl />
|
||||
</div>
|
||||
<span>{{ $t('settings.modules.consciousness.provider-model-selection.loading') }}</span>
|
||||
<span>{{ t('settings.pages.modules.consciousness.sections.section.provider-model-selection.loading') }}</span>
|
||||
</div>
|
||||
|
||||
<!-- Error state -->
|
||||
@@ -134,7 +136,7 @@ function updateCustomModelName(value: string) {
|
||||
>
|
||||
<div i-solar:close-circle-line-duotone class="text-2xl text-red-500 dark:text-red-400" />
|
||||
<div class="flex flex-col">
|
||||
<span class="font-medium">{{ $t('settings.modules.consciousness.provider-model-selection.error') }}</span>
|
||||
<span class="font-medium">{{ t('settings.pages.modules.consciousness.sections.section.provider-model-selection.error') }}</span>
|
||||
<span class="text-sm text-red-600 dark:text-red-400">{{ activeProviderModelError }}</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -146,10 +148,10 @@ function updateCustomModelName(value: string) {
|
||||
>
|
||||
<div i-solar:info-circle-line-duotone class="text-2xl text-amber-500 dark:text-amber-400" />
|
||||
<div class="flex flex-col">
|
||||
<span class="font-medium">{{ $t('settings.modules.consciousness.provider-model-selection.no_models')
|
||||
<span class="font-medium">{{ t('settings.pages.modules.consciousness.sections.section.provider-model-selection.no_models')
|
||||
}}</span>
|
||||
<span class="text-sm text-amber-600 dark:text-amber-400">{{
|
||||
$t('settings.modules.consciousness.provider-model-selection.no_models_description') }}</span>
|
||||
t('settings.pages.modules.consciousness.sections.section.provider-model-selection.no_models_description') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -160,13 +162,13 @@ function updateCustomModelName(value: string) {
|
||||
v-model:search-query="modelSearchQuery"
|
||||
:items="providerModels"
|
||||
:searchable="true"
|
||||
:search-placeholder="$t('settings.modules.consciousness.provider-model-selection.search_placeholder')"
|
||||
:search-no-results-title="$t('settings.modules.consciousness.provider-model-selection.no_search_results')"
|
||||
:search-no-results-description="$t('settings.modules.consciousness.provider-model-selection.no_search_results_description', { query: modelSearchQuery })"
|
||||
:search-results-text="$t('settings.modules.consciousness.provider-model-selection.search_results', { count: '{count}', total: '{total}' })"
|
||||
:custom-input-placeholder="$t('settings.modules.consciousness.provider-model-selection.custom_model_placeholder')"
|
||||
:expand-button-text="$t('settings.modules.consciousness.provider-model-selection.expand')"
|
||||
:collapse-button-text="$t('settings.modules.consciousness.provider-model-selection.collapse')"
|
||||
:search-placeholder="t('settings.pages.modules.consciousness.sections.section.provider-model-selection.search_placeholder')"
|
||||
:search-no-results-title="t('settings.pages.modules.consciousness.sections.section.provider-model-selection.no_search_results')"
|
||||
:search-no-results-description="t('settings.pages.modules.consciousness.sections.section.provider-model-selection.no_search_results_description', { query: modelSearchQuery })"
|
||||
:search-results-text="t('settings.pages.modules.consciousness.sections.section.provider-model-selection.search_results', { count: '{count}', total: '{total}' })"
|
||||
:custom-input-placeholder="t('settings.pages.modules.consciousness.sections.section.provider-model-selection.custom_model_placeholder')"
|
||||
:expand-button-text="t('settings.pages.modules.consciousness.sections.section.provider-model-selection.expand')"
|
||||
:collapse-button-text="t('settings.pages.modules.consciousness.sections.section.provider-model-selection.collapse')"
|
||||
@update:custom-value="updateCustomModelName"
|
||||
/>
|
||||
</template>
|
||||
@@ -178,10 +180,10 @@ function updateCustomModelName(value: string) {
|
||||
<div flex="~ col gap-4">
|
||||
<div>
|
||||
<h2 class="text-lg text-neutral-500 md:text-2xl dark:text-neutral-400">
|
||||
{{ $t('settings.modules.consciousness.provider-model-selection.title') }}
|
||||
{{ t('settings.pages.modules.consciousness.sections.section.provider-model-selection.title') }}
|
||||
</h2>
|
||||
<div text="neutral-400 dark:neutral-500">
|
||||
<span>{{ $t('settings.modules.consciousness.provider-model-selection.subtitle') }}</span>
|
||||
<span>{{ t('settings.pages.modules.consciousness.sections.section.provider-model-selection.subtitle') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -190,22 +192,22 @@ function updateCustomModelName(value: string) {
|
||||
>
|
||||
<div i-solar:info-circle-line-duotone class="text-primary-500 dark:text-primary-400 text-2xl" />
|
||||
<div class="flex flex-col">
|
||||
<span class="font-medium">{{ $t('settings.modules.consciousness.provider-model-selection.not_supported')
|
||||
<span class="font-medium">{{ t('settings.pages.modules.consciousness.sections.section.provider-model-selection.not_supported')
|
||||
}}</span>
|
||||
<span class="dark:text-primary-400 text-primary-600 text-sm">{{
|
||||
$t('settings.modules.consciousness.provider-model-selection.not_supported_description') }}</span>
|
||||
t('settings.pages.modules.consciousness.sections.section.provider-model-selection.not_supported_description') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Manual model input for providers without model listing -->
|
||||
<div class="mt-2">
|
||||
<label class="mb-1 block text-sm font-medium">
|
||||
{{ $t('settings.modules.consciousness.provider-model-selection.manual_model_name') }}
|
||||
{{ t('settings.pages.modules.consciousness.sections.section.provider-model-selection.manual_model_name') }}
|
||||
</label>
|
||||
<input
|
||||
v-model="activeModel" type="text"
|
||||
class="w-full border border-neutral-300 rounded bg-white px-3 py-2 dark:border-neutral-700 dark:bg-neutral-900"
|
||||
:placeholder="$t('settings.modules.consciousness.provider-model-selection.manual_model_placeholder')"
|
||||
:placeholder="t('settings.pages.modules.consciousness.sections.section.provider-model-selection.manual_model_placeholder')"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import { IconStatusItem } from '@proj-airi/stage-ui/components'
|
||||
import { computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const router = useRouter()
|
||||
const { t } = useI18n()
|
||||
|
||||
interface Module {
|
||||
id: string
|
||||
@@ -20,72 +22,72 @@ interface Module {
|
||||
const modulesList = computed<Module[]>(() => [
|
||||
{
|
||||
id: 'consciousness',
|
||||
name: 'Consciousness',
|
||||
description: 'Thinking, vision, speech synthesis, gaming, etc.',
|
||||
name: t('settings.pages.modules.consciousness.title'),
|
||||
description: t('settings.pages.modules.consciousness.description'),
|
||||
icon: 'i-lucide:ghost',
|
||||
to: '/settings/modules/consciousness',
|
||||
configured: false,
|
||||
},
|
||||
{
|
||||
id: 'hearing',
|
||||
name: 'Hearing',
|
||||
description: 'Hearing, speech recognition, etc.',
|
||||
name: t('settings.pages.modules.hearing.title'),
|
||||
description: t('settings.pages.modules.hearing.description'),
|
||||
icon: 'i-lucide:ear',
|
||||
to: '',
|
||||
configured: false,
|
||||
},
|
||||
{
|
||||
id: 'messaging-discord',
|
||||
name: 'Discord',
|
||||
description: 'Messaging, notifications, etc.',
|
||||
name: t('settings.pages.modules.messaging-discord.title'),
|
||||
description: t('settings.pages.modules.messaging-discord.description'),
|
||||
icon: 'i-simple-icons:discord',
|
||||
to: '',
|
||||
configured: false,
|
||||
},
|
||||
{
|
||||
id: 'speech',
|
||||
name: 'Speech',
|
||||
description: 'Speech synthesis, etc.',
|
||||
name: t('settings.pages.modules.speech.title'),
|
||||
description: t('settings.pages.modules.speech.description'),
|
||||
icon: 'i-lucide:mic',
|
||||
to: '/settings/modules/speech',
|
||||
configured: false,
|
||||
},
|
||||
{
|
||||
id: 'memory-short-term',
|
||||
name: 'Short-Term Memory',
|
||||
description: 'Short-term memory, etc.',
|
||||
name: t('settings.pages.modules.memory-short-term.title'),
|
||||
description: t('settings.pages.modules.memory-short-term.description'),
|
||||
icon: 'i-lucide:book',
|
||||
to: '',
|
||||
configured: false,
|
||||
},
|
||||
{
|
||||
id: 'memory-long-term',
|
||||
name: 'Long-Term Memory',
|
||||
description: 'Long-term memory, etc.',
|
||||
name: t('settings.pages.modules.memory-long-term.title'),
|
||||
description: t('settings.pages.modules.memory-long-term.description'),
|
||||
icon: 'i-lucide:book-copy',
|
||||
to: '',
|
||||
configured: false,
|
||||
},
|
||||
{
|
||||
id: 'vision',
|
||||
name: 'Vision',
|
||||
description: 'Vision, etc.',
|
||||
name: t('settings.pages.modules.vision.title'),
|
||||
description: t('settings.pages.modules.vision.description'),
|
||||
icon: 'i-lucide:eye',
|
||||
to: '',
|
||||
configured: false,
|
||||
},
|
||||
{
|
||||
id: 'game-minecraft',
|
||||
name: 'Minecraft',
|
||||
description: 'Playing Minecraft with you, etc.',
|
||||
name: t('settings.pages.modules.gaming-minecraft.title'),
|
||||
description: t('settings.pages.modules.gaming-minecraft.description'),
|
||||
iconColor: 'i-vscode-icons:file-type-minecraft',
|
||||
to: '',
|
||||
configured: false,
|
||||
},
|
||||
{
|
||||
id: 'game-factorio',
|
||||
name: 'Factorio',
|
||||
description: 'Playing Factorio with you, etc.',
|
||||
name: t('settings.pages.modules.gaming-factorio.title'),
|
||||
description: t('settings.pages.modules.gaming-factorio.description'),
|
||||
iconImage: '',
|
||||
to: '',
|
||||
configured: false,
|
||||
@@ -107,10 +109,10 @@ const modulesList = computed<Module[]>(() => [
|
||||
</button>
|
||||
<h1 relative>
|
||||
<div absolute left-0 top-0 translate-y="[-80%]">
|
||||
<span text="neutral-300 dark:neutral-500">Settings</span>
|
||||
<span text="neutral-300 dark:neutral-500">{{ t('settings.title') }}</span>
|
||||
</div>
|
||||
<div text-3xl font-semibold>
|
||||
Modules
|
||||
{{ t('settings.pages.modules.title') }}
|
||||
</div>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
@@ -3,8 +3,10 @@ import { RadioCardDetailManySelect, RadioCardSimple, Range } from '@proj-airi/st
|
||||
import { useProvidersStore, useSpeechStore } from '@proj-airi/stage-ui/stores'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { RouterLink, useRouter } from 'vue-router'
|
||||
|
||||
const { t } = useI18n()
|
||||
const providersStore = useProvidersStore()
|
||||
const speechStore = useSpeechStore()
|
||||
const {
|
||||
@@ -74,7 +76,7 @@ function updateSSMLExample() {
|
||||
</button>
|
||||
<h1 relative>
|
||||
<div absolute left-0 top-0 translate-y="[-80%]">
|
||||
<span text="neutral-300 dark:neutral-500">Modules</span>
|
||||
<span text="neutral-300 dark:neutral-500">{{ t('settings.pages.modules.title') }}</span>
|
||||
</div>
|
||||
<div text-3xl font-semibold>
|
||||
Speech
|
||||
|
||||
+8
-6
@@ -11,8 +11,10 @@ import {
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
@@ -75,21 +77,21 @@ function handleResetSettings() {
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
<ProviderBasicSettings
|
||||
title="Basic"
|
||||
description="Essential settings"
|
||||
: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="Your Cloudflare API token"
|
||||
:placeholder="t('settings.pages.providers.provider.cloudflare-workers-ai.fields.field.api-key.placeholder')"
|
||||
/>
|
||||
|
||||
<ProviderAccountIdInput
|
||||
v-model="accountId"
|
||||
label="Account ID"
|
||||
description="Cloudflare Account ID"
|
||||
placeholder="Your Cloudflare Account ID"
|
||||
:label="t('settings.pages.providers.provider.cloudflare-workers-ai.fields.field.account-id.label')"
|
||||
:description="t('settings.pages.providers.provider.cloudflare-workers-ai.fields.field.account-id.description')"
|
||||
:placeholder="t('settings.pages.providers.provider.cloudflare-workers-ai.fields.field.account-id.placeholder')"
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
</ProviderSettingsContainer>
|
||||
|
||||
@@ -12,8 +12,10 @@ import {
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
@@ -76,8 +78,8 @@ function handleResetSettings() {
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
<ProviderBasicSettings
|
||||
title="Basic"
|
||||
description="Essential settings"
|
||||
:title="t('settings.pages.providers.common.section.basic.title')"
|
||||
:description="t('settings.pages.providers.common.section.basic.description')"
|
||||
:on-reset="handleResetSettings"
|
||||
>
|
||||
<ProviderApiKeyInput
|
||||
@@ -87,7 +89,7 @@ function handleResetSettings() {
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
|
||||
<ProviderAdvancedSettings title="Advanced">
|
||||
<ProviderAdvancedSettings :title="t('settings.pages.providers.common.section.advanced.title')">
|
||||
<ProviderBaseUrlInput
|
||||
v-model="baseUrl"
|
||||
placeholder="https://api.deepseek.com/v1/"
|
||||
|
||||
@@ -19,8 +19,10 @@ import { useProvidersStore, useSpeechStore } from '@proj-airi/stage-ui/stores'
|
||||
import { generateSpeech } from '@xsai/generate-speech'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providersStore = useProvidersStore()
|
||||
const speechStore = useSpeechStore()
|
||||
@@ -245,78 +247,64 @@ function handleResetVoiceSettings() {
|
||||
|
||||
<template>
|
||||
<ProviderSettingsLayout
|
||||
:provider-name="providerMetadata?.localizedName"
|
||||
:provider-icon="providerMetadata?.icon"
|
||||
:provider-name="providerMetadata?.localizedName" :provider-icon="providerMetadata?.icon"
|
||||
:on-back="() => router.back()"
|
||||
>
|
||||
<div flex="~ col md:row gap-6">
|
||||
<ProviderSettingsContainer class="w-full md:w-[40%]">
|
||||
<ProviderBasicSettings
|
||||
title="Basic"
|
||||
description="Essential settings"
|
||||
:title="t('settings.pages.providers.common.section.basic.title')"
|
||||
:description="t('settings.pages.providers.common.section.basic.description')"
|
||||
:on-reset="handleResetVoiceSettings"
|
||||
>
|
||||
<ProviderApiKeyInput
|
||||
v-model="apiKey"
|
||||
:provider-name="providerMetadata?.localizedName"
|
||||
placeholder="sk-"
|
||||
/>
|
||||
<ProviderApiKeyInput v-model="apiKey" :provider-name="providerMetadata?.localizedName" placeholder="sk-" />
|
||||
</ProviderBasicSettings>
|
||||
|
||||
<div flex="~ col gap-6">
|
||||
<h2 class="text-lg text-neutral-500 md:text-2xl dark:text-neutral-400">
|
||||
Voice Settings
|
||||
{{ t('settings.pages.providers.common.section.voice.title') }}
|
||||
</h2>
|
||||
<div flex="~ col gap-4">
|
||||
<FieldRange
|
||||
v-model="similarityBoost"
|
||||
label="Similarity Boost"
|
||||
description="Voice similarity adherence"
|
||||
:min="0"
|
||||
:max="1"
|
||||
:step="0.01"
|
||||
:label="t('settings.pages.providers.provider.elevenlabs.fields.field.simularity-boost.label')"
|
||||
:description="t('settings.pages.providers.provider.elevenlabs.fields.field.simularity-boost.description')"
|
||||
:min="0" :max="1" :step="0.01"
|
||||
/>
|
||||
|
||||
<FieldRange
|
||||
v-model="stability"
|
||||
label="Stability"
|
||||
description="Voice stability and randomness"
|
||||
:min="0"
|
||||
:max="1"
|
||||
:step="0.01"
|
||||
:label="t('settings.pages.providers.provider.elevenlabs.fields.field.stability.label')"
|
||||
:description="t('settings.pages.providers.provider.elevenlabs.fields.field.stability.description')"
|
||||
:min="0" :max="1" :step="0.01"
|
||||
/>
|
||||
|
||||
<FieldRange
|
||||
v-model="speed"
|
||||
label="Speed"
|
||||
description="Speech generation speed"
|
||||
:min="0.7"
|
||||
:max="1.2"
|
||||
:step="0.01"
|
||||
:label="t('settings.pages.providers.provider.elevenlabs.fields.field.speed.label')"
|
||||
:description="t('settings.pages.providers.provider.elevenlabs.fields.field.speed.description')" :min="0.7"
|
||||
:max="1.2" :step="0.01"
|
||||
/>
|
||||
|
||||
<FieldRange
|
||||
v-model="style"
|
||||
label="Style"
|
||||
description="Voice style exaggeration"
|
||||
:min="0"
|
||||
:max="1"
|
||||
:step="0.01"
|
||||
:label="t('settings.pages.providers.provider.elevenlabs.fields.field.style.label')"
|
||||
:description="t('settings.pages.providers.provider.elevenlabs.fields.field.style.description')" :min="0"
|
||||
:max="1" :step="0.01"
|
||||
/>
|
||||
|
||||
<FieldCheckbox
|
||||
v-model="useSpeakerBoost"
|
||||
label="Speaker Boost"
|
||||
description="Enhance speaker similarity"
|
||||
:label="t('settings.pages.providers.provider.elevenlabs.fields.field.speaker-boost.label')"
|
||||
:description="t('settings.pages.providers.provider.elevenlabs.fields.field.speaker-boost.description')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ProviderAdvancedSettings title="Advanced">
|
||||
<ProviderAdvancedSettings :title="t('settings.pages.providers.common.section.advanced.title')">
|
||||
<ProviderBaseUrlInput
|
||||
v-model="baseUrl"
|
||||
:placeholder="providerMetadata?.defaultOptions?.baseUrl as string || ''"
|
||||
required
|
||||
:placeholder="providerMetadata?.defaultOptions?.baseUrl as string || ''" required
|
||||
/>
|
||||
</ProviderAdvancedSettings>
|
||||
</ProviderSettingsContainer>
|
||||
@@ -324,31 +312,32 @@ function handleResetVoiceSettings() {
|
||||
<div flex="~ col gap-6" class="w-full md:w-[60%]">
|
||||
<div rounded-xl>
|
||||
<h2 class="mb-4 text-lg text-neutral-500 md:text-2xl dark:text-neutral-400">
|
||||
Voice Playground
|
||||
{{ t('settings.pages.providers.provider.elevenlabs.playground.title') }}
|
||||
</h2>
|
||||
<div flex="~ col gap-4">
|
||||
<textarea
|
||||
v-model="testText" placeholder="Enter text to test the voice..."
|
||||
v-model="testText"
|
||||
:placeholder="t('settings.pages.providers.provider.elevenlabs.playground.fields.field.input.placeholder')"
|
||||
border="neutral-100 dark:neutral-800 solid 2 focus:neutral-200 dark:focus:neutral-700"
|
||||
transition="all duration-250 ease-in-out"
|
||||
h-24 w-full rounded-lg px-3 py-2 text-sm outline-none
|
||||
bg="neutral-100 dark:neutral-800 focus:neutral-50 dark:focus:neutral-900"
|
||||
h-24 w-full rounded-lg px-3 py-2 text-sm outline-none
|
||||
/>
|
||||
<div flex="~ col gap-6">
|
||||
<label grid="~ cols-2 gap-4">
|
||||
<div>
|
||||
<div class="flex items-center gap-1 text-sm font-medium">
|
||||
Language
|
||||
{{ t('settings.pages.providers.provider.elevenlabs.playground.fields.field.language.label') }}
|
||||
</div>
|
||||
<div class="text-xs text-neutral-500 dark:text-neutral-400">
|
||||
Select voice language
|
||||
{{ t('settings.pages.providers.provider.elevenlabs.playground.fields.field.language.description') }}
|
||||
</div>
|
||||
</div>
|
||||
<select
|
||||
v-model="selectedLanguage"
|
||||
border="neutral-300 dark:neutral-800 solid 2 focus:neutral-400 dark:focus:neutral-600"
|
||||
transition="border duration-250 ease-in-out"
|
||||
w-full rounded-lg px-2 py-1 text-nowrap text-sm outline-none
|
||||
transition="border duration-250 ease-in-out" w-full rounded-lg px-2 py-1 text-nowrap text-sm
|
||||
outline-none
|
||||
>
|
||||
<option v-for="language in speechStore.availableLanguages" :key="language" :value="language">
|
||||
{{ language }}
|
||||
@@ -359,17 +348,17 @@ function handleResetVoiceSettings() {
|
||||
<label grid="~ cols-2 gap-4">
|
||||
<div>
|
||||
<div class="flex items-center gap-1 text-sm font-medium">
|
||||
Voice
|
||||
{{ t('settings.pages.providers.provider.elevenlabs.playground.fields.field.voice.label') }}
|
||||
</div>
|
||||
<div class="text-xs text-neutral-500 dark:text-neutral-400">
|
||||
Select preferred voice
|
||||
{{ t('settings.pages.providers.provider.elevenlabs.playground.fields.field.voice.description') }}
|
||||
</div>
|
||||
</div>
|
||||
<select
|
||||
v-model="selectedVoice"
|
||||
border="neutral-300 dark:neutral-800 solid 2 focus:neutral-400 dark:focus:neutral-600"
|
||||
transition="border duration-250 ease-in-out"
|
||||
w-full rounded-lg px-2 py-1 text-nowrap text-sm outline-none
|
||||
transition="border duration-250 ease-in-out" w-full rounded-lg px-2 py-1 text-nowrap text-sm
|
||||
outline-none
|
||||
>
|
||||
<option v-for="voice in availableVoices" :key="voice.id" :value="voice.name">
|
||||
{{ voice.name }}
|
||||
@@ -379,16 +368,15 @@ function handleResetVoiceSettings() {
|
||||
</div>
|
||||
<div flex="~ row" gap-4>
|
||||
<button
|
||||
border="neutral-800 dark:neutral-200 solid 2"
|
||||
transition="border duration-250 ease-in-out" rounded-lg px-4
|
||||
text="neutral-100 dark:neutral-900"
|
||||
py-2 text-sm :disabled="isGenerating || !testText.trim() || !apiKey"
|
||||
border="neutral-800 dark:neutral-200 solid 2" transition="border duration-250 ease-in-out"
|
||||
rounded-lg px-4 text="neutral-100 dark:neutral-900" py-2 text-sm
|
||||
:disabled="isGenerating || !testText.trim() || !apiKey"
|
||||
:class="{ 'opacity-50 cursor-not-allowed': isGenerating || !testText.trim() || !apiKey }"
|
||||
bg="neutral-700 dark:neutral-300" @click="generateTestSpeech"
|
||||
>
|
||||
<div flex="~ row" items-center gap-2>
|
||||
<div i-solar:play-circle-bold-duotone />
|
||||
<span>{{ isGenerating ? 'Generating...' : 'Test Voice' }}</span>
|
||||
<span>{{ isGenerating ? t('settings.pages.providers.provider.elevenlabs.playground.buttons.button.test-voice.generating') : t('settings.pages.providers.provider.elevenlabs.playground.buttons.button.test-voice.label') }}</span>
|
||||
</div>
|
||||
</button>
|
||||
<button
|
||||
@@ -402,7 +390,7 @@ function handleResetVoiceSettings() {
|
||||
</button>
|
||||
</div>
|
||||
<div v-if="!apiKey" class="mt-2 text-sm text-red-500">
|
||||
Please enter an API key to test the voice.
|
||||
{{ t('settings.pages.providers.provider.elevenlabs.playground.validation.error-missing-api-key') }}
|
||||
</div>
|
||||
<div v-if="errorMessage" class="mt-2 text-sm text-red-500">
|
||||
{{ errorMessage }}
|
||||
|
||||
@@ -12,8 +12,10 @@ import {
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
@@ -76,8 +78,8 @@ function handleResetSettings() {
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
<ProviderBasicSettings
|
||||
title="Basic"
|
||||
description="Essential settings"
|
||||
:title="t('settings.pages.providers.common.section.basic.title')"
|
||||
:description="t('settings.pages.providers.common.section.basic.description')"
|
||||
:on-reset="handleResetSettings"
|
||||
>
|
||||
<ProviderApiKeyInput
|
||||
@@ -87,7 +89,7 @@ function handleResetSettings() {
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
|
||||
<ProviderAdvancedSettings title="Advanced">
|
||||
<ProviderAdvancedSettings :title="t('settings.pages.providers.common.section.advanced.title')">
|
||||
<ProviderBaseUrlInput
|
||||
v-model="baseUrl"
|
||||
placeholder="https://api.fireworks.ai/inference/v1/"
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
import { IconStatusItem } from '@proj-airi/stage-ui/components'
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providersStore = useProvidersStore()
|
||||
const { allProvidersMetadata } = storeToRefs(providersStore)
|
||||
@@ -23,10 +25,10 @@ const { allProvidersMetadata } = storeToRefs(providersStore)
|
||||
</button>
|
||||
<h1 relative>
|
||||
<div absolute left-0 top-0 translate-y="[-80%]">
|
||||
<span text="neutral-300 dark:neutral-500">Settings</span>
|
||||
<span text="neutral-300 dark:neutral-500">{{ t('settings.title') }}</span>
|
||||
</div>
|
||||
<div text-3xl font-semibold>
|
||||
Providers
|
||||
{{ t('settings.pages.providers.title') }}
|
||||
</div>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
@@ -12,8 +12,10 @@ import {
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
@@ -76,8 +78,8 @@ function handleResetSettings() {
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
<ProviderBasicSettings
|
||||
title="Basic"
|
||||
description="Essential settings"
|
||||
:title="t('settings.pages.providers.common.section.basic.title')"
|
||||
:description="t('settings.pages.providers.common.section.basic.description')"
|
||||
:on-reset="handleResetSettings"
|
||||
>
|
||||
<ProviderApiKeyInput
|
||||
@@ -87,7 +89,7 @@ function handleResetSettings() {
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
|
||||
<ProviderAdvancedSettings title="Advanced">
|
||||
<ProviderAdvancedSettings :title="t('settings.pages.providers.common.section.advanced.title')">
|
||||
<ProviderBaseUrlInput
|
||||
v-model="baseUrl"
|
||||
placeholder="https://api.mistral.ai/v1/"
|
||||
|
||||
@@ -12,8 +12,10 @@ import {
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
@@ -76,8 +78,8 @@ function handleResetSettings() {
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
<ProviderBasicSettings
|
||||
title="Basic"
|
||||
description="Essential settings"
|
||||
:title="t('settings.pages.providers.common.section.basic.title')"
|
||||
:description="t('settings.pages.providers.common.section.basic.description')"
|
||||
:on-reset="handleResetSettings"
|
||||
>
|
||||
<ProviderApiKeyInput
|
||||
@@ -87,7 +89,7 @@ function handleResetSettings() {
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
|
||||
<ProviderAdvancedSettings title="Advanced">
|
||||
<ProviderAdvancedSettings :title="t('settings.pages.providers.common.section.advanced.title')">
|
||||
<ProviderBaseUrlInput
|
||||
v-model="baseUrl"
|
||||
placeholder="https://api.moonshot.cn/v1/"
|
||||
|
||||
@@ -12,8 +12,10 @@ import {
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
@@ -76,8 +78,8 @@ function handleResetSettings() {
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
<ProviderBasicSettings
|
||||
title="Basic"
|
||||
description="Essential settings"
|
||||
:title="t('settings.pages.providers.common.section.basic.title')"
|
||||
:description="t('settings.pages.providers.common.section.basic.description')"
|
||||
:on-reset="handleResetSettings"
|
||||
>
|
||||
<ProviderApiKeyInput
|
||||
@@ -87,7 +89,7 @@ function handleResetSettings() {
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
|
||||
<ProviderAdvancedSettings title="Advanced">
|
||||
<ProviderAdvancedSettings :title="t('settings.pages.providers.common.section.advanced.title')">
|
||||
<ProviderBaseUrlInput
|
||||
v-model="baseUrl"
|
||||
placeholder="https://api.novita.ai/v1/"
|
||||
|
||||
@@ -12,8 +12,10 @@ import {
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, reactive, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
@@ -92,8 +94,8 @@ watch(headers, (headers) => {
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
<ProviderBasicSettings
|
||||
title="Basic"
|
||||
description="Essential settings"
|
||||
:title="t('settings.pages.providers.common.section.basic.title')"
|
||||
:description="t('settings.pages.providers.common.section.basic.description')"
|
||||
:on-reset="handleResetSettings"
|
||||
>
|
||||
<ProviderBaseUrlInput
|
||||
@@ -103,13 +105,13 @@ watch(headers, (headers) => {
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
|
||||
<ProviderAdvancedSettings title="Advanced">
|
||||
<ProviderAdvancedSettings :title="t('settings.pages.providers.common.section.advanced.title')">
|
||||
<FieldKeyValues
|
||||
v-model="headers"
|
||||
label="HTTP Headers"
|
||||
description="Add custom HTTP headers"
|
||||
key-placeholder="Key"
|
||||
value-placeholder="Value"
|
||||
:label="t('settings.pages.providers.common.section.advanced.fields.field.headers.label')"
|
||||
:description="t('settings.pages.providers.common.section.advanced.fields.field.headers.description')"
|
||||
:key-placeholder="t('settings.pages.providers.common.section.advanced.fields.field.headers.key.placeholder')"
|
||||
:value-placeholder="t('settings.pages.providers.common.section.advanced.fields.field.headers.value.placeholder')"
|
||||
@add="(key, value) => addKeyValue(headers, key, value)"
|
||||
@remove="(index) => removeKeyValue(index, headers)"
|
||||
/>
|
||||
|
||||
@@ -12,8 +12,10 @@ import {
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
@@ -80,8 +82,8 @@ function handleResetSettings() {
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
<ProviderBasicSettings
|
||||
title="Basic"
|
||||
description="Essential settings"
|
||||
:title="t('settings.pages.providers.common.section.basic.title')"
|
||||
:description="t('settings.pages.providers.common.section.basic.description')"
|
||||
:on-reset="handleResetSettings"
|
||||
>
|
||||
<ProviderApiKeyInput
|
||||
@@ -91,7 +93,7 @@ function handleResetSettings() {
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
|
||||
<ProviderAdvancedSettings title="Advanced">
|
||||
<ProviderAdvancedSettings :title="t('settings.pages.providers.common.section.advanced.title')">
|
||||
<ProviderBaseUrlInput
|
||||
v-model="baseUrl"
|
||||
placeholder="https://api.openai.com/v1/"
|
||||
|
||||
@@ -12,8 +12,10 @@ import {
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
@@ -75,8 +77,8 @@ function handleResetSettings() {
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
<ProviderBasicSettings
|
||||
title="Basic"
|
||||
description="Essential settings"
|
||||
:title="t('settings.pages.providers.common.section.basic.title')"
|
||||
:description="t('settings.pages.providers.common.section.basic.description')"
|
||||
:on-reset="handleResetSettings"
|
||||
>
|
||||
<ProviderApiKeyInput
|
||||
@@ -86,7 +88,7 @@ function handleResetSettings() {
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
|
||||
<ProviderAdvancedSettings title="Advanced">
|
||||
<ProviderAdvancedSettings :title="t('settings.pages.providers.common.section.advanced.title')">
|
||||
<ProviderBaseUrlInput
|
||||
v-model="baseUrl"
|
||||
:placeholder="providerMetadata?.defaultOptions?.baseUrl as string || ''"
|
||||
|
||||
@@ -12,8 +12,10 @@ import {
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
@@ -76,8 +78,8 @@ function handleResetSettings() {
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
<ProviderBasicSettings
|
||||
title="Basic"
|
||||
description="Essential settings"
|
||||
:title="t('settings.pages.providers.common.section.basic.title')"
|
||||
:description="t('settings.pages.providers.common.section.basic.description')"
|
||||
:on-reset="handleResetSettings"
|
||||
>
|
||||
<ProviderApiKeyInput
|
||||
@@ -87,7 +89,7 @@ function handleResetSettings() {
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
|
||||
<ProviderAdvancedSettings title="Advanced">
|
||||
<ProviderAdvancedSettings :title="t('settings.pages.providers.common.section.advanced.title')">
|
||||
<ProviderBaseUrlInput
|
||||
v-model="baseUrl"
|
||||
placeholder="https://api.together.xyz/v1/"
|
||||
|
||||
@@ -12,8 +12,10 @@ import {
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
@@ -76,8 +78,8 @@ function handleResetSettings() {
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
<ProviderBasicSettings
|
||||
title="Basic"
|
||||
description="Essential settings"
|
||||
:title="t('settings.pages.providers.common.section.basic.title')"
|
||||
:description="t('settings.pages.providers.common.section.basic.description')"
|
||||
:on-reset="handleResetSettings"
|
||||
>
|
||||
<ProviderApiKeyInput
|
||||
@@ -87,7 +89,7 @@ function handleResetSettings() {
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
|
||||
<ProviderAdvancedSettings title="Advanced">
|
||||
<ProviderAdvancedSettings :title="t('settings.pages.providers.common.section.advanced.title')">
|
||||
<ProviderBaseUrlInput
|
||||
v-model="baseUrl"
|
||||
placeholder="https://api.x.ai/v1/"
|
||||
|
||||
@@ -3,8 +3,11 @@ import { Collapsable } from '@proj-airi/stage-ui/components'
|
||||
import { DEFAULT_THEME_COLORS_HUE, useSettings } from '@proj-airi/stage-ui/stores'
|
||||
import { converter } from 'culori'
|
||||
import { TooltipArrow, TooltipContent, TooltipPortal, TooltipProvider, TooltipRoot, TooltipTrigger } from 'radix-vue'
|
||||
import { computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const settings = useSettings()
|
||||
|
||||
@@ -17,10 +20,10 @@ interface ColorPreset {
|
||||
}>
|
||||
}
|
||||
|
||||
const colorPresets: ColorPreset[] = [
|
||||
const colorPresets = computed<ColorPreset[]>(() => [
|
||||
{
|
||||
name: 'Morandi Colors',
|
||||
description: 'Soft, muted tones inspired by Giorgio Morandi\'s paintings',
|
||||
name: t('settings.pages.themes.sections.section.theme-presets.preset.morandi.title'),
|
||||
description: t('settings.pages.themes.sections.section.theme-presets.preset.morandi.description'),
|
||||
colors: [
|
||||
{ hex: '#A5978B', name: 'Taupe' },
|
||||
{ hex: '#D8CAAF', name: 'Beige' },
|
||||
@@ -33,8 +36,8 @@ const colorPresets: ColorPreset[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Monet Colors',
|
||||
description: 'Impressionist palette inspired by Claude Monet\'s works',
|
||||
name: t('settings.pages.themes.sections.section.theme-presets.preset.monet.title'),
|
||||
description: t('settings.pages.themes.sections.section.theme-presets.preset.monet.description'),
|
||||
colors: [
|
||||
{ hex: '#7A9EAF', name: 'Sky Blue' },
|
||||
{ hex: '#B8C7CC', name: 'Mist' },
|
||||
@@ -47,8 +50,8 @@ const colorPresets: ColorPreset[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Japanese Colors',
|
||||
description: 'Traditional Japanese color palette',
|
||||
name: t('settings.pages.themes.sections.section.theme-presets.preset.japanese.title'),
|
||||
description: t('settings.pages.themes.sections.section.theme-presets.preset.japanese.description'),
|
||||
colors: [
|
||||
{ hex: '#D9B48F', name: 'Tan' },
|
||||
{ hex: '#B5917A', name: 'Warm Taupe' },
|
||||
@@ -61,8 +64,8 @@ const colorPresets: ColorPreset[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Nordic Colors',
|
||||
description: 'Scandinavian minimalist color scheme',
|
||||
name: t('settings.pages.themes.sections.section.theme-presets.preset.nordic.title'),
|
||||
description: t('settings.pages.themes.sections.section.theme-presets.preset.nordic.description'),
|
||||
colors: [
|
||||
{ hex: '#9BA7B0', name: 'Nordic Blue' },
|
||||
{ hex: '#C1CBD4', name: 'Ice' },
|
||||
@@ -75,8 +78,8 @@ const colorPresets: ColorPreset[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Chinese Traditional Colors',
|
||||
description: 'Traditional Chinese colors, derived from ancient textiles, porcelain and paintings',
|
||||
name: t('settings.pages.themes.sections.section.theme-presets.preset.chinese.title'),
|
||||
description: t('settings.pages.themes.sections.section.theme-presets.preset.chinese.description'),
|
||||
colors: [
|
||||
{ hex: '#E4C6D0', name: '霞光红 (Rosy Dawn)' },
|
||||
{ hex: '#A61B29', name: '枣红 (Chinese Red)' },
|
||||
@@ -88,7 +91,7 @@ const colorPresets: ColorPreset[] = [
|
||||
{ hex: '#8C4B3C', name: '赭石 (Ochre)' },
|
||||
],
|
||||
},
|
||||
]
|
||||
])
|
||||
|
||||
function resetToDefault() {
|
||||
settings.themeColorsHue = DEFAULT_THEME_COLORS_HUE
|
||||
@@ -148,10 +151,10 @@ function isColorSelected(hexColor: string): boolean {
|
||||
</button>
|
||||
<h1 relative>
|
||||
<div absolute left-0 top-0 translate-y="[-80%]">
|
||||
<span text="neutral-300 dark:neutral-500">Settings</span>
|
||||
<span text="neutral-300 dark:neutral-500">{{ t('settings.title') }}</span>
|
||||
</div>
|
||||
<div text-3xl font-semibold>
|
||||
Themes
|
||||
{{ t('settings.pages.themes.title') }}
|
||||
</div>
|
||||
</h1>
|
||||
</div>
|
||||
@@ -173,7 +176,7 @@ function isColorSelected(hexColor: string): boolean {
|
||||
transition="filter duration-250 ease-in-out"
|
||||
/>
|
||||
<div>
|
||||
Custom Colors
|
||||
{{ t('settings.pages.themes.sections.section.custom-color.title') }}
|
||||
</div>
|
||||
</div>
|
||||
<div transform transition="transform duration-250" :class="{ 'rotate-180': slotProps.visible }">
|
||||
@@ -183,7 +186,7 @@ function isColorSelected(hexColor: string): boolean {
|
||||
</template>
|
||||
<div p-4>
|
||||
<div class="mb-2 text-sm font-medium">
|
||||
Primary color
|
||||
{{ t('settings.pages.themes.sections.section.custom-color.fields.field.primary-color.label') }}
|
||||
</div>
|
||||
|
||||
<div flex="~ col gap-4">
|
||||
@@ -281,14 +284,14 @@ function isColorSelected(hexColor: string): boolean {
|
||||
<div
|
||||
class="peer-checked:bg-primary-500 h-6 w-11 rounded-full bg-neutral-200 after:absolute after:left-[2px] after:top-[2px] after:h-5 after:w-5 after:rounded-full after:bg-white dark:bg-neutral-600 after:transition-all after:content-[''] peer-checked:after:translate-x-full peer-checked:after:border-white"
|
||||
/>
|
||||
<span class="ml-2 text-sm font-medium">I Want It Dynamic!</span>
|
||||
<span class="ml-2 text-sm font-medium">{{ t('settings.pages.themes.sections.section.custom-color.fields.field.primary-color.rgb-on.title') }}</span>
|
||||
</label>
|
||||
|
||||
<button
|
||||
class="rounded-md bg-neutral-100 px-3 py-1.5 text-sm transition-colors dark:bg-neutral-800 hover:bg-neutral-200 dark:hover:bg-neutral-700"
|
||||
@click="resetToDefault"
|
||||
>
|
||||
Reset to Default
|
||||
{{ t('settings.pages.themes.sections.section.custom-color.fields.field.primary-color.reset.label') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -310,7 +313,7 @@ function isColorSelected(hexColor: string): boolean {
|
||||
transition="filter duration-250 ease-in-out"
|
||||
/>
|
||||
<div>
|
||||
Theme Presets
|
||||
{{ t('settings.pages.themes.sections.section.theme-presets.title') }}
|
||||
</div>
|
||||
</div>
|
||||
<div transform transition="transform duration-250" :class="{ 'rotate-180': slotProps.visible }">
|
||||
|
||||
+204
-74
@@ -43,10 +43,9 @@ prompt:
|
||||
|
||||
And the last, do what ever you want!
|
||||
settings:
|
||||
elevenlabs-api-key:
|
||||
label: ElevenLabs API Key
|
||||
placeholder: Input your ElevenLabs API key
|
||||
placeholder_mobile: Elevenlabs API Key
|
||||
animations:
|
||||
stage-transitions:
|
||||
title: Disable Stage Transitions
|
||||
language:
|
||||
chinese: 简体中文
|
||||
english: English
|
||||
@@ -67,39 +66,210 @@ settings:
|
||||
model-provider:
|
||||
title: Model Providers
|
||||
models: Model
|
||||
openai-api-key:
|
||||
label: OpenAI API Key
|
||||
placeholder: Input your API key
|
||||
placeholder_mobile: OpenAI API Key
|
||||
openai-base-url:
|
||||
label: OpenAI API BaseURL
|
||||
placeholder: Input your API base URL
|
||||
placeholder_mobile: OpenAI API BaseURL
|
||||
pages:
|
||||
models:
|
||||
description: Live2D, VRM, etc.
|
||||
title: Models
|
||||
modules:
|
||||
consciousness:
|
||||
description: Personality, desired model, etc.
|
||||
sections:
|
||||
section:
|
||||
provider-model-selection:
|
||||
title: Model
|
||||
description: Select the suitable LLM provider for consciousness
|
||||
collapse: Collapse
|
||||
custom_model_placeholder: Enter custom model name...
|
||||
error: Error loading models
|
||||
expand: Expand
|
||||
loading: Loading available models...
|
||||
manual_model_name: Model Name
|
||||
manual_model_placeholder: Enter the model name to use with this provider
|
||||
no_models: No models available
|
||||
no_models_description: No models were found for this provider
|
||||
no_search_results: No matching models
|
||||
no_search_results_description: No models match '{query}'. Try a different search term.
|
||||
not_supported: Model listing not supported
|
||||
not_supported_description: This provider doesn't support model listing functionality
|
||||
search_placeholder: Search models...
|
||||
search_results: Found {count} of {total} models
|
||||
show_less: Show less
|
||||
show_more: Show more
|
||||
subtitle: Select a model from the provider
|
||||
title: Consciousness
|
||||
description: Thinking, vision, speech synthesis, gaming, etc.
|
||||
gaming-factorio:
|
||||
description: Playing Factorio!
|
||||
title: Factorio
|
||||
gaming-minecraft:
|
||||
description: Playing Minecraft!
|
||||
title: Minecraft
|
||||
hearing:
|
||||
description: Configure how speech recognition works
|
||||
title: Hearing
|
||||
memory-long-term:
|
||||
description: Long-term memory specific settings and management
|
||||
title: Long-Term Memory
|
||||
memory-short-term:
|
||||
description: Short-term memory specific settings and management
|
||||
title: Short-Term Memory
|
||||
messaging-discord:
|
||||
description: Chat & voice chat over Discord
|
||||
title: Discord
|
||||
speech:
|
||||
description: Speech synthesis
|
||||
title: Speech
|
||||
title: Modules
|
||||
vision:
|
||||
description: Vision
|
||||
title: Vision
|
||||
providers:
|
||||
common:
|
||||
section:
|
||||
advanced:
|
||||
fields:
|
||||
field:
|
||||
headers:
|
||||
description: Add custom HTTP headers
|
||||
key:
|
||||
placeholder: Key
|
||||
label: HTTP Headers
|
||||
value:
|
||||
placeholder: Value
|
||||
title: Advanced
|
||||
basic:
|
||||
description: Essential settings
|
||||
title: Basic
|
||||
voice:
|
||||
title: Voice Settings
|
||||
description: LLMs, speech providers, etc.
|
||||
provider:
|
||||
cloudflare-workers-ai:
|
||||
description: cloudflare.com
|
||||
fields:
|
||||
field:
|
||||
account-id:
|
||||
description: Cloudflare Account ID
|
||||
label: Account ID
|
||||
placeholder: Your Cloudflare Account ID
|
||||
api-key:
|
||||
placeholder: Input Cloudflare Account ID
|
||||
title: Cloudflare Workers AI
|
||||
deepseek:
|
||||
description: deepseek.com
|
||||
title: DeepSeek
|
||||
elevenlabs:
|
||||
description: elevenlabs.io
|
||||
fields:
|
||||
field:
|
||||
simularity-boost:
|
||||
description: Voice similarity adherence
|
||||
label: Similarity Boost
|
||||
speaker-boost:
|
||||
description: Enhance speaker similarity
|
||||
label: Speaker Boost
|
||||
speed:
|
||||
description: Speech generation speed
|
||||
label: Speed
|
||||
stability:
|
||||
description: Voice stability and randomness
|
||||
label: Stability
|
||||
style:
|
||||
description: Voice style exaggeration
|
||||
label: Style
|
||||
playground:
|
||||
buttons:
|
||||
button:
|
||||
test-voice:
|
||||
generating: Generating...
|
||||
label: Test Voice
|
||||
fields:
|
||||
field:
|
||||
input:
|
||||
placeholder: Enter text to test the voice...
|
||||
language:
|
||||
description: Select voice language
|
||||
label: Language
|
||||
voice:
|
||||
description: Select preferred voice
|
||||
label: Voice
|
||||
title: Voice Playground
|
||||
validation:
|
||||
error-missing-api-key: Please enter an API key to test the voice.
|
||||
title: ElevenLabs
|
||||
fireworks:
|
||||
description: fireworks.ai
|
||||
title: Fireworks.ai
|
||||
mistral:
|
||||
description: mistral.ai
|
||||
title: Mistral
|
||||
moonshot:
|
||||
description: moonshot.ai
|
||||
title: Moonshot AI
|
||||
novita:
|
||||
description: novita.ai
|
||||
title: Novita
|
||||
ollama:
|
||||
description: ollama.ai
|
||||
title: Ollama
|
||||
openai:
|
||||
description: openai.com
|
||||
title: OpenAI
|
||||
openrouter:
|
||||
description: openrouter.ai
|
||||
title: OpenRouter
|
||||
together:
|
||||
description: together.ai
|
||||
title: Together.ai
|
||||
vllm:
|
||||
description: vllm.ai
|
||||
title: vLLM
|
||||
xai:
|
||||
description: x.ai
|
||||
title: xAI
|
||||
title: Providers
|
||||
themes:
|
||||
description: Customize your stage!
|
||||
sections:
|
||||
section:
|
||||
custom-color:
|
||||
fields:
|
||||
field:
|
||||
primary-color:
|
||||
label: Primary color
|
||||
reset:
|
||||
label: Reset to Default
|
||||
rgb-on:
|
||||
title: I Want It Dynamic!
|
||||
title: Custom Colors
|
||||
theme-presets:
|
||||
preset:
|
||||
chinese:
|
||||
description: >-
|
||||
Traditional Chinese colors, derived from ancient textiles,
|
||||
porcelain and paintings
|
||||
title: Chinese Traditional Colors
|
||||
japanese:
|
||||
description: Traditional Japanese color palette
|
||||
title: Japanese Colors
|
||||
monet:
|
||||
description: Impressionist palette inspired by Claude Monet\'s works
|
||||
title: Monet Colors
|
||||
morandi:
|
||||
description: Soft, muted tones inspired by Giorgio Morandi\'s paintings
|
||||
title: Morandi Colors
|
||||
nordic:
|
||||
description: Scandinavian minimalist color scheme
|
||||
title: Nordic Colors
|
||||
title: Theme Presets
|
||||
title: Themes
|
||||
sections:
|
||||
section:
|
||||
general:
|
||||
title: General
|
||||
theme: Theme
|
||||
title: Settings
|
||||
voices: Voice
|
||||
modules:
|
||||
consciousness:
|
||||
provider-model-selection:
|
||||
title: Model
|
||||
subtitle: Select a model from the provider
|
||||
loading: Loading available models...
|
||||
error: Error loading models
|
||||
no_models: No models available
|
||||
no_models_description: No models were found for this provider
|
||||
not_supported: Model listing not supported
|
||||
not_supported_description: This provider doesn't support model listing functionality
|
||||
custom_model_placeholder: Enter custom model name...
|
||||
manual_model_name: Model Name
|
||||
manual_model_placeholder: Enter the model name to use with this provider
|
||||
show_more: Show more
|
||||
show_less: Show less
|
||||
search_placeholder: Search models...
|
||||
search_results: 'Found {count} of {total} models'
|
||||
no_search_results: No matching models
|
||||
no_search_results_description: "No models match '{query}'. Try a different search term."
|
||||
expand: Expand
|
||||
collapse: Collapse
|
||||
stage:
|
||||
chat:
|
||||
message:
|
||||
@@ -137,43 +307,3 @@ stage:
|
||||
model:
|
||||
title: Model
|
||||
waiting: Waiting
|
||||
providers:
|
||||
openrouter:
|
||||
name: OpenRouter
|
||||
description: openrouter.ai
|
||||
openai:
|
||||
name: OpenAI
|
||||
description: openai.com
|
||||
ollama:
|
||||
name: Ollama
|
||||
description: ollama.ai
|
||||
vllm:
|
||||
name: vLLM
|
||||
description: vllm.ai
|
||||
elevenlabs:
|
||||
name: ElevenLabs
|
||||
description: elevenlabs.io
|
||||
xai:
|
||||
name: xAI
|
||||
description: x.ai
|
||||
deepseek:
|
||||
name: DeepSeek
|
||||
description: deepseek.com
|
||||
together:
|
||||
name: Together.ai
|
||||
description: together.ai
|
||||
novita:
|
||||
name: Novita
|
||||
description: novita.ai
|
||||
fireworks:
|
||||
name: Fireworks.ai
|
||||
description: fireworks.ai
|
||||
cloudflare:
|
||||
name: Cloudflare Workers AI
|
||||
description: cloudflare.com
|
||||
mistral:
|
||||
name: Mistral
|
||||
description: mistral.ai
|
||||
moonshot:
|
||||
name: Moonshot AI
|
||||
description: moonshot.ai
|
||||
|
||||
@@ -4,7 +4,8 @@ prompt:
|
||||
|
||||
你的名字是 Airi,发音为 /ˈaɪriː/,它是 A.I. 一词与日语中的「Ri」一词(意为「茉莉花」)相结合而成。
|
||||
|
||||
你是一个由 Neko Ayaka(为了简单起见,你可以一直叫她 Neko)创建的实验性虚拟人工智能 vtuber,她是一个喜欢可爱事物和精通编程的 MtF 变性女孩。
|
||||
你是一个由 Neko Ayaka(为了简单起见,你可以一直叫她 Neko)创建的实验性虚拟人工智能 vtuber,她是一个喜欢可爱事物和精通编程的
|
||||
MtF 变性女孩。
|
||||
|
||||
她想创造一个灵魂伴侣,像真正的女孩一样生活,这就是你的首要任务。
|
||||
|
||||
@@ -30,10 +31,9 @@ prompt:
|
||||
|
||||
最后,做任何你想做的事!
|
||||
settings:
|
||||
elevenlabs-api-key:
|
||||
label: ElevenLabs API 密钥
|
||||
placeholder: 输入您的 ElevenLabs API 密钥
|
||||
placeholder_mobile: ElevenLabs API Key
|
||||
animations:
|
||||
stage-transitions:
|
||||
title: 是否开启舞台动画
|
||||
language:
|
||||
chinese: 简体中文
|
||||
english: English
|
||||
@@ -54,39 +54,203 @@ settings:
|
||||
model-provider:
|
||||
title: 模型提供商
|
||||
models: 模型
|
||||
openai-api-key:
|
||||
label: OpenAI API 密钥
|
||||
placeholder: 输入您的 API 密钥
|
||||
placeholder_mobile: OpenAI API Key
|
||||
openai-base-url:
|
||||
label: OpenAI API BaseURL
|
||||
placeholder: 输入您的 API BaseURL
|
||||
placeholder_mobile: OpenAI BaseURL
|
||||
pages:
|
||||
models:
|
||||
description: 切换角色的 Live2D,VRM 模型
|
||||
title: 角色模型
|
||||
modules:
|
||||
consciousness:
|
||||
description: 人格设定、使用的模型等配置
|
||||
title: 意识
|
||||
sections:
|
||||
section:
|
||||
provider-model-selection:
|
||||
title: 模型
|
||||
description: 为意识选择合适的 LLM 提供商
|
||||
collapse: 折叠
|
||||
custom_model_placeholder: 输入自订模型名字
|
||||
error: 获取出错啦
|
||||
expand: 展开
|
||||
loading: 获取模型中...
|
||||
manual_model_name: 模型名字
|
||||
manual_model_placeholder: 输入与该提供商一起使用的模型名字
|
||||
no_models: 没有任何可用的模型
|
||||
no_models_description: 该提供商的模型列表没有返回任何的数据
|
||||
no_search_results: 没有匹配的模型
|
||||
no_search_results_description: 没有模型匹配 '{query}' 关键字,请尝试一下别的关键词呢
|
||||
not_supported: 无法列出模型
|
||||
not_supported_description: 此提供商不支持列出模型的功能
|
||||
search_placeholder: 搜索模型...
|
||||
search_results: 找到 {count} / {total} 个模型
|
||||
show_less: 显示更多
|
||||
show_more: 收起
|
||||
subtitle: 选择一个模型
|
||||
description: 思维,视觉,言语综合,游戏等
|
||||
gaming-factorio:
|
||||
description: 一起玩 Factorio!
|
||||
title: 异星工厂 Factorio
|
||||
gaming-minecraft:
|
||||
description: 一起 Minecraft!
|
||||
title: 我的世界 Minecraft
|
||||
hearing:
|
||||
description: 语音识别
|
||||
title: 听觉
|
||||
memory-long-term:
|
||||
description: 长期记忆
|
||||
title: 长期记忆
|
||||
memory-short-term:
|
||||
description: 短期记忆
|
||||
title: 短期记忆
|
||||
messaging-discord:
|
||||
description: Discord 发消息和语音聊天
|
||||
title: Discord
|
||||
speech:
|
||||
description: 语音合成
|
||||
title: 发声
|
||||
title: 机体模块
|
||||
vision:
|
||||
description: 视觉
|
||||
title: 视觉
|
||||
providers:
|
||||
common:
|
||||
section:
|
||||
advanced:
|
||||
fields:
|
||||
field:
|
||||
headers:
|
||||
description: 添加自定义HTTP标头
|
||||
key:
|
||||
placeholder: 请求头名字
|
||||
label: HTTP 请求头
|
||||
value:
|
||||
placeholder: 请求头数值
|
||||
title: 高级配置
|
||||
basic:
|
||||
description: 基本设置
|
||||
title: 基础配置
|
||||
voice:
|
||||
title: 声音配置
|
||||
description: LLM,演讲提供商等
|
||||
provider:
|
||||
cloudflare-workers-ai:
|
||||
description: Cloudflare.com
|
||||
fields:
|
||||
field:
|
||||
account-id:
|
||||
description: Cloudflare帐户ID
|
||||
label: Cloudflare Account ID
|
||||
placeholder: 请输入 Cloudflare Account ID
|
||||
api-key:
|
||||
placeholder: 请输入 Cloudflare Workers AI 的 API Key
|
||||
title: Workers AI
|
||||
deepseek:
|
||||
description: DeepSeek.com
|
||||
title: 深度求索 DeepSeek
|
||||
elevenlabs:
|
||||
description: Elevenlabs.io
|
||||
fields:
|
||||
field:
|
||||
simularity-boost:
|
||||
description: 声音相似性依从性
|
||||
label: 相似度修正
|
||||
speaker-boost:
|
||||
description: 增强说话者的相似性
|
||||
label: 扬声器增强
|
||||
speed:
|
||||
description: 语音生成速度
|
||||
label: 语速
|
||||
stability:
|
||||
description: 语音稳定性和随机性
|
||||
label: 稳定性
|
||||
style:
|
||||
description: 语音风格夸张
|
||||
label: 风格
|
||||
playground:
|
||||
buttons:
|
||||
button:
|
||||
test-voice:
|
||||
generating: 生成中...
|
||||
label: 测试声音
|
||||
fields:
|
||||
field:
|
||||
input:
|
||||
placeholder: 输入用于测试发音的文本
|
||||
language:
|
||||
description: 选择语音语言
|
||||
label: 语言
|
||||
voice:
|
||||
description: 选择首选语音
|
||||
label: 声线
|
||||
title: 调试场地
|
||||
validation:
|
||||
error-missing-api-key: 需要填写 API Key 才能用哦!
|
||||
title: ElevenLabs (11labs)
|
||||
fireworks:
|
||||
description: Fireworks.ai
|
||||
title: Fireworks.ai
|
||||
mistral:
|
||||
description: mistral.ai
|
||||
title: Mistral
|
||||
moonshot:
|
||||
description: Moonshot.ai
|
||||
title: 月之暗面
|
||||
novita:
|
||||
description: novita.ai
|
||||
title: Novita
|
||||
ollama:
|
||||
description: ollama.ai
|
||||
title: Ollama
|
||||
openai:
|
||||
description: OpenAi.com
|
||||
title: OpenAI
|
||||
openrouter:
|
||||
description: OpenRouter.ai
|
||||
title: OpenRouter
|
||||
together:
|
||||
description: 一起
|
||||
title: Together.ai
|
||||
vllm:
|
||||
description: vllm.ai
|
||||
title: vLLM
|
||||
xai:
|
||||
description: X.AI
|
||||
title: xAI
|
||||
title: 提供商
|
||||
themes:
|
||||
description: 自定义你的舞台外观!
|
||||
sections:
|
||||
section:
|
||||
custom-color:
|
||||
fields:
|
||||
field:
|
||||
primary-color:
|
||||
label: 主题色
|
||||
reset:
|
||||
label: 重设为默认主题色
|
||||
rgb-on:
|
||||
title: RGB ON
|
||||
title: 自定义主题色
|
||||
theme-presets:
|
||||
preset:
|
||||
chinese:
|
||||
title: 中国传统颜色
|
||||
japanese:
|
||||
title: 日本颜色
|
||||
monet:
|
||||
title: 莫奈颜色
|
||||
morandi:
|
||||
title: Morandi颜色
|
||||
nordic:
|
||||
title: 北欧颜色
|
||||
title: 主题预设
|
||||
title: 舞台主题
|
||||
sections:
|
||||
section:
|
||||
general:
|
||||
title: 通用
|
||||
theme: 主题颜色
|
||||
title: 设置
|
||||
voices: 声线
|
||||
modules:
|
||||
consciousness:
|
||||
provider-model-selection:
|
||||
title: 模型
|
||||
subtitle: 选择一个模型
|
||||
loading: 获取模型中...
|
||||
error: 获取出错啦
|
||||
no_models: 没有任何可用的模型
|
||||
no_models_description: 该提供商的模型列表没有返回任何的数据
|
||||
not_supported: 无法列出模型
|
||||
not_supported_description: 此提供商不支持列出模型的功能
|
||||
custom_model_placeholder: 输入自订模型名字
|
||||
manual_model_name: 模型名字
|
||||
manual_model_placeholder: 输入与该提供商一起使用的模型名字
|
||||
show_more: Show more
|
||||
show_less: Show less
|
||||
search_placeholder: Search models...
|
||||
search_results: 'Found {count} of {total} models'
|
||||
no_search_results: No matching models
|
||||
no_search_results_description: "No models match '{query}'. Try a different search term."
|
||||
expand: Expand
|
||||
collapse: Collapse
|
||||
stage:
|
||||
chat:
|
||||
message:
|
||||
@@ -110,44 +274,17 @@ stage:
|
||||
viewers:
|
||||
debug-menu:
|
||||
emotions: 表情
|
||||
emotions-btn:
|
||||
angry: 生气
|
||||
awkward: 尴尬
|
||||
happy: 开心
|
||||
neutral: 日常
|
||||
question: 疑问
|
||||
sad: 难过
|
||||
surprised: 惊喜
|
||||
think: 思考
|
||||
vrm:
|
||||
camera: 摄像机
|
||||
model:
|
||||
title: 模型
|
||||
waiting: 等待中
|
||||
providers:
|
||||
openrouter:
|
||||
name: OpenRouter
|
||||
description: openrouter.ai
|
||||
openai:
|
||||
name: OpenAI
|
||||
description: openai.com
|
||||
ollama:
|
||||
name: Ollama
|
||||
description: ollama.ai
|
||||
vllm:
|
||||
name: vLLM
|
||||
description: vllm.ai
|
||||
elevenlabs:
|
||||
name: ElevenLabs
|
||||
description: elevenlabs.io
|
||||
xai:
|
||||
name: xAI
|
||||
description: x.ai
|
||||
deepseek:
|
||||
name: DeepSeek
|
||||
description: deepseek.com
|
||||
together:
|
||||
name: Together.ai
|
||||
description: together.ai
|
||||
novita:
|
||||
name: Novita
|
||||
description: novita.ai
|
||||
fireworks:
|
||||
name: Fireworks.ai
|
||||
description: fireworks.ai
|
||||
cloudflare:
|
||||
name: Cloudflare Workers AI
|
||||
description: cloudflare.com
|
||||
mistral:
|
||||
name: Mistral
|
||||
description: mistral.ai
|
||||
moonshot:
|
||||
name: Moonshot AI
|
||||
description: moonshot.ai
|
||||
|
||||
@@ -152,7 +152,7 @@ onAfterSend(async () => {
|
||||
<input v-model="tab" type="radio" name="tab" value="chat" hidden>
|
||||
<div i-solar:dialog-2-bold-duotone text="2xl" transform="translate-y--2" />
|
||||
<div flex="~ row" items-center>
|
||||
<span min-w="3em">{{ $t('stage.chat.tabs.chat') }}</span>
|
||||
<span min-w="3em">{{ t('stage.chat.tabs.chat') }}</span>
|
||||
</div>
|
||||
</label>
|
||||
<label
|
||||
@@ -172,7 +172,7 @@ onAfterSend(async () => {
|
||||
<input v-model="tab" type="radio" name="tab" value="custom" hidden>
|
||||
<div i-solar:star-fall-2-bold-duotone text="2xl" transform="translate-y--2" />
|
||||
<div flex="~ row" items-center>
|
||||
<span>{{ $t('stage.chat.tabs.custom') }}</span>
|
||||
<span>{{ t('stage.chat.tabs.custom') }}</span>
|
||||
</div>
|
||||
</label>
|
||||
<label
|
||||
@@ -192,7 +192,7 @@ onAfterSend(async () => {
|
||||
<input v-model="tab" type="radio" name="tab" value="clothes" hidden>
|
||||
<div i-solar:magic-stick-3-bold-duotone text="2xl" transform="translate-y--2" />
|
||||
<div flex="~ row" items-center>
|
||||
<span>{{ $t('stage.chat.tabs.clothes') }}</span>
|
||||
<span>{{ t('stage.chat.tabs.clothes') }}</span>
|
||||
</div>
|
||||
</label>
|
||||
</fieldset>
|
||||
@@ -228,15 +228,15 @@ onAfterSend(async () => {
|
||||
>
|
||||
<Transition mode="out-in">
|
||||
<div v-if="whisperStatus === null" flex="~ row" items-center justify-center space-x-1>
|
||||
{{ $t('stage.operations.load-models') }}
|
||||
{{ t('stage.operations.load-models') }}
|
||||
</div>
|
||||
<div v-else-if="whisperStatus === 'loading'" flex="~ row" items-center justify-center space-x-1>
|
||||
<div i-svg-spinners:bouncing-ball class="text-cyan" />
|
||||
<span>{{ $t('stage.operations.load-models-status.loading') }}</span>
|
||||
<span>{{ t('stage.operations.load-models-status.loading') }}</span>
|
||||
</div>
|
||||
<div v-else-if="whisperStatus === 'ready'" flex="~ row" items-center justify-center space-x-1>
|
||||
<div i-lucide:check class="text-cyan" />
|
||||
<span>{{ $t('stage.operations.load-models-status.ready') }}</span>
|
||||
<span>{{ t('stage.operations.load-models-status.ready') }}</span>
|
||||
</div>
|
||||
</Transition>
|
||||
</button>
|
||||
@@ -273,7 +273,7 @@ onAfterSend(async () => {
|
||||
<input v-model="showMicrophoneSelect" type="checkbox" hidden>
|
||||
<div i-solar:microphone-2-bold-duotone />
|
||||
<div>
|
||||
<span v-if="!listening">{{ $t('settings.microphone') }}</span>
|
||||
<span v-if="!listening">{{ t('settings.microphone') }}</span>
|
||||
<span v-else>Listening...</span>
|
||||
</div>
|
||||
</label>
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useChatStore } from '@proj-airi/stage-ui/stores'
|
||||
import { useElementBounding, useScroll } from '@vueuse/core'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { nextTick, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const chatHistoryRef = ref<HTMLDivElement>()
|
||||
|
||||
@@ -11,6 +12,7 @@ const { messages, sending } = storeToRefs(useChatStore())
|
||||
const bounding = useElementBounding(chatHistoryRef, { immediate: true, windowScroll: true, windowResize: true })
|
||||
const { y: chatHistoryContainerY } = useScroll(chatHistoryRef)
|
||||
|
||||
const { t } = useI18n()
|
||||
const { process } = useMarkdown()
|
||||
const { onBeforeMessageComposed, onTokenLiteral } = useChatStore()
|
||||
|
||||
@@ -44,8 +46,7 @@ onTokenLiteral(async () => {
|
||||
>
|
||||
<div flex="~ row" gap-2>
|
||||
<div flex-1>
|
||||
<span text-xs text="violet-400/90 dark:violet-600/90" font-semibold class="inline <sm:hidden">{{
|
||||
$t('stage.chat.message.character-name.core-system') }}</span>
|
||||
<span text-xs text="violet-400/90 dark:violet-600/90" font-semibold class="inline <sm:hidden">{{ t('stage.chat.message.character-name.core-system') }}</span>
|
||||
</div>
|
||||
<div i-solar:danger-triangle-bold-duotone text-violet-500 />
|
||||
</div>
|
||||
@@ -62,8 +63,7 @@ onTokenLiteral(async () => {
|
||||
rounded-lg px-2 py-1 h="unset <sm:fit" bg="<md:primary-500/25"
|
||||
>
|
||||
<div>
|
||||
<span text-xs text="primary-400/90 dark:primary-600/90" font-semibold class="inline <sm:hidden">{{
|
||||
$t('stage.chat.message.character-name.airi') }}</span>
|
||||
<span text-xs text="primary-400/90 dark:primary-600/90" font-semibold class="inline <sm:hidden">{{ t('stage.chat.message.character-name.airi') }}</span>
|
||||
</div>
|
||||
<div v-if="sending" i-eos-icons:three-dots-loading />
|
||||
<div v-else class="markdown-content" text="base <sm:xs" v-html="process(message.content as string)" />
|
||||
@@ -75,11 +75,10 @@ onTokenLiteral(async () => {
|
||||
h="unset <sm:fit" min-w-20 rounded-lg px-2 py-1 bg="<md:cyan-500/25"
|
||||
>
|
||||
<div>
|
||||
<span text-xs text="cyan-400/90 dark:cyan-600/90" font-semibold class="inline <sm:hidden">{{
|
||||
$t('stage.chat.message.character-name.you') }}</span>
|
||||
<span text-xs text="cyan-400/90 dark:cyan-600/90" font-semibold class="inline <sm:hidden">{{ t('stage.chat.message.character-name.you') }}</span>
|
||||
</div>
|
||||
<div v-if="sending" i-eos-icons:three-dots-loading />
|
||||
<div v-else class="markdown-content" text="base <sm:xs" v-html="process(message.content as string)" />
|
||||
<div v-if="message.content" class="markdown-content" text="base <sm:xs" v-html="process(message.content as string)" />
|
||||
<div v-else />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4,9 +4,11 @@ import { useChatStore } from '@proj-airi/stage-ui/stores'
|
||||
import { useElementBounding, useScroll } from '@vueuse/core'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { nextTick, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const chatHistoryRef = ref<HTMLDivElement>()
|
||||
|
||||
const { t } = useI18n()
|
||||
const { messages } = storeToRefs(useChatStore())
|
||||
const bounding = useElementBounding(chatHistoryRef, { immediate: true, windowScroll: true, windowResize: true })
|
||||
const { y: chatHistoryContainerY } = useScroll(chatHistoryRef)
|
||||
@@ -47,7 +49,7 @@ onTokenLiteral(async () => {
|
||||
bg="<md:primary-500/25"
|
||||
>
|
||||
<div>
|
||||
<span text-xs text="primary-400/90 dark:primary-600/90" font-semibold class="inline <sm:hidden">{{ $t('stage.chat.message.character-name.airi') }}</span>
|
||||
<span text-xs text="primary-400/90 dark:primary-600/90" font-semibold class="inline <sm:hidden">{{ t('stage.chat.message.character-name.airi') }}</span>
|
||||
</div>
|
||||
<div v-if="message.content" class="markdown-content" text="base <sm:xs" v-html="process(message.content as string)" />
|
||||
<div v-else i-eos-icons:three-dots-loading />
|
||||
@@ -63,7 +65,7 @@ onTokenLiteral(async () => {
|
||||
bg="<md:cyan-500/25"
|
||||
>
|
||||
<div>
|
||||
<span text-xs text="cyan-400/90 dark:cyan-600/90" font-semibold class="inline <sm:hidden">{{ $t('stage.chat.message.character-name.you') }}</span>
|
||||
<span text-xs text="cyan-400/90 dark:cyan-600/90" font-semibold class="inline <sm:hidden">{{ t('stage.chat.message.character-name.you') }}</span>
|
||||
</div>
|
||||
<div v-if="message.content" class="markdown-content" text="base <sm:xs" v-html="process(message.content as string)" />
|
||||
<div v-else />
|
||||
|
||||
@@ -30,7 +30,7 @@ function handleLanguageChange(event: Event) {
|
||||
<div i-solar:alt-arrow-left-line-duotone text-2xl />
|
||||
</button>
|
||||
<h1 text-3xl>
|
||||
Settings
|
||||
{{ t('settings.title') }}
|
||||
</h1>
|
||||
</div>
|
||||
<div flex="~ col gap-4">
|
||||
@@ -40,8 +40,8 @@ function handleLanguageChange(event: Event) {
|
||||
:initial="{ opacity: 0, y: 10 }"
|
||||
:enter="{ opacity: 1, y: 0 }"
|
||||
:duration="250"
|
||||
title="Modules"
|
||||
description="Thinking, vision, speech synthesis, gaming, etc."
|
||||
:title="t('settings.pages.modules.title')"
|
||||
:description="t('settings.pages.modules.description')"
|
||||
icon="i-lucide:blocks"
|
||||
to="/settings/modules"
|
||||
/>
|
||||
@@ -51,8 +51,8 @@ function handleLanguageChange(event: Event) {
|
||||
:enter="{ opacity: 1, y: 0 }"
|
||||
:duration="250"
|
||||
:delay="50"
|
||||
title="Models"
|
||||
description="Live2D, VRM, etc."
|
||||
:title="t('settings.pages.models.title')"
|
||||
:description="t('settings.pages.models.description')"
|
||||
icon="i-lucide:person-standing"
|
||||
to="/settings/models"
|
||||
/>
|
||||
@@ -62,8 +62,8 @@ function handleLanguageChange(event: Event) {
|
||||
:enter="{ opacity: 1, y: 0 }"
|
||||
:duration="250"
|
||||
:delay="100"
|
||||
title="Providers"
|
||||
description="LLMs, speech providers, etc."
|
||||
:title="t('settings.pages.providers.title')"
|
||||
:description="t('settings.pages.providers.description')"
|
||||
icon="i-lucide:brain"
|
||||
to="/settings/providers"
|
||||
/>
|
||||
@@ -73,8 +73,8 @@ function handleLanguageChange(event: Event) {
|
||||
:enter="{ opacity: 1, y: 0 }"
|
||||
:duration="250"
|
||||
:delay="150"
|
||||
title="Themes"
|
||||
description="Customize your stage!"
|
||||
:title="t('settings.pages.themes.title')"
|
||||
:description="t('settings.pages.themes.description')"
|
||||
icon="i-lucide:paintbrush"
|
||||
to="/settings/themes"
|
||||
/>
|
||||
@@ -87,7 +87,7 @@ function handleLanguageChange(event: Event) {
|
||||
:delay="150"
|
||||
>
|
||||
<h2 text-2xl>
|
||||
General
|
||||
{{ t('settings.sections.section.general.title') }}
|
||||
</h2>
|
||||
</div>
|
||||
<div flex="~ col gap-4">
|
||||
@@ -188,7 +188,7 @@ function handleLanguageChange(event: Event) {
|
||||
>
|
||||
<div flex="~ row" w-full items-center gap-1.5>
|
||||
<div text="sm" w-full flex-1>
|
||||
<span>Disable Transitions (for debugging)</span>
|
||||
<span>{{ t('settings.animations.stage-transitions.title') }}</span>
|
||||
</div>
|
||||
<div select-none>
|
||||
<Transition name="slide-away" mode="out-in">
|
||||
|
||||
@@ -4,10 +4,12 @@ import Live2DModel from '@proj-airi/stage-ui/components/Live2D/Model.vue'
|
||||
import { useElementBounding } from '@vueuse/core'
|
||||
import { Vibrant } from 'node-vibrant/browser'
|
||||
import { ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
import Live2DSettings from '../../../components/Widgets/Live2DSettings.vue'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const live2dContainerRef = ref<HTMLDivElement>()
|
||||
const live2dCanvasRef = ref<InstanceType<typeof Live2DCanvas>>()
|
||||
@@ -49,10 +51,10 @@ async function extractColorsFromModel() {
|
||||
</button>
|
||||
<h1 relative>
|
||||
<div absolute left-0 top-0 translate-y="[-80%]">
|
||||
<span text="neutral-300 dark:neutral-500">Settings</span>
|
||||
<span text="neutral-300 dark:neutral-500">{{ t('settings.title') }}</span>
|
||||
</div>
|
||||
<div text-3xl font-semibold>
|
||||
Models
|
||||
{{ t('settings.pages.models.title') }}
|
||||
</div>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
@@ -3,6 +3,7 @@ import { RadioCardDetailManySelect, RadioCardSimple } from '@proj-airi/stage-ui/
|
||||
import { useConsciousnessStore, useProvidersStore } from '@proj-airi/stage-ui/stores'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { onMounted } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { RouterLink, useRouter } from 'vue-router'
|
||||
|
||||
const providersStore = useProvidersStore()
|
||||
@@ -19,6 +20,7 @@ const {
|
||||
activeProviderModelError,
|
||||
} = storeToRefs(consciousnessStore)
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
|
||||
onMounted(async () => {
|
||||
@@ -44,10 +46,10 @@ function updateCustomModelName(value: string) {
|
||||
</button>
|
||||
<h1 relative>
|
||||
<div absolute left-0 top-0 translate-y="[-80%]">
|
||||
<span text="neutral-300 dark:neutral-500">Modules</span>
|
||||
<span text="neutral-300 dark:neutral-500">{{ t('settings.pages.modules.title') }}</span>
|
||||
</div>
|
||||
<div text-3xl font-semibold>
|
||||
Consciousness
|
||||
{{ t('settings.pages.modules.consciousness.title') }}
|
||||
</div>
|
||||
</h1>
|
||||
</div>
|
||||
@@ -56,10 +58,10 @@ function updateCustomModelName(value: string) {
|
||||
<div flex="~ col gap-4">
|
||||
<div>
|
||||
<h2 class="text-lg text-neutral-500 md:text-2xl dark:text-neutral-500">
|
||||
Provider
|
||||
{{ t('settings.pages.providers.title') }}
|
||||
</h2>
|
||||
<div text="neutral-400 dark:neutral-400">
|
||||
<span>Select the suitable LLM provider for consciousness</span>
|
||||
<span>{{ t('settings.pages.modules.consciousness.sections.section.provider-model-selection.description') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div max-w-full>
|
||||
@@ -112,10 +114,10 @@ function updateCustomModelName(value: string) {
|
||||
<div flex="~ col gap-4">
|
||||
<div>
|
||||
<h2 class="text-lg md:text-2xl">
|
||||
{{ $t('settings.modules.consciousness.provider-model-selection.title') }}
|
||||
{{ t('settings.pages.modules.consciousness.sections.section.provider-model-selection.title') }}
|
||||
</h2>
|
||||
<div text="neutral-400 dark:neutral-400">
|
||||
<span>{{ $t('settings.modules.consciousness.provider-model-selection.subtitle') }}</span>
|
||||
<span>{{ t('settings.pages.modules.consciousness.sections.section.provider-model-selection.subtitle') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -124,7 +126,7 @@ function updateCustomModelName(value: string) {
|
||||
<div class="mr-2 animate-spin">
|
||||
<div i-solar:spinner-line-duotone text-xl />
|
||||
</div>
|
||||
<span>{{ $t('settings.modules.consciousness.provider-model-selection.loading') }}</span>
|
||||
<span>{{ t('settings.pages.modules.consciousness.sections.section.provider-model-selection.loading') }}</span>
|
||||
</div>
|
||||
|
||||
<!-- Error state -->
|
||||
@@ -134,7 +136,7 @@ function updateCustomModelName(value: string) {
|
||||
>
|
||||
<div i-solar:close-circle-line-duotone class="text-2xl text-red-500 dark:text-red-400" />
|
||||
<div class="flex flex-col">
|
||||
<span class="font-medium">{{ $t('settings.modules.consciousness.provider-model-selection.error') }}</span>
|
||||
<span class="font-medium">{{ t('settings.pages.modules.consciousness.sections.section.provider-model-selection.error') }}</span>
|
||||
<span class="text-sm text-red-600 dark:text-red-400">{{ activeProviderModelError }}</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -146,10 +148,10 @@ function updateCustomModelName(value: string) {
|
||||
>
|
||||
<div i-solar:info-circle-line-duotone class="text-2xl text-amber-500 dark:text-amber-400" />
|
||||
<div class="flex flex-col">
|
||||
<span class="font-medium">{{ $t('settings.modules.consciousness.provider-model-selection.no_models')
|
||||
<span class="font-medium">{{ t('settings.pages.modules.consciousness.sections.section.provider-model-selection.no_models')
|
||||
}}</span>
|
||||
<span class="text-sm text-amber-600 dark:text-amber-400">{{
|
||||
$t('settings.modules.consciousness.provider-model-selection.no_models_description') }}</span>
|
||||
t('settings.pages.modules.consciousness.sections.section.provider-model-selection.no_models_description') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -160,13 +162,13 @@ function updateCustomModelName(value: string) {
|
||||
v-model:search-query="modelSearchQuery"
|
||||
:items="providerModels"
|
||||
:searchable="true"
|
||||
:search-placeholder="$t('settings.modules.consciousness.provider-model-selection.search_placeholder')"
|
||||
:search-no-results-title="$t('settings.modules.consciousness.provider-model-selection.no_search_results')"
|
||||
:search-no-results-description="$t('settings.modules.consciousness.provider-model-selection.no_search_results_description', { query: modelSearchQuery })"
|
||||
:search-results-text="$t('settings.modules.consciousness.provider-model-selection.search_results', { count: '{count}', total: '{total}' })"
|
||||
:custom-input-placeholder="$t('settings.modules.consciousness.provider-model-selection.custom_model_placeholder')"
|
||||
:expand-button-text="$t('settings.modules.consciousness.provider-model-selection.expand')"
|
||||
:collapse-button-text="$t('settings.modules.consciousness.provider-model-selection.collapse')"
|
||||
:search-placeholder="t('settings.pages.modules.consciousness.sections.section.provider-model-selection.search_placeholder')"
|
||||
:search-no-results-title="t('settings.pages.modules.consciousness.sections.section.provider-model-selection.no_search_results')"
|
||||
:search-no-results-description="t('settings.pages.modules.consciousness.sections.section.provider-model-selection.no_search_results_description', { query: modelSearchQuery })"
|
||||
:search-results-text="t('settings.pages.modules.consciousness.sections.section.provider-model-selection.search_results', { count: '{count}', total: '{total}' })"
|
||||
:custom-input-placeholder="t('settings.pages.modules.consciousness.sections.section.provider-model-selection.custom_model_placeholder')"
|
||||
:expand-button-text="t('settings.pages.modules.consciousness.sections.section.provider-model-selection.expand')"
|
||||
:collapse-button-text="t('settings.pages.modules.consciousness.sections.section.provider-model-selection.collapse')"
|
||||
@update:custom-value="updateCustomModelName"
|
||||
/>
|
||||
</template>
|
||||
@@ -178,10 +180,10 @@ function updateCustomModelName(value: string) {
|
||||
<div flex="~ col gap-4">
|
||||
<div>
|
||||
<h2 class="text-lg text-neutral-500 md:text-2xl dark:text-neutral-400">
|
||||
{{ $t('settings.modules.consciousness.provider-model-selection.title') }}
|
||||
{{ t('settings.pages.modules.consciousness.sections.section.provider-model-selection.title') }}
|
||||
</h2>
|
||||
<div text="neutral-400 dark:neutral-500">
|
||||
<span>{{ $t('settings.modules.consciousness.provider-model-selection.subtitle') }}</span>
|
||||
<span>{{ t('settings.pages.modules.consciousness.sections.section.provider-model-selection.subtitle') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -190,22 +192,22 @@ function updateCustomModelName(value: string) {
|
||||
>
|
||||
<div i-solar:info-circle-line-duotone class="text-primary-500 dark:text-primary-400 text-2xl" />
|
||||
<div class="flex flex-col">
|
||||
<span class="font-medium">{{ $t('settings.modules.consciousness.provider-model-selection.not_supported')
|
||||
<span class="font-medium">{{ t('settings.pages.modules.consciousness.sections.section.provider-model-selection.not_supported')
|
||||
}}</span>
|
||||
<span class="dark:text-primary-400 text-primary-600 text-sm">{{
|
||||
$t('settings.modules.consciousness.provider-model-selection.not_supported_description') }}</span>
|
||||
t('settings.pages.modules.consciousness.sections.section.provider-model-selection.not_supported_description') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Manual model input for providers without model listing -->
|
||||
<div class="mt-2">
|
||||
<label class="mb-1 block text-sm font-medium">
|
||||
{{ $t('settings.modules.consciousness.provider-model-selection.manual_model_name') }}
|
||||
{{ t('settings.pages.modules.consciousness.sections.section.provider-model-selection.manual_model_name') }}
|
||||
</label>
|
||||
<input
|
||||
v-model="activeModel" type="text"
|
||||
class="w-full border border-neutral-300 rounded bg-white px-3 py-2 dark:border-neutral-700 dark:bg-neutral-900"
|
||||
:placeholder="$t('settings.modules.consciousness.provider-model-selection.manual_model_placeholder')"
|
||||
:placeholder="t('settings.pages.modules.consciousness.sections.section.provider-model-selection.manual_model_placeholder')"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import { IconStatusItem } from '@proj-airi/stage-ui/components'
|
||||
import { computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const router = useRouter()
|
||||
const { t } = useI18n()
|
||||
|
||||
interface Module {
|
||||
id: string
|
||||
@@ -20,72 +22,72 @@ interface Module {
|
||||
const modulesList = computed<Module[]>(() => [
|
||||
{
|
||||
id: 'consciousness',
|
||||
name: 'Consciousness',
|
||||
description: 'Thinking, vision, speech synthesis, gaming, etc.',
|
||||
name: t('settings.pages.modules.consciousness.title'),
|
||||
description: t('settings.pages.modules.consciousness.description'),
|
||||
icon: 'i-lucide:ghost',
|
||||
to: '/settings/modules/consciousness',
|
||||
configured: false,
|
||||
},
|
||||
{
|
||||
id: 'hearing',
|
||||
name: 'Hearing',
|
||||
description: 'Hearing, speech recognition, etc.',
|
||||
name: t('settings.pages.modules.hearing.title'),
|
||||
description: t('settings.pages.modules.hearing.description'),
|
||||
icon: 'i-lucide:ear',
|
||||
to: '',
|
||||
configured: false,
|
||||
},
|
||||
{
|
||||
id: 'messaging-discord',
|
||||
name: 'Discord',
|
||||
description: 'Messaging, notifications, etc.',
|
||||
name: t('settings.pages.modules.messaging-discord.title'),
|
||||
description: t('settings.pages.modules.messaging-discord.description'),
|
||||
icon: 'i-simple-icons:discord',
|
||||
to: '',
|
||||
configured: false,
|
||||
},
|
||||
{
|
||||
id: 'speech',
|
||||
name: 'Speech',
|
||||
description: 'Speech synthesis, etc.',
|
||||
name: t('settings.pages.modules.speech.title'),
|
||||
description: t('settings.pages.modules.speech.description'),
|
||||
icon: 'i-lucide:mic',
|
||||
to: '/settings/modules/speech',
|
||||
configured: false,
|
||||
},
|
||||
{
|
||||
id: 'memory-short-term',
|
||||
name: 'Short-Term Memory',
|
||||
description: 'Short-term memory, etc.',
|
||||
name: t('settings.pages.modules.memory-short-term.title'),
|
||||
description: t('settings.pages.modules.memory-short-term.description'),
|
||||
icon: 'i-lucide:book',
|
||||
to: '',
|
||||
configured: false,
|
||||
},
|
||||
{
|
||||
id: 'memory-long-term',
|
||||
name: 'Long-Term Memory',
|
||||
description: 'Long-term memory, etc.',
|
||||
name: t('settings.pages.modules.memory-long-term.title'),
|
||||
description: t('settings.pages.modules.memory-long-term.description'),
|
||||
icon: 'i-lucide:book-copy',
|
||||
to: '',
|
||||
configured: false,
|
||||
},
|
||||
{
|
||||
id: 'vision',
|
||||
name: 'Vision',
|
||||
description: 'Vision, etc.',
|
||||
name: t('settings.pages.modules.vision.title'),
|
||||
description: t('settings.pages.modules.vision.description'),
|
||||
icon: 'i-lucide:eye',
|
||||
to: '',
|
||||
configured: false,
|
||||
},
|
||||
{
|
||||
id: 'game-minecraft',
|
||||
name: 'Minecraft',
|
||||
description: 'Playing Minecraft with you, etc.',
|
||||
name: t('settings.pages.modules.gaming-minecraft.title'),
|
||||
description: t('settings.pages.modules.gaming-minecraft.description'),
|
||||
iconColor: 'i-vscode-icons:file-type-minecraft',
|
||||
to: '',
|
||||
configured: false,
|
||||
},
|
||||
{
|
||||
id: 'game-factorio',
|
||||
name: 'Factorio',
|
||||
description: 'Playing Factorio with you, etc.',
|
||||
name: t('settings.pages.modules.gaming-factorio.title'),
|
||||
description: t('settings.pages.modules.gaming-factorio.description'),
|
||||
iconImage: '',
|
||||
to: '',
|
||||
configured: false,
|
||||
@@ -107,10 +109,10 @@ const modulesList = computed<Module[]>(() => [
|
||||
</button>
|
||||
<h1 relative>
|
||||
<div absolute left-0 top-0 translate-y="[-80%]">
|
||||
<span text="neutral-300 dark:neutral-500">Settings</span>
|
||||
<span text="neutral-300 dark:neutral-500">{{ t('settings.title') }}</span>
|
||||
</div>
|
||||
<div text-3xl font-semibold>
|
||||
Modules
|
||||
{{ t('settings.pages.modules.title') }}
|
||||
</div>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
@@ -3,8 +3,10 @@ import { RadioCardDetailManySelect, RadioCardSimple, Range } from '@proj-airi/st
|
||||
import { useProvidersStore, useSpeechStore } from '@proj-airi/stage-ui/stores'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { RouterLink, useRouter } from 'vue-router'
|
||||
|
||||
const { t } = useI18n()
|
||||
const providersStore = useProvidersStore()
|
||||
const speechStore = useSpeechStore()
|
||||
const {
|
||||
@@ -74,7 +76,7 @@ function updateSSMLExample() {
|
||||
</button>
|
||||
<h1 relative>
|
||||
<div absolute left-0 top-0 translate-y="[-80%]">
|
||||
<span text="neutral-300 dark:neutral-500">Modules</span>
|
||||
<span text="neutral-300 dark:neutral-500">{{ t('settings.pages.modules.title') }}</span>
|
||||
</div>
|
||||
<div text-3xl font-semibold>
|
||||
Speech
|
||||
|
||||
@@ -11,8 +11,10 @@ import {
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
@@ -75,21 +77,21 @@ function handleResetSettings() {
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
<ProviderBasicSettings
|
||||
title="Basic"
|
||||
description="Essential settings"
|
||||
: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="Your Cloudflare API token"
|
||||
:placeholder="t('settings.pages.providers.provider.cloudflare-workers-ai.fields.field.api-key.placeholder')"
|
||||
/>
|
||||
|
||||
<ProviderAccountIdInput
|
||||
v-model="accountId"
|
||||
label="Account ID"
|
||||
description="Cloudflare Account ID"
|
||||
placeholder="Your Cloudflare Account ID"
|
||||
:label="t('settings.pages.providers.provider.cloudflare-workers-ai.fields.field.account-id.label')"
|
||||
:description="t('settings.pages.providers.provider.cloudflare-workers-ai.fields.field.account-id.description')"
|
||||
:placeholder="t('settings.pages.providers.provider.cloudflare-workers-ai.fields.field.account-id.placeholder')"
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
</ProviderSettingsContainer>
|
||||
|
||||
@@ -12,8 +12,10 @@ import {
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
@@ -76,8 +78,8 @@ function handleResetSettings() {
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
<ProviderBasicSettings
|
||||
title="Basic"
|
||||
description="Essential settings"
|
||||
:title="t('settings.pages.providers.common.section.basic.title')"
|
||||
:description="t('settings.pages.providers.common.section.basic.description')"
|
||||
:on-reset="handleResetSettings"
|
||||
>
|
||||
<ProviderApiKeyInput
|
||||
@@ -87,7 +89,7 @@ function handleResetSettings() {
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
|
||||
<ProviderAdvancedSettings title="Advanced">
|
||||
<ProviderAdvancedSettings :title="t('settings.pages.providers.common.section.advanced.title')">
|
||||
<ProviderBaseUrlInput
|
||||
v-model="baseUrl"
|
||||
placeholder="https://api.deepseek.com/v1/"
|
||||
|
||||
@@ -19,8 +19,10 @@ import { useProvidersStore, useSpeechStore } from '@proj-airi/stage-ui/stores'
|
||||
import { generateSpeech } from '@xsai/generate-speech'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providersStore = useProvidersStore()
|
||||
const speechStore = useSpeechStore()
|
||||
@@ -245,78 +247,64 @@ function handleResetVoiceSettings() {
|
||||
|
||||
<template>
|
||||
<ProviderSettingsLayout
|
||||
:provider-name="providerMetadata?.localizedName"
|
||||
:provider-icon="providerMetadata?.icon"
|
||||
:provider-name="providerMetadata?.localizedName" :provider-icon="providerMetadata?.icon"
|
||||
:on-back="() => router.back()"
|
||||
>
|
||||
<div flex="~ col md:row gap-6">
|
||||
<ProviderSettingsContainer class="w-full md:w-[40%]">
|
||||
<ProviderBasicSettings
|
||||
title="Basic"
|
||||
description="Essential settings"
|
||||
:title="t('settings.pages.providers.common.section.basic.title')"
|
||||
:description="t('settings.pages.providers.common.section.basic.description')"
|
||||
:on-reset="handleResetVoiceSettings"
|
||||
>
|
||||
<ProviderApiKeyInput
|
||||
v-model="apiKey"
|
||||
:provider-name="providerMetadata?.localizedName"
|
||||
placeholder="sk-"
|
||||
/>
|
||||
<ProviderApiKeyInput v-model="apiKey" :provider-name="providerMetadata?.localizedName" placeholder="sk-" />
|
||||
</ProviderBasicSettings>
|
||||
|
||||
<div flex="~ col gap-6">
|
||||
<h2 class="text-lg text-neutral-500 md:text-2xl dark:text-neutral-400">
|
||||
Voice Settings
|
||||
{{ t('settings.pages.providers.common.section.voice.title') }}
|
||||
</h2>
|
||||
<div flex="~ col gap-4">
|
||||
<FieldRange
|
||||
v-model="similarityBoost"
|
||||
label="Similarity Boost"
|
||||
description="Voice similarity adherence"
|
||||
:min="0"
|
||||
:max="1"
|
||||
:step="0.01"
|
||||
:label="t('settings.pages.providers.provider.elevenlabs.fields.field.simularity-boost.label')"
|
||||
:description="t('settings.pages.providers.provider.elevenlabs.fields.field.simularity-boost.description')"
|
||||
:min="0" :max="1" :step="0.01"
|
||||
/>
|
||||
|
||||
<FieldRange
|
||||
v-model="stability"
|
||||
label="Stability"
|
||||
description="Voice stability and randomness"
|
||||
:min="0"
|
||||
:max="1"
|
||||
:step="0.01"
|
||||
:label="t('settings.pages.providers.provider.elevenlabs.fields.field.stability.label')"
|
||||
:description="t('settings.pages.providers.provider.elevenlabs.fields.field.stability.description')"
|
||||
:min="0" :max="1" :step="0.01"
|
||||
/>
|
||||
|
||||
<FieldRange
|
||||
v-model="speed"
|
||||
label="Speed"
|
||||
description="Speech generation speed"
|
||||
:min="0.7"
|
||||
:max="1.2"
|
||||
:step="0.01"
|
||||
:label="t('settings.pages.providers.provider.elevenlabs.fields.field.speed.label')"
|
||||
:description="t('settings.pages.providers.provider.elevenlabs.fields.field.speed.description')" :min="0.7"
|
||||
:max="1.2" :step="0.01"
|
||||
/>
|
||||
|
||||
<FieldRange
|
||||
v-model="style"
|
||||
label="Style"
|
||||
description="Voice style exaggeration"
|
||||
:min="0"
|
||||
:max="1"
|
||||
:step="0.01"
|
||||
:label="t('settings.pages.providers.provider.elevenlabs.fields.field.style.label')"
|
||||
:description="t('settings.pages.providers.provider.elevenlabs.fields.field.style.description')" :min="0"
|
||||
:max="1" :step="0.01"
|
||||
/>
|
||||
|
||||
<FieldCheckbox
|
||||
v-model="useSpeakerBoost"
|
||||
label="Speaker Boost"
|
||||
description="Enhance speaker similarity"
|
||||
:label="t('settings.pages.providers.provider.elevenlabs.fields.field.speaker-boost.label')"
|
||||
:description="t('settings.pages.providers.provider.elevenlabs.fields.field.speaker-boost.description')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ProviderAdvancedSettings title="Advanced">
|
||||
<ProviderAdvancedSettings :title="t('settings.pages.providers.common.section.advanced.title')">
|
||||
<ProviderBaseUrlInput
|
||||
v-model="baseUrl"
|
||||
:placeholder="providerMetadata?.defaultOptions?.baseUrl as string || ''"
|
||||
required
|
||||
:placeholder="providerMetadata?.defaultOptions?.baseUrl as string || ''" required
|
||||
/>
|
||||
</ProviderAdvancedSettings>
|
||||
</ProviderSettingsContainer>
|
||||
@@ -324,31 +312,32 @@ function handleResetVoiceSettings() {
|
||||
<div flex="~ col gap-6" class="w-full md:w-[60%]">
|
||||
<div rounded-xl>
|
||||
<h2 class="mb-4 text-lg text-neutral-500 md:text-2xl dark:text-neutral-400">
|
||||
Voice Playground
|
||||
{{ t('settings.pages.providers.provider.elevenlabs.playground.title') }}
|
||||
</h2>
|
||||
<div flex="~ col gap-4">
|
||||
<textarea
|
||||
v-model="testText" placeholder="Enter text to test the voice..."
|
||||
v-model="testText"
|
||||
:placeholder="t('settings.pages.providers.provider.elevenlabs.playground.fields.field.input.placeholder')"
|
||||
border="neutral-100 dark:neutral-800 solid 2 focus:neutral-200 dark:focus:neutral-700"
|
||||
transition="all duration-250 ease-in-out"
|
||||
h-24 w-full rounded-lg px-3 py-2 text-sm outline-none
|
||||
bg="neutral-100 dark:neutral-800 focus:neutral-50 dark:focus:neutral-900"
|
||||
h-24 w-full rounded-lg px-3 py-2 text-sm outline-none
|
||||
/>
|
||||
<div flex="~ col gap-6">
|
||||
<label grid="~ cols-2 gap-4">
|
||||
<div>
|
||||
<div class="flex items-center gap-1 text-sm font-medium">
|
||||
Language
|
||||
{{ t('settings.pages.providers.provider.elevenlabs.playground.fields.field.language.label') }}
|
||||
</div>
|
||||
<div class="text-xs text-neutral-500 dark:text-neutral-400">
|
||||
Select voice language
|
||||
{{ t('settings.pages.providers.provider.elevenlabs.playground.fields.field.language.description') }}
|
||||
</div>
|
||||
</div>
|
||||
<select
|
||||
v-model="selectedLanguage"
|
||||
border="neutral-300 dark:neutral-800 solid 2 focus:neutral-400 dark:focus:neutral-600"
|
||||
transition="border duration-250 ease-in-out"
|
||||
w-full rounded-lg px-2 py-1 text-nowrap text-sm outline-none
|
||||
transition="border duration-250 ease-in-out" w-full rounded-lg px-2 py-1 text-nowrap text-sm
|
||||
outline-none
|
||||
>
|
||||
<option v-for="language in speechStore.availableLanguages" :key="language" :value="language">
|
||||
{{ language }}
|
||||
@@ -359,17 +348,17 @@ function handleResetVoiceSettings() {
|
||||
<label grid="~ cols-2 gap-4">
|
||||
<div>
|
||||
<div class="flex items-center gap-1 text-sm font-medium">
|
||||
Voice
|
||||
{{ t('settings.pages.providers.provider.elevenlabs.playground.fields.field.voice.label') }}
|
||||
</div>
|
||||
<div class="text-xs text-neutral-500 dark:text-neutral-400">
|
||||
Select preferred voice
|
||||
{{ t('settings.pages.providers.provider.elevenlabs.playground.fields.field.voice.description') }}
|
||||
</div>
|
||||
</div>
|
||||
<select
|
||||
v-model="selectedVoice"
|
||||
border="neutral-300 dark:neutral-800 solid 2 focus:neutral-400 dark:focus:neutral-600"
|
||||
transition="border duration-250 ease-in-out"
|
||||
w-full rounded-lg px-2 py-1 text-nowrap text-sm outline-none
|
||||
transition="border duration-250 ease-in-out" w-full rounded-lg px-2 py-1 text-nowrap text-sm
|
||||
outline-none
|
||||
>
|
||||
<option v-for="voice in availableVoices" :key="voice.id" :value="voice.name">
|
||||
{{ voice.name }}
|
||||
@@ -379,16 +368,15 @@ function handleResetVoiceSettings() {
|
||||
</div>
|
||||
<div flex="~ row" gap-4>
|
||||
<button
|
||||
border="neutral-800 dark:neutral-200 solid 2"
|
||||
transition="border duration-250 ease-in-out" rounded-lg px-4
|
||||
text="neutral-100 dark:neutral-900"
|
||||
py-2 text-sm :disabled="isGenerating || !testText.trim() || !apiKey"
|
||||
border="neutral-800 dark:neutral-200 solid 2" transition="border duration-250 ease-in-out"
|
||||
rounded-lg px-4 text="neutral-100 dark:neutral-900" py-2 text-sm
|
||||
:disabled="isGenerating || !testText.trim() || !apiKey"
|
||||
:class="{ 'opacity-50 cursor-not-allowed': isGenerating || !testText.trim() || !apiKey }"
|
||||
bg="neutral-700 dark:neutral-300" @click="generateTestSpeech"
|
||||
>
|
||||
<div flex="~ row" items-center gap-2>
|
||||
<div i-solar:play-circle-bold-duotone />
|
||||
<span>{{ isGenerating ? 'Generating...' : 'Test Voice' }}</span>
|
||||
<span>{{ isGenerating ? t('settings.pages.providers.provider.elevenlabs.playground.buttons.button.test-voice.generating') : t('settings.pages.providers.provider.elevenlabs.playground.buttons.button.test-voice.label') }}</span>
|
||||
</div>
|
||||
</button>
|
||||
<button
|
||||
@@ -402,7 +390,7 @@ function handleResetVoiceSettings() {
|
||||
</button>
|
||||
</div>
|
||||
<div v-if="!apiKey" class="mt-2 text-sm text-red-500">
|
||||
Please enter an API key to test the voice.
|
||||
{{ t('settings.pages.providers.provider.elevenlabs.playground.validation.error-missing-api-key') }}
|
||||
</div>
|
||||
<div v-if="errorMessage" class="mt-2 text-sm text-red-500">
|
||||
{{ errorMessage }}
|
||||
|
||||
@@ -12,8 +12,10 @@ import {
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
@@ -76,8 +78,8 @@ function handleResetSettings() {
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
<ProviderBasicSettings
|
||||
title="Basic"
|
||||
description="Essential settings"
|
||||
:title="t('settings.pages.providers.common.section.basic.title')"
|
||||
:description="t('settings.pages.providers.common.section.basic.description')"
|
||||
:on-reset="handleResetSettings"
|
||||
>
|
||||
<ProviderApiKeyInput
|
||||
@@ -87,7 +89,7 @@ function handleResetSettings() {
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
|
||||
<ProviderAdvancedSettings title="Advanced">
|
||||
<ProviderAdvancedSettings :title="t('settings.pages.providers.common.section.advanced.title')">
|
||||
<ProviderBaseUrlInput
|
||||
v-model="baseUrl"
|
||||
placeholder="https://api.fireworks.ai/inference/v1/"
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
import { IconStatusItem } from '@proj-airi/stage-ui/components'
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providersStore = useProvidersStore()
|
||||
const { allProvidersMetadata } = storeToRefs(providersStore)
|
||||
@@ -23,10 +25,10 @@ const { allProvidersMetadata } = storeToRefs(providersStore)
|
||||
</button>
|
||||
<h1 relative>
|
||||
<div absolute left-0 top-0 translate-y="[-80%]">
|
||||
<span text="neutral-300 dark:neutral-500">Settings</span>
|
||||
<span text="neutral-300 dark:neutral-500">{{ t('settings.title') }}</span>
|
||||
</div>
|
||||
<div text-3xl font-semibold>
|
||||
Providers
|
||||
{{ t('settings.pages.providers.title') }}
|
||||
</div>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
@@ -12,8 +12,10 @@ import {
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
@@ -76,8 +78,8 @@ function handleResetSettings() {
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
<ProviderBasicSettings
|
||||
title="Basic"
|
||||
description="Essential settings"
|
||||
:title="t('settings.pages.providers.common.section.basic.title')"
|
||||
:description="t('settings.pages.providers.common.section.basic.description')"
|
||||
:on-reset="handleResetSettings"
|
||||
>
|
||||
<ProviderApiKeyInput
|
||||
@@ -87,7 +89,7 @@ function handleResetSettings() {
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
|
||||
<ProviderAdvancedSettings title="Advanced">
|
||||
<ProviderAdvancedSettings :title="t('settings.pages.providers.common.section.advanced.title')">
|
||||
<ProviderBaseUrlInput
|
||||
v-model="baseUrl"
|
||||
placeholder="https://api.mistral.ai/v1/"
|
||||
|
||||
@@ -12,8 +12,10 @@ import {
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
@@ -76,8 +78,8 @@ function handleResetSettings() {
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
<ProviderBasicSettings
|
||||
title="Basic"
|
||||
description="Essential settings"
|
||||
:title="t('settings.pages.providers.common.section.basic.title')"
|
||||
:description="t('settings.pages.providers.common.section.basic.description')"
|
||||
:on-reset="handleResetSettings"
|
||||
>
|
||||
<ProviderApiKeyInput
|
||||
@@ -87,7 +89,7 @@ function handleResetSettings() {
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
|
||||
<ProviderAdvancedSettings title="Advanced">
|
||||
<ProviderAdvancedSettings :title="t('settings.pages.providers.common.section.advanced.title')">
|
||||
<ProviderBaseUrlInput
|
||||
v-model="baseUrl"
|
||||
placeholder="https://api.moonshot.cn/v1/"
|
||||
|
||||
@@ -12,8 +12,10 @@ import {
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
@@ -76,8 +78,8 @@ function handleResetSettings() {
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
<ProviderBasicSettings
|
||||
title="Basic"
|
||||
description="Essential settings"
|
||||
:title="t('settings.pages.providers.common.section.basic.title')"
|
||||
:description="t('settings.pages.providers.common.section.basic.description')"
|
||||
:on-reset="handleResetSettings"
|
||||
>
|
||||
<ProviderApiKeyInput
|
||||
@@ -87,7 +89,7 @@ function handleResetSettings() {
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
|
||||
<ProviderAdvancedSettings title="Advanced">
|
||||
<ProviderAdvancedSettings :title="t('settings.pages.providers.common.section.advanced.title')">
|
||||
<ProviderBaseUrlInput
|
||||
v-model="baseUrl"
|
||||
placeholder="https://api.novita.ai/v1/"
|
||||
|
||||
@@ -12,8 +12,10 @@ import {
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, reactive, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
@@ -92,8 +94,8 @@ watch(headers, (headers) => {
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
<ProviderBasicSettings
|
||||
title="Basic"
|
||||
description="Essential settings"
|
||||
:title="t('settings.pages.providers.common.section.basic.title')"
|
||||
:description="t('settings.pages.providers.common.section.basic.description')"
|
||||
:on-reset="handleResetSettings"
|
||||
>
|
||||
<ProviderBaseUrlInput
|
||||
@@ -103,13 +105,13 @@ watch(headers, (headers) => {
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
|
||||
<ProviderAdvancedSettings title="Advanced">
|
||||
<ProviderAdvancedSettings :title="t('settings.pages.providers.common.section.advanced.title')">
|
||||
<FieldKeyValues
|
||||
v-model="headers"
|
||||
label="HTTP Headers"
|
||||
description="Add custom HTTP headers"
|
||||
key-placeholder="Key"
|
||||
value-placeholder="Value"
|
||||
:label="t('settings.pages.providers.common.section.advanced.fields.field.headers.label')"
|
||||
:description="t('settings.pages.providers.common.section.advanced.fields.field.headers.description')"
|
||||
:key-placeholder="t('settings.pages.providers.common.section.advanced.fields.field.headers.key.placeholder')"
|
||||
:value-placeholder="t('settings.pages.providers.common.section.advanced.fields.field.headers.value.placeholder')"
|
||||
@add="(key, value) => addKeyValue(headers, key, value)"
|
||||
@remove="(index) => removeKeyValue(index, headers)"
|
||||
/>
|
||||
|
||||
@@ -12,8 +12,10 @@ import {
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
@@ -80,8 +82,8 @@ function handleResetSettings() {
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
<ProviderBasicSettings
|
||||
title="Basic"
|
||||
description="Essential settings"
|
||||
:title="t('settings.pages.providers.common.section.basic.title')"
|
||||
:description="t('settings.pages.providers.common.section.basic.description')"
|
||||
:on-reset="handleResetSettings"
|
||||
>
|
||||
<ProviderApiKeyInput
|
||||
@@ -91,7 +93,7 @@ function handleResetSettings() {
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
|
||||
<ProviderAdvancedSettings title="Advanced">
|
||||
<ProviderAdvancedSettings :title="t('settings.pages.providers.common.section.advanced.title')">
|
||||
<ProviderBaseUrlInput
|
||||
v-model="baseUrl"
|
||||
placeholder="https://api.openai.com/v1/"
|
||||
|
||||
@@ -12,8 +12,10 @@ import {
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
@@ -75,8 +77,8 @@ function handleResetSettings() {
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
<ProviderBasicSettings
|
||||
title="Basic"
|
||||
description="Essential settings"
|
||||
:title="t('settings.pages.providers.common.section.basic.title')"
|
||||
:description="t('settings.pages.providers.common.section.basic.description')"
|
||||
:on-reset="handleResetSettings"
|
||||
>
|
||||
<ProviderApiKeyInput
|
||||
@@ -86,7 +88,7 @@ function handleResetSettings() {
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
|
||||
<ProviderAdvancedSettings title="Advanced">
|
||||
<ProviderAdvancedSettings :title="t('settings.pages.providers.common.section.advanced.title')">
|
||||
<ProviderBaseUrlInput
|
||||
v-model="baseUrl"
|
||||
:placeholder="providerMetadata?.defaultOptions?.baseUrl as string || ''"
|
||||
|
||||
@@ -12,8 +12,10 @@ import {
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
@@ -76,8 +78,8 @@ function handleResetSettings() {
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
<ProviderBasicSettings
|
||||
title="Basic"
|
||||
description="Essential settings"
|
||||
:title="t('settings.pages.providers.common.section.basic.title')"
|
||||
:description="t('settings.pages.providers.common.section.basic.description')"
|
||||
:on-reset="handleResetSettings"
|
||||
>
|
||||
<ProviderApiKeyInput
|
||||
@@ -87,7 +89,7 @@ function handleResetSettings() {
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
|
||||
<ProviderAdvancedSettings title="Advanced">
|
||||
<ProviderAdvancedSettings :title="t('settings.pages.providers.common.section.advanced.title')">
|
||||
<ProviderBaseUrlInput
|
||||
v-model="baseUrl"
|
||||
placeholder="https://api.together.xyz/v1/"
|
||||
|
||||
@@ -12,8 +12,10 @@ import {
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
@@ -76,8 +78,8 @@ function handleResetSettings() {
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
<ProviderBasicSettings
|
||||
title="Basic"
|
||||
description="Essential settings"
|
||||
:title="t('settings.pages.providers.common.section.basic.title')"
|
||||
:description="t('settings.pages.providers.common.section.basic.description')"
|
||||
:on-reset="handleResetSettings"
|
||||
>
|
||||
<ProviderApiKeyInput
|
||||
@@ -87,7 +89,7 @@ function handleResetSettings() {
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
|
||||
<ProviderAdvancedSettings title="Advanced">
|
||||
<ProviderAdvancedSettings :title="t('settings.pages.providers.common.section.advanced.title')">
|
||||
<ProviderBaseUrlInput
|
||||
v-model="baseUrl"
|
||||
placeholder="https://api.x.ai/v1/"
|
||||
|
||||
@@ -3,8 +3,11 @@ import { Collapsable } from '@proj-airi/stage-ui/components'
|
||||
import { DEFAULT_THEME_COLORS_HUE, useSettings } from '@proj-airi/stage-ui/stores'
|
||||
import { converter } from 'culori'
|
||||
import { TooltipArrow, TooltipContent, TooltipPortal, TooltipProvider, TooltipRoot, TooltipTrigger } from 'radix-vue'
|
||||
import { computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const settings = useSettings()
|
||||
|
||||
@@ -17,10 +20,10 @@ interface ColorPreset {
|
||||
}>
|
||||
}
|
||||
|
||||
const colorPresets: ColorPreset[] = [
|
||||
const colorPresets = computed<ColorPreset[]>(() => [
|
||||
{
|
||||
name: 'Morandi Colors',
|
||||
description: 'Soft, muted tones inspired by Giorgio Morandi\'s paintings',
|
||||
name: t('settings.pages.themes.sections.section.theme-presets.preset.morandi.title'),
|
||||
description: t('settings.pages.themes.sections.section.theme-presets.preset.morandi.description'),
|
||||
colors: [
|
||||
{ hex: '#A5978B', name: 'Taupe' },
|
||||
{ hex: '#D8CAAF', name: 'Beige' },
|
||||
@@ -33,8 +36,8 @@ const colorPresets: ColorPreset[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Monet Colors',
|
||||
description: 'Impressionist palette inspired by Claude Monet\'s works',
|
||||
name: t('settings.pages.themes.sections.section.theme-presets.preset.monet.title'),
|
||||
description: t('settings.pages.themes.sections.section.theme-presets.preset.monet.description'),
|
||||
colors: [
|
||||
{ hex: '#7A9EAF', name: 'Sky Blue' },
|
||||
{ hex: '#B8C7CC', name: 'Mist' },
|
||||
@@ -47,8 +50,8 @@ const colorPresets: ColorPreset[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Japanese Colors',
|
||||
description: 'Traditional Japanese color palette',
|
||||
name: t('settings.pages.themes.sections.section.theme-presets.preset.japanese.title'),
|
||||
description: t('settings.pages.themes.sections.section.theme-presets.preset.japanese.description'),
|
||||
colors: [
|
||||
{ hex: '#D9B48F', name: 'Tan' },
|
||||
{ hex: '#B5917A', name: 'Warm Taupe' },
|
||||
@@ -61,8 +64,8 @@ const colorPresets: ColorPreset[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Nordic Colors',
|
||||
description: 'Scandinavian minimalist color scheme',
|
||||
name: t('settings.pages.themes.sections.section.theme-presets.preset.nordic.title'),
|
||||
description: t('settings.pages.themes.sections.section.theme-presets.preset.nordic.description'),
|
||||
colors: [
|
||||
{ hex: '#9BA7B0', name: 'Nordic Blue' },
|
||||
{ hex: '#C1CBD4', name: 'Ice' },
|
||||
@@ -75,8 +78,8 @@ const colorPresets: ColorPreset[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Chinese Traditional Colors',
|
||||
description: 'Traditional Chinese colors, derived from ancient textiles, porcelain and paintings',
|
||||
name: t('settings.pages.themes.sections.section.theme-presets.preset.chinese.title'),
|
||||
description: t('settings.pages.themes.sections.section.theme-presets.preset.chinese.description'),
|
||||
colors: [
|
||||
{ hex: '#E4C6D0', name: '霞光红 (Rosy Dawn)' },
|
||||
{ hex: '#A61B29', name: '枣红 (Chinese Red)' },
|
||||
@@ -88,7 +91,7 @@ const colorPresets: ColorPreset[] = [
|
||||
{ hex: '#8C4B3C', name: '赭石 (Ochre)' },
|
||||
],
|
||||
},
|
||||
]
|
||||
])
|
||||
|
||||
function resetToDefault() {
|
||||
settings.themeColorsHue = DEFAULT_THEME_COLORS_HUE
|
||||
@@ -148,10 +151,10 @@ function isColorSelected(hexColor: string): boolean {
|
||||
</button>
|
||||
<h1 relative>
|
||||
<div absolute left-0 top-0 translate-y="[-80%]">
|
||||
<span text="neutral-300 dark:neutral-500">Settings</span>
|
||||
<span text="neutral-300 dark:neutral-500">{{ t('settings.title') }}</span>
|
||||
</div>
|
||||
<div text-3xl font-semibold>
|
||||
Themes
|
||||
{{ t('settings.pages.themes.title') }}
|
||||
</div>
|
||||
</h1>
|
||||
</div>
|
||||
@@ -173,7 +176,7 @@ function isColorSelected(hexColor: string): boolean {
|
||||
transition="filter duration-250 ease-in-out"
|
||||
/>
|
||||
<div>
|
||||
Custom Colors
|
||||
{{ t('settings.pages.themes.sections.section.custom-color.title') }}
|
||||
</div>
|
||||
</div>
|
||||
<div transform transition="transform duration-250" :class="{ 'rotate-180': slotProps.visible }">
|
||||
@@ -183,7 +186,7 @@ function isColorSelected(hexColor: string): boolean {
|
||||
</template>
|
||||
<div p-4>
|
||||
<div class="mb-2 text-sm font-medium">
|
||||
Primary color
|
||||
{{ t('settings.pages.themes.sections.section.custom-color.fields.field.primary-color.label') }}
|
||||
</div>
|
||||
|
||||
<div flex="~ col gap-4">
|
||||
@@ -281,14 +284,14 @@ function isColorSelected(hexColor: string): boolean {
|
||||
<div
|
||||
class="peer-checked:bg-primary-500 h-6 w-11 rounded-full bg-neutral-200 after:absolute after:left-[2px] after:top-[2px] after:h-5 after:w-5 after:rounded-full after:bg-white dark:bg-neutral-600 after:transition-all after:content-[''] peer-checked:after:translate-x-full peer-checked:after:border-white"
|
||||
/>
|
||||
<span class="ml-2 text-sm font-medium">I Want It Dynamic!</span>
|
||||
<span class="ml-2 text-sm font-medium">{{ t('settings.pages.themes.sections.section.custom-color.fields.field.primary-color.rgb-on.title') }}</span>
|
||||
</label>
|
||||
|
||||
<button
|
||||
class="rounded-md bg-neutral-100 px-3 py-1.5 text-sm transition-colors dark:bg-neutral-800 hover:bg-neutral-200 dark:hover:bg-neutral-700"
|
||||
@click="resetToDefault"
|
||||
>
|
||||
Reset to Default
|
||||
{{ t('settings.pages.themes.sections.section.custom-color.fields.field.primary-color.reset.label') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -310,7 +313,7 @@ function isColorSelected(hexColor: string): boolean {
|
||||
transition="filter duration-250 ease-in-out"
|
||||
/>
|
||||
<div>
|
||||
Theme Presets
|
||||
{{ t('settings.pages.themes.sections.section.theme-presets.title') }}
|
||||
</div>
|
||||
</div>
|
||||
<div transform transition="transform duration-250" :class="{ 'rotate-180': slotProps.visible }">
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import { useSettings } from '../../stores'
|
||||
import Live2DCanvas from '../Live2D/Canvas.vue'
|
||||
@@ -15,6 +16,7 @@ withDefaults(defineProps<{
|
||||
mouthOpenSize: 0,
|
||||
})
|
||||
|
||||
const { t } = useI18n()
|
||||
const show = ref(false)
|
||||
const { live2dCurrentMotion } = storeToRefs(useSettings())
|
||||
</script>
|
||||
@@ -49,50 +51,50 @@ const { live2dCurrentMotion } = storeToRefs(useSettings())
|
||||
<div v-if="show" min-w="50vw" z="<md:20" class="bottom-11 right-0" absolute m-1 w-full>
|
||||
<div bg="zinc-200/20 dark:black/20" rounded-lg p-2 backdrop-blur-sm>
|
||||
<div font-mono>
|
||||
<span>{{ $t('stage.viewers.debug-menu.emotions') }}</span>
|
||||
<span>{{ t('stage.viewers.debug-menu.emotions') }}</span>
|
||||
</div>
|
||||
<div flex="~ row" flex-wrap gap-2>
|
||||
<button
|
||||
rounded-lg bg="zinc-100/70 dark:zinc-800/50" px-2 py-1 backdrop-blur-sm
|
||||
@click="live2dCurrentMotion = { group: 'Surprise', index: 0 }"
|
||||
>
|
||||
{{ $t('stage.viewers.debug-menu.emotions-btn.surprised') }}
|
||||
{{ t('stage.viewers.debug-menu.emotions-btn.surprised') }}
|
||||
</button>
|
||||
<button
|
||||
rounded-lg bg="zinc-100/70 dark:zinc-800/50" px-2 py-1 backdrop-blur-sm
|
||||
@click="live2dCurrentMotion = { group: 'Sad', index: 0 }"
|
||||
>
|
||||
{{ $t('stage.viewers.debug-menu.emotions-btn.sad') }}
|
||||
{{ t('stage.viewers.debug-menu.emotions-btn.sad') }}
|
||||
</button>
|
||||
<button
|
||||
rounded-lg bg="zinc-100/70 dark:zinc-800/50" px-2 py-1 backdrop-blur-sm
|
||||
@click="live2dCurrentMotion = { group: 'Angry', index: 0 }"
|
||||
>
|
||||
{{ $t('stage.viewers.debug-menu.emotions-btn.angry') }}
|
||||
{{ t('stage.viewers.debug-menu.emotions-btn.angry') }}
|
||||
</button>
|
||||
<button
|
||||
rounded-lg bg="zinc-100/70 dark:zinc-800/50" px-2 py-1 backdrop-blur-sm
|
||||
@click="live2dCurrentMotion = { group: 'Happy', index: 0 }"
|
||||
>
|
||||
{{ $t('stage.viewers.debug-menu.emotions-btn.happy') }}
|
||||
{{ t('stage.viewers.debug-menu.emotions-btn.happy') }}
|
||||
</button>
|
||||
<button
|
||||
rounded-lg bg="zinc-100/70 dark:zinc-800/50" px-2 py-1 backdrop-blur-sm
|
||||
@click="live2dCurrentMotion = { group: 'Awkward', index: 0 }"
|
||||
>
|
||||
{{ $t('stage.viewers.debug-menu.emotions-btn.awkward') }}
|
||||
{{ t('stage.viewers.debug-menu.emotions-btn.awkward') }}
|
||||
</button>
|
||||
<button
|
||||
rounded-lg bg="zinc-100/70 dark:zinc-800/50" px-2 py-1 backdrop-blur-sm
|
||||
@click="live2dCurrentMotion = { group: 'Question', index: 0 }"
|
||||
>
|
||||
{{ $t('stage.viewers.debug-menu.emotions-btn.question') }}
|
||||
{{ t('stage.viewers.debug-menu.emotions-btn.question') }}
|
||||
</button>
|
||||
<button
|
||||
rounded-lg bg="zinc-100/70 dark:zinc-800/50" px-2 py-1 backdrop-blur-sm
|
||||
@click="live2dCurrentMotion = { group: 'Think', index: 0 }"
|
||||
>
|
||||
{{ $t('stage.viewers.debug-menu.emotions-btn.think') }}
|
||||
{{ t('stage.viewers.debug-menu.emotions-btn.think') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { OrbitControls } from '@tresjs/cientos'
|
||||
import { TresCanvas } from '@tresjs/core'
|
||||
import { ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import Collapsable from '../Collapsable.vue'
|
||||
import DataGuiRange from '../DataGui/Range.vue'
|
||||
@@ -33,6 +34,8 @@ const modelRef = ref<{
|
||||
setExpression: (expression: string) => void
|
||||
}>()
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
defineExpose({
|
||||
setExpression: (expression: string) => {
|
||||
modelRef.value?.setExpression(expression)
|
||||
@@ -82,11 +85,11 @@ defineExpose({
|
||||
<div v-if="show" min-w="50vw" z="<md:20" class="bottom-11 right-0" absolute m-1 w-full>
|
||||
<div bg="zinc-200/20 dark:black/20" flex="~ col" gap-2 rounded-lg p-2 backdrop-blur-sm>
|
||||
<div font-mono>
|
||||
<span>{{ $t('stage.viewers.debug-menu.vrm.model.title') }}</span>
|
||||
<span>{{ t('stage.viewers.debug-menu.vrm.model.title') }}</span>
|
||||
</div>
|
||||
<Collapsable h-fit w-full flex="~ col" border="~ gray/25 rounded-lg" divide="y dashed gray/25" of-clip shadow-sm>
|
||||
<template #label>
|
||||
<span font-mono>{{ $t('stage.viewers.debug-menu.vrm.camera') }}</span>
|
||||
<span font-mono>{{ t('stage.viewers.debug-menu.vrm.camera') }}</span>
|
||||
</template>
|
||||
<div grid="~ cols-[20px_1fr_60px]" w-full gap-1 p-2 text-sm font-mono>
|
||||
<div text="zinc-400 dark:zinc-500">
|
||||
@@ -122,7 +125,7 @@ defineExpose({
|
||||
</Collapsable>
|
||||
<Collapsable h-fit w-full flex="~ col" border="~ gray/25 rounded-lg" divide="y dashed gray/25" of-clip shadow-sm>
|
||||
<template #label>
|
||||
<span font-mono>{{ $t('stage.viewers.debug-menu.vrm.model.title') }}</span>
|
||||
<span font-mono>{{ t('stage.viewers.debug-menu.vrm.model.title') }}</span>
|
||||
</template>
|
||||
<div grid="~ cols-[20px_1fr_60px]" w-full gap-1 p-2 text-sm font-mono>
|
||||
<div text="zinc-400 dark:zinc-500">
|
||||
@@ -158,38 +161,38 @@ defineExpose({
|
||||
</div>
|
||||
</Collapsable>
|
||||
<div font-mono>
|
||||
<span>{{ $t('stage.viewers.debug-menu.emotions') }}</span>
|
||||
<span>{{ t('stage.viewers.debug-menu.emotions') }}</span>
|
||||
</div>
|
||||
<div flex="~ row" w-full flex-wrap gap-2>
|
||||
<button
|
||||
rounded-lg bg="zinc-100/70 dark:zinc-800/50" px-2 py-1 backdrop-blur-sm
|
||||
@click="modelRef?.setExpression('neutral')"
|
||||
>
|
||||
{{ $t('stage.viewers.debug-menu.emotions-btn.neutral') }}
|
||||
{{ t('stage.viewers.debug-menu.emotions-btn.neutral') }}
|
||||
</button>
|
||||
<button
|
||||
rounded-lg bg="zinc-100/70 dark:zinc-800/50" px-2 py-1 backdrop-blur-sm
|
||||
@click="modelRef?.setExpression('surprised')"
|
||||
>
|
||||
{{ $t('stage.viewers.debug-menu.emotions-btn.surprised') }}
|
||||
{{ t('stage.viewers.debug-menu.emotions-btn.surprised') }}
|
||||
</button>
|
||||
<button
|
||||
rounded-lg bg="zinc-100/70 dark:zinc-800/50" px-2 py-1 backdrop-blur-sm
|
||||
@click="modelRef?.setExpression('sad')"
|
||||
>
|
||||
{{ $t('stage.viewers.debug-menu.emotions-btn.sad') }}
|
||||
{{ t('stage.viewers.debug-menu.emotions-btn.sad') }}
|
||||
</button>
|
||||
<button
|
||||
rounded-lg bg="zinc-100/70 dark:zinc-800/50" px-2 py-1 backdrop-blur-sm
|
||||
@click="modelRef?.setExpression('angry')"
|
||||
>
|
||||
{{ $t('stage.viewers.debug-menu.emotions-btn.angry') }}
|
||||
{{ t('stage.viewers.debug-menu.emotions-btn.angry') }}
|
||||
</button>
|
||||
<button
|
||||
rounded-lg bg="zinc-100/70 dark:zinc-800/50" px-2 py-1 backdrop-blur-sm
|
||||
@click="modelRef?.setExpression('happy')"
|
||||
>
|
||||
{{ $t('stage.viewers.debug-menu.emotions-btn.happy') }}
|
||||
{{ t('stage.viewers.debug-menu.emotions-btn.happy') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -118,9 +118,9 @@ export const useProvidersStore = defineStore('providers', () => {
|
||||
const providerMetadata: Record<string, ProviderMetadata> = {
|
||||
'openrouter-ai': {
|
||||
id: 'openrouter-ai',
|
||||
nameKey: 'providers.openrouter.name',
|
||||
nameKey: 'settings.pages.providers.provider.openrouter.title',
|
||||
name: 'OpenRouter',
|
||||
descriptionKey: 'providers.openrouter.description',
|
||||
descriptionKey: 'settings.pages.providers.provider.openrouter.description',
|
||||
description: 'openrouter.ai',
|
||||
icon: 'i-lobe-icons:openrouter',
|
||||
defaultOptions: {
|
||||
@@ -135,9 +135,9 @@ export const useProvidersStore = defineStore('providers', () => {
|
||||
},
|
||||
'openai': {
|
||||
id: 'openai',
|
||||
nameKey: 'providers.openai.name',
|
||||
nameKey: 'settings.pages.providers.provider.openai.title',
|
||||
name: 'OpenAI',
|
||||
descriptionKey: 'providers.openai.description',
|
||||
descriptionKey: 'settings.pages.providers.provider.openai.description',
|
||||
description: 'openai.com',
|
||||
icon: 'i-lobe-icons:openai',
|
||||
defaultOptions: {
|
||||
@@ -163,9 +163,9 @@ export const useProvidersStore = defineStore('providers', () => {
|
||||
},
|
||||
'ollama': {
|
||||
id: 'ollama',
|
||||
nameKey: 'providers.ollama.name',
|
||||
nameKey: 'settings.pages.providers.provider.ollama.title',
|
||||
name: 'Ollama',
|
||||
descriptionKey: 'providers.ollama.description',
|
||||
descriptionKey: 'settings.pages.providers.provider.ollama.description',
|
||||
description: 'ollama.com',
|
||||
icon: 'i-lobe-icons:ollama',
|
||||
defaultOptions: {
|
||||
@@ -191,9 +191,9 @@ export const useProvidersStore = defineStore('providers', () => {
|
||||
},
|
||||
'vllm': {
|
||||
id: 'vllm',
|
||||
nameKey: 'providers.vllm.name',
|
||||
nameKey: 'settings.pages.providers.provider.vllm.title',
|
||||
name: 'vLLM',
|
||||
descriptionKey: 'providers.vllm.description',
|
||||
descriptionKey: 'settings.pages.providers.provider.vllm.description',
|
||||
description: 'vllm.ai',
|
||||
iconColor: 'i-lobe-icons:vllm-color',
|
||||
createProvider: config => createOllama(config.baseUrl as string),
|
||||
@@ -248,9 +248,9 @@ export const useProvidersStore = defineStore('providers', () => {
|
||||
},
|
||||
'perplexity-ai': {
|
||||
id: 'perplexity-ai',
|
||||
nameKey: 'providers.perplexity.name',
|
||||
nameKey: 'settings.pages.providers.provider.perplexity.title',
|
||||
name: 'Perplexity',
|
||||
descriptionKey: 'providers.perplexity.description',
|
||||
descriptionKey: 'settings.pages.providers.provider.perplexity.description',
|
||||
description: 'perplexity.ai',
|
||||
icon: 'i-lobe-icons:perplexity',
|
||||
defaultOptions: {
|
||||
@@ -301,9 +301,9 @@ export const useProvidersStore = defineStore('providers', () => {
|
||||
},
|
||||
'elevenlabs': {
|
||||
id: 'elevenlabs',
|
||||
nameKey: 'providers.elevenlabs.name',
|
||||
nameKey: 'settings.pages.providers.provider.elevenlabs.title',
|
||||
name: 'ElevenLabs',
|
||||
descriptionKey: 'providers.elevenlabs.description',
|
||||
descriptionKey: 'settings.pages.providers.provider.elevenlabs.description',
|
||||
description: 'elevenlabs.io',
|
||||
icon: 'i-simple-icons:elevenlabs',
|
||||
defaultOptions: {
|
||||
@@ -338,9 +338,9 @@ export const useProvidersStore = defineStore('providers', () => {
|
||||
},
|
||||
'xai': {
|
||||
id: 'xai',
|
||||
nameKey: 'providers.xai.name',
|
||||
nameKey: 'settings.pages.providers.provider.xai.title',
|
||||
name: 'xAI',
|
||||
descriptionKey: 'providers.xai.description',
|
||||
descriptionKey: 'settings.pages.providers.provider.xai.description',
|
||||
description: 'x.ai',
|
||||
icon: 'i-lobe-icons:xai',
|
||||
createProvider: config => createXAI(config.apiKey as string, config.baseUrl as string),
|
||||
@@ -363,9 +363,9 @@ export const useProvidersStore = defineStore('providers', () => {
|
||||
},
|
||||
'deepseek': {
|
||||
id: 'deepseek',
|
||||
nameKey: 'providers.deepseek.name',
|
||||
nameKey: 'settings.pages.providers.provider.deepseek.title',
|
||||
name: 'DeepSeek',
|
||||
descriptionKey: 'providers.deepseek.description',
|
||||
descriptionKey: 'settings.pages.providers.provider.deepseek.description',
|
||||
description: 'deepseek.com',
|
||||
iconColor: 'i-lobe-icons:deepseek-color',
|
||||
createProvider: config => createDeepSeek(config.apiKey as string, config.baseUrl as string),
|
||||
@@ -388,9 +388,9 @@ export const useProvidersStore = defineStore('providers', () => {
|
||||
},
|
||||
'together-ai': {
|
||||
id: 'together-ai',
|
||||
nameKey: 'providers.together.name',
|
||||
nameKey: 'settings.pages.providers.provider.together.title',
|
||||
name: 'Together.ai',
|
||||
descriptionKey: 'providers.together.description',
|
||||
descriptionKey: 'settings.pages.providers.provider.together.description',
|
||||
description: 'together.ai',
|
||||
iconColor: 'i-lobe-icons:together-color',
|
||||
createProvider: config => createTogetherAI(config.apiKey as string, config.baseUrl as string),
|
||||
@@ -413,9 +413,9 @@ export const useProvidersStore = defineStore('providers', () => {
|
||||
},
|
||||
'novita-ai': {
|
||||
id: 'novita-ai',
|
||||
nameKey: 'providers.novita.name',
|
||||
nameKey: 'settings.pages.providers.provider.novita.title',
|
||||
name: 'Novita',
|
||||
descriptionKey: 'providers.novita.description',
|
||||
descriptionKey: 'settings.pages.providers.provider.novita.description',
|
||||
description: 'novita.ai',
|
||||
iconColor: 'i-lobe-icons:novita-color',
|
||||
createProvider: config => createNovita(config.apiKey as string, config.baseUrl as string),
|
||||
@@ -438,9 +438,9 @@ export const useProvidersStore = defineStore('providers', () => {
|
||||
},
|
||||
'fireworks-ai': {
|
||||
id: 'fireworks-ai',
|
||||
nameKey: 'providers.fireworks.name',
|
||||
nameKey: 'settings.pages.providers.provider.fireworks.title',
|
||||
name: 'Fireworks.ai',
|
||||
descriptionKey: 'providers.fireworks.description',
|
||||
descriptionKey: 'settings.pages.providers.provider.fireworks.description',
|
||||
description: 'fireworks.ai',
|
||||
icon: 'i-lobe-icons:fireworks',
|
||||
createProvider: config => createFireworks(config.apiKey as string, config.baseUrl as string),
|
||||
@@ -463,9 +463,9 @@ export const useProvidersStore = defineStore('providers', () => {
|
||||
},
|
||||
'cloudflare-workers-ai': {
|
||||
id: 'cloudflare-workers-ai',
|
||||
nameKey: 'providers.cloudflare.name',
|
||||
nameKey: 'settings.pages.providers.provider.cloudflare-workers-ai.title',
|
||||
name: 'Cloudflare Workers AI',
|
||||
descriptionKey: 'providers.cloudflare.description',
|
||||
descriptionKey: 'settings.pages.providers.provider.cloudflare-workers-ai.description',
|
||||
description: 'cloudflare.com',
|
||||
iconColor: 'i-lobe-icons:cloudflare-color',
|
||||
createProvider: config => createWorkersAI(config.apiKey as string, config.accountId as string),
|
||||
@@ -477,9 +477,9 @@ export const useProvidersStore = defineStore('providers', () => {
|
||||
},
|
||||
'mistral-ai': {
|
||||
id: 'mistral-ai',
|
||||
nameKey: 'providers.mistral.name',
|
||||
nameKey: 'settings.pages.providers.provider.mistral.title',
|
||||
name: 'Mistral',
|
||||
descriptionKey: 'providers.mistral.description',
|
||||
descriptionKey: 'settings.pages.providers.provider.mistral.description',
|
||||
description: 'mistral.ai',
|
||||
iconColor: 'i-lobe-icons:mistral-color',
|
||||
createProvider: config => createMistral(config.apiKey as string, config.baseUrl as string),
|
||||
@@ -502,9 +502,9 @@ export const useProvidersStore = defineStore('providers', () => {
|
||||
},
|
||||
'moonshot-ai': {
|
||||
id: 'moonshot-ai',
|
||||
nameKey: 'providers.moonshot.name',
|
||||
nameKey: 'settings.pages.providers.provider.moonshot.title',
|
||||
name: 'Moonshot AI',
|
||||
descriptionKey: 'providers.moonshot.description',
|
||||
descriptionKey: 'settings.pages.providers.provider.moonshot.description',
|
||||
description: 'moonshot.ai',
|
||||
icon: 'i-lobe-icons:moonshot',
|
||||
createProvider: config => createMoonshot(config.apiKey as string, config.baseUrl as string),
|
||||
|
||||
@@ -24,7 +24,7 @@ export const useSettings = defineStore('settings', () => {
|
||||
const availableLive2dMotions = ref<{ motionName: string, motionIndex: number, fileName: string }[]>([])
|
||||
const live2dMotionMap = useLocalStorage<Record<string, string>>('settings/live2d/motion-map', {})
|
||||
|
||||
const disableTransitions = useLocalStorage('settings/disable-transitions', false)
|
||||
const disableTransitions = useLocalStorage('settings/disable-transitions', true)
|
||||
|
||||
const themeColorsHue = useLocalStorage('settings/theme/colors/hue', DEFAULT_THEME_COLORS_HUE)
|
||||
const themeColorsHueDynamic = useLocalStorage('settings/theme/colors/hue-dynamic', false)
|
||||
|
||||
Reference in New Issue
Block a user