Add AI-powered description generation for video content
Integrates OpenAI API to generate video descriptions using AI, with new API endpoints for single and bulk generation, and a UI button in the admin panel to trigger the process. Includes OpenAI dependency and a new `aiService.ts` file. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 170e18f0-0f13-4eca-8643-546bba1dd8cc Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/8cc42625-c1f5-4e43-99bd-77f2c4dedee2/170e18f0-0f13-4eca-8643-546bba1dd8cc/td5Y4HG
This commit is contained in:
@@ -18,6 +18,7 @@ import sharp from "sharp";
|
||||
import fetch from "node-fetch";
|
||||
import { setupAuth, isAuthenticated, isAdmin } from "./replitAuth";
|
||||
import { ObjectStorageService, ObjectNotFoundError } from "./objectStorage";
|
||||
import { generateVideoDescription, generateBulkDescriptions } from "./aiService";
|
||||
|
||||
// Extend express session
|
||||
declare module "express-session" {
|
||||
@@ -1080,6 +1081,88 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
||||
}
|
||||
});
|
||||
|
||||
// ===== AI DESCRIPTION ROUTES =====
|
||||
|
||||
// Generate AI description for single video (admin only)
|
||||
app.post('/api/admin/videos/:id/generate-description', isAdmin, async (req, res) => {
|
||||
try {
|
||||
const videoId = req.params.id;
|
||||
const { maxCharacters = 500, includeArtistInfo = true, includeLabelInfo = true } = req.body;
|
||||
|
||||
// Get video details
|
||||
const video = await storage.getVideo(videoId);
|
||||
if (!video) {
|
||||
return res.status(404).json({ message: "Video not found" });
|
||||
}
|
||||
|
||||
// Generate description using AI
|
||||
const description = await generateVideoDescription(video.title, {
|
||||
maxCharacters,
|
||||
language: "slovenian",
|
||||
includeArtistInfo,
|
||||
includeLabelInfo
|
||||
});
|
||||
|
||||
res.json({
|
||||
description,
|
||||
title: video.title,
|
||||
characterCount: description.length,
|
||||
maxCharacters
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error generating AI description:", error);
|
||||
res.status(500).json({
|
||||
message: error instanceof Error ? error.message : "Failed to generate description"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Generate AI descriptions for multiple videos (admin only)
|
||||
app.post('/api/admin/videos/generate-descriptions-bulk', isAdmin, async (req, res) => {
|
||||
try {
|
||||
const { videoIds, maxCharacters = 500, includeArtistInfo = true, includeLabelInfo = true } = req.body;
|
||||
|
||||
if (!Array.isArray(videoIds) || videoIds.length === 0) {
|
||||
return res.status(400).json({ message: "Video IDs array is required" });
|
||||
}
|
||||
|
||||
if (videoIds.length > 50) {
|
||||
return res.status(400).json({ message: "Maximum 50 videos can be processed at once" });
|
||||
}
|
||||
|
||||
// Get video details for all requested videos
|
||||
const videos = [];
|
||||
for (const id of videoIds) {
|
||||
const video = await storage.getVideo(id);
|
||||
if (video) {
|
||||
videos.push({ id: video.id, title: video.title });
|
||||
}
|
||||
}
|
||||
|
||||
// Generate descriptions using AI
|
||||
const results = await generateBulkDescriptions(videos, {
|
||||
maxCharacters,
|
||||
language: "slovenian",
|
||||
includeArtistInfo,
|
||||
includeLabelInfo
|
||||
});
|
||||
|
||||
res.json({
|
||||
results,
|
||||
processed: results.length,
|
||||
successful: results.filter(r => !r.error).length,
|
||||
failed: results.filter(r => r.error).length
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error generating bulk AI descriptions:", error);
|
||||
res.status(500).json({
|
||||
message: error instanceof Error ? error.message : "Failed to generate descriptions"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const httpServer = createServer(app);
|
||||
return httpServer;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user