'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); } } }