VeriFlow / server.js
tensonyin
deploy with port 7860
bce6c0d
Raw
History Blame Contribute Delete
8.19 kB
// server/index.ts
import express from "express";
import cors from "cors";
import dotenv from "dotenv";
import multer from "multer";
import { execFile } from "child_process";
import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";
dotenv.config();
var __filename = fileURLToPath(import.meta.url);
var __dirname = path.dirname(__filename);
var app = express();
var PORT = process.env.PORT || 3001;
var isBundled = fs.existsSync(path.join(__dirname, "dist"));
var distPath = isBundled ? path.join(__dirname, "dist") : path.join(__dirname, "../dist");
var difyApiKey = "";
try {
const configPath = isBundled ? path.join(__dirname, "config.json") : path.join(__dirname, "../config.json");
if (fs.existsSync(configPath)) {
const configData = JSON.parse(fs.readFileSync(configPath, "utf8"));
if (configData.dify_api_key) {
difyApiKey = configData.dify_api_key;
}
}
} catch (e) {
console.error("Failed to read config.json:", e);
}
var DIFY_API_KEY = process.env.DIFY_API_KEY || difyApiKey;
if (!DIFY_API_KEY) {
console.warn("\n\u26A0\uFE0F [WARNING]: DIFY_API_KEY is not configured! Please configure it in config.json or environment variables.\n");
}
var upload = multer({ storage: multer.memoryStorage() });
app.use(cors());
app.use(express.json());
app.get("/api/health", (req, res) => {
res.json({ status: "ok", message: "Backend is running!" });
});
app.get("/api/proxy-image", async (req, res) => {
const imageUrl = req.query.url;
if (!imageUrl) return res.status(400).send("No URL provided");
try {
const fetchRes = await fetch(imageUrl);
const buffer = await fetchRes.arrayBuffer();
res.set("Content-Type", fetchRes.headers.get("content-type") || "image/jpeg");
res.send(Buffer.from(buffer));
} catch (e) {
res.status(500).send("Error proxying image");
}
});
app.post("/api/analyze", upload.array("files", 5), async (req, res) => {
try {
if (!DIFY_API_KEY) {
return res.status(500).json({
success: false,
error: "Dify API Key is not configured on the server. Please configure it in config.json or environment variables."
});
}
const query = req.body.query || "";
const files = req.files;
const difyFileObjects = [];
if (files && files.length > 0) {
for (const file of files) {
const formData = new FormData();
const blob = new Blob([file.buffer], { type: file.mimetype });
formData.append("file", blob, file.originalname);
formData.append("user", "web-user");
const uploadRes = await fetch("https://api.dify.ai/v1/files/upload", {
method: "POST",
headers: {
"Authorization": `Bearer ${DIFY_API_KEY}`
},
body: formData
});
if (!uploadRes.ok) {
const err = await uploadRes.text();
console.error("File upload failed:", err);
throw new Error(`Failed to upload file to Dify: ${err}`);
}
const uploadData = await uploadRes.json();
let type = "document";
if (file.mimetype.startsWith("image/")) type = "image";
else if (file.mimetype.startsWith("audio/")) type = "audio";
else if (file.mimetype.startsWith("video/")) type = "video";
difyFileObjects.push({
type,
transfer_method: "local_file",
upload_file_id: uploadData.id
});
}
}
const isElderlyModeStr = req.body.isElderlyMode === "true" ? "true" : "false";
const workflowPayload = {
inputs: {
upload_files: difyFileObjects,
user_text: query,
isElderlyMode: isElderlyModeStr
},
response_mode: "streaming",
user: "web-user"
};
const runRes = await fetch("https://api.dify.ai/v1/workflows/run", {
method: "POST",
headers: {
"Authorization": `Bearer ${DIFY_API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify(workflowPayload)
});
if (!runRes.ok) {
const errText = await runRes.text();
console.error("Workflow run failed:", errText);
try {
const errJson = JSON.parse(errText);
return res.status(runRes.status).json({ success: false, error: errJson.message || errJson.code || "Workflow failed to start", details: errJson });
} catch (e) {
return res.status(runRes.status).json({ success: false, error: errText });
}
}
res.setHeader("Content-Type", "text/event-stream");
res.setHeader("Cache-Control", "no-cache");
res.setHeader("Connection", "keep-alive");
if (runRes.body) {
const reader = runRes.body.getReader();
const decoder = new TextDecoder("utf-8");
let buffer = "";
const pump = async () => {
while (true) {
const { done, value } = await reader.read();
if (done) {
res.end();
break;
}
res.write(value);
buffer += decoder.decode(value, { stream: true });
let lines = buffer.split("\n");
buffer = lines.pop() || "";
for (let line of lines) {
line = line.trim();
if (line.startsWith("data: ")) {
try {
const data = JSON.parse(line.substring(6));
if (data.event === "node_finished" && data.data) {
const title = data.data.title || data.data.node_type || "Unknown Node";
const outputText = data.data.outputs?.text || data.data.outputs?.answer || data.data.outputs?.string;
const outputAll = data.data.outputs;
console.log(`
======================================================`);
console.log(`\u{1F7E2} [NODE FINISHED]: ${title}`);
if (outputText) {
console.log(`[TEXT OUTPUT]:
${outputText}`);
} else {
console.log(`[OUTPUT DATA]:`, JSON.stringify(outputAll, null, 2));
}
console.log(`======================================================
`);
}
} catch (e) {
}
}
}
}
};
pump().catch((err) => {
console.error("Stream error:", err);
res.end();
});
} else {
res.end();
}
} catch (error) {
console.error("Error in analysis:", error);
res.status(500).json({ success: false, error: "Internal Server Error", details: error.message || String(error) });
}
});
app.post("/api/tts", async (req, res) => {
try {
const { text, voice, rate } = req.body;
if (!text) {
return res.status(400).json({ error: "No text provided" });
}
const voiceName = voice || "zh-CN-XiaoyiNeural";
const speechRate = rate || "-12%";
const tempFileName = `tts_${Date.now()}_${Math.floor(Math.random() * 1e3)}.mp3`;
const tempFilePath = path.join(process.cwd(), tempFileName);
execFile("edge-tts", [
"--voice",
voiceName,
"--text",
text,
`--rate=${speechRate}`,
"--write-media",
tempFilePath
], (error, stdout, stderr) => {
if (error) {
console.error("edge-tts execution failed:", error, stderr);
return res.status(500).json({ error: "TTS generation failed", details: error.message });
}
res.sendFile(tempFilePath, (err) => {
fs.unlink(tempFilePath, (unlinkErr) => {
if (unlinkErr) console.error("Failed to unlink temporary TTS file:", unlinkErr);
});
if (err) {
console.error("Error sending TTS file:", err);
}
});
});
} catch (err) {
console.error("TTS endpoint error:", err);
res.status(500).json({ error: "Internal Server Error in TTS endpoint", details: err.message });
}
});
app.use(express.static(distPath));
app.get("*", (req, res) => {
const indexPage = path.join(distPath, "index.html");
if (fs.existsSync(indexPage)) {
res.sendFile(indexPage);
} else {
res.status(404).send('Frontend not built. Run "npm run build" first.');
}
});
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});