/**
* خادم TTS مع واجهة HTML تدعم بلوجر ووردبريس
* يستخدم Coqui TTS ويحمّل النماذج تلقائيًا عند أول تشغيل
*/
const express = require("express");
const cors = require("cors");
const bodyParser = require("body-parser");
const { exec } = require("child_process");
const fs = require("fs");
const path = require("path");
const app = express();
app.use(cors());
app.use(bodyParser.json({ limit: "5mb" }));
const TMP_DIR = "/tmp";
const PORT = process.env.PORT || 3000;
// مسارات النماذج
const VOICES = {
male: "tts_models/ar/male",
female: "tts_models/ar/female",
};
// فحص إذا كان النموذج موجود
function checkModelInstalled(modelName) {
const homeDir = process.env.HOME || "/root";
const modelPath = path.join(
homeDir,
".local",
"share",
"tts",
"models",
modelName.replace(/\//g, "_")
);
return fs.existsSync(modelPath);
}
// تنزيل نموذج
function installModel(modelName) {
return new Promise((resolve, reject) => {
console.log(`⬇️ تنزيل النموذج: ${modelName} ...`);
exec(`tts --model_name "${modelName}" --list_models > /dev/null`, (err) => {
if (err) return reject(err);
resolve();
});
});
}
// التأكد من تثبيت النماذج
async function ensureModels() {
for (const [voice, modelName] of Object.entries(VOICES)) {
if (!checkModelInstalled(modelName)) {
console.log(`🔄 النموذج (${voice}) غير موجود. تحميله...`);
await installModel(modelName);
console.log(`✅ تم تحميل النموذج (${voice})`);
} else {
console.log(`✅ النموذج (${voice}) موجود بالفعل`);
}
}
}
// API لتحويل النص لصوت
app.post("/tts", (req, res) => {
const text = req.body.text || "";
const voice = req.body.voice || "male";
if (!text.trim()) return res.status(400).json({ error: "النص مطلوب" });
if (!VOICES[voice]) return res.status(400).json({ error: "الصوت غير مدعوم" });
const tempFile = path.join(TMP_DIR, `tts_${Date.now()}.wav`);
const command = `tts --text "${text.replace(/"/g, '\\"')}" --model_name "${VOICES[voice]}" --out_path "${tempFile}"`;
exec(command, (err) => {
if (err) {
console.error("TTS error:", err);
return res.status(500).json({ error: "خطأ في توليد الصوت" });
}
fs.readFile(tempFile, (err, data) => {
if (err) {
console.error("File read error:", err);
return res.status(500).json({ error: "تعذر قراءة ملف الصوت" });
}
res.set("Content-Type", "audio/wav");
res.send(data);
fs.unlink(tempFile, () => {});
});
});
});
// صفحة HTML
app.get("/", (req, res) => {
res.send(`
قراءة المقالة صوتياً
اختر القارئ للاستماع إلى المقالة
`);
});
// تشغيل الخادم
(async () => {
console.log("🔍 فحص النماذج...");
try {
await ensureModels();
app.listen(PORT, () => {
console.log(`🚀 الخادم يعمل على http://localhost:${PORT}`);
});
} catch (e) {
console.error("❌ خطأ أثناء تحميل النماذج:", e);
process.exit(1);
}
})();