基于矩阵分解算法的智能Steam游戏AI推荐系统——深度学习算法应用(含python、ipynb工程源码)+数据集(三)

目录

  • 前言
  • 总体设计
    • 系统整体结构图
    • 系统流程图
  • 运行环境
  • 模块实现
    • 1. 数据预处理
    • 2. 模型构建
      • 1)定义模型结构
      • 2)优化损失函数
    • 3. 模型训练及保存
      • 1)模型训练
      • 2)模型保存
    • 4. 模型应用
      • 1)制作页面
      • 2)模型导入及调用
      • 3)模型应用代码
  • 相关其它博客
  • 工程源代码下载
  • 其它资料下载


在这里插入图片描述

前言

本项目采用了矩阵分解算法,用于对玩家已游玩的数据进行深入分析。它的目标是从众多游戏中筛选出最适合该玩家的游戏,以实现一种相对精准的游戏推荐系统。

首先,项目会收集并分析玩家已经玩过的游戏数据,包括游戏名称、游戏时长、游戏评分等信息。这些数据构成了一个大型的用户-游戏交互矩阵,其中每一行代表一个玩家,每一列代表一个游戏,矩阵中的值表示玩家与游戏之间的交互情况。

接下来,项目运用矩阵分解算法,将用户-游戏这稀疏矩阵用两个小矩阵——特征-游戏矩阵和用户-特征矩阵,进行近似替代。这个分解过程会将玩家和游戏映射到一个潜在的特征空间,从而能够推断出玩家与游戏之间的潜在关系。

一旦模型训练完成,系统可以根据玩家的游戏历史,预测他们可能喜欢的游戏。这种预测是基于玩家与其他玩家的相似性以及游戏与其他游戏的相似性来实现的。因此,系统可以为每个玩家提供个性化的游戏推荐,考虑到他们的游戏偏好和历史行为。

总的来说,本项目的目标是通过矩阵分解和潜在因子模型,提供一种更为精准的游戏推荐系统。这种个性化推荐可以提高玩家的游戏体验,同时也有助于游戏平台提供更好的游戏推广和增加用户黏性。

总体设计

本部分包括系统整体结构图和系统流程图。

系统整体结构图

系统整体结构如图所示。

在这里插入图片描述

系统流程图

系统流程如图所示。

在这里插入图片描述

运行环境

本部分包括 Python 环境、TensorFlow环境、 PyQt5环境。

详见博客:https://blog.csdn.net/qq_31136513/article/details/133148686#_38

模块实现

本项目包括4个模块:数据预处理、模型构建、模型训练及保存、模型测试,下面分别给出各模块的功能介绍及相关代码。

1. 数据预处理

数据集来源于Kaggle,链接地址为https://www.kaggle.com/tamber/steam-video-games,此数据集包含了用户的ID、游戏名称、是否购买或游玩、游戏时长,其中:共包含12393名用户,涉及游戏数量5155款。将数据集置于Jupyter工作路径下的steam-video-games文件夹中。

详见博客:https://blog.csdn.net/qq_31136513/article/details/133148686#1__97

2. 模型构建

数据加载进模型之后,需要定义模型结构,并优化损失函数。

1)定义模型结构

使用矩阵分解算法,将用户-游戏这稀疏矩阵用两个小矩阵——特征-游戏矩阵和用户-特征矩阵,进行近似替代。

详见博客:https://blog.csdn.net/qq_31136513/article/details/133151049#1_54

2)优化损失函数

L2范数常用于矩阵分解算法的损失函数中。因此,本项目的损失函数也引入了L2范数以避免过拟合现象。使用Adagrad优化器优化模型参数。

详见博客:https://blog.csdn.net/qq_31136513/article/details/133151049#2_91

3. 模型训练及保存

由于本项目使用的数据集中,将游戏的DLC (Downloadable Content,后续可下载内容)单独作为另一款游戏列举,因此,在计算准确率时,DLC和游戏本体判定为同一款游戏,同系列的游戏也可以判定为同一款。

详见博客:https://blog.csdn.net/qq_31136513/article/details/133151049#3__105

1)模型训练

详见博客:https://blog.csdn.net/qq_31136513/article/details/133151049#1_148

2)模型保存

为方便使用模型,需要将训练得到的结果使用Joblib进行保存。

详见博客:https://blog.csdn.net/qq_31136513/article/details/133151049#2_187

4. 模型应用

一是制作页面的布局,获取并检查输入的数据;二是将获取的数据-与之前保存的模型进行匹配达到应用效果。

1)制作页面

相关操作如下:

(1)使用代码绘制页面的基础布局,创建Recommandation类。

class Recommandation(QWidget):
#初始化def __init__(self):super().__init__()self.initUI()
#初始化布局def initUI(self):#设置界面的初始位置和大小self.setGeometry(600,200,450,550)#窗口名self.setWindowTitle('steam游戏推荐')#设置组件,以下为标签self.lb1 = QLabel('请输入游戏名:',self)#这是所在位置self.lb1.move(20,20)self.lb2 = QLabel('请输入游戏名:',self)self.lb2.move(20,80)self.lb3 = QLabel('请输入游戏名:',self)self.lb3.move(20,140)self.lb4 = QLabel('请输入游戏名:',self)self.lb4.move(20,200)self.lb5 = QLabel('请输入游戏名:',self)self.lb5.move(20,260)#以下为下拉输入框的创建self.combobox1 = QComboBox(self, minimumWidth=200)self.combobox1.move(100,20)self.combobox1.setEditable(True)self.combobox2 = QComboBox(self, minimumWidth=200)self.combobox2.move(100,80)self.combobox2.setEditable(True)self.combobox3 = QComboBox(self, minimumWidth=200)self.combobox3.move(100,140)self.combobox3.setEditable(True)self.combobox4 = QComboBox(self, minimumWidth=200)self.combobox4.move(100,200)self.combobox4.setEditable(True)self.combobox5 = QComboBox(self, minimumWidth=200)self.combobox5.move(100,260)self.combobox5.setEditable(True)#以下为输入的按键设置self.bt1 = QPushButton('请输入游戏时间',self)self.bt1.move(330,20)self.bt2 = QPushButton('请输入游戏时间',self)self.bt2.move(330,80)self.bt3 = QPushButton('请输入游戏时间',self)self.bt3.move(330,140)self.bt4 = QPushButton('请输入游戏时间',self)self.bt4.move(330,200)self.bt5 = QPushButton('请输入游戏时间',self)self.bt5.move(330,260)#推荐按钮self.bt=QPushButton('推荐开始',self)self.bt.move(20,400)#初始化下拉输入框self.init_combobox()#连接按键与槽self.bt1.clicked.connect(self.timeDialog)self.bt2.clicked.connect(self.timeDialog)self.bt3.clicked.connect(self.timeDialog)self.bt4.clicked.connect(self.timeDialog)self.bt5.clicked.connect(self.timeDialog)#连接推荐self.bt.clicked.connect(self.recommand) 

connect()是Qt特有的信号与槽机制,槽接收到信号进行处理。在这里使用了clicked 作为信号,单击按键会发出信号。

(2)初始化下拉输入框,将gamelist输入进下拉框的菜单,以及添加自动补全机能。

#初始化下拉输入框
def init_combobox(self):#增加选项元素for i in range(len(gamelist)):self.combobox1.addItem(gamelist[i])self.combobox2.addItem(gamelist[i])self.combobox3.addItem(gamelist[i])self.combobox4.addItem(gamelist[i])self.combobox5.addItem(gamelist[i])self.combobox1.setCurrentIndex(-1)self.combobox2.setCurrentIndex(-1)self.combobox3.setCurrentIndex(-1)self.combobox4.setCurrentIndex(-1)self.combobox5.setCurrentIndex(-1)#增加自动补全self.completer = QCompleter(gamelist)#补全方式self.completer.setFilterMode(Qt.MatchStartsWith)self.completer.setCompletionMode(QCompleter.PopupCompletion)self.combobox1.setCompleter(self.completer)self.combobox2.setCompleter(self.completer)self.combobox3.setCompleter(self.completer)self.combobox4.setCompleter(self.completer)self.combobox5.setCompleter(self.completer)

(3)设置槽,同时存储数据

相关操作如下:

    def timeDialog(self):
#获取信号sender = self.sender()if sender == self.bt1:#获取下拉输入框1输入的游戏名gamename = self.combobox1.currentText()#通过字典game2idx查询获得的游戏名所对应的序列号gameid = game2idx.get(gamename)#没有序列号的情况,可以理解为未输入正确的游戏名,或者输入为空if gameid == None:#这种情况下生成一个MessageBox报错reply = QMessageBox.information(self,'Error','请输入正确的游戏名!', QMessageBox.Close)else:#输入正确的情况,将游戏名字、ID,分别记录到一个字典里,方便保存与更改gamedict[1] = gamenameidxdict[1] = gameid#弹出一个文本输入框,要求输入对应游戏时长text, ok = QInputDialog.getDouble(self, '游戏时间', '请输入游戏时间:', min = 0.1)#如果输入正确,将时长记录到一个字典中,方便保存与更改if ok:timedict[1] = textelif sender == self.bt2:gamename = self.combobox2.currentText()gameid = game2idx.get(gamename)if gameid == None:reply = QMessageBox.information(self,'Error','请输入正确的游戏名!', QMessageBox.Close)else:gamedict[2] = gamenameidxdict[2] = gameidtext, ok = QInputDialog.getDouble(self, '游戏时间', '请输入游戏时间:', min = 0.1)if ok:timedict[2] = textelif sender == self.bt3:gamename = self.combobox3.currentText()gameid = game2idx.get(gamename)if gameid == None:reply = QMessageBox.information(self,'Error','请输入正确的游戏名!', QMessageBox.Close)else:gamedict[3] = gamenameidxdict[3] = gameidtext, ok = QInputDialog.getDouble(self, '游戏时间', '请输入游戏时间:', min = 0.1)if ok:timedict[3] = textelif sender == self.bt4:gamename = self.combobox4.currentText()gameid = game2idx.get(gamename)if gameid == None:reply = QMessageBox.information(self,'Error','请输入正确的游戏名!', QMessageBox.Close)else:gamedict[4] = gamenameidxdict[4] = gameidtext, ok = QInputDialog.getDouble(self, '游戏时间', '请输入游戏时间:', min = 0.1)if ok:timedict[4] = textelif sender == self.bt5:gamename = self.combobox5.currentText()gameid = game2idx.get(gamename)if gameid == None:reply = QMessageBox.information(self,'Error','请输入正确的游戏名!', QMessageBox.Close)else:gamedict[5] = gamenameidxdict[5] = gameidtext, ok = QInputDialog.getDouble(self, '游戏时间', '请输入游戏时间:', min = 0.1)if ok:timedict[5] = text 

(4) 验证数据是否输入完毕,以及准备调用模型

   def recommand(self):#验证是否存在没有写入的数据c = 0for i in range(1,6):if gamedict[i] == "NULL":c+=1if idxdict[i] == "NULL":c+=1if timedict[i] == "NULL":c+=1#全部写完的情况if c == 0:#将字典转化为列表usertime = list(timedict.values())useridx = list(idxdict.values())#调用模型allrecidx = UserSimilarity(useridx,usertime)#降序排列数据rr = np.argsort(-allrecidx)#获取排行前五的游戏IDtop_k = rr[:5]#将ID对应的游戏名字输入数组for i in top_k:recgame.append(idx2game[i])#将数组转化为字符串并输出reclist = ','.join(recgame)reply = QMessageBox.information(self,'推荐的游戏','给您推荐的游戏是'+reclist, QMessageBox.Close)#存在没有写完的数据,要求重新写入else:reply = QMessageBox.information(self,'Error','请输入全部数据!', QMessageBox.Close)

2)模型导入及调用

相关操作如下:

(1)加载当前文件夹下的Save_data模型

game2idx = joblib.load('./Save_data/game2idx.pkl')
idx2game = joblib.load('./Save_data/idx2game.pkl')
rec = joblib.load('./Save_data/rec.pkl')
hours = joblib.load('./Save_data/hours.pkl')
buy = joblib.load('./Save_data/buy.pkl')
users = joblib.load('./Save_data/buyers.pkl')

(2)创建一个用户相似度函数,用于刻画Qt里收集到的数据与训练出的用户相似度最高的数据作为输出

def UserSimilarity(games, game_hours):similarity = np.zeros(len(users)) # 用户相似度矩阵for i in range(len(users)):#计算用户输入的游戏与数据集中每个用户购买游戏的重合度coincidence = 0 #重合度,每重合一个游戏加1positions = [] #重合游戏在games中的位置#获取数据集中的第i个玩家与用户输入的重合情况for ii in range(len(games)):if games[ii] in np.where(buy[users[i], :] == 1)[0]:coincidence += 1positions.append(ii)#如果没有重合,则相似度为0,跳过if coincidence == 0:continuesimi = []#将重合的游戏,根据时长和相同游戏的时长差取绝对值,根据e^-x计算出相似度for position in positions:game = games[position]hour = abs(game_hours[position] - hours[users[i], game])simi.append(math.exp(-hour))#对所有相似度取均值,得到用户与数据集中第i个玩家的相似度similarity[i]similarity[i] = sum(simi) / coincidence#相似度与玩家—游戏矩阵每一行相乘for i in range(len(users)):user = users[i]rec[user] = rec[user] * similarity[i]new_rec = np.zeros(len(rec[0])) # 1*n_games矩阵#将玩家—游戏矩阵按列相加,得到用户对每个游戏的喜好程度,即new_rec矩阵for i in range(len(new_rec)):for user in users:new_rec[i] += rec[user][int(i)]return new_rec

3)模型应用代码

相关代码如下:

import joblib
import numpy as np
import pandas as pd
import math
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
#读取数据
game2idx = joblib.load('./Save_data/game2idx.pkl')
idx2game = joblib.load('./Save_data/idx2game.pkl')
rec = joblib.load('./Save_data/rec.pkl')
hours = joblib.load('./Save_data/hours.pkl')
buy = joblib.load('./Save_data/buy.pkl')
users = joblib.load('./Save_data/buyers.pkl')
#游戏名称列表
gamelist = list(game2idx)
#游戏数
n_game = len(gamelist)
#传入字典
gamedict = {1:"NULL",2:"NULL",3:"NULL",4:"NULL",5:"NULL"}
timedict = {1:"NULL",2:"NULL",3:"NULL",4:"NULL",5:"NULL"}
idxdict = {1:"NULL",2:"NULL",3:"NULL",4:"NULL",5:"NULL"}
#下面两个是要传递的
usertime=[]
useridx=[]
#下面是返回的推荐游戏
recgame=[]
#相似度推荐
def UserSimilarity(games, game_hours):similarity = np.zeros(len(users)) #用户相似度矩阵for i in range(len(users)):#计算用户输入的游戏与数据集中每个用户购买游戏的重合度coincidence = 0 #重合度positions = [] #重合游戏在games中的位置for ii in range(len(games)):if games[ii] in np.where(buy[users[i], :] == 1)[0]:coincidence += 1positions.append(ii)if coincidence == 0:continuesimi = []for position in positions:game = games[position]hour = abs(game_hours[position] - hours[users[i], game])simi.append(math.exp(-hour))similarity[i] = sum(simi) / coincidence#相似度与玩家—游戏矩阵每一行相乘for i in range(len(users)):user = users[i]rec[user] = rec[user] * similarity[i]new_rec = np.zeros(len(rec[0])) #1*n_games矩阵for i in range(len(new_rec)):for user in users:new_rec[i] += rec[user][int(i)]return new_rec
class Recommandation(QWidget):#初始化def __init__(self):super().__init__()self.initUI()#初始化布局def initUI(self):#设置界面的初始位置和大小self.setGeometry(600,200,450,550)#窗口名self.setWindowTitle('steam游戏推荐')#设置组件,以下为标签self.lb1 = QLabel('请输入游戏名:',self)#这是所在位置self.lb1.move(20,20)self.lb2 = QLabel('请输入游戏名:',self)self.lb2.move(20,80)self.lb3 = QLabel('请输入游戏名:',self)self.lb3.move(20,140)self.lb4 = QLabel('请输入游戏名:',self)self.lb4.move(20,200)self.lb5 = QLabel('请输入游戏名:',self)self.lb5.move(20,260)#以下为下拉输入框的创建self.combobox1 = QComboBox(self, minimumWidth=200)self.combobox1.move(100,20)self.combobox1.setEditable(True)self.combobox2 = QComboBox(self, minimumWidth=200)self.combobox2.move(100,80)self.combobox2.setEditable(True)self.combobox3 = QComboBox(self, minimumWidth=200)self.combobox3.move(100,140)self.combobox3.setEditable(True)self.combobox4 = QComboBox(self, minimumWidth=200)self.combobox4.move(100,200)self.combobox4.setEditable(True)self.combobox5 = QComboBox(self, minimumWidth=200)self.combobox5.move(100,260)self.combobox5.setEditable(True)#以下为输入的按键设置self.bt1 = QPushButton('请输入游戏时间',self)self.bt1.move(330,20)self.bt2 = QPushButton('请输入游戏时间',self)self.bt2.move(330,80)self.bt3 = QPushButton('请输入游戏时间',self)self.bt3.move(330,140)self.bt4 = QPushButton('请输入游戏时间',self)self.bt4.move(330,200)self.bt5 = QPushButton('请输入游戏时间',self)self.bt5.move(330,260)#推荐按钮self.bt=QPushButton('推荐开始',self)self.bt.move(20,400)#初始化下拉输入框self.init_combobox()#连接按键与槽self.bt1.clicked.connect(self.timeDialog)self.bt2.clicked.connect(self.timeDialog)self.bt3.clicked.connect(self.timeDialog)self.bt4.clicked.connect(self.timeDialog)self.bt5.clicked.connect(self.timeDialog)#连接推荐self.bt.clicked.connect(self.recommand)#初始化下拉输入框   def init_combobox(self):#增加选项元素for i in range(len(gamelist)):self.combobox1.addItem(gamelist[i])self.combobox2.addItem(gamelist[i])self.combobox3.addItem(gamelist[i])self.combobox4.addItem(gamelist[i])self.combobox5.addItem(gamelist[i])self.combobox1.setCurrentIndex(-1)self.combobox2.setCurrentIndex(-1)self.combobox3.setCurrentIndex(-1)self.combobox4.setCurrentIndex(-1)self.combobox5.setCurrentIndex(-1)#增加自动补全self.completer = QCompleter(gamelist)#补全方式self.completer.setFilterMode(Qt.MatchStartsWith)self.completer.setCompletionMode(QCompleter.PopupCompletion)self.combobox1.setCompleter(self.completer)self.combobox2.setCompleter(self.completer)self.combobox3.setCompleter(self.completer)self.combobox4.setCompleter(self.completer)self.combobox5.setCompleter(self.completer)def timeDialog(self):#获取信号sender = self.sender()if sender == self.bt1:#获取下拉输入框1输入的游戏名gamename = self.combobox1.currentText()#通过字典game2idx查询获得的游戏名所对应的序列号gameid = game2idx.get(gamename)#没有序列号的情况,可以理解为未输入正确的游戏名,或者输入为空if gameid == None:#这种情况下生成一个MessageBox报错reply = QMessageBox.information(self,'Error','请输入正确的游戏名!', QMessageBox.Close)else:#输入正确的情况,将游戏名字、ID,分别记录到一个字典里,方便保存与更改gamedict[1] = gamenameidxdict[1] = gameid#弹出一个文本输入框,要求输入对应的游戏时长text, ok = QInputDialog.getDouble(self, '游戏时间', '请输入游戏时间:', min = 0.1)#如果输入正确,将时长记录到一个字典中,方便保存与更改if ok:timedict[1] = textelif sender == self.bt2:gamename = self.combobox2.currentText()gameid = game2idx.get(gamename)if gameid == None:reply = QMessageBox.information(self,'Error','请输入正确的游戏名!', QMessageBox.Close)else:gamedict[2] = gamenameidxdict[2] = gameidtext, ok = QInputDialog.getDouble(self, '游戏时间', '请输入游戏时间:', min = 0.1)if ok:timedict[2] = textelif sender == self.bt3:gamename = self.combobox3.currentText()gameid = game2idx.get(gamename)if gameid == None:reply = QMessageBox.information(self,'Error','请输入正确的游戏名!', QMessageBox.Close)else:gamedict[3] = gamenameidxdict[3] = gameidtext, ok = QInputDialog.getDouble(self, '游戏时间', '请输入游戏时间:', min = 0.1)if ok:timedict[3] = textelif sender == self.bt4:gamename = self.combobox4.currentText()gameid = game2idx.get(gamename)if gameid == None:reply = QMessageBox.information(self,'Error','请输入正确的游戏名!', QMessageBox.Close)else:gamedict[4] = gamenameidxdict[4] = gameidtext, ok = QInputDialog.getDouble(self, '游戏时间', '请输入游戏时间:', min = 0.1)if ok:timedict[4] = textelif sender == self.bt5:gamename = self.combobox5.currentText()gameid = game2idx.get(gamename)if gameid == None:reply = QMessageBox.information(self,'Error','请输入正确的游戏名!', QMessageBox.Close)else:gamedict[5] = gamenameidxdict[5] = gameidtext, ok = QInputDialog.getDouble(self, '游戏时间', '请输入游戏时间:', min = 0.1)if ok:timedict[5] = textdef recommand(self):#验证是否存在没有写入的数据c = 0for i in range(1,6):if gamedict[i] == "NULL":c+=1if idxdict[i] == "NULL":c+=1if timedict[i] == "NULL":c+=1#全部写完的情况if c == 0:#将字典转化为列表usertime = list(timedict.values())useridx = list(idxdict.values())#调用模型allrecidx = UserSimilarity(useridx,usertime)#降序排列数据rr = np.argsort(-allrecidx)#获取排行前五的游戏IDtop_k = rr[:5]#将ID对应的游戏名字输入数组for i in top_k:recgame.append(idx2game[i])#将数组转化为字符串并输出reclist = ','.join(recgame)reply = QMessageBox.information(self,'推荐的游戏','给您推荐的游戏是'+reclist, QMessageBox.Close)#存在没有写完的数据,要求重新写入else:reply = QMessageBox.information(self,'Error','请输入全部数据!', QMessageBox.Close)
#主函数
if __name__ == "__main__":app = QApplication(sys.argv)w = Recommandation()w.show()sys.exit(app.exec_())

相关其它博客

基于矩阵分解算法的智能Steam游戏AI推荐系统——深度学习算法应用(含python、ipynb工程源码)+数据集(一)

基于矩阵分解算法的智能Steam游戏AI推荐系统——深度学习算法应用(含python、ipynb工程源码)+数据集(二)

基于矩阵分解算法的智能Steam游戏AI推荐系统——深度学习算法应用(含python、ipynb工程源码)+数据集(四)

工程源代码下载

详见本人博客资源下载页


其它资料下载

如果大家想继续了解人工智能相关学习路线和知识体系,欢迎大家翻阅我的另外一篇博客《重磅 | 完备的人工智能AI 学习——基础知识学习路线,所有资料免关注免套路直接网盘下载》
这篇博客参考了Github知名开源平台,AI技术平台以及相关领域专家:Datawhale,ApacheCN,AI有道和黄海广博士等约有近100G相关资料,希望能帮助到所有小伙伴们。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/138212.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

zabbix监控多实例redis

Zabbix监控多实例Redis 软件名称软件版本Zabbix Server6.0.17Zabbix Agent5.4.1Redis6.2.10 Zabbix客户端配置 编辑自动发现脚本 vim /usr/local/zabbix/scripts/redis_discovery.sh #!/bin/bash #Fucation:redis low-level discovery #Script_name redis_discovery.sh red…

【操作系统】实验一 Linux初步

文章目录 Linux初步一、实验目的二、实验内容 Linux初步 一、实验目的 通过proc文件系统观察整个Linux内核和系统的一些重要特征,并编写一个程序,使用proc文件系统获得以及修改系统的各种配置参数。 本实验需要学生具有Linux的基本操作技能&#xff0c…

Rust常见编程概念

变量和可变性 rust使用let声明变量,变量默认是不可改变的。通过在let后面加上mut,可以声明可变变量。可以在变量名后加:和类型名,来显式声明变量类型,例如: let a:u32 1; 常量 常量使用const声明,变量名…

【Tricks】关于如何防止edge浏览器偷取chrome浏览器的账号

《关于如何防止edge浏览器偷取chrome浏览器的账号》 前段时间edge自动更新了,我并没有太在意界面的问题。但是由于我使用同一个网站平台时,例如b站,甚至是邮箱,edge的账号和chrome的账号会自动同步,这就导致我很难短时…

Centos7部署gitlab

建议服务器配置不低于2C8G 1、安装必要的依赖 sudo yum install -y curl policycoreutils-python openssh-server perl2、配置极狐GitLab 软件源镜像 curl -fsSL https://packages.gitlab.cn/repository/raw/scripts/setup.sh | /bin/bash sudo yum install gitlab-jh -y3、…

安防视频/视频汇聚平台EasyCVR使用onvif探测添加设备通道详细步骤来啦!

视频云存储/安防监控EasyCVR视频汇聚平台基于云边端智能协同,支持海量视频的轻量化接入与汇聚、转码与处理、全网智能分发、视频集中存储等。音视频流媒体视频平台EasyCVR拓展性强,视频能力丰富,具体可实现视频监控直播、视频轮播、视频录像、…

uniapp打包安卓后在安卓屏上实现开机自启动

实现开机自启动(使用插件) 打开插件地址安卓开机自启动 Fvv-AutoStart - DCloud 插件市场 使用方法 选择你要开启自启动的项目 在项目的manifest.json中app-plus下写入以下代码 注意需要替换 android_package_name 为自己的,不然无法进行安卓apk打包 "nativePlugins&q…

【计算机网络】IP协议第一讲(协议格式介绍)

IP协议 1.协议头格式1.1 概念介绍1.2补充说明1.2.1 8位生存时间---TTL1.2.2 16位首部检验和 首先明确一个概念:TCP/IP协议是配合使用的,TCP负责可靠传输策略,IP则是负责传输,TCP协议是位于传输层提供的是策略解决可靠性问题&#…

pytest一些常见的插件

Pytest拥有丰富的插件架构,超过800个以上的外部插件和活跃的社区,在PyPI项目中以“ pytest- *”为标识。 本篇将列举github标星超过两百的一些插件进行实战演示。 插件库地址:http://plugincompat.herokuapp.com/ 1、pytest-html&#xff1…

【操作系统】聊聊什么是CPU上下文切换

对于linux来说,本身就是一个多任务运行的操作系统,运行远大于CPU核心数的程序,从用户视角来看是并发执行,而在CPU视角看其实是将不同的CPU时间片进行分割,每个程序执行一下,就切换到别的程序执行。那么这个…

EasyExcel看完肯定行

EasyExcel看完肯定行 1.随便创建一个Excel表格 2.引入依赖 <dependencies><dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.1.1</version></dependency><!-- 方便操作…

【Redis】Redis 的学习教程(十一)之使用 Redis 实现分布式锁

1. 分布式锁概念 在多线程环境下&#xff0c;为了保证数据的线程安全&#xff0c;锁保证同一时刻&#xff0c;只有一个可以访问和更新共享数据。在单机系统我们可以使用 synchronized 锁、Lock 锁保证线程安全。 synchronized 锁是 Java 提供的一种内置锁&#xff0c;在单个 …

jenkins自动化脚本集成时钉钉消息未发送

在进行jenkins自动化脚本集成时&#xff0c;需要配置钉钉发送消息。钉钉的配置正确&#xff0c;测试钉钉消息发送成功&#xff0c;但是当构建项目时&#xff0c;却没有收到钉钉消息&#xff0c;报错如下&#xff1a; [钉钉插件]发送消息时报错: java.lang.NullPointerExceptio…

大转盘抽奖活动制作流程,让你轻松打造火爆营销活动

抽奖活动一直是商家吸引顾客、推广产品的利器之一。而如何让抽奖活动更加顺利、高效地进行呢&#xff1f;今天我们就要介绍的就是乔拓云平台&#xff0c;通过它&#xff0c;商家可以轻松地制作、发布抽奖活动&#xff0c;让您的营销更加便捷、迅速&#xff01;以下是具体操作步…

【智能电表数据接入物联网平台实践】

智能电表数据接入物联网平台实践 设备接线准备设备调试代码实现Modbus TCP Client 读取电表数据读取寄存器数据转成32bit Float格式然后使用modbusTCP Client 读取数据 使用mqtt协议接入物联网平台最终代码实现 设备接线准备 设备调试 代码实现 Modbus TCP Client 读取电表数…

音乐随行,公网畅享,群辉Audiostation给你带来听歌新体验!

文章目录 本教程解决的问题是&#xff1a;按照本教程方法操作后&#xff0c;达到的效果是本教程使用环境&#xff1a;1 群晖系统安装audiostation套件2 下载移动端app3 内网穿透&#xff0c;映射至公网 很多老铁想在上班路上听点喜欢的歌或者相声解解闷儿&#xff0c;于是打开手…

Go 多版本管理工具

Go 多版本管理工具 文章目录 Go 多版本管理工具一、go get 命令1.1 使用方法&#xff1a; 二、Goenv三、GVM (Go Version Manager)四、voidint/g4.1 安装4.2 冲突4.3 使用 在平时开发中&#xff0c;本地新旧项目并行开发的过程中&#xff0c;你大概率会遇到一个令人头疼的问题&…

开发者福利!李彦宏将在百度世界大会手把手教你做AI原生应用

目录 一、写在前面 二、大模型社区 2.1 加入频道 2.2 创建应用 一、写在前面 1. “把最先进的技术用到极致&#xff0c;把最先进的应用做到极致。” 2. “每个产品都在热火朝天地重构&#xff0c;不断加深对AI原生应用的理解。” 3. “这就是真正的AI原生应用&#xff0c;这…

9月21日作业

登录代码&#xff1a; widget.h #ifndef REGISTER_H #define REGISTER_H#include <QWidget> #include <QDebug> #include <QSqlDatabase> #include <QSqlQuery> #include <QMessageBox>namespace Ui { class Register; }class Register : publ…

Linux开发工具之编辑器-vim

vim简单来说就是一款文本编辑器&#xff0c;用于写代码&#xff0c;更是一款多模式编辑器 vim的基本概念 vim有许多种模式&#xff0c;但是铁三角是以下三种模式&#xff1a;命令模式&#xff0c;插入模式&#xff0c;底行模式 1 正常/普通/命令模式&#xff08;默认打开&…