807 lines
32 KiB
PHP
807 lines
32 KiB
PHP
<?php
|
|
|
|
namespace app\KitchenScale3\controller\app;
|
|
|
|
use think\Db;
|
|
use think\Controller;
|
|
|
|
class Guessyoulike extends Controller {
|
|
|
|
protected $kitchenscale_db_msg = [
|
|
// 'cookbook' => 'app_user_cookbook', //食谱表
|
|
// 'cookbook_label' => 'app_user_cookbook_label', //食谱标签表
|
|
// 'cookbook_food_relation' => 'app_user_cookbook_food_relation', //食谱跟食材关系表
|
|
'foodlist2' => 'app_z_national_standard_food_type_2_multilingual', //食材标签表2
|
|
'foodlist3' => 'app_z_national_standard_food_type_3_multilingual', //食材表
|
|
'kcal_log' => 'app_user_kcal_log_multilingual', //用户饮食记录表记录用户吃了什么食材
|
|
'search_history' => 'app_user_search_history_multilingual', //用户搜索记录表,记录用户搜索过什么内容
|
|
// 'tag_preference' => 'app_user_tag_preference', //用户标签偏好表
|
|
'recommend_cache' => 'app_recommend_cache_multilingual' //智能推荐缓存表
|
|
];
|
|
|
|
protected $config = [
|
|
'tag_limit' => 2,
|
|
'item_limit' => 12,
|
|
'cache_time' => 3600
|
|
];
|
|
protected $translations = [
|
|
'zh' => '搜索最多的食材',
|
|
'en' => 'Most Searched Ingredients',
|
|
'jp' => '最も検索された食材',
|
|
'fra' => 'Ingrédients les Plus Recherchés',
|
|
'de' => 'Am Häufigsten Gesuchte Lebensmittel',
|
|
'kor' => '가장 많이 검색된 재료',
|
|
'ru' => 'Самые Искомые Ингредиенты',
|
|
'pt' => 'Ingredientes Mais Pesquisados',
|
|
'spa' => 'Ingredientes Más Buscados',
|
|
'ara' => 'المكونات الأكثر بحثًا'
|
|
];
|
|
protected $food_2_ys = [
|
|
'Dairy and Egg Products' => [
|
|
'zh' => '乳制品和蛋类',
|
|
'en' => 'Dairy and Egg Products',
|
|
'jp' => '乳製品と卵製品',
|
|
'fra' => 'Produits laitiers et œufs',
|
|
'de' => 'Milch- und Eiprodukte',
|
|
'kor' => '유제품 및 계란 제품',
|
|
'ru' => 'Молочные продукты и яйца',
|
|
'pt' => 'Laticínios e Ovos',
|
|
'spa' => 'Productos lácteos y huevos',
|
|
'ara' => 'منتجات الألبان والبيض'
|
|
],
|
|
'Spices and Herbs' => [
|
|
'zh' => '香料和香草',
|
|
'en' => 'Spices and Herbs',
|
|
'jp' => 'スパイスとハーブ',
|
|
'fra' => 'Épices et herbes',
|
|
'de' => 'Gewürze und Kräuter',
|
|
'kor' => '향신료 및 허브',
|
|
'ru' => 'Специи и травы',
|
|
'pt' => 'Especiarias e Ervas',
|
|
'spa' => 'Especias y hierbas',
|
|
'ara' => 'التوابل والأعشاب'
|
|
],
|
|
'Baby Foods' => [
|
|
'zh' => '婴儿食品',
|
|
'en' => 'Baby Foods',
|
|
'jp' => 'ベビーフード',
|
|
'fra' => 'Aliments pour bébés',
|
|
'de' => 'Babynahrung',
|
|
'kor' => '아기 음식',
|
|
'ru' => 'Детское питание',
|
|
'pt' => 'Alimentos para Bebês',
|
|
'spa' => 'Alimentos para bebés',
|
|
'ara' => 'أغذية الأطفال'
|
|
],
|
|
'Fats and Oils' => [
|
|
'zh' => '脂肪和油脂',
|
|
'en' => 'Fats and Oils',
|
|
'jp' => '油脂',
|
|
'fra' => 'Graisses et huiles',
|
|
'de' => 'Fette und Öle',
|
|
'kor' => '지방과 오일',
|
|
'ru' => 'Жиры и масла',
|
|
'pt' => 'Gorduras e Óleos',
|
|
'spa' => 'Grasas y aceites',
|
|
'ara' => 'الدهون والزيوت'
|
|
],
|
|
'Poultry Products' => [
|
|
'zh' => '家禽产品',
|
|
'en' => 'Poultry Products',
|
|
'jp' => '家禽製品',
|
|
'fra' => 'Produits de volaille',
|
|
'de' => 'Geflügelprodukte',
|
|
'kor' => '가금류 제품',
|
|
'ru' => 'Продукты из птицы',
|
|
'pt' => 'Produtos Avícolas',
|
|
'spa' => 'Productos avícolas',
|
|
'ara' => 'منتجات الدواجن'
|
|
],
|
|
'Soups, Sauces, and Gravies' => [
|
|
'zh' => '汤、酱汁和肉汁',
|
|
'en' => 'Soups, Sauces, and Gravies',
|
|
'jp' => 'スープ、ソース、グレービー',
|
|
'fra' => 'Soupes, sauces et jus',
|
|
'de' => 'Suppen, Saucen und Soßen',
|
|
'kor' => '수프, 소스, 그레이비',
|
|
'ru' => 'Супы, соусы и подливки',
|
|
'pt' => 'Sopas, Molhos e Caldos',
|
|
'spa' => 'Sopas, salsas y salsas',
|
|
'ara' => 'الشوربات والصلصات والمرق'
|
|
],
|
|
'Sausages and Luncheon Meats' => [
|
|
'zh' => '香肠和午餐肉',
|
|
'en' => 'Sausages and Luncheon Meats',
|
|
'jp' => 'ソーセージとランチョンミート',
|
|
'fra' => 'Saucisses et viandes froides',
|
|
'de' => 'Wurstwaren und Aufschnitt',
|
|
'kor' => '소시지와 점심 고기',
|
|
'ru' => 'Колбасные изделия и мясные нарезки',
|
|
'pt' => 'Salsichas e Carnes Frias',
|
|
'spa' => 'Salchichas y fiambres',
|
|
'ara' => 'النقانق واللحوم الباردة'
|
|
],
|
|
'Breakfast Cereals' => [
|
|
'zh' => '早餐谷物',
|
|
'en' => 'Breakfast Cereals',
|
|
'jp' => '朝食用シリアル',
|
|
'fra' => 'Céréales pour petit-déjeuner',
|
|
'de' => 'Frühstückscerealien',
|
|
'kor' => '아침 식사 시리얼',
|
|
'ru' => 'Сухие завтраки',
|
|
'pt' => 'Cereais Matinais',
|
|
'spa' => 'Cereales para el desayuno',
|
|
'ara' => 'حبوب الإفطار'
|
|
],
|
|
'Fruits and Fruit Juices' => [
|
|
'zh' => '水果和果汁',
|
|
'en' => 'Fruits and Fruit Juices',
|
|
'jp' => 'フルーツとフルーツジュース',
|
|
'fra' => 'Fruits et jus de fruits',
|
|
'de' => 'Früchte und Fruchtsäfte',
|
|
'kor' => '과일과 과일 주스',
|
|
'ru' => 'Фрукты и фруктовые соки',
|
|
'pt' => 'Frutas e Sucos de Frutas',
|
|
'spa' => 'Frutas y jugos de frutas',
|
|
'ara' => 'الفواكه وعصائر الفاكهة'
|
|
],
|
|
'Pork Products' => [
|
|
'zh' => '猪肉产品',
|
|
'en' => 'Pork Products',
|
|
'jp' => '豚肉製品',
|
|
'fra' => 'Produits de porc',
|
|
'de' => 'Schweinefleischprodukte',
|
|
'kor' => '돼지고기 제품',
|
|
'ru' => 'Свиные продукты',
|
|
'pt' => 'Produtos de Porco',
|
|
'spa' => 'Productos de cerdo',
|
|
'ara' => 'منتجات لحم الخنزير'
|
|
],
|
|
'Vegetables and Vegetable Products' => [
|
|
'zh' => '蔬菜和蔬菜制品',
|
|
'en' => 'Vegetables and Vegetable Products',
|
|
'jp' => '野菜と野菜製品',
|
|
'fra' => 'Légumes et produits végétaux',
|
|
'de' => 'Gemüse und Gemüseprodukte',
|
|
'kor' => '채소와 채소 제품',
|
|
'ru' => 'Овощи и овощные продукты',
|
|
'pt' => 'Vegetais e Produtos Vegetais',
|
|
'spa' => 'Verduras y productos vegetales',
|
|
'ara' => 'الخضروات ومنتجات الخضروات'
|
|
],
|
|
'Nut and Seed Products' => [
|
|
'zh' => '坚果和种子产品',
|
|
'en' => 'Nut and Seed Products',
|
|
'jp' => 'ナッツと種子製品',
|
|
'fra' => 'Noix et graines',
|
|
'de' => 'Nuss- und Samenprodukte',
|
|
'kor' => '견과류와 씨앗 제품',
|
|
'ru' => 'Орехи и семена',
|
|
'pt' => 'Nozes e Sementes',
|
|
'spa' => 'Frutos secos y semillas',
|
|
'ara' => 'المكسرات والبذور'
|
|
],
|
|
'Beef Products' => [
|
|
'zh' => '牛肉产品',
|
|
'en' => 'Beef Products',
|
|
'jp' => '牛肉製品',
|
|
'fra' => 'Produits de bœuf',
|
|
'de' => 'Rindfleischprodukte',
|
|
'kor' => '쇠고기 제품',
|
|
'ru' => 'Говяжьи продукты',
|
|
'pt' => 'Produtos de Carne Bovina',
|
|
'spa' => 'Productos de res',
|
|
'ara' => 'منتجات لحم البقر'
|
|
],
|
|
'Beverages' => [
|
|
'zh' => '饮料',
|
|
'en' => 'Beverages',
|
|
'jp' => '飲料',
|
|
'fra' => 'Boissons',
|
|
'de' => 'Getränke',
|
|
'kor' => '음료',
|
|
'ru' => 'Напитки',
|
|
'pt' => 'Bebidas',
|
|
'spa' => 'Bebidas',
|
|
'ara' => 'المشروبات'
|
|
],
|
|
'Finfish and Shellfish Products' => [
|
|
'zh' => '鱼类和贝类产品',
|
|
'en' => 'Finfish and Shellfish Products',
|
|
'jp' => '魚介類製品',
|
|
'fra' => 'Poissons et fruits de mer',
|
|
'de' => 'Fisch- und Schalentiere',
|
|
'kor' => '어류 및 갑각류 제품',
|
|
'ru' => 'Рыба и морепродукты',
|
|
'pt' => 'Peixes e Frutos do Mar',
|
|
'spa' => 'Pescados y mariscos',
|
|
'ara' => 'الأسماك والمحار'
|
|
],
|
|
'Legumes and Legume Products' => [
|
|
'zh' => '豆类和豆制品',
|
|
'en' => 'Legumes and Legume Products',
|
|
'jp' => '豆類と豆製品',
|
|
'fra' => 'Légumineuses et produits dérivés',
|
|
'de' => 'Hülsenfrüchte und Hülsenfruchtprodukte',
|
|
'kor' => '콩류와 콩 제품',
|
|
'ru' => 'Бобовые и продукты из них',
|
|
'pt' => 'Legumes e Produtos de Legumes',
|
|
'spa' => 'Legumbres y productos de legumbres',
|
|
'ara' => 'البقوليات ومنتجاتها'
|
|
],
|
|
'Lamb, Veal, and Game Products' => [
|
|
'zh' => '羊肉、小牛肉和野味产品',
|
|
'en' => 'Lamb, Veal, and Game Products',
|
|
'jp' => '羊肉、子牛肉、ジビエ製品',
|
|
'fra' => 'Agneau, veau et gibier',
|
|
'de' => 'Lamm, Kalb und Wild',
|
|
'kor' => '양고기, 송아지고기, 야생고기 제품',
|
|
'ru' => 'Баранина, телятина и дичь',
|
|
'pt' => 'Cordeiro, Vitela e Caça',
|
|
'spa' => 'Cordero, ternera y caza',
|
|
'ara' => 'لحم الضأن والعجل والصيد'
|
|
],
|
|
'Baked Products' => [
|
|
'zh' => '烘焙产品',
|
|
'en' => 'Baked Products',
|
|
'jp' => '焼き菓子',
|
|
'fra' => 'Produits de boulangerie',
|
|
'de' => 'Backwaren',
|
|
'kor' => '구운 제품',
|
|
'ru' => 'Хлебобулочные изделия',
|
|
'pt' => 'Produtos Assados',
|
|
'spa' => 'Productos horneados',
|
|
'ara' => 'المخبوزات'
|
|
],
|
|
'Sweets' => [
|
|
'zh' => '糖果甜点',
|
|
'en' => 'Sweets',
|
|
'jp' => 'お菓子',
|
|
'fra' => 'Sucreries',
|
|
'de' => 'Süßigkeiten',
|
|
'kor' => '과자',
|
|
'ru' => 'Сладости',
|
|
'pt' => 'Doces',
|
|
'spa' => 'Dulces',
|
|
'ara' => 'الحلويات'
|
|
],
|
|
'Cereal Grains and Pasta' => [
|
|
'zh' => '谷物和面食',
|
|
'en' => 'Cereal Grains and Pasta',
|
|
'jp' => '穀物とパスタ',
|
|
'fra' => 'Céréales et pâtes',
|
|
'de' => 'Getreide und Nudeln',
|
|
'kor' => '곡물과 파스타',
|
|
'ru' => 'Зерновые и макаронные изделия',
|
|
'pt' => 'Grãos e Massas',
|
|
'spa' => 'Cereales y pasta',
|
|
'ara' => 'الحبوب والمعكرونة'
|
|
],
|
|
'Fast Foods' => [
|
|
'zh' => '快餐食品',
|
|
'en' => 'Fast Foods',
|
|
'jp' => 'ファストフード',
|
|
'fra' => 'Fast-foods',
|
|
'de' => 'Fast Food',
|
|
'kor' => '패스트푸드',
|
|
'ru' => 'Фастфуд',
|
|
'pt' => 'Fast Foods',
|
|
'spa' => 'Comida rápida',
|
|
'ara' => 'الوجبات السريعة'
|
|
],
|
|
'Meals, Entrees, and Side Dishes' => [
|
|
'zh' => '餐食、主菜和配菜',
|
|
'en' => 'Meals, Entrees, and Side Dishes',
|
|
'jp' => '食事、メインディッシュ、サイドディッシュ',
|
|
'fra' => 'Repas, plats principaux et accompagnements',
|
|
'de' => 'Mahlzeiten, Hauptgerichte und Beilagen',
|
|
'kor' => '식사, 메인 요리, 사이드 디시',
|
|
'ru' => 'Блюда, основные блюда и гарниры',
|
|
'pt' => 'Refeições, Pratos Principais e Acompanhamentos',
|
|
'spa' => 'Comidas, platos principales y guarniciones',
|
|
'ara' => 'الوجبات والأطباق الرئيسية والأطباق الجانبية'
|
|
],
|
|
'Snacks' => [
|
|
'zh' => '零食',
|
|
'en' => 'Snacks',
|
|
'jp' => 'スナック',
|
|
'fra' => 'Snacks',
|
|
'de' => 'Snacks',
|
|
'kor' => '과자',
|
|
'ru' => 'Закуски',
|
|
'pt' => 'Lanches',
|
|
'spa' => 'Aperitivos',
|
|
'ara' => 'الوجبات الخفيفة'
|
|
],
|
|
'American Indian/Alaska Native Foods' => [
|
|
'zh' => '美洲印第安/阿拉斯加原住民食品',
|
|
'en' => 'American Indian/Alaska Native Foods',
|
|
'jp' => 'アメリカ先住民/アラスカ先住民の食品',
|
|
'fra' => 'Aliments amérindiens/autochtones d\'Alaska',
|
|
'de' => 'Indianische/alaskische Ureinwohner-Lebensmittel',
|
|
'kor' => '아메리카 원주민/알래스카 원주민 음식',
|
|
'ru' => 'Пища американских индейцев/коренных жителей Аляски',
|
|
'pt' => 'Alimentos dos Nativos Americanos/Alasca',
|
|
'spa' => 'Alimentos de nativos americanos/de Alaska',
|
|
'ara' => 'أطعمة الأمريكيين الأصليين/سكان ألاسكا الأصليين'
|
|
],
|
|
'Restaurant Foods' => [
|
|
'zh' => '餐厅食品',
|
|
'en' => 'Restaurant Foods',
|
|
'jp' => 'レストランフード',
|
|
'fra' => 'Plats de restaurant',
|
|
'de' => 'Restaurantgerichte',
|
|
'kor' => '레스토랑 음식',
|
|
'ru' => 'Ресторанная еда',
|
|
'pt' => 'Comidas de Restaurante',
|
|
'spa' => 'Comidas de restaurante',
|
|
'ara' => 'أطعمة المطاعم'
|
|
],
|
|
'Branded Food Products Database' => [
|
|
'zh' => '品牌食品数据库',
|
|
'en' => 'Branded Food Products Database',
|
|
'jp' => 'ブランド食品データベース',
|
|
'fra' => 'Base de données de produits alimentaires de marque',
|
|
'de' => 'Markenlebensmittel-Datenbank',
|
|
'kor' => '브랜드 식품 데이터베이스',
|
|
'ru' => 'База данных брендовых продуктов питания',
|
|
'pt' => 'Banco de Dados de Produtos Alimentícios Marcados',
|
|
'spa' => 'Base de datos de productos alimenticios de marca',
|
|
'ara' => 'قاعدة بيانات المنتجات الغذائية ذات العلامات التجارية'
|
|
],
|
|
'Quality Control Materials' => [
|
|
'zh' => '质量控制材料',
|
|
'en' => 'Quality Control Materials',
|
|
'jp' => '品質管理材料',
|
|
'fra' => 'Matériaux de contrôle qualité',
|
|
'de' => 'Qualitätskontrollmaterialien',
|
|
'kor' => '품질 관리 재료',
|
|
'ru' => 'Материалы для контроля качества',
|
|
'pt' => 'Materiais de Controle de Qualidade',
|
|
'spa' => 'Materiales de control de calidad',
|
|
'ara' => 'مواد مراقبة الجودة'
|
|
],
|
|
'Alcoholic Beverages' => [
|
|
'zh' => '酒精饮料',
|
|
'en' => 'Alcoholic Beverages',
|
|
'jp' => 'アルコール飲料',
|
|
'fra' => 'Boissons alcoolisées',
|
|
'de' => 'Alkoholische Getränke',
|
|
'kor' => '알코올 음료',
|
|
'ru' => 'Алкогольные напитки',
|
|
'pt' => 'Bebidas Alcoólicas',
|
|
'spa' => 'Bebidas alcohólicas',
|
|
'ara' => 'المشروبات الكحولية'
|
|
]
|
|
];
|
|
|
|
/**
|
|
* 猜你喜欢主接口
|
|
*/
|
|
public function getGuessYouLike($user_id = 1, $type = 'food', $limit = null,$language = 'zh') {
|
|
try {
|
|
$cfc = Db::connect('cfc_db');
|
|
// dump(1);
|
|
// 设置限制数量
|
|
$tag_limit = $limit ? intval($limit) : $this->config['tag_limit'];
|
|
$item_limit = $this->config['item_limit'];
|
|
|
|
// 检查缓存
|
|
// $cache_key = $user_id . ':' . $type;
|
|
// $cache_result = $this->getCache($cfc, $cache_key);
|
|
// // die;
|
|
// if ($cache_result !== null) {
|
|
// return $cache_result;
|
|
// }
|
|
// dump($language);
|
|
// 判断用户是否有历史数据
|
|
$has_history = $this->checkUserHistory($cfc, $user_id);
|
|
|
|
if (!$has_history) {
|
|
|
|
// 新用户,返回最火信息(仅一个标签)
|
|
$result = $this->getPopularRecommendations($cfc, $type, 1, $item_limit,$language);
|
|
// dump($result);
|
|
} else {
|
|
// 老用户,根据类型返回个性化推荐
|
|
if ($type === 'cookbook') {
|
|
// $result = $this->getCookbookRecommendations($cfc, $user_id, $tag_limit, $item_limit,$language);
|
|
|
|
} else {
|
|
$result = $this->getFoodRecommendations($cfc, $user_id, $tag_limit, $item_limit,$language);
|
|
}
|
|
}
|
|
|
|
// 确保返回格式正确
|
|
if (!is_array($result)) {
|
|
$result = [];
|
|
}
|
|
|
|
// 更新缓存
|
|
// $this->updateCache($cfc, $cache_key, $user_id, $type, $result);
|
|
|
|
return $result;
|
|
|
|
} catch (\Exception $e) {
|
|
// 记录错误日志
|
|
\think\Log::error('猜你喜欢功能错误: ' . $e->getMessage());
|
|
return [];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 检查用户是否有历史数据
|
|
*/
|
|
private function checkUserHistory($db, $user_id) {
|
|
try {
|
|
// 检查饮食记录
|
|
$kcal_result = $db->query("
|
|
SELECT COUNT(*) as count
|
|
FROM {$this->kitchenscale_db_msg['kcal_log']}
|
|
WHERE aud_id = ? AND is_del = 0
|
|
", [$user_id]);
|
|
$kcal_count = $kcal_result[0]['count'] ?? 0;
|
|
|
|
// 检查搜索记录
|
|
$search_result = $db->query("
|
|
SELECT COUNT(*) as count
|
|
FROM {$this->kitchenscale_db_msg['search_history']}
|
|
WHERE user_id = ? AND is_del = 0
|
|
", [$user_id]);
|
|
$search_count = $search_result[0]['count'] ?? 0;
|
|
|
|
return ($kcal_count > 0 || $search_count > 0);
|
|
} catch (\Exception $e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取缓存数据
|
|
*/
|
|
private function getCache($db, $cache_key) {
|
|
try {
|
|
$cache_result = $db->query("
|
|
SELECT id, cache_key, user_id, keyword, recommend_data, hit_count, last_hit, is_del, create_time
|
|
FROM {$this->kitchenscale_db_msg['recommend_cache']}
|
|
WHERE cache_key = ? AND is_del = 0
|
|
", [$cache_key]);
|
|
|
|
if (!empty($cache_result)) {
|
|
$cache = $cache_result[0];
|
|
$last_hit_timestamp = strtotime($cache['last_hit']);
|
|
|
|
if (time() - $last_hit_timestamp < $this->config['cache_time']) {
|
|
// 更新命中次数和时间
|
|
$db->execute("
|
|
UPDATE {$this->kitchenscale_db_msg['recommend_cache']}
|
|
SET hit_count = hit_count + 1, last_hit = GETDATE()
|
|
WHERE id = ?
|
|
", [$cache['id']]);
|
|
|
|
$data = json_decode($cache['recommend_data'], true);
|
|
return is_array($data) ? $data : null;
|
|
}
|
|
}
|
|
} catch (\Exception $e) {
|
|
// 忽略缓存错误,继续执行
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* 更新缓存
|
|
*/
|
|
private function updateCache($db, $cache_key, $user_id, $keyword, $data) {
|
|
try {
|
|
$current_time = date('Y-m-d H:i:s');
|
|
$recommend_data = json_encode($data, JSON_UNESCAPED_UNICODE);
|
|
|
|
// 检查是否存在缓存
|
|
$existing_result = $db->query("
|
|
SELECT id FROM {$this->kitchenscale_db_msg['recommend_cache']}
|
|
WHERE cache_key = ? AND is_del = 0
|
|
", [$cache_key]);
|
|
|
|
if (!empty($existing_result)) {
|
|
// 更新现有缓存
|
|
$db->execute("
|
|
UPDATE {$this->kitchenscale_db_msg['recommend_cache']}
|
|
SET user_id = ?, keyword = ?, recommend_data = ?, hit_count = 1,
|
|
last_hit = ?, create_time = ?
|
|
WHERE cache_key = ? AND is_del = 0
|
|
", [$user_id, $keyword, $recommend_data, $current_time, $current_time, $cache_key]);
|
|
} else {
|
|
// 插入新缓存
|
|
$db->execute("
|
|
INSERT INTO {$this->kitchenscale_db_msg['recommend_cache']}
|
|
(cache_key, user_id, keyword, recommend_data, hit_count, last_hit, create_time, is_del)
|
|
VALUES (?, ?, ?, ?, 1, ?, ?, 0)
|
|
", [$cache_key, $user_id, $keyword, $recommend_data, $current_time, $current_time]);
|
|
}
|
|
} catch (\Exception $e) {
|
|
// 忽略缓存更新错误
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取热门推荐(新用户)
|
|
*/
|
|
private function getPopularRecommendations($db, $type, $tag_limit, $item_limit,$language) {
|
|
// dump($type);
|
|
if ($type === 'cookbook') {
|
|
return $this->getPopularCookbooks($db, $tag_limit, $item_limit);
|
|
} else {
|
|
// dump(111);
|
|
return $this->getPopularFoods($db, $tag_limit, $item_limit,$language);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取热门食谱(新用户)
|
|
*/
|
|
private function getPopularCookbooks($db, $tag_limit, $item_limit) {
|
|
try {
|
|
// 简化查询,避免复杂关联导致的错误
|
|
$popular_cookbooks = $db->query("
|
|
SELECT TOP {$item_limit}
|
|
id,
|
|
title as name
|
|
FROM {$this->kitchenscale_db_msg['cookbook']}
|
|
WHERE is_del = 0
|
|
ORDER BY likes_num DESC, read_it DESC, create_time DESC
|
|
");
|
|
// dump('sp');
|
|
// dump($popular_cookbooks);
|
|
$result = [];
|
|
$label_data = [];
|
|
|
|
foreach ($popular_cookbooks as $cookbook) {
|
|
$label_data[] = [
|
|
'name' => $cookbook['name'] ?? '未知食谱',
|
|
'id' => $cookbook['id'] ?? 0,
|
|
'type' => 'cookbook'
|
|
];
|
|
}
|
|
|
|
if (!empty($label_data)) {
|
|
$result['最火食谱搜索'] = $label_data;
|
|
}
|
|
|
|
return $result;
|
|
} catch (\Exception $e) {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取热门食材(新用户)
|
|
*/
|
|
private function getPopularFoods($db, $tag_limit, $item_limit,$language) {
|
|
try {
|
|
// dump(2222);
|
|
// // 简化查询,避免复杂关联导致的错误
|
|
$popular_foods = $db->query("
|
|
SELECT TOP {$item_limit}
|
|
id,
|
|
keyword as name,
|
|
COUNT(*) as num
|
|
FROM {$this->kitchenscale_db_msg['search_history']}
|
|
WHERE is_del = 0 AND type = 'food'
|
|
GROUP BY id, keyword
|
|
ORDER BY num DESC
|
|
");
|
|
// dump('sc');
|
|
// dump($popular_foods);
|
|
// dump($language);
|
|
if($language == 'zh'){
|
|
$language_key = 'food_name';
|
|
}else{
|
|
if(!$language){
|
|
$language_key = 'food_name';
|
|
}else{
|
|
$language_key = 'food_name_'.$language;
|
|
}
|
|
|
|
}
|
|
// dump($language);
|
|
$popular_foods_2 = [];
|
|
if(count($popular_foods) < $item_limit){
|
|
$num = $item_limit - count($popular_foods);
|
|
// dump($num);
|
|
|
|
$popular_foods_2 = $db->query("
|
|
SELECT TOP {$num}
|
|
id,
|
|
$language_key as name
|
|
FROM {$this->kitchenscale_db_msg['foodlist3']}
|
|
WHERE is_del = 0
|
|
ORDER BY is_popular DESC, $language_key ASC
|
|
");
|
|
}
|
|
// dump($popular_foods_2);
|
|
|
|
foreach ($popular_foods_2 as $key => $value) {
|
|
$popular_foods[] = $value;
|
|
}
|
|
|
|
|
|
$result = [];
|
|
$label_data = [];
|
|
|
|
foreach ($popular_foods as $food) {
|
|
$label_data[] = [
|
|
'name' => $food['name'] ?? '????',
|
|
'id' => $food['id'] ?? 0,
|
|
'type' => 'food'
|
|
];
|
|
}
|
|
|
|
if (!empty($label_data)) {
|
|
// dump($label_data);
|
|
// dump($this->translations[$language]);
|
|
if($language){
|
|
$result[$this->translations[$language]] = $label_data;
|
|
}else{
|
|
$result[$this->translations['zh']] = $label_data;
|
|
}
|
|
}
|
|
// dump($result);
|
|
// die;
|
|
return $result;
|
|
} catch (\Exception $e) {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取个性化食谱推荐(老用户)
|
|
*/
|
|
private function getCookbookRecommendations($db, $user_id, $tag_limit, $item_limit) {
|
|
try {
|
|
// 获取用户最常吃的食材
|
|
$user_top_foods = $db->query("
|
|
SELECT TOP 10 food_id, COUNT(*) as eat_count
|
|
FROM {$this->kitchenscale_db_msg['kcal_log']}
|
|
WHERE aud_id = ? AND is_del = 0
|
|
GROUP BY food_id
|
|
ORDER BY eat_count DESC
|
|
", [$user_id]);
|
|
|
|
if (empty($user_top_foods)) {
|
|
return $this->getPopularCookbooks($db, $tag_limit, $item_limit);
|
|
}
|
|
|
|
$food_ids = array_column($user_top_foods, 'food_id');
|
|
if (empty($food_ids)) {
|
|
return $this->getPopularCookbooks($db, $tag_limit, $item_limit);
|
|
}
|
|
$food_ids_str = implode(',', $food_ids);
|
|
|
|
// 获取包含这些食材的食谱标签
|
|
$preferred_labels = $db->query("
|
|
SELECT TOP {$tag_limit} lbl.id, lbl.name, COUNT(DISTINCT cb.id) as match_count
|
|
FROM {$this->kitchenscale_db_msg['cookbook_label']} lbl
|
|
INNER JOIN {$this->kitchenscale_db_msg['cookbook']} cb ON lbl.id = cb.cook_label AND cb.is_del = 0
|
|
INNER JOIN {$this->kitchenscale_db_msg['cookbook_food_relation']} cfr ON cb.id = cfr.cookbook_id
|
|
WHERE lbl.is_del = 0 AND cfr.food_id IN ({$food_ids_str})
|
|
GROUP BY lbl.id, lbl.name
|
|
ORDER BY match_count DESC
|
|
");
|
|
|
|
$result = [];
|
|
foreach ($preferred_labels as $label) {
|
|
// 使用子查询避免GROUP BY复杂性问题
|
|
$cookbooks = $db->query("
|
|
SELECT TOP {$item_limit} cb.id, cb.title as name
|
|
FROM {$this->kitchenscale_db_msg['cookbook']} cb
|
|
WHERE cb.id IN (
|
|
SELECT DISTINCT cfr.cookbook_id
|
|
FROM {$this->kitchenscale_db_msg['cookbook_food_relation']} cfr
|
|
WHERE cfr.food_id IN ({$food_ids_str})
|
|
)
|
|
AND cb.cook_label = ?
|
|
AND cb.is_del = 0
|
|
ORDER BY cb.likes_num DESC, cb.read_it DESC
|
|
", [$label['id']]);
|
|
|
|
$label_data = [];
|
|
foreach ($cookbooks as $cookbook) {
|
|
$label_data[] = [
|
|
'name' => $cookbook['name'] ?? '未知食谱',
|
|
'id' => $cookbook['id'] ?? 0,
|
|
'type' => 'cookbook'
|
|
];
|
|
}
|
|
|
|
if (!empty($label_data)) {
|
|
$result[$label['name'] ?? '未知标签'] = $label_data;
|
|
}
|
|
}
|
|
|
|
return $result;
|
|
} catch (\Exception $e) {
|
|
return $this->getPopularCookbooks($db, $tag_limit, $item_limit);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取个性化食材推荐(老用户)
|
|
*/
|
|
private function getFoodRecommendations($db, $user_id, $tag_limit, $item_limit,$language) {
|
|
try {
|
|
// 获取用户最常吃的食材
|
|
$user_top_foods = $db->query("
|
|
SELECT TOP 10 food_id, COUNT(*) as eat_count
|
|
FROM {$this->kitchenscale_db_msg['kcal_log']}
|
|
WHERE aud_id = ? AND is_del = 0
|
|
GROUP BY food_id
|
|
ORDER BY eat_count DESC
|
|
", [$user_id]);
|
|
|
|
// dump($user_id);
|
|
// dump($language);
|
|
|
|
|
|
if (empty($user_top_foods)) {
|
|
return $this->getPopularFoods($db, $tag_limit, $item_limit,$language);
|
|
}
|
|
|
|
$food_ids = array_column($user_top_foods, 'food_id');
|
|
if (empty($food_ids)) {
|
|
return $this->getPopularFoods($db, $tag_limit, $item_limit,$language);
|
|
}
|
|
$food_ids_str = implode(',', $food_ids);
|
|
|
|
// 获取用户偏好食材的分类
|
|
$preferred_categories = $db->query("
|
|
SELECT TOP {$tag_limit} f2.id, f2.name, COUNT(DISTINCT f3.id) as food_count
|
|
FROM {$this->kitchenscale_db_msg['foodlist2']} f2
|
|
INNER JOIN {$this->kitchenscale_db_msg['foodlist3']} f3 ON f2.id = f3.two_id
|
|
WHERE f3.id IN ({$food_ids_str}) AND f2.is_del = 0 AND f3.is_del = 0
|
|
GROUP BY f2.id, f2.name
|
|
ORDER BY food_count DESC
|
|
");
|
|
|
|
$result = [];
|
|
if($language == 'zh'){
|
|
$language_key = 'food_name';
|
|
}else{
|
|
if(!$language){
|
|
$language = 'zh';
|
|
$language_key = 'food_name';
|
|
}else{
|
|
$language_key = 'food_name_'.$language;
|
|
}
|
|
|
|
}
|
|
foreach ($preferred_categories as $category) {
|
|
// 获取该分类下的其他食材
|
|
$foods = $db->query("
|
|
SELECT TOP {$item_limit} id, $language_key as name
|
|
FROM {$this->kitchenscale_db_msg['foodlist3']}
|
|
WHERE two_id = ? AND is_del = 0 AND id NOT IN ({$food_ids_str})
|
|
ORDER BY is_popular DESC, $language_key ASC
|
|
", [$category['id']]);
|
|
// dump($foods);
|
|
$category_data = [];
|
|
foreach ($foods as $food) {
|
|
$category_data[] = [
|
|
'name' => $food['name'] ?? '????',
|
|
'id' => $food['id'] ?? 0,
|
|
'type' => 'food'
|
|
];
|
|
}
|
|
|
|
if (!empty($category_data)) {
|
|
$result[$this->food_2_ys[$category['name']][$language] ?? '????'] = $category_data;
|
|
}
|
|
}
|
|
|
|
return $result;
|
|
} catch (\Exception $e) {
|
|
return $this->getPopularFoods($db, $tag_limit, $item_limit,$language);
|
|
}
|
|
}
|
|
} |