From 9ddcdc9ec6f9d8c9e4cae341dcf5005d9b61500a Mon Sep 17 00:00:00 2001 From: Song367 <601337784@qq.com> Date: Wed, 18 Mar 2026 15:34:17 +0800 Subject: [PATCH] api base url --- .env | 3 ++- .env.example | 5 +++++ README.md | 7 +++++++ src/components/EditorScreen.tsx | 3 ++- src/components/ExportModal.tsx | 3 ++- src/lib/apiBasePath.ts | 19 +++++++++++++++++++ src/services/subtitleService.ts | 3 ++- src/services/ttsService.ts | 4 +++- 8 files changed, 42 insertions(+), 5 deletions(-) create mode 100644 src/lib/apiBasePath.ts diff --git a/.env b/.env index f69fa83..3ea8e64 100644 --- a/.env +++ b/.env @@ -1,4 +1,5 @@ GEMINI_API_KEY="AIzaSyAex0MkGj_X-h3L38334xVdZsFzOcU9cC0" ARK_API_KEY="e96194a9-8eda-4a90-a211-6db288045bdc" MINIMAX_API_KEY="eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJHcm91cE5hbWUiOiLkuIrmtbfpopzpgJTnp5HmioDmnInpmZDlhazlj7giLCJVc2VyTmFtZSI6IuadqOmqpSIsIkFjY291bnQiOiIiLCJTdWJqZWN0SUQiOiIxNzI4NzEyMzI0OTc5NjI2ODM5IiwiUGhvbmUiOiIxMzM4MTU1OTYxOCIsIkdyb3VwSUQiOiIxNzI4NzEyMzI0OTcxMjM4MjMxIiwiUGFnZU5hbWUiOiIiLCJNYWlsIjoiIiwiQ3JlYXRlVGltZSI6IjIwMjUtMDYtMDYgMTU6MDU6NTUiLCJUb2tlblR5cGUiOjEsImlzcyI6Im1pbmltYXgifQ.aw1AUJnBYxXerJ4qNUaXM3DqPTd94WSVHWRiIpnjImhuCia3Ta1AyANTQTx__2CF5eByHOaHJFHhBCg6KgHUEaR6TiWFn0fWwXaU7XgnHwbvD4pNAmF_uYxMKbi-a6IyIGNyFdEMy22V5JEqfY4okAco5U96cnSOQZH7lyIBpvOsesjZU6L9q6Tf2jvlcnO9QG8GPg2DVpeL8Q3zLuYWezN4Wk6N-ISwQmZUwBYL3BhYamsFqCdSEyMd_uYQ_aQJa5tmlQqpimtALiutFshPUXB6VsvXEO6q-lCZ6Tg8QWwlFHkmEtUMQw4pWoX25d7Us06VFUhvV6pOzvM7yqCaWw" -VITE_BASE_URL=/video_translate/ \ No newline at end of file +VITE_BASE_URL=/video_translate/ +VITE_API_BASE_PATH=/video_translate/api \ No newline at end of file diff --git a/.env.example b/.env.example index b493f07..2db7bb0 100644 --- a/.env.example +++ b/.env.example @@ -12,6 +12,11 @@ DEFAULT_LLM_PROVIDER="doubao" # Defaults to doubao-seed-2-0-pro-260215. DOUBAO_MODEL="doubao-seed-2-0-pro-260215" +# VITE_API_BASE_PATH: Optional frontend API base path. +# Defaults to /api. +# Set to /video_translate/api when the app is served under /video_translate. +# VITE_API_BASE_PATH="/video_translate/api" + # MINIMAX_API_KEY: Required for MiniMax TTS API calls. # Use a MiniMax API secret key that has TTS access enabled. MINIMAX_API_KEY="YOUR_MINIMAX_API_KEY" diff --git a/README.md b/README.md index c9b94c8..639803d 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ View your app in AI Studio: https://ai.studio/apps/a38a3cd5-7f82-49f0-a26e-99be4 3. Optional defaults: `DEFAULT_LLM_PROVIDER=doubao` `DOUBAO_MODEL=doubao-seed-2-0-pro-260215` + `VITE_API_BASE_PATH=/api` (optional) `FFMPEG_PATH=/path/to/ffmpeg` (optional) `FFPROBE_PATH=/path/to/ffprobe` (optional) 4. Run the app: @@ -34,6 +35,12 @@ View your app in AI Studio: https://ai.studio/apps/a38a3cd5-7f82-49f0-a26e-99be4 3. `TTS` stays fixed on `MiniMax` regardless of the selected LLM. 4. All provider keys are read from `.env`; the browser no longer calls LLM providers directly. +## Deploying Under a Subpath + +1. If your site is hosted under a subpath (for example `https://ai.yantootech.com/video_translate/`), set: + `VITE_API_BASE_PATH=/video_translate/api` +2. Keep backend routes unchanged (`/api/*` on the server); the frontend will prepend the configured base path. + ## Subtitle Generation 1. Subtitle generation is now driven by server-side multimodal LLM calls on the uploaded video file. diff --git a/src/components/EditorScreen.tsx b/src/components/EditorScreen.tsx index c31c8d5..67ac1f1 100644 --- a/src/components/EditorScreen.tsx +++ b/src/components/EditorScreen.tsx @@ -7,6 +7,7 @@ import { LlmProvider, PipelineQuality, Subtitle, TextStyles } from '../types'; import { generateSubtitlePipeline } from '../services/subtitleService'; import { generateTTS } from '../services/ttsService'; import { MINIMAX_VOICES } from '../voices'; +import { apiUrl } from '../lib/apiBasePath'; export default function EditorScreen({ videoFile, targetLanguage, trimRange, onBack }: { videoFile: File | null; targetLanguage: string; trimRange?: {start: number, end: number} | null; onBack: () => void }) { const [subtitles, setSubtitles] = useState([]); @@ -182,7 +183,7 @@ export default function EditorScreen({ videoFile, targetLanguage, trimRange, onB const formData = new FormData(); formData.append('video', videoFile); - const response = await axios.post('/api/separate-vocal', formData, { + const response = await axios.post(apiUrl('/separate-vocal'), formData, { headers: { 'Content-Type': 'multipart/form-data' } diff --git a/src/components/ExportModal.tsx b/src/components/ExportModal.tsx index 9ae0b59..69cbb23 100644 --- a/src/components/ExportModal.tsx +++ b/src/components/ExportModal.tsx @@ -3,6 +3,7 @@ import { X, Download, Loader2, CheckCircle2, AlertCircle } from 'lucide-react'; import axios from 'axios'; import { Subtitle, TextStyles } from '../types'; import { buildExportPayload } from '../lib/exportPayload'; +import { apiUrl } from '../lib/apiBasePath'; interface ExportModalProps { onClose: () => void; @@ -61,7 +62,7 @@ export default function ExportModal({ onClose, videoFile, subtitles, bgmUrl, bgm setProgress(p => (p < 90 ? p + 2 : p)); }, 500); - const response = await axios.post('/api/export-video', formData, { + const response = await axios.post(apiUrl('/export-video'), formData, { headers: { 'Content-Type': 'multipart/form-data' } diff --git a/src/lib/apiBasePath.ts b/src/lib/apiBasePath.ts new file mode 100644 index 0000000..4e8faed --- /dev/null +++ b/src/lib/apiBasePath.ts @@ -0,0 +1,19 @@ +const normalizeBasePath = (value: string | undefined) => { + const trimmed = value?.trim(); + if (!trimmed) { + return '/api'; + } + + if (/^https?:\/\//i.test(trimmed)) { + return trimmed.replace(/\/+$/, ''); + } + + const withLeadingSlash = trimmed.startsWith('/') ? trimmed : `/${trimmed}`; + return withLeadingSlash.replace(/\/+$/, ''); +}; + +export const apiUrl = (path: string) => { + const basePath = normalizeBasePath(import.meta.env.VITE_API_BASE_PATH); + const normalizedPath = path.startsWith('/') ? path : `/${path}`; + return `${basePath}${normalizedPath}`; +}; diff --git a/src/services/subtitleService.ts b/src/services/subtitleService.ts index 112ab8e..98c3804 100644 --- a/src/services/subtitleService.ts +++ b/src/services/subtitleService.ts @@ -1,4 +1,5 @@ import { LlmProvider, PipelineQuality, SubtitlePipelineResult } from '../types'; +import { apiUrl } from '../lib/apiBasePath'; type JsonResponseResult = | { ok: true; status: number; data: T } @@ -56,7 +57,7 @@ export const generateSubtitlePipeline = async ( formData.append('trimRange', JSON.stringify(trimRange)); } - const resp = await fetchImpl('/api/generate-subtitles', { + const resp = await fetchImpl(apiUrl('/generate-subtitles'), { method: 'POST', body: formData, }); diff --git a/src/services/ttsService.ts b/src/services/ttsService.ts index 4387200..61c5f33 100644 --- a/src/services/ttsService.ts +++ b/src/services/ttsService.ts @@ -1,3 +1,5 @@ +import { apiUrl } from '../lib/apiBasePath'; + type JsonResponseResult = | { ok: true; status: number; data: T } | { ok: false; status: number; error: string }; @@ -64,7 +66,7 @@ export const generateTTS = async ( } const audio = await withRetry(async () => { - const resp = await fetch('/api/tts', { + const resp = await fetch(apiUrl('/tts'), { method: 'POST', headers: { 'Content-Type': 'application/json',