mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-11-01 16:29:29 +00:00
feat(grok): 网关 Voice TTS/STT/Realtime 与分组音频定价
- 中继 xAI Voice HTTP(/tts /stt /custom-voices)与 Realtime WS(/realtime) 仅 Grok 分组可用;账号选调度沿用 chat 能力,不依赖创作中心 - Voice URL 固定走 api.x.ai(CLI proxy base 自动回落) - 分组级 audio_realtime / TTS / STT 单价:schema + migration 218 + admin API + GroupsView 表单与 i18n(无创作中心 UI)
This commit is contained in:
@@ -1483,6 +1483,57 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Grok Voice 显式定价(仅 grok 平台) -->
|
||||
<div
|
||||
v-if="createForm.platform === 'grok'"
|
||||
class="border-t border-gray-200 dark:border-dark-400 pt-4 mt-4"
|
||||
>
|
||||
<h4 class="text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
||||
{{ t("admin.groups.voicePricing.title") }}
|
||||
</h4>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400 mb-3">
|
||||
{{ t("admin.groups.voicePricing.description") }}
|
||||
</p>
|
||||
<div class="grid grid-cols-1 gap-3 md:grid-cols-3">
|
||||
<div>
|
||||
<label class="input-label">{{ t("admin.groups.voicePricing.audioRealtimePerMin") }}</label>
|
||||
<input
|
||||
v-model.number="createForm.audio_realtime_price_per_min"
|
||||
type="number"
|
||||
step="0.000001"
|
||||
min="0"
|
||||
class="input"
|
||||
:placeholder="t('admin.groups.voicePricing.pricePlaceholder')"
|
||||
data-testid="create-audio-realtime-price"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="input-label">{{ t("admin.groups.voicePricing.audioTtsPerMillionChars") }}</label>
|
||||
<input
|
||||
v-model.number="createForm.audio_tts_price_per_million_chars"
|
||||
type="number"
|
||||
step="0.000001"
|
||||
min="0"
|
||||
class="input"
|
||||
:placeholder="t('admin.groups.voicePricing.pricePlaceholder')"
|
||||
data-testid="create-audio-tts-price"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="input-label">{{ t("admin.groups.voicePricing.audioSttPerHour") }}</label>
|
||||
<input
|
||||
v-model.number="createForm.audio_stt_price_per_hour"
|
||||
type="number"
|
||||
step="0.000001"
|
||||
min="0"
|
||||
class="input"
|
||||
:placeholder="t('admin.groups.voicePricing.pricePlaceholder')"
|
||||
data-testid="create-audio-stt-price"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- OpenAI Live 开关(仅 openai 平台) -->
|
||||
<div
|
||||
v-if="createForm.platform === 'openai'"
|
||||
@@ -3123,6 +3174,57 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Grok Voice 显式定价(仅 grok 平台) -->
|
||||
<div
|
||||
v-if="editForm.platform === 'grok'"
|
||||
class="border-t border-gray-200 dark:border-dark-400 pt-4 mt-4"
|
||||
>
|
||||
<h4 class="text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
||||
{{ t("admin.groups.voicePricing.title") }}
|
||||
</h4>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400 mb-3">
|
||||
{{ t("admin.groups.voicePricing.description") }}
|
||||
</p>
|
||||
<div class="grid grid-cols-1 gap-3 md:grid-cols-3">
|
||||
<div>
|
||||
<label class="input-label">{{ t("admin.groups.voicePricing.audioRealtimePerMin") }}</label>
|
||||
<input
|
||||
v-model.number="editForm.audio_realtime_price_per_min"
|
||||
type="number"
|
||||
step="0.000001"
|
||||
min="0"
|
||||
class="input"
|
||||
:placeholder="t('admin.groups.voicePricing.pricePlaceholder')"
|
||||
data-testid="edit-audio-realtime-price"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="input-label">{{ t("admin.groups.voicePricing.audioTtsPerMillionChars") }}</label>
|
||||
<input
|
||||
v-model.number="editForm.audio_tts_price_per_million_chars"
|
||||
type="number"
|
||||
step="0.000001"
|
||||
min="0"
|
||||
class="input"
|
||||
:placeholder="t('admin.groups.voicePricing.pricePlaceholder')"
|
||||
data-testid="edit-audio-tts-price"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="input-label">{{ t("admin.groups.voicePricing.audioSttPerHour") }}</label>
|
||||
<input
|
||||
v-model.number="editForm.audio_stt_price_per_hour"
|
||||
type="number"
|
||||
step="0.000001"
|
||||
min="0"
|
||||
class="input"
|
||||
:placeholder="t('admin.groups.voicePricing.pricePlaceholder')"
|
||||
data-testid="edit-audio-stt-price"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- OpenAI Live 开关(仅 openai 平台) -->
|
||||
<div
|
||||
v-if="editForm.platform === 'openai'"
|
||||
@@ -4806,6 +4908,9 @@ const createForm = reactive({
|
||||
video_model_prices: createVideoModelPricesForm(),
|
||||
// Codex 网页搜索按次计费(仅 openai 平台使用);null = 使用默认价 0.01
|
||||
web_search_price_per_call: null as number | null,
|
||||
audio_realtime_price_per_min: null as number | null,
|
||||
audio_tts_price_per_million_chars: null as number | null,
|
||||
audio_stt_price_per_hour: null as number | null,
|
||||
// 高峰时段倍率配置
|
||||
peak_rate_enabled: false,
|
||||
peak_start: "",
|
||||
@@ -5161,6 +5266,9 @@ const editForm = reactive({
|
||||
video_model_prices: createVideoModelPricesForm(),
|
||||
// Codex 网页搜索按次计费(仅 openai 平台使用);null = 使用默认价 0.01
|
||||
web_search_price_per_call: null as number | null,
|
||||
audio_realtime_price_per_min: null as number | null,
|
||||
audio_tts_price_per_million_chars: null as number | null,
|
||||
audio_stt_price_per_hour: null as number | null,
|
||||
// 高峰时段倍率配置
|
||||
peak_rate_enabled: false,
|
||||
peak_start: "",
|
||||
@@ -5611,6 +5719,9 @@ const closeCreateModal = () => {
|
||||
createForm.video_price_1080p = null;
|
||||
createForm.video_model_prices = createVideoModelPricesForm();
|
||||
createForm.web_search_price_per_call = null;
|
||||
createForm.audio_realtime_price_per_min = null;
|
||||
createForm.audio_tts_price_per_million_chars = null;
|
||||
createForm.audio_stt_price_per_hour = null;
|
||||
createForm.peak_rate_enabled = false;
|
||||
createForm.peak_start = "";
|
||||
createForm.peak_end = "";
|
||||
@@ -5775,6 +5886,15 @@ const handleCreateGroup = async () => {
|
||||
requestData.video_price_480p = emptyToNull(requestData.video_price_480p);
|
||||
requestData.video_price_720p = emptyToNull(requestData.video_price_720p);
|
||||
requestData.video_price_1080p = emptyToNull(requestData.video_price_1080p);
|
||||
requestData.audio_realtime_price_per_min = emptyToNull(
|
||||
requestData.audio_realtime_price_per_min,
|
||||
);
|
||||
requestData.audio_tts_price_per_million_chars = emptyToNull(
|
||||
requestData.audio_tts_price_per_million_chars,
|
||||
);
|
||||
requestData.audio_stt_price_per_hour = emptyToNull(
|
||||
requestData.audio_stt_price_per_hour,
|
||||
);
|
||||
requestData.web_search_price_per_call = emptyToNull(
|
||||
requestData.web_search_price_per_call,
|
||||
);
|
||||
@@ -5835,6 +5955,9 @@ const handleEdit = async (group: AdminGroup) => {
|
||||
group.video_model_prices,
|
||||
);
|
||||
editForm.web_search_price_per_call = group.web_search_price_per_call ?? null;
|
||||
editForm.audio_realtime_price_per_min = group.audio_realtime_price_per_min ?? null;
|
||||
editForm.audio_tts_price_per_million_chars = group.audio_tts_price_per_million_chars ?? null;
|
||||
editForm.audio_stt_price_per_hour = group.audio_stt_price_per_hour ?? null;
|
||||
editForm.peak_rate_enabled = group.peak_rate_enabled ?? false;
|
||||
editForm.peak_start = group.peak_start ?? "";
|
||||
editForm.peak_end = group.peak_end ?? "";
|
||||
@@ -5916,6 +6039,9 @@ const closeEditModal = () => {
|
||||
editForm.video_price_1080p = null;
|
||||
editForm.video_model_prices = createVideoModelPricesForm();
|
||||
editForm.web_search_price_per_call = null;
|
||||
editForm.audio_realtime_price_per_min = null;
|
||||
editForm.audio_tts_price_per_million_chars = null;
|
||||
editForm.audio_stt_price_per_hour = null;
|
||||
resetMessagesDispatchFormState(editForm);
|
||||
editForm.allow_live = false;
|
||||
resetModelsListState(editModelsListState);
|
||||
@@ -6021,6 +6147,15 @@ const handleUpdateGroup = async () => {
|
||||
payload.video_price_480p = emptyPriceToClear(payload.video_price_480p);
|
||||
payload.video_price_720p = emptyPriceToClear(payload.video_price_720p);
|
||||
payload.video_price_1080p = emptyPriceToClear(payload.video_price_1080p);
|
||||
payload.audio_realtime_price_per_min = emptyPriceToClear(
|
||||
payload.audio_realtime_price_per_min,
|
||||
);
|
||||
payload.audio_tts_price_per_million_chars = emptyPriceToClear(
|
||||
payload.audio_tts_price_per_million_chars,
|
||||
);
|
||||
payload.audio_stt_price_per_hour = emptyPriceToClear(
|
||||
payload.audio_stt_price_per_hour,
|
||||
);
|
||||
payload.web_search_price_per_call = emptyPriceToClear(
|
||||
payload.web_search_price_per_call,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user