一、项目简介
本项目是一套基于Python开发的AI智能联系人管理程序,主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Python学习者。
包含:项目源码、项目文档等,该项目附带全部源码可作为毕设使用。
项目都经过严格调试,确保可以运行!
二、开发环境要求
本系统的软件开发及运行环境具体如下。
操作系统:Windows 7、Windows 10。
Python版本:Python 3.7。
开发工具:PyCharm 2018。
Python内置模块:sys、os、base64、json、collections。
第三方模块:PyQt5、requests、pandas、Pillow(PIL)、phone、pyecharts、openpyxl、xlrd、pyecharts_snapshot。
说明:由于PIL仅支持到Python 2.7,我们的项目为Python3.x,所以这里导入模块Pillow代替PIL,Pillow为PIL的兼任版本。项目中对图片操作导入模块使用form PIL import Image。
三、系统功能
首页
添加联系人窗口
名片信息展示
选择名片
搜索联系人
编辑联系人
删除联系人
查看联系人分布饼图等功能
四、页面功能
在PyCharm中运行《AI智能联系人管理》即可进入如图1所示的系统主界面。
具体的操作步骤如下:
(1)添加联系人。在主界面中,单击“添加”按钮,将打开添加联系人窗口,在该窗口中,单击“选择名片”按钮,选择一张名片对应的图片,系统将自动识别该名片中的信息,并且显示到右侧的文本框中,效果如图2所示。如果没有名片也可手动输入联系人信息。
(2)搜索联系人。在主界面顶部的文本框中,输入要搜索的内容,单击“搜索”按钮,将从已经保存的联系人信息中查找相应的内容,如果找到对应的内容,将显示在下方,如图3所示,否则给出显示“没有搜索内容”的提示对话框,如图4所示。
说明:在查找联系人时,也可以单击索引字母按钮,按拼音索引来查找。
(3)编辑或删除联系人。在显示联系人时,每个联系人的右侧都有两个按钮(如图5所示),一个是“编辑”,另一个是“删除”,单击不同的按钮将实现相应的功能。
(4)查看联系人的分布。在主界面中,单击“查看联系人分布”按钮,将打开“联系人分布”窗口,在该窗口中将以饼图显示联系人的分布,如图6所示。
五、部分源码展示
# qt5模块 from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5.QtWidgets import * from PyQt5.QtGui import * from PyQt5.QtWebEngineWidgets import * from PyQt5.QtCore import * # 自定义模块 import mainpage import addpage import gridlayout import editpage import pinyintool # 内置模块 import sys import requests, base64, json import collections import os import re # 第三方模块 import pandas as pd from pandas import DataFrame from PIL import Image import phone from pyecharts import Pie # 获取文件的路径 cdir = os.getcwd() # 文件路径 path=cdir+'/res/datafile/' # 读取路径 判断是否创建了文件 if not os.path.exists(path): # 根据路径建立文件夹 os.makedirs(path) # 姓名 公司 电话 手机 邮件 地址 城市 分类 name comp tel mobile email addr city type cardfile = pd.DataFrame(columns=['name', 'comp', 'tel', 'mobile', 'email', 'addr', 'city', 'type']) # 生成xlsx文件 cardfile.to_excel(path+'名片信息表.xlsx', sheet_name='data', index=None) # 编辑页面 class editWindow(QWidget,editpage.Ui_Form): # 初始化方法 def __init__(self): # 找到父类 首页面 super(editWindow, self).__init__() # 初始化页面方法 self.setupUi(self) # 为保存按钮添加事件 self.pushButton_2.clicked.connect(self.editkeep) # 显示添加名片页面 def OPEN(self): # 显示页面 self.show() # 保存编辑内容 def editkeep(self): # 获取按钮名称 indexName = self.pushButton_2.objectName() # 获取表 pi_table = pd.read_excel(path + '名片信息表.xlsx', sheet_name='data') # 获取控件信息 # 'name', 'comp', 'tel', 'mobile', 'email', 'addr', 'city', 'type' name = self.lineEdit.text() comp = self.lineEdit_2.text() tel = self.lineEdit_3.text() mobile = self.lineEdit_4.text() email = self.lineEdit_5.text() addr = self.lineEdit_6.text() # 判断手机号是否为空 if mobile.strip(): # 根据手机号判断区域 try: info = phone.Phone().find(int(mobile)) except Exception as e: print("根据手机号判断区域时出错", e) QMessageBox.critical(self, "错误:", "手机号码不正确!", QMessageBox.Ok) # 弹出提示对话框 self.lineEdit_4.setFocus() # 让手机文本框获得焦点 return # 判断手机号是否正确返回信息 if info == None: city = '其他' else: # 正确返回信息获取省 city = info['province'] else: city = '其他' # 判断姓名是否为空 if name.strip(): # 获取首字母拼音 type = pinyintool.getPinyin(name[0]) # 根据行号删除数据 datas = pi_table.drop(index=[int(indexName)], axis=0) data = datas.append({'name': name, 'comp': comp, 'tel': tel, 'mobile': mobile, 'email': email, 'addr': addr, 'city': city, 'type': type }, ignore_index=True) # 更新xlsx文件 DataFrame(data).to_excel(path + '名片信息表.xlsx', sheet_name='data', index=False) self.close() window.dataall() else: QMessageBox.information(self, '提示信息', '姓名不能为空') pass #首页列表样式 class griditem(QWidget,gridlayout.Ui_Form): # 初始化方法 def __init__(self): # 找到父类 首页面 super(griditem, self).__init__() # 初始化页面方法 self.setupUi(self) # 显示饼图类 class HtmlWindows(QMainWindow): def __init__(self): super(QMainWindow,self).__init__() self.setGeometry(200, 200, 850, 500) self.browser = QWebEngineView() def set(self,title,hurl): self.setWindowTitle(title) d = os.path.dirname(os.path.realpath(sys.argv[0])) # 获取当前文件所在路径 d=re.sub(r'\\','/',d) # 将路径中的分隔符\替换为/ url=d+'/res/datafile/'+hurl self.browser.load(QUrl(url)) self.setCentralWidget(self.browser) # 首页页面 class parentWindow(QWidget,mainpage.Ui_Form): # 初始化方法 def __init__(self): # 找到父类 首页面 super(parentWindow, self).__init__() # 初始化页面方法 self.setupUi(self) # 标签按钮绑定事件 self.pushButton_3.clicked.connect(self.dataall) self.pushButton_4.clicked.connect(lambda:self.dataother('A')) self.pushButton_6.clicked.connect(lambda:self.dataother('B')) self.pushButton_5.clicked.connect(lambda:self.dataother('C')) self.pushButton_7.clicked.connect(lambda:self.dataother('D')) self.pushButton_8.clicked.connect(lambda:self.dataother('E')) self.pushButton_9.clicked.connect(lambda:self.dataother('F')) self.pushButton_10.clicked.connect(lambda:self.dataother('G')) self.pushButton_11.clicked.connect(lambda:self.dataother('H')) self.pushButton_12.clicked.connect(lambda:self.dataother('I')) self.pushButton_13.clicked.connect(lambda:self.dataother('J')) self.pushButton_14.clicked.connect(lambda:self.dataother('K')) self.pushButton_15.clicked.connect(lambda:self.dataother('L')) self.pushButton_16.clicked.connect(lambda:self.dataother('M')) self.pushButton_17.clicked.connect(lambda:self.dataother('N')) self.pushButton_18.clicked.connect(lambda:self.dataother('O')) self.pushButton_19.clicked.connect(lambda:self.dataother('P')) self.pushButton_20.clicked.connect(lambda:self.dataother('Q')) self.pushButton_21.clicked.connect(lambda:self.dataother('R')) self.pushButton_22.clicked.connect(lambda:self.dataother('S')) self.pushButton_23.clicked.connect(lambda:self.dataother('T')) self.pushButton_24.clicked.connect(lambda:self.dataother('U')) self.pushButton_25.clicked.connect(lambda:self.dataother('V')) self.pushButton_26.clicked.connect(lambda:self.dataother('W')) self.pushButton_27.clicked.connect(lambda:self.dataother('X')) self.pushButton_28.clicked.connect(lambda:self.dataother('Y')) self.pushButton_29.clicked.connect(lambda:self.dataother('Z')) # 搜索按钮绑定事件 self.pushButton.clicked.connect(self.seachbtn) self.pushButton_30.clicked.connect(self.lookpie) # 显示全部数据 self.dataall() # 显示饼图 def lookpie(self): # 获取表数据 # 读取文件内容 pi_table = pd.read_excel(path + '名片信息表.xlsx', sheet_name='data') # 获取城市信息 citattr = pi_table['city'].values # 判断是否有城市信息 if len(citattr)==0: # 没有信息提示 QMessageBox.information(self, '提示信息', '没有联系人') return attr = [] v1 = [] # 循环表里city项 for i in citattr: # 判断city项是否包含在attr里 if not i in attr: # 不包含在attr表里时候添加到attr里 attr.append(i) # Counter(计数器)是对字典的补充,用于追踪值的出现次数。 d = collections.Counter(citattr) # 循环城市列表 for k in attr: # d[k] 是k在列表d中出现的次数 v1.append(d[k]) # 生成饼图 pie = Pie("联系人分布") pie.add("", attr, v1, is_label_show=True) pie.show_config() pie.render(path+'联系人分布饼图.html') # 显示饼图 htmlwidows.set('联系人分布','联系人分布饼图.html') htmlwidows.show() pass #搜索功能 def seachbtn(self): # 读取文件内容 pi_table = pd.read_excel(path + '名片信息表.xlsx', sheet_name='data') seachk=self.lineEdit.text() # 查询数据 用户名和公司如果有一个包含搜索内容筛选出来 cardArray = pi_table[(pi_table['name'].str.contains(seachk)) | (pi_table['comp'].str.contains(seachk))].values tb = pi_table[(pi_table['name'].str.contains(seachk)) | (pi_table['comp'].str.contains(seachk))] if len(cardArray) == 0: QMessageBox.information(self, '提示信息', '没有搜索内容') else: # 每次点循环删除管理器的组件 while self.gridLayout.count(): # 获取第一个组件 item = self.gridLayout.takeAt(0) widget = item.widget() # 删除组件 widget.deleteLater() i = -1 for n in range(len(cardArray)): # x 确定每行显示的个数 0,1,2 每行3个 x = n % 3 # 当x为0的时候设置换行 行数+1 if x == 0: i += 1 item = griditem() item.label_8.setText('姓名:' + str(cardArray[n][0])) item.label_9.setText('公司:' + str(cardArray[n][1])) item.label_10.setText('电话:' + str(cardArray[n][2])) item.label_11.setText('手机:' + str(cardArray[n][3])) item.label_12.setText('邮箱:' + str(cardArray[n][4])) item.label_13.setText('地址:' + str(cardArray[n][5])) # 设置名称 为获取项目行数 item.pushButton.setObjectName(str(tb.index.tolist()[n])) item.pushButton_3.setObjectName(str(tb.index.tolist()[n])) # 为按钮绑定点击事件 item.pushButton.clicked.connect(self.edit) item.pushButton_3.clicked.connect(self.deletedata) # 动态给gridlayout添加布局 self.gridLayout.addWidget(item, i, x) # 设置上下滑动控件可以滑动 把scrollAreaWidgetContents_2添加到scrollArea中 self.scrollAreaWidgetContents.setMinimumHeight(i * 200) # girdlayout 添加到滑动控件中 self.scrollAreaWidgetContents.setLayout(self.gridLayout) #显示全部数据 def dataall(self): # 每次点循环删除管理器的组件 while self.gridLayout.count(): # 获取第一个组件 item = self.gridLayout.takeAt(0) widget = item.widget() # 删除组件 widget.deleteLater() i=-1 # 读取文件内容 pi_table = pd.read_excel(path + '名片信息表.xlsx', sheet_name='data') # 获取所有数据 cardArray = pi_table.values # 循环数据 for n in range(len(cardArray)): # x 确定每行显示的个数 0,1,2 每行3个 x = n % 3 # 当x为0的时候设置换行,即行数+1 if x == 0: i += 1 item = griditem() item.label_8.setText('姓名:'+str(cardArray[n][0])) item.label_9.setText('公司:'+str(cardArray[n][1])) item.label_10.setText('电话:'+str(cardArray[n][2])) item.label_11.setText('手机:'+str(cardArray[n][3])) item.label_12.setText('邮箱:'+str(cardArray[n][4])) item.label_13.setText('地址:'+str(cardArray[n][5])) # 设置名称 为获取项目行数 item.pushButton.setObjectName(str(pi_table.index.tolist()[n])) item.pushButton_3.setObjectName(str(pi_table.index.tolist()[n])) # 为按钮绑定点击事件 item.pushButton.clicked.connect(self.edit) item.pushButton_3.clicked.connect(self.deletedata) # 动态添加控件到gridlayout中 self.gridLayout.addWidget(item,i, x) # 设置上下滑动控件可以滑动 把scrollAreaWidgetContents_2添加到scrollArea中 self.scrollAreaWidgetContents.setMinimumHeight(i*200) # 设置gridlayout到滑动控件中 self.scrollAreaWidgetContents.setLayout(self.gridLayout) pass # 删除数据方法 def deletedata(self): # 获取信号源 点击的按钮 sender = self.gridLayout.sender() # 获取按钮名称 indexName = sender.objectName() # 获取表信息 pi_table = pd.read_excel(path + '名片信息表.xlsx', sheet_name='data') # 根据行号删除数据 data=pi_table.drop(index=[int(indexName)], axis=0) # 更新xlsx文件 DataFrame(data).to_excel(path + '名片信息表.xlsx', sheet_name='data', index=False) # 显示全部数据 self.dataall() # 编辑数据 def edit(self): # 获取信号源 点击的按钮 sender = self.gridLayout.sender() # 获取按钮名称 indexName=sender.objectName() pi_table = pd.read_excel(path + '名片信息表.xlsx', sheet_name='data') # 根据行号 获取数据 cardArray =pi_table.iloc[[indexName]].values # 打开编辑页面 editWindow.OPEN() # 设置数据 editWindow.lineEdit.setText(str(cardArray[0][0])) editWindow.lineEdit_2.setText(str(cardArray[0][1])) editWindow.lineEdit_3.setText(str(cardArray[0][2])) editWindow.lineEdit_4.setText(str(cardArray[0][3])) editWindow.lineEdit_5.setText(str(cardArray[0][4])) editWindow.lineEdit_6.setText(str(cardArray[0][5])) # 设置按钮名称 editWindow.pushButton_2.setObjectName(str(indexName)) pass # 显示部分数据 def dataother(self,typeAZ): # 每次点循环删除管理器的组件 while self.gridLayout.count(): # 获取第一个组件 item = self.gridLayout.takeAt(0) # 获取布局 widget = item.widget() # 删除组件 widget.deleteLater() pass # 读取文件内容 pi_table = pd.read_excel(path + '名片信息表.xlsx', sheet_name='data') i = -1 # 筛选内容 cardArray = pi_table[pi_table['type'] == typeAZ].values tb= pi_table[pi_table['type'] == typeAZ] for n in range(len(cardArray)): # x 确定每行显示的个数 0,1,2 每行3个 x = n % 3 # 当x为0的时候设置换行 行数+1 if x == 0: i += 1 item = griditem() item.label_8.setText('姓名:' + str(cardArray[n][0])) item.label_9.setText('公司:' + str(cardArray[n][1])) item.label_10.setText('电话:' + str(cardArray[n][2])) item.label_11.setText('手机:' + str(cardArray[n][3])) item.label_12.setText('邮箱:' + str(cardArray[n][4])) item.label_13.setText('地址:' + str(cardArray[n][5])) # 设置名称 为获取项目行数 item.pushButton.setObjectName(str(tb.index.tolist()[n])) item.pushButton_3.setObjectName(str(tb.index.tolist()[n])) # 为按钮绑定点击事件 item.pushButton.clicked.connect(self.edit) item.pushButton_3.clicked.connect(self.deletedata) # 动态设置控件 self.gridLayout.addWidget(item, i, x) # 动态设置滑动控件滑动高度 self.scrollAreaWidgetContents.setMinimumHeight(i * 200) # giridLayout 添加到滑动控件中 self.scrollAreaWidgetContents.setLayout(self.gridLayout) #添加名片页面 class childWindow(QWidget,addpage.Ui_Form): # 初始化方法 def __init__(self): # 找到父类 添加名片页面 super(childWindow, self).__init__() # 初始化页面方法 self.setupUi(self) # 给选择名片按钮添加事件 self.pushButton.clicked.connect(self.openfile) # 给保存按钮添加事件 self.pushButton_2.clicked.connect(self.keep) #保存名片信息到文档 def keep(self): pi_table = pd.read_excel(path + '名片信息表.xlsx', sheet_name='data') # 获取输出框内容 name =self.lineEdit.text() comp = self.lineEdit_2.text() tel= self.lineEdit_3.text() mobile= self.lineEdit_4.text() email= self.lineEdit_5.text() addr= self.lineEdit_6.text() # 判断手机号是否为空 if mobile.strip(): # 根据手机号判断区域 try: info = phone.Phone().find(int(mobile)) except Exception as e: print("根据手机号判断区域时出错",e) QMessageBox.critical(self,"错误:","手机号码不正确!",QMessageBox.Ok) # 弹出提示对话框 self.lineEdit_4.setFocus() # 让手机文本框获得焦点 return # 判断手机号是否正确返回信息 if info==None: city = '其他' else: # 正确返回信息获取省 city = info['province'] else: city = '其他' # 判断姓名是否为空 if name.strip(): # 获取首字母拼音 type=pinyintool.getPinyin(name[0]) # 添加数据 data = pi_table.append({'name': name, 'comp': comp, 'tel': tel, 'mobile': mobile, 'email': email, 'addr': addr, 'city': city, 'type': type, }, ignore_index=True) # 更新xlsx文件 DataFrame(data).to_excel(path + '名片信息表.xlsx', sheet_name='data', index=False) # 首页面显示全部数据 window.dataall() # 关闭添加页面 self.close() else: QMessageBox.information(self, '提示信息', '姓名不能为空') pass # 显示添加名片页面 def OPEN(self): # 移除控件上图片 self.label_2.setPixmap(QPixmap("")) # 移除输入框内容 self.lineEdit.setText("") self.lineEdit_2.setText("") self.lineEdit_3.setText("") self.lineEdit_4.setText("") self.lineEdit_5.setText("") self.lineEdit_6.setText("") # 显示页面 self.show() #选择名片按钮执行方法 def openfile(self): # 启动选择文件对话空,查找jpg以及png图片 self.download_path = QFileDialog.getOpenFileName(self, "选择要识别的图片", "/", "Image Files(*.jpg *.png)") # 判断是否选择图片 if not self.download_path[0].strip(): # 没有选择图片执行 # 消息对话框 information 提问对话框 question 警告对话框 warning # 严重错误对话框 critical 关于对话框 about QMessageBox.information(self, '提示信息', '没有选择名片图片') pass ........................
六、源码地址
https://download.csdn.net/download/weixin_43860634/88335299