bump version to 1.8.2

This commit is contained in:
小鱼开发
2026-06-08 13:30:02 +08:00
parent c98509c07a
commit 4612abeb9e
15 changed files with 57 additions and 30 deletions
+1 -1
View File
@@ -9,7 +9,7 @@
**美家卡智影**是一款面向桌面端的 AI 视频创作应用,采用"Python 后端 API + Tauri 桌面前端"的混合架构。
- **产品标识**: `cn.meijiaka.ai-video` / `cn.meijiaka.ai-zy`
- **版本**: `1.8.1`
- **版本**: `1.8.2`
- **核心功能**: AI 脚本生成、AI 配音合成(TTS)、声音复刻、视频生成(Vidu)、视频字幕生成、压制成片(FFmpeg)、项目本地持久化
### 技术栈总览
+1 -1
View File
@@ -1 +1 @@
1.8.1
1.8.2
+1 -1
View File
@@ -4,7 +4,7 @@
# === 基础配置 ===
APP_NAME=美家卡智影 API
APP_VERSION=1.8.1
APP_VERSION=1.8.2
# ⚠️ 生产环境必须设为 false
DEBUG=true
ENV=development
+1 -1
View File
@@ -24,7 +24,7 @@ class Settings(BaseSettings):
# 应用基础配置
APP_NAME: str = Field(default="美家卡智影 API", description="应用名称")
APP_VERSION: str = Field(default="1.8.1", description="应用版本")
APP_VERSION: str = Field(default="1.8.2", description="应用版本")
DEBUG: bool = Field(default=False, description="调试模式")
ENV: Literal["development", "staging", "production"] = Field(
default="development", description="运行环境"
+1 -1
View File
@@ -1,6 +1,6 @@
[project]
name = "meijiaka-ai-api"
version = "1.8.1"
version = "1.8.2"
description = "美家卡智影 - AI 视频创作后端 API"
authors = [{ name = "Meijiaka Team" }]
readme = "README.md"
+1 -1
View File
@@ -944,7 +944,7 @@ wheels = [
[[package]]
name = "meijiaka-ai-api"
version = "1.8.1"
version = "1.8.2"
source = { virtual = "." }
dependencies = [
{ name = "aiohttp" },
+1 -1
View File
@@ -9,7 +9,7 @@
**美家卡智影**(产品名)是一款基于 Tauri v2 + React 19 + TypeScript 的桌面端 AI 视频创作应用。
- **产品标识**: `cn.meijiaka.ai-video`
- **版本**: `1.8.1`
- **版本**: `1.8.2`
- **窗口尺寸**: 1200×800,不可缩放(`resizable: false`
- **核心功能**: AI 脚本生成、AI 配音合成、视频生成、压制成片(FFmpeg)、项目本地持久化
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "tauri-app",
"version": "1.8.1",
"version": "1.8.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "tauri-app",
"version": "1.8.1",
"version": "1.8.2",
"dependencies": {
"@microsoft/fetch-event-source": "^2.0.1",
"@tanstack/react-virtual": "^3.13.23",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "tauri-app",
"private": true,
"version": "1.8.1",
"version": "1.8.2",
"type": "module",
"scripts": {
"dev": "vite",
+1 -1
View File
@@ -4219,7 +4219,7 @@ dependencies = [
[[package]]
name = "tauri-app"
version = "1.8.1"
version = "1.8.2"
dependencies = [
"base64 0.22.1",
"chrono",
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "tauri-app"
version = "1.8.1"
version = "1.8.2"
description = "美家卡智影 - AI 视频创作桌面应用"
authors = ["美家卡科技"]
edition = "2021"
@@ -55,20 +55,24 @@ fn validate_nine_sixteen_aspect(width: u32, height: u32) -> Result<(), String> {
Ok(())
}
/// 根据素材最高度决定目标输出分辨率
/// 根据素材最高度决定目标输出分辨率
///
/// 向上统一到最高素材的分辨率:只要存在 1080p 素材,成片就输出 1080p
/// 避免高分辨率素材被强制压缩到 720p 导致画面模糊。
/// 720p 素材会被放大拼接,虽然略有损失,但优于整体降质。
fn resolve_target_resolution(heights: &[u32]) -> Option<(u32, u32)> {
let min_height = heights.iter().min()?;
if *min_height <= 1280 {
Some((720, 1280))
} else {
let max_height = heights.iter().max()?;
if *max_height >= 1920 {
Some((1080, 1920))
} else {
Some((720, 1280))
}
}
/// 拼接视频片段
///
/// 1. 探测所有片段分辨率并校验 9:16 比例
/// 2. 按最高度决定目标输出分辨率
/// 2. 按最高度决定目标输出分辨率(向上统一,避免高分辨率素材被压糊)
/// 3. 统一标准化后拼接
#[tauri::command]
pub async fn concat_video_clips(
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "美家卡智影",
"version": "1.8.1",
"version": "1.8.2",
"identifier": "cn.meijiaka.ai-zy",
"build": {
"beforeDevCommand": "npm run dev",
@@ -143,7 +143,7 @@ export default function VoiceMaterialLibrary() {
// 音频文件验证
const validateAudioFile = (file: File): Promise<{ valid: boolean; error?: string }> => {
return new Promise(resolve => {
const maxSize = 20 * 1024 * 1024; // 20MB
const maxSize = 50 * 1024 * 1024; // 50MB
if (file.size > maxSize) {
resolve({ valid: false, error: `文件大小 ${(file.size / 1024 / 1024).toFixed(1)}MB,要求不超过 20MB` });
return;
@@ -260,6 +260,7 @@ export default function VoiceMaterialLibrary() {
progress.update('正在生成专属音色...');
progress.success('复刻成功', 200);
} catch (err) {
console.error('[VoiceMaterialLibrary] handleUpload catch:', err, '类型:', typeof err, '是Error?', err instanceof Error);
const msg = err instanceof Error ? err.message : '上传失败';
if (msg.includes('402') || msg.includes('积分不足')) {
setShowPointsModal(true);
@@ -419,7 +420,7 @@ export default function VoiceMaterialLibrary() {
<div style={{ fontSize: 'var(--font-sm)' }}></div>
<div style={{ fontSize: 'var(--font-xs)', marginTop: 6, lineHeight: 1.6 }}>
<div> MP3 / M4A / WAV / MP4</div>
<div> 10 ~ 2 20MB</div>
<div> 10 ~ 2 50MB</div>
</div>
</div>
)}
+31 -9
View File
@@ -8,7 +8,7 @@
import { create } from 'zustand';
import type { VoiceInfo, VoiceMaterial } from '../api/modules/voice';
import * as voiceApi from '../api/modules/voice';
import { writeFile, remove, BaseDirectory } from '@tauri-apps/plugin-fs';
import { writeFile, remove, mkdir, BaseDirectory } from '@tauri-apps/plugin-fs';
import { join, appLocalDataDir } from '@tauri-apps/api/path';
interface VoiceState {
@@ -136,33 +136,45 @@ export const useVoiceStore = create<VoiceState & VoiceActions>()(
try {
const ext = file.name.substring(file.name.lastIndexOf('.')).toLowerCase();
console.log('[VoiceStore] addVoiceMaterial 开始, ext=', ext, 'fileName=', file.name, 'size=', file.size);
if (ext === '.mp4') {
// MP4 需要先本地提取音频
tempVideoPath = await join('temp', `upload_${Date.now()}_${Math.random().toString(36).slice(2, 8)}.mp4`);
console.log('[VoiceStore] tempVideoPath=', tempVideoPath);
// 1a. 将 File 写入本地临时文件(使用 BaseDirectory.AppLocalData
console.log('[VoiceStore] 开始 writeFile...');
await mkdir('temp', { baseDir: BaseDirectory.AppLocalData, recursive: true });
const arrayBuffer = await file.arrayBuffer();
const uint8Array = new Uint8Array(arrayBuffer);
await writeFile(tempVideoPath, uint8Array, { baseDir: BaseDirectory.AppLocalData });
console.log('[VoiceStore] writeFile 完成');
// 1b. 调用 FFmpeg 提取音频(Rust 返回绝对路径)
tempMp3Path = await voiceApi.extractAudioFromVideo(
await join(await appLocalDataDir(), tempVideoPath)
);
const videoAbsPath = await join(await appLocalDataDir(), tempVideoPath);
console.log('[VoiceStore] 开始 extractAudioFromVideo, path=', videoAbsPath);
tempMp3Path = await voiceApi.extractAudioFromVideo(videoAbsPath);
console.log('[VoiceStore] extractAudioFromVideo 完成, mp3Path=', tempMp3Path);
// 1c. 上传提取的 MP3
console.log('[VoiceStore] 开始 uploadLocalAudioFile...');
sourceUrl = await voiceApi.uploadLocalAudioFile(tempMp3Path);
console.log('[VoiceStore] uploadLocalAudioFile 完成, url=', sourceUrl);
} else {
// 音频文件直接上传
console.log('[VoiceStore] 直接上传音频文件...');
sourceUrl = await voiceApi.uploadAudio(file);
console.log('[VoiceStore] uploadAudio 完成, url=', sourceUrl);
}
// 2. 提交 Vidu 同步克隆
console.log('[VoiceStore] 开始 submitCloneTask...');
const cloneResult = await voiceApi.submitCloneTask({
sourceAudioUrl: sourceUrl,
voiceName: name,
});
console.log('[VoiceStore] submitCloneTask 完成, result=', cloneResult);
// 3. Vidu 同步返回,直接 ready
const material: VoiceMaterial = {
@@ -174,26 +186,36 @@ export const useVoiceStore = create<VoiceState & VoiceActions>()(
status: 'ready',
createdAt: new Date().toISOString(),
};
console.log('[VoiceStore] material=', material);
// 4. 保存到本地 JSON
console.log('[VoiceStore] 开始 saveVoiceMaterial...');
await voiceApi.saveVoiceMaterial(material);
console.log('[VoiceStore] saveVoiceMaterial 完成');
set(state => ({ voiceMaterials: [material, ...state.voiceMaterials] }));
console.log('[VoiceStore] addVoiceMaterial 成功返回');
return material;
} catch (err) {
console.error('[VoiceStore] addVoiceMaterial 异常:', err, '类型:', typeof err, '是Error?', err instanceof Error, 'message:', (err as Error)?.message);
throw err;
} finally {
// 清理临时文件
console.log('[VoiceStore] finally 清理, tempVideoPath=', tempVideoPath, 'tempMp3Path=', tempMp3Path);
if (tempVideoPath) {
try {
await remove(tempVideoPath, { baseDir: BaseDirectory.AppLocalData });
} catch {
// 忽略清理错误
console.log('[VoiceStore] 清理 tempVideoPath 成功');
} catch (e) {
console.error('[VoiceStore] 清理 tempVideoPath 失败:', e);
}
}
if (tempMp3Path) {
try {
await remove(tempMp3Path);
} catch {
// 忽略清理错误
await remove(tempMp3Path, { baseDir: BaseDirectory.AppLocalData });
console.log('[VoiceStore] 清理 tempMp3Path 成功');
} catch (e) {
console.error('[VoiceStore] 清理 tempMp3Path 失败:', e);
}
}
}