From d24b40c9ec11d01124212946e3e5c5c6b2180c5a Mon Sep 17 00:00:00 2001 From: zhangpu <1250681871@qq.com> Date: Thu, 13 Nov 2025 14:24:41 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=8A=A0=E8=8F=9C=E5=93=81?= =?UTF-8?q?=E5=90=8E=EF=BC=8C=E5=A4=84=E7=90=86=E9=9C=80=E8=A6=81=E7=A8=8B?= =?UTF-8?q?=E5=BA=8F=E9=87=8D=E5=90=AF=E6=89=8D=E7=94=9F=E6=95=88=E7=9A=84?= =?UTF-8?q?Bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- exp_multimodal/exp_multimodal_gui.py | 45 +++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/exp_multimodal/exp_multimodal_gui.py b/exp_multimodal/exp_multimodal_gui.py index 3ff8ae5..329fac5 100644 --- a/exp_multimodal/exp_multimodal_gui.py +++ b/exp_multimodal/exp_multimodal_gui.py @@ -792,6 +792,9 @@ class MultiModalFoodApp: self.root.after(0, lambda: messagebox.showinfo("成功", f"索引构建完成!默认菜品:{len(default_labels)}个,自定义菜品:{len(self.custom_dishes)}个,总计:{len(all_labels)}个")) self.root.after(0, lambda: self.openset_status_label.configure(text=f"索引已构建 ({len(all_labels)}个菜品)", text_color="green")) + # 新增:重新加载索引到内存 + self.root.after(0, self.reload_openset_matcher) + except Exception as e: self.root.after(0, lambda: messagebox.showerror("错误", f"构建索引失败: {e}")) self.root.after(0, lambda: self.openset_status_label.configure(text="构建失败", text_color="red")) @@ -824,6 +827,32 @@ class MultiModalFoodApp: messagebox.showerror("错误", f"索引测试失败: {e}") self.openset_status_label.configure(text="索引无效", text_color="red") + def reload_openset_matcher(self): + """重新加载向量索引(用于索引更新后刷新)""" + try: + index_path = self.openset_index_path_var.get() + + # 检查索引是否存在 + required_files = ["dish_names.json", "dish_embeddings.npy", "faiss_index.bin"] + for fname in required_files: + if not os.path.exists(os.path.join(index_path, fname)): + print(f"[ReloadMatcher] 索引文件不完整,缺少: {fname}") + return False + + # 重新创建 matcher 和 embedder + embedder_url = self.ollama_url_var.get().strip() or DEFAULT_OLLAMA_URL + embedder_model = self.openset_embedder_model_var.get().strip() + self.openset_embedder = OllamaEmbedder(base_url=embedder_url, model=embedder_model) + self.openset_matcher = DishNameMatcher(index_dir=index_path) + + num_dishes = len(self.openset_matcher.dish_names) + print(f"[ReloadMatcher] 成功重载索引,包含 {num_dishes} 个菜品") + return True + + except Exception as e: + print(f"[ReloadMatcher] 重载失败: {e}") + return False + # -------------------- 识别流程 -------------------- def start_recognition(self): if not self.uploaded_images: @@ -1298,10 +1327,10 @@ class MultiModalFoodApp: messagebox.showinfo("成功", f"已添加菜品:{dish_name}") - # 询问是否立即重建索引 + # 自动重建索引(后台线程,不阻塞UI) if self.auto_rebuild_index_var.get(): - if messagebox.askyesno("重建索引", "是否立即重建向量索引?"): - self.build_openset_index() + self.openset_status_label.configure(text="正在自动重建索引...", text_color="orange") + threading.Thread(target=self._build_index_thread, daemon=True).start() def import_dishes_from_json(self): """从JSON文件批量导入菜品""" @@ -1345,13 +1374,15 @@ class MultiModalFoodApp: messagebox.showinfo( "导入完成", - f"成功导入 {added_count} 个新菜品" f"(总计导入{len(new_dishes)}个,其中{len(new_dishes)-added_count}个已存在)" + f"当前自定义菜品数:{len(self.custom_dishes)}" + f"成功导入 {added_count} 个新菜品" + + f"(总计导入{len(new_dishes)}个,其中{len(new_dishes)-added_count}个已存在)" + + f"当前自定义菜品数:{len(self.custom_dishes)}" ) - # 询问是否重建索引 + # 自动重建索引(后台线程) if self.auto_rebuild_index_var.get() and added_count > 0: - if messagebox.askyesno("重建索引", f"已添加{added_count}个新菜品,是否立即重建向量索引?"): - self.build_openset_index() + self.openset_status_label.configure(text="正在自动重建索引...", text_color="orange") + threading.Thread(target=self._build_index_thread, daemon=True).start() except Exception as e: messagebox.showerror("错误", f"导入失败: {e}")