mirror of
https://github.com/R0m1k3/Socialflow.git
synced 2026-10-11 17:26:45 +02:00
refactor: remove Piper TTS, keep edge_tts only
- Remove piper_url from ReelRequest model and all function signatures - Remove generate_tts_piper() function and Piper branch in generate_tts_with_subs() - Remove /api/piper/config routes from server/routes.ts - Remove piperConfig table, schemas and storage methods - Remove piper_config migration - Remove Piper TTS settings UI card - Update "Piper TTS" labels to "TTS — voix activée" edge_tts is now the only TTS engine, using precise word-boundary timing
This commit is contained in:
1 parent
8736e4f6a0
commit
59bc56aedc
12 files changed
+46
-265
No files matched your search
@@ -152,18 +152,6 @@ export async function migrate() {
|
||||
);
|
||||
`);
|
||||
|
||||
// piper_config
|
||||
await client.query(`
|
||||
CREATE TABLE IF NOT EXISTS "piper_config" (
|
||||
"id" varchar PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"user_id" varchar NOT NULL REFERENCES "users"("id") ON DELETE cascade,
|
||||
"url" text NOT NULL,
|
||||
"created_at" timestamp DEFAULT now(),
|
||||
"updated_at" timestamp DEFAULT now(),
|
||||
CONSTRAINT piper_config_user_id_unique UNIQUE ("user_id")
|
||||
);
|
||||
`);
|
||||
|
||||
console.log("[Migration] Safe migration completed.");
|
||||
} catch (error) {
|
||||
console.error("[Migration] Error during migration:", error);
|
||||
|
||||
+1
-38
@@ -10,7 +10,7 @@ import passport from "./auth";
|
||||
import { z } from "zod";
|
||||
import { openRouterService } from "./services/openrouter";
|
||||
import { minioService as cloudinaryService, buildMinioUrl } from "./services/minio";
|
||||
import { insertPostSchema, insertScheduledPostSchema, insertSocialPageSchema, insertAiGenerationSchema, insertCloudinaryConfigSchema, updateCloudinaryConfigSchema, insertOpenrouterConfigSchema, updateOpenrouterConfigSchema, insertPiperConfigSchema, updatePiperConfigSchema, insertUserSchema, postMedia, type SocialPage } from "@shared/schema";
|
||||
import { insertPostSchema, insertScheduledPostSchema, insertSocialPageSchema, insertAiGenerationSchema, insertCloudinaryConfigSchema, updateCloudinaryConfigSchema, insertOpenrouterConfigSchema, updateOpenrouterConfigSchema, insertUserSchema, postMedia, type SocialPage } from "@shared/schema";
|
||||
import type { User, InsertUser, ScheduledPost } from "@shared/schema";
|
||||
import { analyticsRouter } from "./routes/analytics";
|
||||
import { reelsRouter } from "./routes/reels";
|
||||
@@ -423,43 +423,6 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
||||
// Analytics Routes
|
||||
app.use("/api/analytics", requireAuth, analyticsRouter);
|
||||
|
||||
// Piper TTS Configuration Routes
|
||||
app.get("/api/piper/config", requireAuth, async (req, res) => {
|
||||
try {
|
||||
const user = req.user as User;
|
||||
const config = await storage.getPiperConfig(user.id);
|
||||
if (!config) {
|
||||
return res.json(null);
|
||||
}
|
||||
return res.json(config);
|
||||
} catch (error) {
|
||||
console.error("Error fetching Piper config:", error);
|
||||
res.status(500).json({ error: "Failed to fetch configuration" });
|
||||
}
|
||||
});
|
||||
|
||||
app.post("/api/piper/config", requireAuth, async (req, res) => {
|
||||
try {
|
||||
const user = req.user as User;
|
||||
const data = updatePiperConfigSchema.parse(req.body);
|
||||
|
||||
let config = await storage.getPiperConfig(user.id);
|
||||
if (config) {
|
||||
config = await storage.updatePiperConfig(user.id, data);
|
||||
} else {
|
||||
if (!data.url) {
|
||||
return res.status(400).json({ error: "URL is required" });
|
||||
}
|
||||
config = await storage.createPiperConfig({ ...data as any, userId: user.id });
|
||||
}
|
||||
|
||||
res.json({ success: true });
|
||||
} catch (error) {
|
||||
console.error("Error saving Piper config:", error);
|
||||
res.status(500).json({ error: "Failed to save configuration" });
|
||||
}
|
||||
});
|
||||
|
||||
// Reels & Music Routes
|
||||
app.use("/api", requireAuth, reelsRouter);
|
||||
app.use("/api/remotion", requireAuth, remotionRouter);
|
||||
|
||||
+4
-17
@@ -320,18 +320,12 @@ reelsRouter.post('/reels/preview', async (req: Request, res: Response) => {
|
||||
|
||||
const finalWordDuration = wordDuration;
|
||||
|
||||
let piperUrl: string | undefined;
|
||||
if (ttsEnabled) {
|
||||
const piperCfg = await storage.getPiperConfig(user.id);
|
||||
piperUrl = piperCfg?.url ?? undefined;
|
||||
}
|
||||
|
||||
// Traiter la vidéo via FFmpeg
|
||||
const result = await ffmpegService.processReelFromUrl(resolveInternalUrl(media.originalUrl), {
|
||||
text: overlayText,
|
||||
musicUrl: finalMusicUrl,
|
||||
ttsEnabled,
|
||||
piperUrl,
|
||||
ttsVoice,
|
||||
wordDuration: finalWordDuration,
|
||||
fontSize,
|
||||
musicVolume,
|
||||
@@ -370,8 +364,7 @@ reelsRouter.post('/reels/tts-preview', async (req: Request, res: Response) => {
|
||||
return res.status(400).json({ error: 'Texte requis' });
|
||||
}
|
||||
|
||||
const piperCfg = await storage.getPiperConfig(user.id);
|
||||
const result = await ffmpegService.previewTTS(text, piperCfg?.url);
|
||||
const result = await ffmpegService.previewTTS(text, voice);
|
||||
|
||||
if (!result.success) {
|
||||
return res.status(500).json({ error: result.error || 'Erreur de génération TTS' });
|
||||
@@ -550,19 +543,13 @@ async function processReelBackground(
|
||||
|
||||
const finalWordDuration = wordDuration ?? 0.6;
|
||||
|
||||
let piperUrlBg: string | undefined;
|
||||
if (ttsEnabled) {
|
||||
const piperCfg = await storage.getPiperConfig(userId);
|
||||
piperUrlBg = piperCfg?.url ?? undefined;
|
||||
}
|
||||
|
||||
console.log('🔊 [Background] TTS config:', { ttsEnabled, hasPiperUrl: !!piperUrlBg });
|
||||
console.log('🔊 [Background] TTS config:', { ttsEnabled, ttsVoice });
|
||||
|
||||
const ffmpegResult = await ffmpegService.processReelFromUrl(resolveInternalUrl(media.originalUrl), {
|
||||
text: overlayText,
|
||||
musicUrl: finalMusicUrl,
|
||||
ttsEnabled,
|
||||
piperUrl: piperUrlBg,
|
||||
ttsVoice,
|
||||
wordDuration: finalWordDuration,
|
||||
fontSize,
|
||||
musicVolume,
|
||||
|
||||
@@ -12,7 +12,7 @@ interface FFmpegReelRequest {
|
||||
music_id?: string; // ID de la musique (catalogue FFmpeg)
|
||||
music_url?: string; // OU URL directe de la musique
|
||||
tts_enabled?: boolean; // Activation du TTS
|
||||
piper_url?: string; // URL du serveur Piper TTS
|
||||
tts_voice?: string; // Voix TTS (ex: fr-FR-VivienneNeural)
|
||||
word_duration?: number; // Durée par mot (default: 0.6s)
|
||||
font_size?: number; // Taille police (default: 24)
|
||||
music_volume?: number; // Volume musique (default: 0.25)
|
||||
@@ -71,7 +71,7 @@ export class FFmpegService {
|
||||
musicId?: string;
|
||||
musicUrl?: string;
|
||||
ttsEnabled?: boolean;
|
||||
piperUrl?: string;
|
||||
ttsVoice?: string;
|
||||
wordDuration?: number;
|
||||
fontSize?: number;
|
||||
musicVolume?: number;
|
||||
@@ -90,7 +90,7 @@ export class FFmpegService {
|
||||
music_id: options.musicId,
|
||||
music_url: options.musicUrl,
|
||||
tts_enabled: options.ttsEnabled,
|
||||
piper_url: options.piperUrl,
|
||||
tts_voice: options.ttsVoice,
|
||||
word_duration: options.wordDuration ?? 0.6,
|
||||
font_size: options.fontSize ?? 64,
|
||||
music_volume: options.musicVolume ?? 0.25,
|
||||
@@ -172,7 +172,7 @@ export class FFmpegService {
|
||||
musicId?: string;
|
||||
musicUrl?: string;
|
||||
ttsEnabled?: boolean;
|
||||
piperUrl?: string;
|
||||
ttsVoice?: string;
|
||||
wordDuration?: number;
|
||||
fontSize?: number;
|
||||
musicVolume?: number;
|
||||
@@ -191,7 +191,7 @@ export class FFmpegService {
|
||||
music_id: options.musicId,
|
||||
music_url: options.musicUrl,
|
||||
tts_enabled: options.ttsEnabled,
|
||||
piper_url: options.piperUrl,
|
||||
tts_voice: options.ttsVoice,
|
||||
word_duration: options.wordDuration ?? 0.6,
|
||||
font_size: options.fontSize ?? 64,
|
||||
music_volume: options.musicVolume ?? 0.25,
|
||||
@@ -216,7 +216,6 @@ export class FFmpegService {
|
||||
hasMusicId: !!options.musicId,
|
||||
hasMusicUrl: !!options.musicUrl,
|
||||
ttsEnabled: options.ttsEnabled,
|
||||
hasPiperUrl: !!options.piperUrl,
|
||||
drawText: options.drawText,
|
||||
});
|
||||
|
||||
@@ -291,7 +290,7 @@ export class FFmpegService {
|
||||
}
|
||||
async previewTTS(
|
||||
text: string,
|
||||
piperUrl?: string
|
||||
ttsVoice?: string
|
||||
): Promise<{ success: boolean; audioBase64?: string; error?: string }> {
|
||||
const config = this.ensureConfigured();
|
||||
|
||||
@@ -305,7 +304,7 @@ export class FFmpegService {
|
||||
body: JSON.stringify({
|
||||
text,
|
||||
tts_enabled: true,
|
||||
piper_url: piperUrl,
|
||||
tts_voice: ttsVoice,
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
+1
-26
@@ -31,9 +31,6 @@ import {
|
||||
musicFavorites,
|
||||
type MusicFavorite,
|
||||
type InsertMusicFavorite,
|
||||
piperConfig,
|
||||
type PiperConfig,
|
||||
type InsertPiperConfig,
|
||||
audioTracks,
|
||||
type AudioTrack,
|
||||
type InsertAudioTrack,
|
||||
@@ -120,15 +117,11 @@ export interface IStorage {
|
||||
|
||||
// Audio Tracks
|
||||
getAudioTracks(): Promise<AudioTrack[]>;
|
||||
// Audio Tracks
|
||||
getAudioTrack(id: string): Promise<AudioTrack | undefined>;
|
||||
createAudioTrack(track: InsertAudioTrack): Promise<AudioTrack>;
|
||||
deleteAudioTrack(id: string): Promise<void>;
|
||||
|
||||
// Piper Config
|
||||
getPiperConfig(userId: string): Promise<PiperConfig | undefined>;
|
||||
createPiperConfig(config: InsertPiperConfig): Promise<PiperConfig>;
|
||||
updatePiperConfig(userId: string, config: Partial<InsertPiperConfig>): Promise<PiperConfig>;
|
||||
|
||||
// App Config
|
||||
getAppConfig(): Promise<AppConfig | undefined>;
|
||||
upsertAppConfig(data: Partial<Pick<AppConfig, 'externalApiKey'>>): Promise<AppConfig>;
|
||||
@@ -590,24 +583,6 @@ export class DatabaseStorage implements IStorage {
|
||||
const [created] = await db.insert(appConfig).values(data).returning();
|
||||
return created;
|
||||
}
|
||||
// Piper Config
|
||||
async getPiperConfig(userId: string): Promise<PiperConfig | undefined> {
|
||||
const [config] = await db.select().from(piperConfig).where(eq(piperConfig.userId, userId));
|
||||
return config || undefined;
|
||||
}
|
||||
|
||||
async createPiperConfig(config: InsertPiperConfig): Promise<PiperConfig> {
|
||||
const [newConfig] = await db.insert(piperConfig).values(config).returning();
|
||||
return newConfig;
|
||||
}
|
||||
|
||||
async updatePiperConfig(userId: string, config: Partial<InsertPiperConfig>): Promise<PiperConfig> {
|
||||
const [updated] = await db.update(piperConfig)
|
||||
.set({ ...config, updatedAt: new Date() })
|
||||
.where(eq(piperConfig.userId, userId))
|
||||
.returning();
|
||||
return updated;
|
||||
}
|
||||
}
|
||||
|
||||
export const storage = new DatabaseStorage();
|
||||
Reference in new issue
Block a user