搭建简单的GPT聊天机器人

目录

第一步

进行语料库读取、文本预处理,完成data_utls.py

第二步

进行Seq2Seq模型的构建,完成Seq2Seq.py

第三步

进行模型参数设置、加载词典和数据、数据准备、GPU设置、构建优化器和损失函数,进行模型的训练和测试,完成execute.py。

第四步

通过给出的前端代码,调用flask前端进行测试,完成app.py文件,使用网页端聊天机器人聊天对话。


有问题后台私信

第一步

进行语料库读取、文本预处理,完成data_utls.py

data_utls.py

'''
数据处理器
'''import os
import jieba
from tkinter import _flatten
import json# 读取语料库文件
def read_corpus(corpus_path='../data/dialog/'):'''corpus_path:读取文件的路径'''corpus_files = os.listdir(corpus_path)  # 列出文件路径下所有文件 corpus = []for corpus_file in corpus_files:  # 循环读取各个文件内容with open(os.path.join(corpus_path, corpus_file), 'r', encoding='utf-8') as f:corpus.extend(f.readlines())corpus = [i.replace('\n', '') for i in corpus]return corpus  # 返回语料库的列表数据print('语料库读取完成!'.center(30, '='))
corpus = read_corpus(corpus_path='../data/dialog/')
print('语料库展示: \n', corpus[:6])# 分词
def word_cut(corpus, userdict='../data/ids/mydict.txt'):'''corpus:语料userdict:自定义词典'''jieba.load_userdict(userdict)  # 加载自定义词典corpus_cut = [jieba.lcut(i) for i in corpus]  # 分词print('分词完成'.center(30, '='))return corpus_cut# 构建词典
def get_dict(corpus_cut):'''corpus_cut:分词后的语料文件'''tmp = _flatten(corpus_cut)  # 将分词结果列表拉直all_dict = list(set(tmp))  # 去除重复词,保留所有出现的唯一的词id2words = {i: j for i, j in enumerate(all_dict)}  words2id = dict(zip(id2words.values(), id2words.keys()))  # 构建词典print('词典构建完成'.center(30, '='))return all_dict, id2words, words2id# 执行分词
corpus_cut = word_cut(corpus, userdict='../data/ids/mydict.txt')
print('分词结果展示: \n', corpus_cut[:2])
# 获取字典
all_dict, id2words, words2id = get_dict(corpus_cut)
print('词典展示: \n', all_dict[:6])# 文件保存
def save(all_dict, corpus_cut, file_path='../tmp'):'''all_dict: 获取的词典file_path: 文件保存路径corpus_cut: 分词后的语料文件'''if not os.path.exists(file_path):os.makedirs(file_path)  # 如果文件夹不存在则新建source = corpus_cut[::2]  # 问target = corpus_cut[1::2]  # 答# 构建文件的对应字典file = {'all_dict.txt': all_dict, 'source.txt': source, 'target.txt': target}# 分别进行文件处理并保存for i in file.keys():if i in ['all_dict.txt']:with open(os.path.join(file_path, i), 'w', encoding='utf-8') as f:f.writelines(['\n'.join(file[i])])else:with open(os.path.join(file_path, i), 'w', encoding='utf-8') as f:f.writelines([' '.join(i) + '\n' for i in file[i]])
print('文件已保存'.center(30, '='))# 执行保存
save(all_dict, corpus_cut, file_path='../tmp')

第二步

进行Seq2Seq模型的构建,完成Seq2Seq.py

import tensorflow as tf
import typing# 编码
class Encoder(tf.keras.Model):# 设置参数def __init__(self, vocab_size: int, embedding_dim: int, enc_units: int) -> None:'''vocab_size: 词库大小embedding_dim: 词向量维度enc_units: LSTM层的神经元数量'''super(Encoder, self).__init__()self.enc_units = enc_units# 词嵌入层self.embedding = tf.keras.layers.Embedding(vocab_size, embedding_dim)# LSTM层,GRU是简单的LSTM层self.gru = tf.keras.layers.GRU(self.enc_units, return_sequences=True, return_state=True)# 定义神经网络的传输顺序def call(self, x: tf.Tensor, **kwargs) -> typing.Tuple[tf.Tensor, tf.Tensor]:'''x: 输入的文本'''x = self.embedding(x)output, state = self.gru(x)return output, state  # 输出预测结果和当前状态# 注意力机制
class BahdanauAttention(tf.keras.Model):# 设置参数def __init__(self, units: int) -> None:'''units: 神经元数据量'''super(BahdanauAttention, self).__init__()self.W1 = tf.keras.layers.Dense(units)  # 全连接层self.W2 = tf.keras.layers.Dense(units)  # 全连接层self.V = tf.keras.layers.Dense(1)  # 输出层# 设置注意力的计算方式def call(self, query: tf.Tensor, values: tf.Tensor, **kwargs) -> typing.Tuple[tf.Tensor, tf.Tensor]:'''query: 上一层输出的特征值values: 上一层输出的计算结果'''# 维度增加一维hidden_with_time_axis = tf.expand_dims(query, 1)  # 构造计算方法score = self.V(tf.nn.tanh(self.W1(values) + self.W2(hidden_with_time_axis)))# 计算权重attention_weights = tf.nn.softmax(score, axis=1)# 计算输出context_vector = attention_weights * valuescontext_vector = tf.reduce_sum(context_vector, axis=1)return context_vector, attention_weights  # 输出特征向量和权重# 解码
class Decoder(tf.keras.Model):# 设置参数def __init__(self, vocab_size: int, embedding_dim: int, dec_units: int):'''vocab_size: 词库大小embedding_dim: 词向量维度dec_units: LSTM层的神经元数量'''super(Decoder, self).__init__()self.dec_units = dec_units# 词嵌入层self.embedding = tf.keras.layers.Embedding(vocab_size, embedding_dim)# 添加LSTM层self.gru = tf.keras.layers.GRU(self.dec_units, return_sequences=True, return_state=True)# 全连接层self.fc = tf.keras.layers.Dense(vocab_size)# 添加注意力机制self.attention = BahdanauAttention(self.dec_units)# 设置神经网络传输顺序def call(self, x: tf.Tensor, hidden: tf.Tensor, enc_output: tf.Tensor) \-> typing.Tuple[tf.Tensor, tf.Tensor, tf.Tensor]:'''x: 输入的文本hidden: 上一层输出的特征值enc_output: 上一层输出的计算结果'''# 计算注意力机制层的结果context_vector, attention_weights = self.attention(hidden, enc_output)# 次嵌入层x = self.embedding(x)# 词嵌入结果和注意力机制的结果合并x = tf.concat([tf.expand_dims(context_vector, 1), x], axis=-1)# 添加注意力机制output, state = self.gru(x)# 输出结果更新维度output = tf.reshape(output, (-1, output.shape[2]))# 输出层x = self.fc(output)return x, state, attention_weights  # 输出预测结果,当前状态和权重

第三步

进行模型参数设置、加载词典和数据、数据准备、GPU设置、构建优化器和损失函数,进行模型的训练和测试,完成execute.py。


import os
import datetime
from Seq2Seq import Encoder, Decoder
import tensorflow as tf# 设置参数
data_path = '../data/ids'  # 文件路径
epoch = 100  # 迭代训练次数
batch_size = 15  # 每批次样本数
embedding_dim = 256  # 词嵌入维度
hidden_dim = 512  # 隐层神经元个数
shuffle_buffer_size = 4  # 清洗数据集时将缓冲的实例数
device = -1  # 使用的设备ID,-1即不使用GPU
checkpoint_path = '../tmp/model'  # 模型参数保存的路径
MAX_LENGTH = 50  # 句子的最大词长
CONST = {'_BOS': 0, '_EOS': 1, '_PAD': 2, '_UNK': 3}# 最大输出句子的长度# 加载词典
print(f'[{datetime.datetime.now()}] 加载词典...')
data_path = '../data/ids'
CONST = {'_BOS': 0, '_EOS': 1, '_PAD': 2, '_UNK': 3}
table = tf.lookup.StaticHashTable(  # 初始化后即不可变的通用哈希表。initializer=tf.lookup.TextFileInitializer(os.path.join(data_path, 'all_dict.txt'),tf.string,tf.lookup.TextFileIndex.WHOLE_LINE,tf.int64,tf.lookup.TextFileIndex.LINE_NUMBER),  # 要使用的表初始化程序。有关支持的键和值类型,请参见HashTable内核。default_value=CONST['_UNK'] - len(CONST)  # 表中缺少键时使用的值。
)# 加载数据
print(f'[{datetime.datetime.now()}] 加载预处理后的数据...')# 构造序列化的键值对字典
def to_tmp(text):'''text: 文本'''tokenized = tf.strings.split(tf.reshape(text, [1]), sep=' ')tmp = table.lookup(tokenized.values) + len(CONST)return tmp# 增加开始和结束标记
def add_start_end_tokens(tokens):'''tokens: 列化的键值对字典'''tmp = tf.concat([[CONST['_BOS']], tf.cast(tokens, tf.int32), [CONST['_EOS']]], axis=0)return tmp# 获取数据
def get_dataset(src_path: str, table: tf.lookup.StaticHashTable) -> tf.data.Dataset:'''src_path: 文件路径table:初始化后不可变的通用哈希表。'''dataset = tf.data.TextLineDataset(src_path)dataset = dataset.map(to_tmp)dataset = dataset.map(add_start_end_tokens)return dataset# 获取数据
src_train = get_dataset(os.path.join(data_path, 'source.txt'), table)
tgt_train = get_dataset(os.path.join(data_path, 'target.txt'), table)# 把数据和特征构造为tf数据集
train_dataset = tf.data.Dataset.zip((src_train, tgt_train))# 过滤数据实例数
def filter_instance_by_max_length(src: tf.Tensor, tgt: tf.Tensor) -> tf.Tensor:'''src: 特征tgt: 标签 '''return tf.logical_and(tf.size(src) <= MAX_LENGTH, tf.size(tgt) <= MAX_LENGTH)train_dataset = train_dataset.filter(filter_instance_by_max_length)  # 过滤数据
train_dataset = train_dataset.shuffle(shuffle_buffer_size)  # 打乱数据
train_dataset = train_dataset.padded_batch(  # 将数据长度变为一致,长度不足用_PAD补齐batch_size,padded_shapes=([MAX_LENGTH + 2], [MAX_LENGTH + 2]),padding_values=(CONST['_PAD'], CONST['_PAD']),drop_remainder=True,
)
# 提升产生下一个批次数据的效率
train_dataset = train_dataset.prefetch(tf.data.experimental.AUTOTUNE) # 模型参数保存的路径如果不存在则新建
if not os.path.exists(checkpoint_path):os.makedirs(checkpoint_path)# 获得当前主机上GPU运算设备的列表
gpus = tf.config.experimental.list_physical_devices('GPU')
if 0 <= device and 0 < len(gpus):# 限制TensorFlow仅使用指定的GPUtf.config.experimental.set_visible_devices(gpus[device], 'GPU')logical_gpus = tf.config.experimental.list_logical_devices('GPU')# 建模
print(f'[{datetime.datetime.now()}] 创建一个seq2seq模型...')
encoder = Encoder(table.size().numpy() + len(CONST), embedding_dim, hidden_dim)
decoder = Decoder(table.size().numpy() + len(CONST), embedding_dim, hidden_dim)# 设置优化器
print(f'[{datetime.datetime.now()}] 准备优化器...')
optimizer = tf.keras.optimizers.Adam()# 设置损失函数
print(f'[{datetime.datetime.now()}] 设置损失函数...')
# 损失值计算方式
loss_object = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True, reduction='none')
# 损失函数
def loss_function(loss_object, real: tf.Tensor, pred: tf.Tensor) -> tf.Tensor:'''loss_object: 损失值计算方式real: 真实值pred: 预测值'''# 计算真实值和预测值的误差loss_ = loss_object(real, pred)# 返回输出并不相等的值,并用_PAD填充mask = tf.math.logical_not(tf.math.equal(real, CONST['_PAD']))# 数据格式转换为跟损失值一致mask = tf.cast(mask, dtype=loss_.dtype)return tf.reduce_mean(loss_ * mask)  # 返回平均误差# 设置模型保存
checkpoint = tf.train.Checkpoint(optimizer=optimizer, encoder=encoder, decoder=decoder)# 训练
def train_step(src: tf.Tensor, tgt: tf.Tensor):'''src: 输入的文本tgt: 标签'''# 获取标签维度tgt_width, tgt_length = tgt.shapeloss = 0# 创建梯度带,用于反向计算导数with tf.GradientTape() as tape:# 对输入的文本编码enc_output, enc_hidden = encoder(src)# 设置解码的神经元数目与编码的神经元数目相等dec_hidden = enc_hidden# 根据标签对数据解码for t in range(tgt_length - 1):# 更新维度,新增1维dec_input = tf.expand_dims(tgt[:, t], 1)# 解码predictions, dec_hidden, dec_out = decoder(dec_input, dec_hidden, enc_output)# 计算损失值loss += loss_function(loss_object, tgt[:, t + 1], predictions)# 计算一次训练的平均损失值batch_loss = loss / tgt_length# 更新预测值variables = encoder.trainable_variables + decoder.trainable_variables# 反向求导gradients = tape.gradient(loss, variables)# 利用优化器更新权重optimizer.apply_gradients(zip(gradients, variables))return batch_loss  # 返回每次迭代训练的损失值print(f'[{datetime.datetime.now()}] 开始训练模型...')
# 根据设定的训练次数去训练模型
for ep in range(epoch):# 设置损失值total_loss = 0# 将每批次的数据取出,放入模型里for batch, (src, tgt) in enumerate(train_dataset):# 训练并计算损失值batch_loss = train_step(src, tgt)total_loss += batch_lossif ep % 100 == 0:# 每100训练次保存一次模型checkpoint_prefix = os.path.join(checkpoint_path, 'ckpt')checkpoint.save(file_prefix=checkpoint_prefix)print(f'[{datetime.datetime.now()}] 迭代次数: {ep+1} 损失值: {total_loss:.4f}')# 模型预测
def predict(sentence='你好'):# 导入训练参数checkpoint.restore(tf.train.latest_checkpoint(checkpoint_path))# 给句子添加开始和结束标记sentence = '_BOS' + sentence + '_EOS'# 读取字段with open(os.path.join(data_path, 'all_dict.txt'), 'r', encoding='utf-8') as f:all_dict = f.read().split()# 构建: 词-->id的映射字典word2id = {j: i+len(CONST) for i, j in enumerate(all_dict)}word2id.update(CONST)# 构建: id-->词的映射字典id2word = dict(zip(word2id.values(), word2id.keys()))# 分词时保留_EOS 和 _BOSfrom jieba import lcut, add_wordfor i in ['_EOS', '_BOS']:add_word(i)# 添加识别不到的词,用_UNK表示inputs = [word2id.get(i, CONST['_UNK']) for i in lcut(sentence)]# 长度填充inputs = tf.keras.preprocessing.sequence.pad_sequences([inputs], maxlen=MAX_LENGTH, padding='post', value=CONST['_PAD'])# 将数据转为tensorflow的数据类型inputs = tf.convert_to_tensor(inputs)# 空字符串,用于保留预测结果result = ''# 编码enc_out, enc_hidden = encoder(inputs)dec_hidden = enc_hiddendec_input = tf.expand_dims([word2id['_BOS']], 0)for t in range(MAX_LENGTH):# 解码predictions, dec_hidden, attention_weights = decoder(dec_input, dec_hidden, enc_out)# 预测出词语对应的idpredicted_id = tf.argmax(predictions[0]).numpy()# 通过字典的映射,用id寻找词,遇到_EOS停止输出if id2word.get(predicted_id, '_UNK') == '_EOS':break# 未预测出来的词用_UNK替代result += id2word.get(predicted_id, '_UNK')dec_input = tf.expand_dims([predicted_id], 0)return result # 返回预测结果print('预测示例: \n', predict(sentence='你好,在吗'))

第四步

通过给出的前端代码,调用flask前端进行测试,完成app.py文件,使用网页端聊天机器人聊天对话。

app.py代码

import tensorflow as tf
import os
from Seq2Seq import Encoder, Decoder
from jieba import lcut, add_word
from flask import Flask, render_template, request, jsonify# 设置参数
data_path = '../data/ids'  # 数据路径
embedding_dim = 256  # 词嵌入维度
hidden_dim = 512  # 隐层神经元个数
checkpoint_path = '../tmp/model'  # 模型参数保存的路径
MAX_LENGTH = 50  # 句子的最大词长
CONST = {'_BOS': 0, '_EOS': 1, '_PAD': 2, '_UNK': 3}# 聊天预测
def chat(sentence='你好'):# 初始化所有词语的哈希表table = tf.lookup.StaticHashTable(  # 初始化后即不可变的通用哈希表。initializer=tf.lookup.TextFileInitializer(os.path.join(data_path, 'all_dict.txt'),tf.string,tf.lookup.TextFileIndex.WHOLE_LINE,tf.int64,tf.lookup.TextFileIndex.LINE_NUMBER),  # 要使用的表初始化程序。有关支持的键和值类型,请参见HashTable内核。default_value=CONST['_UNK'] - len(CONST)  # 表中缺少键时使用的值。)# 实例化编码器和解码器encoder = Encoder(table.size().numpy() + len(CONST), embedding_dim, hidden_dim)decoder = Decoder(table.size().numpy() + len(CONST), embedding_dim, hidden_dim)optimizer = tf.keras.optimizers.Adam()  # 优化器# 模型保存路径checkpoint = tf.train.Checkpoint(optimizer=optimizer, encoder=encoder, decoder=decoder)# 导入训练参数checkpoint.restore(tf.train.latest_checkpoint(checkpoint_path))# 给句子添加开始和结束标记sentence = '_BOS' + sentence + '_EOS'# 读取字段with open(os.path.join(data_path, 'all_dict.txt'), 'r', encoding='utf-8') as f:all_dict = f.read().split()# 构建: 词-->id的映射字典word2id = {j: i + len(CONST) for i, j in enumerate(all_dict)}word2id.update(CONST)# 构建: id-->词的映射字典id2word = dict(zip(word2id.values(), word2id.keys()))# 分词时保留_EOS 和 _BOSfor i in ['_EOS', '_BOS']:add_word(i)# 添加识别不到的词,用_UNK表示inputs = [word2id.get(i, CONST['_UNK']) for i in lcut(sentence)]# 长度填充inputs = tf.keras.preprocessing.sequence.pad_sequences([inputs], maxlen=MAX_LENGTH, padding='post', value=CONST['_PAD'])# 将数据转为tensorflow的数据类型inputs = tf.convert_to_tensor(inputs)# 空字符串,用于保留预测结果result = ''# 编码enc_out, enc_hidden = encoder(inputs)dec_hidden = enc_hiddendec_input = tf.expand_dims([word2id['_BOS']], 0)for t in range(MAX_LENGTH):# 解码predictions, dec_hidden, attention_weights = decoder(dec_input, dec_hidden, enc_out)# 预测出词语对应的idpredicted_id = tf.argmax(predictions[0]).numpy()# 通过字典的映射,用id寻找词,遇到_EOS停止输出if id2word.get(predicted_id, '_UNK') == '_EOS':break# 未预测出来的词用_UNK替代result += id2word.get(predicted_id, '_UNK')dec_input = tf.expand_dims([predicted_id], 0)return result  # 返回预测结果# 实例化APP
app = Flask(__name__, static_url_path='/static')@app.route('/message', methods=['POST'])
# 定义应答函数,用于获取输入信息并返回相应的答案
def reply():# 从请求中获取参数信息req_msg = request.form['msg']# 将语句使用结巴分词进行分词# req_msg = " ".join(jieba.cut(req_msg))# 调用decode_line对生成回答信息res_msg = chat(req_msg)# 将unk值的词用微笑符号代替res_msg = res_msg.replace('_UNK', '^_^')res_msg = res_msg.strip()# 如果接受到的内容为空,则给出相应的回复if res_msg == ' ':res_msg = '我们来聊聊天吧'return jsonify({'text': res_msg})@app.route("/")
# 在网页上展示对话
def index():return render_template('index.html')# 启动APP
if (__name__ == '__main__'):app.run(host='127.0.0.1', port=8808)

页面代码

<!DOCTYPE html>
<html ><head><meta charset="UTF-8"><title>TIPDM</title><link rel="stylesheet" href="static/css/normalize.css"><link rel='stylesheet prefetch' href='https://fonts.googleapis.com/css?family=Open+Sans'><link rel='stylesheet prefetch' href='/static/js/jquery.mCustomScrollbar.min.css'><link rel="stylesheet" href="static/css/style.css"><script src="/static/js/jquery-latest.js"></script></head><body onload="init()" id="page_body"><div class="chat">
<div class="chat-title"><h1>中文聊天机器人</h1><h2>咱们唠个五毛钱的天呗</h2><figure class="avatar"><img src="static/res/7.png" /></figure>
</div>
<div class="messages"><div class="messages-content"></div>
</div>
<div class="message-box"><textarea type="text" class="message-input" placeholder="Type message..."></textarea><button type="submit" class="message-submit">Send</button>
</div></div>
<div class="bg"></div><script src='/static/js/jquery.min.js'></script>
<script src='/static/js/jquery.mCustomScrollbar.concat.min.js'></script><script src="static/js/index.js"></script></body>
</html>

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

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

相关文章

快速排序:高效分割与递归,排序领域的王者算法

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《数据结构&算法》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! &#x1f4cb; 前言 快速排序这个名词&#xff0c;快排之所以叫快排肯定是有点东西的。他在处理大规模数据集时表现及其…

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之线性布局容器Row组件

鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#xff08;ArkUI&#xff09;之线性布局容器Row组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、Row组件 沿水平方向布局容器。 子组件 可以包含子组件。 接口 Row(…

【头歌实训】Spark 完全分布式的安装和部署(新)

文章目录 第1关&#xff1a; Standalone 分布式集群搭建任务描述相关知识课程视频Spark分布式安装模式主机映射免密登录准备Spark安装包配置环境变量修改 spark-env.sh 配置文件修改 slaves 文件分发安装包启动spark验证安装 编程要求测试说明答案代码 第1关&#xff1a; Stand…

『精』CSS 小技巧之BEM规范

『精』CSS 小技巧之BEM规范 文章目录 『精』CSS 小技巧之BEM规范一、什么是BEM&#xff1f;二、BEM要怎么用&#xff1f;三、不用BEM会少个胳膊吗&#xff1f;&#x1f48a;四、Sass与BEM的结合&#x1f388;五、块与修饰符应放在一块&#x1f47f;参考资料&#x1f498;推荐博…

XIAO ESP32S3之物体检测加入视频流

一、前言 由于XIAO ESP32S3开发套件没有显示屏配件&#xff0c;因此加入http视频流功能&#xff0c;可通过浏览器请求ESP32S3上的视频流。 二、思路 1、XIAO ESP32S3启动后通过wifi连接到AP&#xff1b; 2、启动http服务器&#xff0c;注册get_mjpeg处理函数&#xff1b; 3…

PyTorch实战:基于Seq2seq模型处理机器翻译任务(模型预测)

文章目录 引言数据预处理加载字典对象en2id和zh2id文本分词 加载训练好的Seq2Seq模型模型预测完整代码结束语 引言 随着全球化的深入&#xff0c;翻译需求日益增长。传统的人工翻译方式虽然质量高&#xff0c;但效率低&#xff0c;成本高。机器翻译的出现&#xff0c;为解决这…

虚函数的讲解

文章目录 虚函数的声明与定义代码演示基类Person派生类Man派生类Woman 测试代码动态绑定静态绑定访问私有虚函数总结一下通过成员函数指针调用函数的方式 虚函数的声明与定义 虚函数存在于C的类、结构体等中&#xff0c;不能存在于全局函数中&#xff0c;只能作为成员函数存在…

IntelliJ IDEA [插件 MybatisX] mapper和xml间跳转

文章目录 1. 安装插件2. 如何使用3. 主要功能总结 MybatisX 是一款为 IntelliJ IDEA 提供支持的 MyBatis 开发插件 它通过提供丰富的功能集&#xff0c;大大简化了 MyBatis XML 文件的编写、映射关系的可视化查看以及 SQL 语句的调试等操作。本文将介绍如何安装、配置和使用 In…

知识库问答LangChain+LLM的二次开发:商用时的典型问题及其改进方案

前言 如之前的文章所述&#xff0c;我司下半年成立大模型项目团队之后&#xff0c;我虽兼管整个项目团队&#xff0c;但为让项目的推进效率更高&#xff0c;故分成了三大项目组 第一项目组由霍哥带头负责类似AIGC模特生成系统第二项目组由阿荀带头负责论文审稿GPT以及AI agen…

基于飞浆OCR的文本框box及坐标中心点检测JSON格式保存文本

OCR的文本框box及JSON数据保存 需求说明 一、借助飞浆框出OCR识别的文本框 二、以圆圈形式标出每个框的中心点位置 三、以JSON及文本格式保存OCR识别的文本 四、以文本格式保存必要的文本信息 解决方法 一、文本的坐标来自飞浆的COR识别 二、借助paddleocr的draw_ocr画出…

go语言,ent库与gorm库,插入一条null值的time数据

情景介绍 使用go语言&#xff0c;我需要保存xxxTime的字段至数据库中&#xff0c;这个字段可能为空&#xff0c;也可能是一段时间。我采取的是统一先赋值为空&#xff0c;若有需要&#xff0c;则再进行插入&#xff08;需要根据另一个字段判断是否插入&#xff09; 在我的数据…

最新国内使用GPT4教程,GPT语音对话使用,Midjourney绘画,ChatFile文档对话总结+DALL-E3文生图

一、前言 ChatGPT3.5、GPT4.0、GPT语音对话、Midjourney绘画&#xff0c;文档对话总结DALL-E3文生图&#xff0c;相信对大家应该不感到陌生吧&#xff1f;简单来说&#xff0c;GPT-4技术比之前的GPT-3.5相对来说更加智能&#xff0c;会根据用户的要求生成多种内容甚至也可以和…

HPCC:高精度拥塞控制

HPCC&#xff1a;高精度拥塞控制 文章目录 HPCC&#xff1a;高精度拥塞控制摘要1 引言1.1 背景1.2 现有CC的局限性1.3 HPCC的提出 2 研究动机2.1 大型RDMA部署2.2 RDMA目标2.3 当前RDMA CC中的权衡DCQCNTIMELY 2.4 下一代高速CC 3 技术方案3.1 INT3.2 HPCC设计3.3 HPPC的参数 4…

浅谈WPF之ToolTip工具提示

在日常应用中&#xff0c;当鼠标放置在某些控件上时&#xff0c;都会有相应的信息提示&#xff0c;从软件易用性上来说&#xff0c;这是一个非常友好的功能设计。那在WPF中&#xff0c;如何进行控件信息提示呢&#xff1f;这就是本文需要介绍的ToolTip【工具提示】内容&#xf…

数据结构入门到入土——List的介绍

目录 一&#xff0c;什么是List&#xff1f; 二&#xff0c;常见接口介绍 三&#xff0c;List的使用 一&#xff0c;什么是List&#xff1f; 在集合框架中&#xff0c;List是一个接口&#xff0c;继承自Collection。 Collection也是一个接口&#xff0c;该接口中规范了后序容…

MATLAB中./和/,.*和*,.^和^的区别

MATLAB中./和/&#xff0c;.*和*&#xff0c;.^ 和^ 的区别 MATLAB中./和/&#xff0c;.*和*&#xff0c;.^ 和^ 的区别./ 和 / 的区别.//实验实验结果 .* 和 * 的区别.**实验实验结果 .^ 和^ 的区别.^n^n实验运行结果 MATLAB中./和/&#xff0c;.和&#xff0c;.^ 和^ 的区别 …

关于SQL时间盲注(基于sleep函数)的手动测试、burpsuite爆破、sqlmap全自动化注入

SQL时间注入是一种常见的SQL注入攻击方式&#xff0c;攻击者通过在SQL语句中注入时间相关的代码&#xff0c;来获取敏感信息或者执行非法操作。其基本原理如下&#xff1a; 攻击者向Web应用程序中输入一段恶意代码&#xff0c;通过SQL语句查询数据库&#xff0c;并注入时间相关…

钉钉机器人接入定时器(钉钉API+XXL-JOB)

钉钉机器人接入定时器&#xff08;钉钉APIXXL-JOB&#xff09; 首先需要创建钉钉内部群 在群设置中找到机器人选项 选择“自定义”机器人 通过Webhook接入自定义服务 创建完成后会生成一个send URL和一个加签码 下面就是干货 代码部分了 DingDingUtil.sendMessageByText(webho…

什么是迁移学习(Transfer Learning)?定义,优势,方法

迄今为止&#xff0c;大多数人工智能&#xff08;AI&#xff09;项目都是通过监督学习技术构建的。监督学习是一种从无到有构建机器学习&#xff08;ML&#xff09;模型的方法&#xff0c;它对推动AI发展起到了关键作用。然而&#xff0c;由于需要大量的数据集和强大的计算能力…

账号租号平台PHP源码,支持单独租用或合租使用

源码简介 租号平台源码&#xff0c;采用常见的租号模式。 平台的主要功能如下&#xff1a; 支持单独租用或采用合租模式&#xff1b; 采用易支付通用接口进行支付&#xff1b; 添加邀请返利功能&#xff0c;以便站长更好地推广&#xff1b; 提供用户提现功能&#xff1b;…