feat: 上传
This commit is contained in:
@@ -6,7 +6,6 @@
|
||||
"dev:translate-h5": "pnpm --filter translate-h5 dev",
|
||||
"build:translate-h5": "pnpm --filter translate-h5 build",
|
||||
"dev": "vite",
|
||||
"dev:https": "vite --https",
|
||||
"build": "tsc && vite build",
|
||||
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
||||
"preview": "vite preview"
|
||||
@@ -34,6 +33,7 @@
|
||||
"react-router-dom": "^6.20.0",
|
||||
"react-slick": "^0.29.0",
|
||||
"slick-carousel": "^1.8.1",
|
||||
"vconsole": "^3.15.1",
|
||||
"weixin-js-sdk": "^1.6.5",
|
||||
"zustand": "^4.4.6"
|
||||
},
|
||||
|
||||
44
pnpm-lock.yaml
generated
44
pnpm-lock.yaml
generated
@@ -74,6 +74,9 @@ importers:
|
||||
slick-carousel:
|
||||
specifier: ^1.8.1
|
||||
version: 1.8.1(jquery@3.7.1)
|
||||
vconsole:
|
||||
specifier: ^3.15.1
|
||||
version: 3.15.1
|
||||
weixin-js-sdk:
|
||||
specifier: ^1.6.5
|
||||
version: 1.6.5
|
||||
@@ -616,67 +619,56 @@ packages:
|
||||
resolution: {integrity: sha512-u72Mzc6jyJwKjJbZZcIYmd9bumJu7KNmHYdue43vT1rXPm2rITwmPWF0mmPzLm9/vJWxIRbao/jrQmxTO0Sm9w==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.50.0':
|
||||
resolution: {integrity: sha512-S4UefYdV0tnynDJV1mdkNawp0E5Qm2MtSs330IyHgaccOFrwqsvgigUD29uT+B/70PDY1eQ3t40+xf6wIvXJyg==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-arm64-gnu@4.50.0':
|
||||
resolution: {integrity: sha512-1EhkSvUQXJsIhk4msxP5nNAUWoB4MFDHhtc4gAYvnqoHlaL9V3F37pNHabndawsfy/Tp7BPiy/aSa6XBYbaD1g==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.50.0':
|
||||
resolution: {integrity: sha512-EtBDIZuDtVg75xIPIK1l5vCXNNCIRM0OBPUG+tbApDuJAy9mKago6QxX+tfMzbCI6tXEhMuZuN1+CU8iDW+0UQ==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-loongarch64-gnu@4.50.0':
|
||||
resolution: {integrity: sha512-BGYSwJdMP0hT5CCmljuSNx7+k+0upweM2M4YGfFBjnFSZMHOLYR0gEEj/dxyYJ6Zc6AiSeaBY8dWOa11GF/ppQ==}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-ppc64-gnu@4.50.0':
|
||||
resolution: {integrity: sha512-I1gSMzkVe1KzAxKAroCJL30hA4DqSi+wGc5gviD0y3IL/VkvcnAqwBf4RHXHyvH66YVHxpKO8ojrgc4SrWAnLg==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.50.0':
|
||||
resolution: {integrity: sha512-bSbWlY3jZo7molh4tc5dKfeSxkqnf48UsLqYbUhnkdnfgZjgufLS/NTA8PcP/dnvct5CCdNkABJ56CbclMRYCA==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-musl@4.50.0':
|
||||
resolution: {integrity: sha512-LSXSGumSURzEQLT2e4sFqFOv3LWZsEF8FK7AAv9zHZNDdMnUPYH3t8ZlaeYYZyTXnsob3htwTKeWtBIkPV27iQ==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-s390x-gnu@4.50.0':
|
||||
resolution: {integrity: sha512-CxRKyakfDrsLXiCyucVfVWVoaPA4oFSpPpDwlMcDFQvrv3XY6KEzMtMZrA+e/goC8xxp2WSOxHQubP8fPmmjOQ==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-x64-gnu@4.50.0':
|
||||
resolution: {integrity: sha512-8PrJJA7/VU8ToHVEPu14FzuSAqVKyo5gg/J8xUerMbyNkWkO9j2ExBho/68RnJsMGNJq4zH114iAttgm7BZVkA==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-x64-musl@4.50.0':
|
||||
resolution: {integrity: sha512-SkE6YQp+CzpyOrbw7Oc4MgXFvTw2UIBElvAvLCo230pyxOLmYwRPwZ/L5lBe/VW/qT1ZgND9wJfOsdy0XptRvw==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-openharmony-arm64@4.50.0':
|
||||
resolution: {integrity: sha512-PZkNLPfvXeIOgJWA804zjSFH7fARBBCpCXxgkGDRjjAhRLOR8o0IGS01ykh5GYfod4c2yiiREuDM8iZ+pVsT+Q==}
|
||||
@@ -721,28 +713,24 @@ packages:
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@swc/core-linux-arm64-musl@1.13.5':
|
||||
resolution: {integrity: sha512-9+ZxFN5GJag4CnYnq6apKTnnezpfJhCumyz0504/JbHLo+Ue+ZtJnf3RhyA9W9TINtLE0bC4hKpWi8ZKoETyOQ==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@swc/core-linux-x64-gnu@1.13.5':
|
||||
resolution: {integrity: sha512-WD530qvHrki8Ywt/PloKUjaRKgstQqNGvmZl54g06kA+hqtSE2FTG9gngXr3UJxYu/cNAjJYiBifm7+w4nbHbA==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@swc/core-linux-x64-musl@1.13.5':
|
||||
resolution: {integrity: sha512-Luj8y4OFYx4DHNQTWjdIuKTq2f5k6uSXICqx+FSabnXptaOBAbJHNbHT/06JZh6NRUouaf0mYXN0mcsqvkhd7Q==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@swc/core-win32-arm64-msvc@1.13.5':
|
||||
resolution: {integrity: sha512-cZ6UpumhF9SDJvv4DA2fo9WIzlNFuKSkZpZmPG1c+4PFSEMy5DFOjBSllCvnqihCabzXzpn6ykCwBmHpy31vQw==}
|
||||
@@ -1151,6 +1139,13 @@ packages:
|
||||
copy-anything@2.0.6:
|
||||
resolution: {integrity: sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==}
|
||||
|
||||
copy-text-to-clipboard@3.2.2:
|
||||
resolution: {integrity: sha512-T6SqyLd1iLuqPA90J5N4cTalrtovCySh58iiZDGJ6FGznbclKh4UI+FGacQSgFzwKG77W7XT5gwbVEbd9cIH1A==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
core-js@3.45.1:
|
||||
resolution: {integrity: sha512-L4NPsJlCfZsPeXukyzHFlg/i7IIVwHSItR0wg0FLNqYClJ4MQYTYLbC7EkjKYRLZF2iof2MUgN0EGy7MdQFChg==}
|
||||
|
||||
cosmiconfig@6.0.0:
|
||||
resolution: {integrity: sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -1857,6 +1852,9 @@ packages:
|
||||
ms@2.1.3:
|
||||
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
||||
|
||||
mutation-observer@1.0.3:
|
||||
resolution: {integrity: sha512-M/O/4rF2h776hV7qGMZUH3utZLO/jK7p8rnNgGkjKUw8zCGjRQPxB8z6+5l8+VjRUQ3dNYu4vjqXYLr+U8ZVNA==}
|
||||
|
||||
nano-memoize@3.0.16:
|
||||
resolution: {integrity: sha512-JyK96AKVGAwVeMj3MoMhaSXaUNqgMbCRSQB3trUV8tYZfWEzqUBKdK1qJpfuNXgKeHOx1jv/IEYTM659ly7zUA==}
|
||||
|
||||
@@ -2359,6 +2357,9 @@ packages:
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
|
||||
vconsole@3.15.1:
|
||||
resolution: {integrity: sha512-KH8XLdrq9T5YHJO/ixrjivHfmF2PC2CdVoK6RWZB4yftMykYIaXY1mxZYAic70vADM54kpMQF+dYmvl5NRNy1g==}
|
||||
|
||||
vite-plugin-checker@0.8.0:
|
||||
resolution: {integrity: sha512-UA5uzOGm97UvZRTdZHiQVYFnd86AVn8EVaD4L3PoVzxH+IZSfaAw14WGFwX9QS23UW3lV/5bVKZn6l0w+q9P0g==}
|
||||
engines: {node: '>=14.16'}
|
||||
@@ -3594,6 +3595,10 @@ snapshots:
|
||||
dependencies:
|
||||
is-what: 3.14.1
|
||||
|
||||
copy-text-to-clipboard@3.2.2: {}
|
||||
|
||||
core-js@3.45.1: {}
|
||||
|
||||
cosmiconfig@6.0.0:
|
||||
dependencies:
|
||||
'@types/parse-json': 4.0.2
|
||||
@@ -4344,6 +4349,8 @@ snapshots:
|
||||
|
||||
ms@2.1.3: {}
|
||||
|
||||
mutation-observer@1.0.3: {}
|
||||
|
||||
nano-memoize@3.0.16: {}
|
||||
|
||||
nanoid@3.3.11: {}
|
||||
@@ -4837,6 +4844,13 @@ snapshots:
|
||||
dependencies:
|
||||
react: 18.3.1
|
||||
|
||||
vconsole@3.15.1:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.28.3
|
||||
copy-text-to-clipboard: 3.2.2
|
||||
core-js: 3.45.1
|
||||
mutation-observer: 1.0.3
|
||||
|
||||
vite-plugin-checker@0.8.0(eslint@9.34.0)(optionator@0.9.4)(typescript@5.9.2)(vite@6.3.5(@types/node@20.19.12)(less@4.4.1)(terser@5.44.0)):
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.27.1
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"dev:https": "vite --https",
|
||||
"build": "tsc && vite build",
|
||||
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
||||
"preview": "vite preview"
|
||||
|
||||
40
projects/translate-h5/src/api/translate.ts
Normal file
40
projects/translate-h5/src/api/translate.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import useAxios from "axios-hooks";
|
||||
import { Page, Result } from "@/types/http";
|
||||
|
||||
export interface MockResult {
|
||||
id: number;
|
||||
}
|
||||
|
||||
export interface MockPage {
|
||||
id: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* fetch the data
|
||||
* 详细使用可以查看 useAxios 的文档
|
||||
*/
|
||||
export const useUploadAudio = () => {
|
||||
const url = `/app-api/ai/sample/translate`;
|
||||
|
||||
const [{ data, loading, error }, execute] = useAxios<Result<any>>(
|
||||
{
|
||||
url,
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "multipart/form-data",
|
||||
},
|
||||
},
|
||||
{ manual: true } // 手动触发
|
||||
);
|
||||
|
||||
const uploadAudio = (formData: FormData) => {
|
||||
return execute({
|
||||
data: formData,
|
||||
headers: {
|
||||
"Content-Type": "multipart/form-data",
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return { data, loading, error, uploadAudio };
|
||||
};
|
||||
@@ -1,49 +1,51 @@
|
||||
import Axios, {
|
||||
AxiosError,
|
||||
AxiosInstance as AxiosType,
|
||||
AxiosResponse,
|
||||
InternalAxiosRequestConfig
|
||||
} from 'axios';
|
||||
import {STORAGE_AUTHORIZE_KEY} from "@/composables/authorization.ts";
|
||||
AxiosError,
|
||||
AxiosInstance as AxiosType,
|
||||
AxiosResponse,
|
||||
InternalAxiosRequestConfig,
|
||||
} from "axios";
|
||||
import { STORAGE_AUTHORIZE_KEY } from "@/composables/authorization.ts";
|
||||
|
||||
export interface ResponseBody<T = any> {
|
||||
code: number;
|
||||
data?: T;
|
||||
msg: string;
|
||||
code: number;
|
||||
data?: T;
|
||||
msg: string;
|
||||
}
|
||||
|
||||
async function requestHandler(config: InternalAxiosRequestConfig): Promise<InternalAxiosRequestConfig> {
|
||||
const token = localStorage.getItem(STORAGE_AUTHORIZE_KEY);
|
||||
if (token) {
|
||||
config.headers[STORAGE_AUTHORIZE_KEY] = token;
|
||||
}
|
||||
return config;
|
||||
async function requestHandler(
|
||||
config: InternalAxiosRequestConfig
|
||||
): Promise<InternalAxiosRequestConfig> {
|
||||
const token = localStorage.getItem(STORAGE_AUTHORIZE_KEY);
|
||||
if (token) {
|
||||
config.headers[STORAGE_AUTHORIZE_KEY] = token;
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
function responseHandler(response: AxiosResponse<ResponseBody>): AxiosResponse<ResponseBody> {
|
||||
// 响应拦截器逻辑...
|
||||
return response;
|
||||
// 响应拦截器逻辑...
|
||||
return response;
|
||||
}
|
||||
|
||||
function errorHandler(error: AxiosError<ResponseBody>): Promise<AxiosError<ResponseBody>> {
|
||||
// 错误处理逻辑...
|
||||
return Promise.reject(error);
|
||||
// 错误处理逻辑...
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
class AxiosInstance {
|
||||
private readonly instance: AxiosType;
|
||||
private readonly instance: AxiosType;
|
||||
|
||||
constructor(baseURL: string) {
|
||||
this.instance = Axios.create({baseURL});
|
||||
constructor(baseURL: string) {
|
||||
this.instance = Axios.create({ baseURL });
|
||||
|
||||
this.instance.interceptors.request.use(requestHandler, errorHandler);
|
||||
this.instance.interceptors.response.use(responseHandler, errorHandler);
|
||||
}
|
||||
this.instance.interceptors.request.use(requestHandler, errorHandler);
|
||||
this.instance.interceptors.response.use(responseHandler, errorHandler);
|
||||
}
|
||||
|
||||
public getInstance(): AxiosType {
|
||||
return this.instance;
|
||||
}
|
||||
public getInstance(): AxiosType {
|
||||
return this.instance;
|
||||
}
|
||||
}
|
||||
|
||||
const baseURL = import.meta.env.VITE_BASE_URL || 'http://127.0.0.1:8080';
|
||||
const baseURL = import.meta.env.VITE_BASE_URL || "http://192.168.1.231:48080";
|
||||
export const axiosInstance = new AxiosInstance(baseURL).getInstance();
|
||||
|
||||
@@ -5,7 +5,8 @@ import microphoneSvg from "@/assets/translate/microphone.svg";
|
||||
import microphoneDisabledSvg from "@/assets/translate/microphoneDisabledSvg.svg";
|
||||
import { createStartRecordSound, createSendSound } from "@/utils/voice";
|
||||
import "./index.less";
|
||||
|
||||
import { useUploadAudio } from "@/api/translate";
|
||||
import VConsole from "vconsole";
|
||||
interface DefinedProps {
|
||||
onRecordingComplete: (url: string, finalDuration: number) => void;
|
||||
isRecording: boolean;
|
||||
@@ -13,6 +14,7 @@ interface DefinedProps {
|
||||
}
|
||||
function Index(props: DefinedProps) {
|
||||
const { isRecording } = props;
|
||||
const { loading: uploadLoading, error: uploadError, uploadAudio } = useUploadAudio();
|
||||
const [hasPermission, setHasPermission] = useState<boolean>(false); //是否有权限
|
||||
const [isPermissioning, setIsPermissioning] = useState<boolean>(true); //获取权限中
|
||||
const [recordingDuration, setRecordingDuration] = useState<number>(0); //录音时长进度
|
||||
@@ -23,6 +25,12 @@ function Index(props: DefinedProps) {
|
||||
// 音效相关
|
||||
const sendSoundRef = useRef<HTMLAudioElement | null>(null);
|
||||
const startRecordSoundRef = useRef<HTMLAudioElement | null>(null);
|
||||
useEffect(() => {
|
||||
// 只在开发环境启用
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
new VConsole();
|
||||
}
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
initializeSounds();
|
||||
checkMicrophonePermission();
|
||||
@@ -59,7 +67,17 @@ function Index(props: DefinedProps) {
|
||||
console.error("音效初始化失败:", error);
|
||||
}
|
||||
};
|
||||
const handleUploadAudio = async (formData: FormData) => {
|
||||
// 打印FormData内容
|
||||
|
||||
console.log(formData);
|
||||
try {
|
||||
const response = await uploadAudio(formData);
|
||||
console.log("上传成功:", response.data);
|
||||
} catch (error) {
|
||||
console.error("上传失败:", error);
|
||||
}
|
||||
};
|
||||
const renderBtn = useCallback(() => {
|
||||
if (!hasPermission) {
|
||||
//没有权限
|
||||
@@ -210,7 +228,7 @@ function Index(props: DefinedProps) {
|
||||
//录音完成
|
||||
// 在发送时检查录音时长
|
||||
const onRecordingComplete = useCallback(
|
||||
(blob: Blob) => {
|
||||
async (blob: Blob) => {
|
||||
if (isCancelledRef.current) {
|
||||
Toast.show("已取消");
|
||||
return;
|
||||
@@ -221,6 +239,10 @@ function Index(props: DefinedProps) {
|
||||
|
||||
return;
|
||||
}
|
||||
const formData = new FormData();
|
||||
formData.append("file", blob);
|
||||
|
||||
await handleUploadAudio(formData);
|
||||
const audioUrl = URL.createObjectURL(blob);
|
||||
const audio = new Audio();
|
||||
audio.src = audioUrl;
|
||||
@@ -231,7 +253,7 @@ function Index(props: DefinedProps) {
|
||||
Toast.show("录音时间太短,请重新录音");
|
||||
return;
|
||||
}
|
||||
alert(audio.duration);
|
||||
// alert(audio.duration);
|
||||
playSound(sendSoundRef);
|
||||
props.onRecordingComplete?.(audioUrl, Math.floor(audio.duration));
|
||||
});
|
||||
|
||||
@@ -4,12 +4,18 @@ import path, { resolve } from "path";
|
||||
import { inspectorServer } from "@react-dev-inspector/vite-plugin";
|
||||
import basicSsl from "@vitejs/plugin-basic-ssl";
|
||||
export default defineConfig({
|
||||
plugins: [react(), basicSsl()],
|
||||
// basicSsl()
|
||||
plugins: [react()],
|
||||
server: {
|
||||
https: {},
|
||||
port: 3000,
|
||||
host: "0.0.0.0",
|
||||
open: true,
|
||||
proxy: {
|
||||
"/app-api": {
|
||||
target: "http://192.168.1.231:48080",
|
||||
changeOrigin: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
css: {
|
||||
modules: {},
|
||||
|
||||
Reference in New Issue
Block a user