dev: 增加相似度检查

This commit is contained in:
Julian Freeman
2024-07-19 16:34:27 -04:00
parent 24e2184659
commit 5feaa5f3b3
6 changed files with 149 additions and 12 deletions

View File

@@ -9,7 +9,9 @@ columns_d = {
"opt": Column("opt", DataType.TEXT),
"url": Column("url", DataType.BLOB),
"notes": Column("notes", DataType.BLOB),
"path": Column("path", DataType.BLOB, nullable=False),
"uuid": Column("uuid", DataType.TEXT, nullable=False),
"filepath": Column("filepath", DataType.BLOB, nullable=False),
"path": Column("path", DataType.BLOB),
}
all_columns = [
@@ -20,6 +22,8 @@ all_columns = [
columns_d["opt"],
columns_d["url"],
columns_d["notes"],
columns_d["uuid"],
columns_d["filepath"],
columns_d["path"],
]
@@ -29,3 +33,9 @@ query_columns = [
columns_d["username"],
columns_d["url"],
]
# 从数据库中读取 UUID 和 文件路径分析相似度
sim_columns = [
columns_d["uuid"],
columns_d["filepath"],
]

View File

@@ -41,7 +41,9 @@ def read_kps_to_db(kps_file: str | PathLike[str], password: str,
extract_otp(entry.otp),
blob_fy(trim_str(entry.url)),
blob_fy(entry.notes),
blob_fy("::".join([kps_file] + entry.path[:-1])),
str(entry.uuid),
blob_fy(kps_file),
blob_fy("::".join(entry.path[:-1])),
])
sqh.insert_into(table_name, all_columns[1:], values)

View File

@@ -8,7 +8,13 @@ from lib.kps_operations import read_kps_to_db
class GbxKpsLogin(QtWidgets.QGroupBox):
def __init__(self, path: str, sqh: Sqlite3Worker, config: dict, parent=None):
def __init__(
self,
path: str,
sqh: Sqlite3Worker,
config: dict,
parent: QtWidgets.QWidget = None
):
super().__init__(parent)
self.sqh = sqh
self.config = config
@@ -75,10 +81,12 @@ class GbxKpsLogin(QtWidgets.QGroupBox):
def on_pbn_load_clicked(self):
try:
read_kps_to_db(kps_file=self.lne_path.text(),
password=self.lne_password.text(),
table_name=self.config["table_name"],
sqh=self.sqh)
read_kps_to_db(
kps_file=self.lne_path.text(),
password=self.lne_password.text(),
table_name=self.config["table_name"],
sqh=self.sqh
)
except CredentialsError:
QtWidgets.QMessageBox.critical(self, "密码错误",
f"{self.lne_path.text()}\n密码错误")

View File

@@ -3,6 +3,8 @@ from PySide6 import QtWidgets, QtCore, QtGui
from .page_load import PageLoad
from .page_query import PageQuery
from .page_similar import PageSimilar
from .cmbx_styles import StyleComboBox
from lib.Sqlite3Helper import Sqlite3Worker
from lib.db_columns_def import all_columns
@@ -10,7 +12,13 @@ from lib.config_utils import write_config
class UiKpsUnifier(object):
def __init__(self, default_db_path: str, config: dict, sqh: Sqlite3Worker, window: QtWidgets.QMainWindow):
def __init__(
self,
default_db_path: str,
config: dict,
sqh: Sqlite3Worker,
window: QtWidgets.QMainWindow
):
window.setWindowTitle('KeePassXC 多合一')
self.cw = QtWidgets.QWidget(window)
self.vly_m = QtWidgets.QVBoxLayout()
@@ -26,7 +34,8 @@ class UiKpsUnifier(object):
self.menu_view = self.menu_bar.addMenu("视图")
self.act_load = QtGui.QAction("加载", self.cw)
self.act_query = QtGui.QAction("查询", self.cw)
self.menu_view.addActions([self.act_load, self.act_query])
self.act_similar = QtGui.QAction("相似度", self.cw)
self.menu_view.addActions([self.act_load, self.act_query, self.act_similar])
self.menu_help = self.menu_bar.addMenu("帮助")
self.act_about = QtGui.QAction("关于", self.cw)
@@ -51,6 +60,8 @@ class UiKpsUnifier(object):
self.sw_m.addWidget(self.page_load)
self.page_query = PageQuery(sqh, config, self.cw)
self.sw_m.addWidget(self.page_query)
self.page_similar = PageSimilar(sqh, config, self.cw)
self.sw_m.addWidget(self.page_similar)
def update_sqh(self, sqh: Sqlite3Worker):
self.page_load.update_sqh(sqh)
@@ -71,6 +82,8 @@ class KpsUnifier(QtWidgets.QMainWindow):
self.ui.act_open.triggered.connect(self.on_act_open_triggered)
self.ui.act_load.triggered.connect(self.on_act_load_triggered)
self.ui.act_query.triggered.connect(self.on_act_query_triggered)
self.ui.act_similar.triggered.connect(self.on_act_similar_triggered)
self.ui.act_about.triggered.connect(self.on_act_about_triggered)
self.ui.act_about_qt.triggered.connect(self.on_act_about_qt_triggered)
@@ -114,6 +127,9 @@ class KpsUnifier(QtWidgets.QMainWindow):
def on_act_query_triggered(self):
self.ui.sw_m.setCurrentIndex(1)
def on_act_similar_triggered(self):
self.ui.sw_m.setCurrentIndex(2)
def on_act_about_triggered(self):
QtWidgets.QMessageBox.about(
self,

View File

@@ -1,7 +1,6 @@
# coding: utf8
import sqlite3
from pathlib import Path
from PySide6 import QtWidgets
from .gbx_kps_login import GbxKpsLogin
@@ -10,7 +9,12 @@ from lib.Sqlite3Helper import Sqlite3Worker
class WgLoadKps(QtWidgets.QWidget):
def __init__(self, sqh: Sqlite3Worker, config: dict, parent=None):
def __init__(
self,
sqh: Sqlite3Worker,
config: dict,
parent: QtWidgets.QWidget = None
):
super().__init__(parent)
self.sqh = sqh
self.config = config
@@ -55,7 +59,12 @@ class WgLoadKps(QtWidgets.QWidget):
class PageLoad(QtWidgets.QWidget):
def __init__(self, sqh: Sqlite3Worker, config: dict, parent=None):
def __init__(
self,
sqh: Sqlite3Worker,
config: dict,
parent: QtWidgets.QWidget = None
):
super().__init__(parent)
self.sqh = sqh
self.config = config

92
src/page_similar.py Normal file
View File

@@ -0,0 +1,92 @@
# coding: utf8
from itertools import combinations
from uuid import UUID
from PySide6 import QtWidgets, QtCore
from PySide6.QtCore import QAbstractTableModel
from lib.Sqlite3Helper import Sqlite3Worker
from lib.db_columns_def import sim_columns
class SimilarDataModel(QAbstractTableModel):
def __init__(self, similar_data: list[tuple], parent=None):
super().__init__(parent)
self.similar_data = similar_data
self.headers = ["文件1", "文件2", "相似度"]
def rowCount(self, parent: QtCore.QModelIndex = ...):
return len(self.similar_data)
def columnCount(self, parent: QtCore.QModelIndex = ...):
return len(self.headers)
def data(self, index: QtCore.QModelIndex, role: int = ...):
if role == QtCore.Qt.ItemDataRole.DisplayRole:
return self.similar_data[index.row()][index.column()]
if role == QtCore.Qt.ItemDataRole.TextAlignmentRole:
if index.column() == 2:
return QtCore.Qt.AlignmentFlag.AlignRight | QtCore.Qt.AlignmentFlag.AlignVCenter
def headerData(self, section: int, orientation: QtCore.Qt.Orientation, role: int = ...):
if orientation == QtCore.Qt.Orientation.Horizontal:
if role == QtCore.Qt.ItemDataRole.DisplayRole:
return self.headers[section]
class PageSimilar(QtWidgets.QWidget):
def __init__(
self,
sqh: Sqlite3Worker,
config: dict,
parent: QtWidgets.QWidget = None
):
super().__init__(parent)
self.sqh = sqh
self.config = config
self.hly_m = QtWidgets.QHBoxLayout()
self.setLayout(self.hly_m)
self.vly_left = QtWidgets.QVBoxLayout()
self.hly_m.addLayout(self.vly_left)
self.pbn_read_db = QtWidgets.QPushButton("读取数据库", self)
self.pbn_read_db.setMinimumWidth(config["button_min_width"])
self.vly_left.addWidget(self.pbn_read_db)
self.vly_left.addStretch(1)
self.tbv_m = QtWidgets.QTableView(self)
self.hly_m.addWidget(self.tbv_m)
self.pbn_read_db.clicked.connect(self.on_pbn_read_db_clicked)
def on_pbn_read_db_clicked(self):
_, results = self.sqh.select(self.config["table_name"], sim_columns)
file_uuids: dict[str, list[UUID]] = {}
for u, filepath in results:
filepath = filepath.decode("utf8")
if filepath not in file_uuids:
file_uuids[filepath] = []
file_uuids[filepath].append(u)
files = file_uuids.keys()
if len(files) < 2:
QtWidgets.QMessageBox.warning(self, "警告", "数据库中存在的文件数少于 2无法检查相似度。")
return
similar_data: list[tuple] = []
comb = combinations(files, 2)
for i, j in list(comb):
uuids_i = file_uuids[i]
uuids_j = file_uuids[j]
len_i = len(uuids_i)
len_j = len(uuids_j)
set_inter = set(uuids_i).intersection(uuids_j)
sim = (len(set_inter) * 2) / (len_i + len_j)
similar_data.append((i, j, f"{sim * 100:.2f}"))
model = SimilarDataModel(similar_data, self)
self.tbv_m.setModel(model)