import PDFParser from './pdf-parser.js';
class GoodbookTools {
constructor() {
this.pdfParser = new PDFParser();
this.initialized = false;
}
async initialize() {
if (!this.initialized) {
this.initialized = await this.pdfParser.initialize();
}
return this.initialized;
}
getToolDefinitions() {
return [
{
name: "search_food_standards",
description: "Search for specific food preparation standards, recipes, or cooking guidelines in the food service literature",
inputSchema: {
type: "object",
properties: {
query: {
type: "string",
description: "Search term or phrase to look for in the food standards document"
},
section: {
type: "string",
description: "Optional: specific section to search within (use list_sections to see available sections)"
}
},
required: ["query"]
}
},
{
name: "get_cooking_guidelines",
description: "Get cooking guidelines and standards for specific dishes or cooking methods",
inputSchema: {
type: "object",
properties: {
dish_type: {
type: "string",
description: "Type of dish or cooking method to get guidelines for"
},
section: {
type: "string",
description: "Optional: specific section to look in"
}
},
required: ["dish_type"]
}
},
{
name: "list_sections",
description: "List all available sections in the food service standards document",
inputSchema: {
type: "object",
properties: {},
required: []
}
},
{
name: "get_section_content",
description: "Get content from a specific section of the food standards document",
inputSchema: {
type: "object",
properties: {
section_name: {
type: "string",
description: "Name of the section to retrieve content from"
},
limit: {
type: "number",
description: "Maximum number of characters to return (default: 1000)"
}
},
required: ["section_name"]
}
},
{
name: "get_food_safety_info",
description: "Get food safety information and hygiene standards",
inputSchema: {
type: "object",
properties: {
topic: {
type: "string",
description: "Specific food safety topic (temperature, storage, hygiene, etc.)"
}
},
required: ["topic"]
}
},
{
name: "find_recipe_standards",
description: "Find standardized recipes and preparation methods for specific dishes",
inputSchema: {
type: "object",
properties: {
dish_name: {
type: "string",
description: "Name of the dish to find recipe standards for"
},
cuisine_type: {
type: "string",
description: "Optional: type of cuisine or cooking style"
}
},
required: ["dish_name"]
}
}
];
}
async handleTool(name, arguments_) {
if (!this.initialized) {
await this.initialize();
}
if (!this.initialized) {
return {
content: [{
type: "text",
text: "Error: Could not initialize PDF parser. Please check if the menu.pdf file exists."
}]
};
}
try {
switch (name) {
case "search_food_standards":
return await this.searchFoodStandards(arguments_.query, arguments_.section);
case "get_cooking_guidelines":
return await this.getCookingGuidelines(arguments_.dish_type, arguments_.section);
case "list_sections":
return await this.listSections();
case "get_section_content":
return await this.getSectionContent(arguments_.section_name, arguments_.limit);
case "get_food_safety_info":
return await this.getFoodSafetyInfo(arguments_.topic);
case "find_recipe_standards":
return await this.findRecipeStandards(arguments_.dish_name, arguments_.cuisine_type);
default:
return {
content: [{
type: "text",
text: `Unknown tool: ${name}`
}]
};
}
} catch (error) {
return {
content: [{
type: "text",
text: `Error executing tool ${name}: ${error.message}`
}]
};
}
}
async searchFoodStandards(query, section = null) {
// Расширенный поиск с синонимами
const expandedQueries = this.expandSearchQuery(query);
let allResults = [];
for (const searchQuery of expandedQueries) {
const results = this.pdfParser.searchContent(searchQuery, section);
if (results.results) {
allResults.push(...results.results);
}
}
// Удаляем дубликаты
const uniqueResults = allResults.filter((result, index, self) =>
index === self.findIndex(r => r.content === result.content)
);
let response = `Search results for "${query}"`;
if (section) {
response += ` in section "${section}"`;
}
response += `:\n\nFound ${uniqueResults.length} matches\n\n`;
if (uniqueResults.length === 0) {
response += "No matching content found.";
} else {
uniqueResults.slice(0, 15).forEach((result, index) => {
response += `Result ${index + 1}:\n`;
if (result.before) response += `Context: ${result.before}\n`;
response += `> ${result.content}\n`;
if (result.after) response += `Context: ${result.after}\n`;
response += "\n";
});
}
return {
content: [{
type: "text",
text: response
}]
};
}
// Новый метод для расширения поисковых запросов
expandSearchQuery(query) {
const synonyms = {
// Синонимы для блюд
'котлеты': ['котлеты', 'биточки', 'зразы'],
'картофельные': ['картофельные', 'картофель', 'из картофеля'],
'морковные': ['морковные', 'морковь', 'из моркови', 'морковочные'],
'творог': ['творог', 'творожный', 'сыр творожный', 'кварк'],
'суп': ['суп', 'похлебка', 'бульон', 'борщ', 'щи', 'солянка'],
'пиво': ['пиво', 'пивной', 'с пивом', 'на пиве'],
'сладкий': ['сладкий', 'десертный', 'фруктовый'],
'плов': ['плов', 'рис с мясом', 'узбекский плов'],
'борщ': ['борщ', 'свекольный суп', 'украинский борщ'],
'паста': ['паста', 'макароны', 'спагетти', 'лапша'],
'тирамису': ['тирамису', 'итальянский десерт', 'маскарпоне'],
'пельмени': ['пельмени', 'вареники', 'манты', 'хинкали'],
'салат': ['салат', 'оливье', 'овощной'],
'десерт': ['десерт', 'сладкое', 'торт', 'пирог', 'выпечка'],
// Синонимы для процессов
'приготовление': ['приготовление', 'готовка', 'варка', 'жарка', 'тушение'],
'температура': ['температура', 'градус', 'нагрев', 'охлаждение'],
'безопасность': ['безопасность', 'гигиена', 'санитария', 'чистота'],
'хранение': ['хранение', 'консервация', 'сохранность'],
// Синонимы для ингредиентов
'мясо': ['мясо', 'говядина', 'свинина', 'баранина', 'курица'],
'овощи': ['овощи', 'морковь', 'лук', 'капуста', 'картофель'],
'специи': ['специи', 'приправы', 'пряности', 'соль', 'перец']
};
const queryWords = query.toLowerCase().split(/\s+/);
const expandedQueries = [query]; // Включаем оригинальный запрос
// Добавляем варианты с синонимами
for (const word of queryWords) {
if (synonyms[word]) {
for (const synonym of synonyms[word]) {
if (synonym !== word) {
const newQuery = query.replace(new RegExp(word, 'gi'), synonym);
if (!expandedQueries.includes(newQuery)) {
expandedQueries.push(newQuery);
}
}
}
}
}
return expandedQueries;
}
async getCookingGuidelines(dishType, section = null) {
// Search for cooking-related terms
const cookingTerms = [
dishType,
`приготовление ${dishType}`,
`готовка ${dishType}`,
`рецепт ${dishType}`,
`preparation ${dishType}`,
`cooking ${dishType}`,
`recipe ${dishType}`
];
let allResults = [];
for (const term of cookingTerms) {
const results = this.pdfParser.searchContent(term, section);
if (results.results) {
allResults.push(...results.results);
}
}
// Remove duplicates
const uniqueResults = allResults.filter((result, index, self) =>
index === self.findIndex(r => r.content === result.content)
);
let response = `Cooking guidelines for "${dishType}":\n\n`;
if (uniqueResults.length === 0) {
response += "No specific cooking guidelines found for this dish type.";
} else {
uniqueResults.slice(0, 10).forEach((result, index) => {
response += `Guideline ${index + 1}:\n`;
response += `${result.content}\n\n`;
});
}
return {
content: [{
type: "text",
text: response
}]
};
}
async listSections() {
const sections = this.pdfParser.getSections();
let response = "Available sections in the food standards document:\n\n";
sections.forEach((section, index) => {
response += `${index + 1}. ${section.name}\n`;
response += ` Content length: ${section.contentLength} items\n`;
response += ` Preview: ${section.preview}\n\n`;
});
return {
content: [{
type: "text",
text: response
}]
};
}
async getSectionContent(sectionName, limit = 1000) {
const content = this.pdfParser.getContent(sectionName, limit);
if (content.error) {
return {
content: [{
type: "text",
text: `Error: ${content.error}`
}]
};
}
return {
content: [{
type: "text",
text: `Content from section "${content.section}":\n\n${content.content}`
}]
};
}
async getFoodSafetyInfo(topic) {
const safetyTerms = [
topic,
`безопасность ${topic}`,
`гигиена ${topic}`,
`санитария ${topic}`,
`температура ${topic}`,
`хранение ${topic}`,
`safety ${topic}`,
`hygiene ${topic}`,
`sanitation ${topic}`,
`temperature ${topic}`,
`storage ${topic}`
];
let allResults = [];
for (const term of safetyTerms) {
const results = this.pdfParser.searchContent(term);
if (results.results) {
allResults.push(...results.results);
}
}
const uniqueResults = allResults.filter((result, index, self) =>
index === self.findIndex(r => r.content === result.content)
);
let response = `Food safety information for "${topic}":\n\n`;
if (uniqueResults.length === 0) {
response += "No specific food safety information found for this topic.";
} else {
uniqueResults.slice(0, 8).forEach((result, index) => {
response += `Safety guideline ${index + 1}:\n`;
response += `${result.content}\n\n`;
});
}
return {
content: [{
type: "text",
text: response
}]
};
}
async findRecipeStandards(dishName, cuisineType = null) {
const recipeTerms = [
dishName,
`рецепт ${dishName}`,
`стандарт ${dishName}`,
`приготовление ${dishName}`,
`recipe ${dishName}`,
`standard ${dishName}`,
`preparation ${dishName}`
];
if (cuisineType) {
recipeTerms.push(`${cuisineType} ${dishName}`);
}
let allResults = [];
for (const term of recipeTerms) {
const results = this.pdfParser.searchContent(term);
if (results.results) {
allResults.push(...results.results);
}
}
const uniqueResults = allResults.filter((result, index, self) =>
index === self.findIndex(r => r.content === result.content)
);
let response = `Recipe standards for "${dishName}"`;
if (cuisineType) response += ` (${cuisineType} cuisine)`;
response += ":\n\n";
if (uniqueResults.length === 0) {
response += "No specific recipe standards found for this dish.";
} else {
uniqueResults.slice(0, 8).forEach((result, index) => {
response += `Standard ${index + 1}:\n`;
response += `${result.content}\n\n`;
});
}
return {
content: [{
type: "text",
text: response
}]
};
}
}
export default GoodbookTools;