Metadata ve çeviri ile ilgili düzeltmeler. UI değişiklikleri.
This commit is contained in:
@@ -4,10 +4,11 @@ import cors from 'cors';
|
||||
import bcrypt from 'bcryptjs';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { tmpdir } from 'os';
|
||||
import { join } from 'path';
|
||||
import { dirname, join } from 'path';
|
||||
import { promises as fs } from 'fs';
|
||||
import { v4 as uuidV4 } from 'uuid';
|
||||
import Epub from 'epub-gen';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const requiredEnv = [
|
||||
'SUPABASE_URL',
|
||||
@@ -22,6 +23,7 @@ requiredEnv.forEach((key) => {
|
||||
}
|
||||
});
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const app = express();
|
||||
const PORT = process.env.PORT || 4000;
|
||||
const ORIGIN = process.env.CLIENT_ORIGIN || 'http://localhost:5173';
|
||||
@@ -260,8 +262,10 @@ app.post('/translate', async (req, res) => {
|
||||
return res.status(400).json({ message: 'Çevrilecek metin bulunamadı.' });
|
||||
}
|
||||
|
||||
console.log('[Translate] İstek alındı', { length: text.length, snippet: text.slice(0, 60) });
|
||||
try {
|
||||
const translated = await translateWithGlm(text);
|
||||
console.log('[Translate] Çeviri başarıyla döndü');
|
||||
return res.json({ text: translated });
|
||||
} catch (error) {
|
||||
console.error('GLM çeviri hatası:', error);
|
||||
@@ -275,9 +279,17 @@ app.post('/generate-epub', async (req, res) => {
|
||||
return res.status(400).json({ message: 'text is required' });
|
||||
}
|
||||
|
||||
const title = meta?.title || 'imgPub OCR Export';
|
||||
const author = meta?.author || 'imgPub';
|
||||
const title = meta?.title?.trim() || 'imgPub OCR Export';
|
||||
const filename = meta?.filename || `imgpub${Date.now()}.epub`;
|
||||
const authors =
|
||||
Array.isArray(meta?.authors) && meta.authors.length
|
||||
? meta.authors.filter(Boolean)
|
||||
: meta?.author
|
||||
? [meta.author]
|
||||
: ['imgPub'];
|
||||
const publisher = meta?.publisher || 'imgPub';
|
||||
const language = meta?.language || 'tr';
|
||||
const description = meta?.description || title;
|
||||
|
||||
const content = [
|
||||
{
|
||||
@@ -288,6 +300,18 @@ app.post('/generate-epub', async (req, res) => {
|
||||
|
||||
const outputPath = join(tmpdir(), `imgpub-${uuidV4()}.epub`);
|
||||
let coverPath;
|
||||
const metadataPayload = {
|
||||
subtitle: meta?.subtitle,
|
||||
description: meta?.description,
|
||||
categories: Array.isArray(meta?.categories) ? meta.categories : [],
|
||||
publishedDate: meta?.publishedDate,
|
||||
language: meta?.language,
|
||||
pageCount: meta?.pageCount,
|
||||
averageRating: meta?.averageRating,
|
||||
ratingsCount: meta?.ratingsCount,
|
||||
identifiers: Array.isArray(meta?.identifiers) ? meta.identifiers : [],
|
||||
infoLink: meta?.infoLink,
|
||||
};
|
||||
|
||||
try {
|
||||
if (cover?.data) {
|
||||
@@ -298,7 +322,16 @@ app.post('/generate-epub', async (req, res) => {
|
||||
await fs.writeFile(coverPath, coverBuffer);
|
||||
}
|
||||
|
||||
const epubOptions = { title, author, content };
|
||||
const epubOptions = {
|
||||
title,
|
||||
author: authors,
|
||||
publisher,
|
||||
description,
|
||||
lang: language,
|
||||
content,
|
||||
bookMetadata: metadataPayload,
|
||||
customOpfTemplatePath: join(__dirname, 'templates', 'content.opf.ejs'),
|
||||
};
|
||||
if (coverPath) {
|
||||
epubOptions.cover = coverPath;
|
||||
}
|
||||
|
||||
@@ -112,6 +112,12 @@ export const translateWithGlm = async (text) => {
|
||||
};
|
||||
}
|
||||
|
||||
console.log('[GLM] İstek hazırlanıyor', {
|
||||
endpoint: GLM_API_URL,
|
||||
model: GLM_MODEL,
|
||||
snippet: text.slice(0, 80),
|
||||
});
|
||||
|
||||
const response = await fetch(GLM_API_URL, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
@@ -125,7 +131,20 @@ export const translateWithGlm = async (text) => {
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
|
||||
const payload = await response.json().catch(() => ({}));
|
||||
let payload = {};
|
||||
try {
|
||||
payload = await response.json();
|
||||
} catch (error) {
|
||||
console.error('[GLM] JSON parse başarısız', error);
|
||||
}
|
||||
|
||||
console.log('[GLM] Yanıt alındı', {
|
||||
status: response.status,
|
||||
ok: response.ok,
|
||||
hasOutput: Boolean(payload?.output || payload?.choices || payload?.content),
|
||||
error: payload?.error,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const message =
|
||||
payload?.error?.message ||
|
||||
@@ -136,7 +155,9 @@ export const translateWithGlm = async (text) => {
|
||||
|
||||
const translated = extractContent(payload);
|
||||
if (!translated) {
|
||||
console.error('[GLM] Boş içerik döndü', payload);
|
||||
throw new Error('GLM çıktısı boş döndü.');
|
||||
}
|
||||
console.log('[GLM] Çeviri tamamlandı');
|
||||
return translated;
|
||||
};
|
||||
|
||||
100
server/templates/content.opf.ejs
Normal file
100
server/templates/content.opf.ejs
Normal file
@@ -0,0 +1,100 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<package xmlns="http://www.idpf.org/2007/opf"
|
||||
version="3.0"
|
||||
unique-identifier="BookId"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:dcterms="http://purl.org/dc/terms/"
|
||||
xml:lang="en"
|
||||
xmlns:media="http://www.idpf.org/epub/vocab/overlays/#"
|
||||
prefix="ibooks: http://vocabulary.itunes.apple.com/rdf/ibooks/vocabulary-extensions-1.0/">
|
||||
|
||||
<metadata xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:opf="http://www.idpf.org/2007/opf">
|
||||
|
||||
<dc:identifier id="BookId"><%= id %></dc:identifier>
|
||||
<meta refines="#BookId" property="identifier-type" scheme="onix:codelist5">22</meta>
|
||||
<meta property="dcterms:identifier" id="meta-identifier">BookId</meta>
|
||||
<dc:title><%= title %></dc:title>
|
||||
<% if (bookMetadata && bookMetadata.subtitle) { %>
|
||||
<meta property="dcterms:alternative"><%= bookMetadata.subtitle %></meta>
|
||||
<% } %>
|
||||
<meta property="dcterms:title" id="meta-title"><%= title %></meta>
|
||||
<dc:language><%= lang || "en" %></dc:language>
|
||||
<meta property="dcterms:language" id="meta-language"><%= lang || "en" %></meta>
|
||||
<meta property="dcterms:modified"><%= (new Date()).toISOString().split(".")[0]+ "Z" %></meta>
|
||||
<dc:creator id="creator"><%= author.length ? author.join(",") : author %></dc:creator>
|
||||
<meta refines="#creator" property="file-as"><%= author.length ? author.join(",") : author %></meta>
|
||||
<meta property="dcterms:publisher"><%= publisher || "anonymous" %></meta>
|
||||
<dc:publisher><%= publisher || "anonymous" %></dc:publisher>
|
||||
<% var date = new Date(); var year = date.getFullYear(); var month = date.getMonth() + 1; var day = date.getDate(); var stringDate = "" + year + "-" + month + "-" + day; %>
|
||||
<meta property="dcterms:date"><%= bookMetadata && bookMetadata.publishedDate ? bookMetadata.publishedDate : stringDate %></meta>
|
||||
<dc:date><%= bookMetadata && bookMetadata.publishedDate ? bookMetadata.publishedDate : stringDate %></dc:date>
|
||||
<% if (bookMetadata && bookMetadata.description) { %>
|
||||
<dc:description><%= bookMetadata.description %></dc:description>
|
||||
<meta property="dcterms:description"><%= bookMetadata.description %></meta>
|
||||
<% } %>
|
||||
<% if (bookMetadata && bookMetadata.categories && bookMetadata.categories.length) { bookMetadata.categories.forEach(function(category){ %>
|
||||
<dc:subject><%= category %></dc:subject>
|
||||
<% }); } %>
|
||||
<% if (bookMetadata && bookMetadata.identifiers && bookMetadata.identifiers.length) { bookMetadata.identifiers.forEach(function(identifier, idx){ %>
|
||||
<meta property="dcterms:identifier" id="extra-id-<%= idx %>"><%= identifier.identifier %></meta>
|
||||
<% }); } %>
|
||||
<% if (bookMetadata && bookMetadata.pageCount) { %>
|
||||
<meta property="schema:pageCount"><%= bookMetadata.pageCount %></meta>
|
||||
<% } %>
|
||||
<% if (bookMetadata && bookMetadata.averageRating) { %>
|
||||
<meta property="schema:ratingValue"><%= bookMetadata.averageRating %></meta>
|
||||
<% } %>
|
||||
<% if (bookMetadata && bookMetadata.ratingsCount) { %>
|
||||
<meta property="schema:ratingCount"><%= bookMetadata.ratingsCount %></meta>
|
||||
<% } %>
|
||||
<% if (bookMetadata && bookMetadata.infoLink) { %>
|
||||
<meta property="dcterms:source"><%= bookMetadata.infoLink %></meta>
|
||||
<% } %>
|
||||
<meta property="dcterms:rights">All rights reserved</meta>
|
||||
<dc:rights>Copyright © <%= (new Date()).getFullYear() %> by <%= publisher || "anonymous" %></dc:rights>
|
||||
<meta name="cover" content="image_cover"/>
|
||||
<meta name="generator" content="epub-gen" />
|
||||
<meta property="ibooks:specified-fonts">true</meta>
|
||||
|
||||
</metadata>
|
||||
|
||||
<manifest>
|
||||
<item id="ncx" href="toc.ncx" media-type="application/x-dtbncx+xml" />
|
||||
<item id="toc" href="toc.xhtml" media-type="application/xhtml+xml" properties="nav"/>
|
||||
<item id="css" href="style.css" media-type="text/css" />
|
||||
|
||||
<% if(locals.cover) { %>
|
||||
<item id="image_cover" href="cover.<%= _coverExtension %>" media-type="<%= _coverMediaType %>" />
|
||||
<% } %>
|
||||
|
||||
<% images.forEach(function(image, index){ %>
|
||||
<item id="image_<%= index %>" href="images/<%= image.id %>.<%= image.extension %>" media-type="<%= image.mediaType %>" />
|
||||
<% }) %>
|
||||
|
||||
<% content.forEach(function(content, index){ %>
|
||||
<item id="content_<%= index %>_<%= content.id %>" href="<%= content.href %>" media-type="application/xhtml+xml" />
|
||||
<% }) %>
|
||||
|
||||
<% fonts.forEach(function(font, index){%>
|
||||
<item id="font_<%= index%>" href="fonts/<%= font %>" media-type="application/x-font-ttf" />
|
||||
<%})%>
|
||||
</manifest>
|
||||
|
||||
<spine toc="ncx">
|
||||
<% content.forEach(function(content, index){ %>
|
||||
<% if(content.beforeToc && !content.excludeFromToc){ %>
|
||||
<itemref idref="content_<%= index %>_<%= content.id %>"/>
|
||||
<% } %>
|
||||
<% }) %>
|
||||
<itemref idref="toc" />
|
||||
<% content.forEach(function(content, index){ %>
|
||||
<% if(!content.beforeToc && !content.excludeFromToc){ %>
|
||||
<itemref idref="content_<%= index %>_<%= content.id %>"/>
|
||||
<% } %>
|
||||
<% }) %>
|
||||
</spine>
|
||||
<guide>
|
||||
<reference type="text" title="Table of Content" href="toc.xhtml"/>
|
||||
</guide>
|
||||
</package>
|
||||
Reference in New Issue
Block a user