diff --git a/.github/actions/setup-swiftlint/action.yml b/.github/actions/setup-swiftlint/action.yml index 55f9f606e..355cb8f83 100644 --- a/.github/actions/setup-swiftlint/action.yml +++ b/.github/actions/setup-swiftlint/action.yml @@ -44,17 +44,28 @@ runs: shell: bash run: | if [[ "${{ inputs.version }}" == "latest" ]]; then - VERSION=$(curl -s https://api.github.com/repos/realm/SwiftLint/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') - if [[ -z "$VERSION" ]]; then - echo "Error: Failed to get latest version" + # Fetch the latest release tag using a more robust method + API_RESPONSE=$(curl -s https://api.github.com/repos/realm/SwiftLint/releases/latest) + # Try using jq if available (most GitHub Actions runners have it) + if command -v jq >/dev/null 2>&1; then + VERSION=$(echo "$API_RESPONSE" | jq -r '.tag_name // empty') + else + # Fallback: parse JSON manually with sed, being very specific about the tag_name field + VERSION=$(echo "$API_RESPONSE" | sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1) + fi + + # Validate the version looks correct (should contain version numbers) + if [[ -z "$VERSION" ]] || [[ "$VERSION" == "null" ]] || [[ ! "$VERSION" =~ ^[0-9] ]]; then + echo "Error: Failed to get latest version or got invalid version: '$VERSION'" + echo "API Response (first 50 lines):" + echo "$API_RESPONSE" | head -50 exit 1 fi echo "Latest version: $VERSION" else VERSION="${{ inputs.version }}" - if [[ ! "$VERSION" =~ ^v ]]; then - VERSION="v$VERSION" - fi + # Remove 'v' prefix if user provided it, since SwiftLint tags don't use it + VERSION="${VERSION#v}" echo "Using specified version: $VERSION" fi echo "version=$VERSION" >> $GITHUB_OUTPUT diff --git a/.gitignore b/.gitignore index 026d97c30..644073761 100644 --- a/.gitignore +++ b/.gitignore @@ -121,4 +121,4 @@ plugins-local plugins-development #ia -GEMINI.md \ No newline at end of file +GEMINI.md diff --git a/packages/stage-pages/src/pages/settings/modules/hearing.vue b/packages/stage-pages/src/pages/settings/modules/hearing.vue index af66d5fb7..41f1e94ba 100644 --- a/packages/stage-pages/src/pages/settings/modules/hearing.vue +++ b/packages/stage-pages/src/pages/settings/modules/hearing.vue @@ -8,10 +8,10 @@ import { useAudioContext } from '@proj-airi/stage-ui/stores/audio' import { useHearingSpeechInputPipeline, useHearingStore } from '@proj-airi/stage-ui/stores/modules/hearing' import { useProvidersStore } from '@proj-airi/stage-ui/stores/providers' import { useSettingsAudioDevice } from '@proj-airi/stage-ui/stores/settings' -import { Button, FieldCheckbox, FieldRange, FieldSelect } from '@proj-airi/ui' +import { Button, FieldCheckbox, FieldInput, FieldRange, FieldSelect } from '@proj-airi/ui' import { until } from '@vueuse/core' import { storeToRefs } from 'pinia' -import { computed, onUnmounted, ref, watch } from 'vue' +import { computed, onMounted, onUnmounted, ref, watch } from 'vue' import { useI18n } from 'vue-i18n' const { t } = useI18n() @@ -222,8 +222,29 @@ const speakingIndicatorClass = computed(() => { } }) -function updateCustomModelName(value: string) { - activeCustomModelName.value = value +function updateCustomModelName(value: string | undefined) { + const modelValue = value || '' + activeCustomModelName.value = modelValue + activeTranscriptionModel.value = modelValue +} + +// Sync OpenAI Compatible model from provider config +function syncOpenAICompatibleSettings() { + if (activeTranscriptionProvider.value !== 'openai-compatible-audio-transcription') + return + + const providerConfig = providersStore.getProviderConfig(activeTranscriptionProvider.value) + // Always sync model from provider config (override any existing value from previous provider) + if (providerConfig?.model) { + activeTranscriptionModel.value = providerConfig.model as string + updateCustomModelName(providerConfig.model as string) + } + else { + // If no model in provider config, use default + const defaultModel = 'whisper-1' + activeTranscriptionModel.value = defaultModel + updateCustomModelName(defaultModel) + } } onStopRecord(async (recording) => { @@ -427,6 +448,7 @@ watch(activeTranscriptionProvider, async (provider) => { return await hearingStore.loadModelsForProvider(provider) + syncOpenAICompatibleSettings() // Auto-select first model for Web Speech API if no model is selected if (provider === 'browser-web-speech-api' && !activeTranscriptionModel.value) { @@ -438,6 +460,11 @@ watch(activeTranscriptionProvider, async (provider) => { } }, { immediate: true }) +onMounted(async () => { + // Audio devices are loaded on demand when user requests them + syncOpenAICompatibleSettings() +}) + onUnmounted(() => { stopSTTTest() stopAudioMonitoring() @@ -537,19 +564,25 @@ onUnmounted(() => { -
+

{{ t('settings.pages.modules.consciousness.sections.section.provider-model-selection.title') }}

- {{ t('settings.pages.modules.consciousness.sections.section.provider-model-selection.subtitle') }} + + + {{ t('settings.pages.modules.consciousness.sections.section.provider-model-selection.subtitle') }} + + + Enter the transcription model to use (e.g., 'whisper-1', 'gpt-4o-transcribe') +
-
+
@@ -558,14 +591,26 @@ onUnmounted(() => { - + +
+ +
+ + - -