api base url
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 1m0s
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 1m0s
This commit is contained in:
parent
4031d21dcc
commit
9ddcdc9ec6
1
.env
1
.env
@ -2,3 +2,4 @@ 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/
|
||||
VITE_API_BASE_PATH=/video_translate/api
|
||||
@ -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"
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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<Subtitle[]>([]);
|
||||
@ -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'
|
||||
}
|
||||
|
||||
@ -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'
|
||||
}
|
||||
|
||||
19
src/lib/apiBasePath.ts
Normal file
19
src/lib/apiBasePath.ts
Normal file
@ -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}`;
|
||||
};
|
||||
@ -1,4 +1,5 @@
|
||||
import { LlmProvider, PipelineQuality, SubtitlePipelineResult } from '../types';
|
||||
import { apiUrl } from '../lib/apiBasePath';
|
||||
|
||||
type JsonResponseResult<T> =
|
||||
| { 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,
|
||||
});
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { apiUrl } from '../lib/apiBasePath';
|
||||
|
||||
type JsonResponseResult<T> =
|
||||
| { 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',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user