Files
amazon-book-search/lib/module.js
sbilketay 5991736cd4 feat: Add raw description field and fix npm test compatibility
Major improvements and bug fixes:

🔧 Core Features:
- Add descriptionRaw field to API response (Amazon original text)
- Maintain backward compatibility with existing description field
- Enable comparison between raw and AI-enhanced descriptions

🛠️ Technical Fixes:
- Fix npm test compatibility issues (Chai, Mocha, Cheerio versions)
- Resolve ES module vs CommonJS conflicts
- Fix module variable references and error handling
- Update Gemini AI model to gemini-2.0-flash

🔒 Security:
- Remove hardcoded API keys from source code and tests
- Add input validation for ISBN parameters
- Improve error handling with proper message formatting

 Testing:
- Add comprehensive test coverage for raw description feature
- Fix all test failures (15/15 tests passing)
- Add comparison tests between raw and Gemini descriptions

📚 Documentation:
- Add comprehensive analysis and troubleshooting reports
- Document Gemini AI integration and API usage
- Include build and deployment guides

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
2025-11-09 15:59:09 +03:00

107 lines
3.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const { GoogleGenerativeAI } = require("@google/generative-ai");
const cheerio = require("cheerio");
const geminiDescriptionEdit = async (description, geminiApiKey, location) => {
if (geminiApiKey != undefined) {
const genAI = new GoogleGenerativeAI(geminiApiKey);
const model = genAI.getGenerativeModel({ model: "gemini-2.0-flash" });
let prompt;
if (location == "en") {
prompt =
description +
" based on the text above, provide a detailed book description of similar length. Do not add any comments to the text, remain completely faithful to it. Only provide the book description, without using a title like book description.";
} else {
prompt =
description +
" yukarıdaki metine bağlı kalarak, benzer uzunlukta bir kitap tanımı ver. Metine hiçbir yorum katma, metine tamamen sadık kal. Sadece kitap tanımını ver, Kitap Tanımı şeklinde bir başlık kullanma";
}
const result = await model.generateContent(prompt);
const response = await result.response;
return response.text();
} else {
return description;
}
};
const extractBookId = (html) => {
const $ = cheerio.load(html);
let bookId = null;
$("[data-csa-c-item-id]").each((index, element) => {
const itemId = $(element).attr("data-csa-c-item-id");
if (!itemId.startsWith("amzn1.asin.1.B")) {
bookId = itemId
.replace(/^amzn1\.asin(\.amzn1)?\./, "")
.replace(/^1\./, "");
return false; // Exit loop after finding the first valid bookId
}
});
return bookId;
};
const extractBookPage = ($) => {
const text = $("div.rpi-attribute-value span").text(); // İçeriği al
const numberMatch = text.match(/\d+/); // Yalnızca rakamları al
return numberMatch ? parseInt(numberMatch[0], 10) : null; // Sayıyı döndür
};
const extractBookPublisher = ($) => {
const publisherParentDiv = $(".rpi-icon.book_details-publisher").parent();
const publisherDiv = publisherParentDiv.next();
const spanInsidePublisherSibling = publisherDiv.find("span");
return spanInsidePublisherSibling.text();
};
const extractBookDate = ($) => {
const dateParentDiv = $(".rpi-icon.book_details-publication_date").parent();
const dateDiv = dateParentDiv.next();
const spanInsideDateSibling = dateDiv.find("span");
return spanInsideDateSibling.text();
};
const extractBookDetails = async (html, isbn, geminiApiKey, location) => {
const extractedText = html
.match(
/<div\s[^>]*class="a-expander-content a-expander-partial-collapse-content"[^>]*>(.*?)<\/div>/s
)?.[1]
?.replace(/<[^>]+>/g, "")
.trim();
// Sonucu yazdır
const $ = cheerio.load(html);
const title = $("#imgTagWrapperId img").attr("alt");
const thumbImage = $("#imgTagWrapperId img").attr("src");
const authorName = $(".author a").text();
const descriptionRaw = $("#bookDescription_feature_div .a-expander-content")
.text()
.trim();
const description = await geminiDescriptionEdit(
descriptionRaw,
geminiApiKey,
location
);
const page = extractBookPage($);
const publisher = extractBookPublisher($);
const date = extractBookDate($);
const ratingText = $('i[data-hook="average-star-rating"] .a-icon-alt').text();
const ratingMatch = ratingText.match(/[\d.,]+/);
const rate = ratingMatch ? ratingMatch[0].replace(",", ".") : null;
return {
title,
thumbImage,
authorName,
description,
descriptionRaw, // Amazon'dan gelen ham açıklama
page,
publisher,
isbn,
date,
rate
};
};
module.exports = { extractBookId, extractBookDetails };