使用向量数据库pinecone构建应用04:混合搜索 Hybrid Search

Building Applications with Vector Databases

下面是这门课的学习笔记:https://www.deeplearning.ai/short-courses/building-applications-vector-databases/

Learn to create six exciting applications of vector databases and implement them using Pinecone.

Build a hybrid search app that combines both text and images for improved multimodal search results.

Learn how to build an app that measures and ranks facial similarity.

文章目录

  • Building Applications with Vector Databases
  • Lesson 4 - Hybrid Search
      • Import the Needed Packages
      • Setup Pinecone
      • Load the Dataset
      • Create the Sparse Vector Using BM25
      • Create the Dense Vector Using CLIP
      • Create Embeddings Using Sparse and Dense
      • Run Your Query
      • Scaling the Hybrid Search
      • 1. More Dense
      • 2. More Sparse
      • More Dense or More Sparse?

Lesson 4 - Hybrid Search

参考:https://docs.pinecone.io/docs/hybrid-search

混合查询是一种在搜索过程中同时结合语义搜索(semantic search)和关键词搜索(keyword search)的方法。在这种查询中,搜索引擎会同时考虑文本的语义信息以及关键词的匹配程度,以提供更相关的搜索结果。

具体来说,在混合查询中,语义搜索通常使用文本的语义信息来计算相似度,例如使用文本嵌入向量(dense embeddings)来表示文本的语义信息。这种方法可以捕获文本之间的语义相似度,即使查询文本与文档之间没有直接的关键词匹配,也能够找到相关的结果。但是,对于领域外的查询(out-of-domain queries),语义搜索的结果可能不够准确或不够相关。

为了提高搜索结果的相关性,混合查询还结合了关键词搜索的结果。关键词搜索通常根据关键词的匹配程度来进行检索,例如使用词频-逆文档频率(TF-IDF)等方法。这种方法可以捕获文本中关键词的匹配程度,即使文本之间的语义相似度较低,但如果它们包含相同的关键词,则可能被认为是相关的。

通过在查询过程中同时使用语义搜索和关键词搜索,混合查询可以更全面地考虑文本的相关性,从而提供更相关的搜索结果。这种方法特别适用于处理领域外查询或文本之间语义相似度较低的情况,可以改善搜索结果的质量和相关性。

在这里插入图片描述

Import the Needed Packages

import warnings
warnings.filterwarnings('ignore')
from datasets import load_dataset
from pinecone_text.sparse import BM25Encoder
from pinecone import Pinecone, ServerlessSpec
from DLAIUtils import Utilsfrom sentence_transformers import SentenceTransformer
from tqdm.auto import tqdm
import torch
import os
utils = Utils()
PINECONE_API_KEY = utils.get_pinecone_api_key()

Setup Pinecone

device = 'cuda' if torch.cuda.is_available() else 'cpu'
print(device)utils = Utils()
INDEX_NAME = utils.create_dlai_index_name('dl-ai')pinecone = Pinecone(api_key=PINECONE_API_KEY)if INDEX_NAME in [index.name for index in pinecone.list_indexes()]:pinecone.delete_index(INDEX_NAME)
pinecone.create_index(INDEX_NAME,dimension=512,metric="dotproduct",spec=ServerlessSpec(cloud='aws', region='us-west-2')
)
index = pinecone.Index(INDEX_NAME)

其中Utils的包如下

import os
import sys
from dotenv import load_dotenv, find_dotenvclass Utils:def __init__(self):passdef create_dlai_index_name(self, index_name):openai_key = ''if self.is_colab(): # google colabfrom google.colab import userdataopenai_key = userdata.get("OPENAI_API_KEY")else: # jupyter notebookopenai_key = os.getenv("OPENAI_API_KEY")return f'{index_name}-{openai_key[-36:].lower().replace("_", "-")}'def is_colab(self):return 'google.colab' in sys.modulesdef get_openai_api_key(self):_ = load_dotenv(find_dotenv())return os.getenv("OPENAI_API_KEY")def get_pinecone_api_key(self):_ = load_dotenv(find_dotenv())return os.getenv("PINECONE_API_KEY")

Load the Dataset

从huggingface上下载数据集

fashion = load_dataset("ashraq/fashion-product-images-small",split="train"
)
fashion

在这段代码中,split 参数用于指定加载数据集的哪个部分。在机器学习中,数据集通常被分为几个不同的部分,比如训练集(train)、验证集(validation)和测试集(test)。这些部分用于不同的目的,例如训练模型、调整超参数以及评估模型性能。

在这个特定的例子中,split="train" 表示加载数据集中的训练集部分。这意味着加载的数据集将包含用于训练模型的数据样本。通常,训练集用于拟合模型的参数,使其能够从数据中学习并进行预测。

Output

Dataset({features: ['id', 'gender', 'masterCategory', 'subCategory', 'articleType', 'baseColour', 'season', 'year', 'usage', 'productDisplayName', 'image'],num_rows: 44072
})

输出image图片测试一下

images = fashion['image']
metadata = fashion.remove_columns('image') # 去掉image列
images[900]

Output

在这里插入图片描述

展示metadata的前五行:

metadata = metadata.to_pandas()
metadata.head() # 用于返回数据集的前几行,默认情况下是前五行

Output

在这里插入图片描述

Create the Sparse Vector Using BM25

在这里插入图片描述

chatGPT对BM25的介绍

BM25(Best Matching 25)是一种用于信息检索的概率模型,是根据概率论原理和统计学原理设计的。它是 BM 系列算法中的一种,通常用于在大规模文本数据集中执行全文搜索和相关性排序。BM25 最初是由Robertson 等人于 1994 年提出的,并且被广泛应用于搜索引擎和文档检索系统中。

BM25 的主要思想是衡量查询词与文档之间的相关性,并根据相关性对文档进行排序。它考虑了查询词的频率、文档的长度以及文档集合中包含查询词的文档数量等因素,从而更好地衡量文档的相关性。与传统的向量空间模型(如 TF-IDF)相比,BM25 能够更好地处理长文档、稀疏查询以及文档长度不均匀的情况。

BM25 模型的计算公式包括多个参数,如查询词频率、文档长度、文档集合的平均长度等。这些参数可以根据具体的应用场景和数据集进行调整,以获得更好的搜索性能。

总的来说,BM25 是一种用于信息检索的强大模型,广泛应用于各种搜索引擎和文档检索系统中,能够有效地提高搜索结果的质量和相关性。

bm25 = BM25Encoder()
bm25.fit(metadata['productDisplayName'])
metadata['productDisplayName'][0]

Output

'Turtle Check Men Navy Blue Shirt'
bm25.encode_queries(metadata['productDisplayName'][0])
bm25.encode_documents(metadata['productDisplayName'][0])

在这段代码中,bm25.encode_queries(metadata['productDisplayName'][0])bm25.encode_documents(metadata['productDisplayName'][0]) 是使用 BM25 编码器对查询和文档进行编码的操作。

具体来说:

  • bm25.encode_queries(metadata['productDisplayName'][0]):这个方法用于对查询进行编码。在信息检索任务中,查询通常是用户输入的搜索词或短语。这个方法将输入的查询文本编码成 BM25 编码器所能理解的形式,以便后续可以与已编码的文档进行比较,找到与查询最相关的文档。

  • bm25.encode_documents(metadata['productDisplayName'][0]):这个方法用于对文档进行编码。在信息检索任务中,文档通常是待检索的数据项,例如产品描述、文章内容等。这个方法将输入的文档文本编码成 BM25 编码器所能理解的形式,以便后续可以与已编码的查询进行比较,找到与查询最相关的文档。

总的来说,这两个方法都是将文本数据使用 BM25 编码器进行编码的操作,以便在信息检索任务中进行相关性匹配和排序。encode_queries() 方法用于对查询进行编码,而 encode_documents() 方法用于对文档进行编码。

Output

{'indices': [23789636,1830646559,632192512,931643408,3905155331,3828986392],'values': [0.4449638258432887,0.4449638258432887,0.4449638258432887,0.4449638258432887,0.4449638258432887,0.4449638258432887]}

Create the Dense Vector Using CLIP

在这里插入图片描述

model = SentenceTransformer('sentence-transformers/clip-ViT-B-32', device=device)
model
dense_vec = model.encode([metadata['productDisplayName'][0]])
dense_vec.shape

Output

(1, 512)

len(fashion)

Output

44072

Create Embeddings Using Sparse and Dense

在这里插入图片描述

(Note: fashion_data_num = 1000): In this lab, we've initially set fashion_data_num to 1000 for speedier results, allowing you to observe the outcomes faster. Once you've done an initial run, consider increasing this value. You'll likely notice better and more relevant results.

batch_size = 100
fashion_data_num = 1000for i in tqdm(range(0, min(fashion_data_num,len(fashion)), batch_size)):# find end of batchi_end = min(i+batch_size, len(fashion))# extract metadata batchmeta_batch = metadata.iloc[i:i_end]meta_dict = meta_batch.to_dict(orient="records")# concatinate all metadata field except for id and year to form a single string# 这句话的理解请看下面的解释meta_batch = [" ".join(x) for x in meta_batch.loc[:, ~meta_batch.columns.isin(['id', 'year'])].values.tolist()]# extract image batchimg_batch = images[i:i_end]# create sparse BM25 vectorssparse_embeds = bm25.encode_documents([text for text in meta_batch])# create dense vectorsdense_embeds = model.encode(img_batch).tolist()# create unique IDsids = [str(x) for x in range(i, i_end)]upserts = []# loop through the data and create dictionaries for uploading documents to pinecone indexfor _id, sparse, dense, meta in zip(ids, sparse_embeds, dense_embeds, meta_dict):upserts.append({'id': _id,'sparse_values': sparse,'values': dense,'metadata': meta})# upload the documents to the new hybrid indexindex.upsert(upserts)# show index description after uploading the documents
index.describe_index_stats()

上述代码的解释

meta_batch.loc[:, ~meta_batch.columns.isin(['id', 'year'])]:这部分代码首先使用 .loc[] 方法从 DataFrame 中选择所有行和除了’id’和’year’列以外的其他列。~meta_batch.columns.isin(['id', 'year']) 用于创建一个布尔值的 Series,表示除了’id’和’year’列以外的其他列。然后,meta_batch.loc[:, ~meta_batch.columns.isin(['id', 'year'])] 使用这个布尔值的 Series 进行列的选择。

在这个上下文中,~ 是按位取反运算符。在 Pandas 中,它用于对布尔值 Series 或条件表达式的结果进行逐元素取反。

具体来说,~meta_batch.columns.isin(['id', 'year']) 创建了一个布尔值 Series,其中包含了与 DataFrame 列名是否包含在 [‘id’, ‘year’] 列表中相对应的布尔值。然后,~ 运算符对这个布尔值 Series 进行逐元素取反,即将 True 变为 False,将 False 变为 True。这样,最终得到的布尔值 Series 中,对于原始 DataFrame 中的列名中包含在 [‘id’, ‘year’] 中的列,其值为 False,否则为 True。这就实现了对除了’id’和’year’列以外的其他列进行选择。

Output

{'dimension': 512,'index_fullness': 0.0,'namespaces': {'': {'vector_count': 900}},'total_vector_count': 900}

Run Your Query

query data参考:https://docs.pinecone.io/docs/query-data

参考:

query = "dark blue french connection jeans for men"sparse = bm25.encode_queries(query)
dense = model.encode(query).tolist() result = index.query(top_k=14,vector=dense,sparse_vector=sparse,include_metadata=True
)imgs = [images[int(r["id"])] for r in result["matches"]]
imgs

在这段代码中:

  • vector 参数:表示稠密向量(dense vector),通常用于传递由模型生成的文本嵌入向量(dense embeddings)。在这里,dense 变量包含了模型对查询文本 query 生成的稠密嵌入向量。

  • sparse_vector 参数:表示稀疏向量(sparse vector),通常用于传递由 BM25 编码器生成的查询编码(query encoding)。在这里,sparse 变量包含了 BM25 编码器对查询文本 query 生成的稀疏编码。这种编码形式通常用于在基于 BM25 的索引中执行检索操作。

综合起来,这两个参数分别用于传递模型生成的稠密嵌入向量和 BM25 编码器生成的稀疏编码,以便于在索引中执行检索操作,并返回与查询文本相关的最相关的文档。

Output

[<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=60x80>,<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=60x80>,<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=60x80>,<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=60x80>,<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=60x80>,<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=60x80>,<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=60x80>,<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=60x80>,<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=60x80>,<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=60x80>]

display结果

from IPython.core.display import HTML
from io import BytesIO
from base64 import b64encode# function to display product images
def display_result(image_batch):figures = []for img in image_batch:b = BytesIO()img.save(b, format='png')figures.append(f'''<figure style="margin: 5px !important;"><img src="data:image/png;base64,{b64encode(b.getvalue()).decode('utf-8')}" style="width: 90px; height: 120px" ></figure>''')return HTML(data=f'''<div style="display: flex; flex-flow: row wrap; text-align: center;">{''.join(figures)}</div>''')
display_result(imgs)

Output

在这里插入图片描述

Scaling the Hybrid Search

def hybrid_scale(dense, sparse, alpha: float):"""Hybrid vector scaling using a convex combinationalpha * dense + (1 - alpha) * sparseArgs:dense: Array of floats representingsparse: a dict of `indices` and `values`alpha: float between 0 and 1 where 0 == sparse onlyand 1 == dense only"""if alpha < 0 or alpha > 1:raise ValueError("Alpha must be between 0 and 1")# scale sparse and dense vectors to create hybrid search vecshsparse = {'indices': sparse['indices'],'values':  [v * (1 - alpha) for v in sparse['values']]}hdense = [v * alpha for v in dense]return hdense, hsparse

1. More Dense

question = "dark blue french connection jeans for men"
#Closer to 0==more sparse, closer to 1==more dense
hdense, hsparse = hybrid_scale(dense, sparse, alpha=1)
result = index.query(top_k=6,vector=hdense,sparse_vector=hsparse,include_metadata=True
)
imgs = [images[int(r["id"])] for r in result["matches"]]
display_result(imgs)

Output

在这里插入图片描述

for x in result["matches"]:print(x["metadata"]['productDisplayName'])

Output

Peter England Men Party Blue Jeans
John Miller Men Reglur Black Trousers
Lee Men Blue Chicago Fit Jeans
Locomotive Men Washed Blue Jeans
Lee Men Blue Chicago Fit Jeans
Gini and Jony Boys Solid Black Jeans
Peter England Men Black Jeans
Tokyo Talkies Women Navy Slim Fit Jeans
Jealous 21 Women's Aaren Black Jegging
John Miller Men Solid Type Black Trousers

2. More Sparse

question = "dark blue french connection jeans for men"
#Closer to 0==more sparse, closer to 1==more dense
hdense, hsparse = hybrid_scale(dense, sparse, alpha=0)
result = index.query(top_k=6,vector=hdense,sparse_vector=hsparse,include_metadata=True
)
imgs = [images[int(r["id"])] for r in result["matches"]]
display_result(imgs)

Output

在这里插入图片描述

for x in result["matches"]:print(x["metadata"]['productDisplayName'])

Output

French Connection Men Maroon T-shirt
Lee Men Blue Chicago Fit Jeans
Peter England Men Party Blue Jeans
Lee Men Blue Chicago Fit Jeans
Denizen Women Blue Jeans
French Connection Women Beige Handbag
Jealous 21 Women Washed Blue Jeans
Peter England Men Black Jeans
Peter England Men Party Black Jeans
Gini and Jony Boys Solid Black Jeans

More Dense or More Sparse?

question = "dark blue french connection jeans for men"
#Closer to 0==more sparse, closer to 1==more dense
hdense, hsparse = hybrid_scale(dense, sparse, alpha=0.5)
result = index.query(top_k=6,vector=hdense,sparse_vector=hsparse,include_metadata=True
)
imgs = [images[int(r["id"])] for r in result["matches"]]
display_result(imgs)

Output

在这里插入图片描述

for x in result["matches"]:print(x["metadata"]['productDisplayName'])

Output

Peter England Men Party Blue Jeans
John Miller Men Reglur Black Trousers
Lee Men Blue Chicago Fit Jeans
Locomotive Men Washed Blue Jeans
Lee Men Blue Chicago Fit Jeans
Gini and Jony Boys Solid Black Jeans
Peter England Men Black Jeans
Tokyo Talkies Women Navy Slim Fit Jeans
Jealous 21 Women's Aaren Black Jegging
John Miller Men Solid Type Black Trousers

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

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

相关文章

ARM处理器有哪些工作模式和寄存器?各寄存器作用是什么?ARM异常中断处理流程?

《嵌入式工程师自我修养/C语言》系列——ARM处理器有哪些工作模式和寄存器&#xff1f;各寄存器作用是什么&#xff1f; 一、ARM处理器的工作模式及寄存器1.1 ARM处理器的工作模式1.2 ARM处理器中的寄存器 二、ARM 异常中断处理2.1 什么是异常&#xff1f;异常向量表是什么&…

用关联规则学习之购物篮分析

&#x1f349;CSDN小墨&晓末:https://blog.csdn.net/jd1813346972 个人介绍: 研一&#xff5c;统计学&#xff5c;干货分享          擅长Python、Matlab、R等主流编程软件          累计十余项国家级比赛奖项&#xff0c;参与研究经费10w、40w级横向 文…

【Python_Zebra斑马打印机编程学习笔记(二)】基于BarTender将btw文件转换为zpl文件

基于BarTender将btw文件转换为zpl文件 基于BarTender将btw文件转换为zpl文件前言一、BarTender1、BarTender 介绍2、BarTender 安装 二、导出 ZPL 文件1、导出 ZPL 文件步骤2、Zebra 打印机驱动安装 基于BarTender将btw文件转换为zpl文件 前言 本文介绍如何基于 BarTender 软…

深入理解JS的执行上下文、词法作用域和闭包(中)

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

.NET指定图片地址下载并转换Base64字符串

需求描述 需要调用第三方图片上传接口上传图片&#xff0c;对方图片格式只能接收Base64字符串。所以我们需要将系统服务器的图片通过Url下载下来&#xff0c;然后转换成Base64字符串。接下来我们将使用HttpClient类库下载图片并将其转换为Base64格式的字符串。 代码示例 /// &…

新手入门C语言之移位操作符和位操作符

在C语言中&#xff0c;移位操作符和位操作符是专门针对二进制的数字进行&#xff0c;因此&#xff0c;在描述移位操作符和位操作符之前&#xff0c;我们先来了解十进制&#xff0c;二进制&#xff0c;八进制&#xff0c;十六进制等的含义以及相互之间的转化。 一.进制以及相互…

《隐私计算简易速速上手小册》第7章:隐私计算与云计算/边缘计算(2024 最新版)

文章目录 7.1 云计算中的隐私保护7.1.1 基础知识7.1.2 主要案例:使用 Python 实现云数据的安全上传和访问7.1.3 拓展案例 1:实现基于角色的访问控制7.1.4 拓展案例 2:使用 Python 保护 API 安全7.2 边缘计算的隐私问题7.2.1 基础知识7.2.2 主要案例:使用 Python 实现边缘设…

Flink join详解(含两类API及coGroup、connect详解)

Flink SQL支持对动态表进行复杂而灵活的连接操作。 为了处理不同的场景&#xff0c;需要多种查询语义&#xff0c;因此有几种不同类型的 Join。 默认情况下&#xff0c;joins 的顺序是没有优化的。表的 join 顺序是在 FROM 从句指定的。可以通过把更新频率最低的表放在第一个、…

使用yolo-seg模型实现自定义自动动态抠图

yolov8导航 如果大家想要了解关于yolov8的其他任务和相关内容可以点击这个链接&#xff0c;我这边整理了许多其他任务的说明博文&#xff0c;后续也会持续更新&#xff0c;包括yolov8模型优化、sam等等的相关内容。 YOLOv8&#xff08;附带各种任务详细说明链接&#xff09; …

DFT系列文章之 《BIST技术》

BIST&#xff1a;BIST是在设计时在电路中植入相关功能电路用于提供自我测试功能的技术&#xff0c;以此降低器件测试对自动测试设备&#xff08;ATE&#xff09;的依赖程度。 ATE&#xff1a;ATE是Automatic Test Equipment的缩写&#xff0c;根据客户的测试要求、图纸及参考方…

Element table 实现表格行、列拖拽功能

安装包 npm install sortablejs --save <template><div class"draggable" style"padding: 20px"><el-table row-key"id" :data"tableData" style"width: 100%" border><el-table-columnv-for"(it…

VS中使用xcopy生成后命令报9009错误

错误现象: download下来的代码&#xff0c;在另一台电脑能使用生成后命令xcopy&#xff0c;换一台电脑后该命令不能使用&#xff0c;报如下错误&#xff1a; 2.错误原因&#xff1a; 这是因为xcopy /Y 为Windows程序命令&#xff0c;xcopy其实是Windows下的一个xcopy.exe,如果…

nginx 模块 常见内置变量 location

一、nginx 模块 ngx_http_core_module 核心模块 ngx_http_access_module 访问控制模块 deny allow ngx_http_auth_basic_module 身份验证 小红小名&#xff08;虚拟用户&#xff09; ftp也有虚拟用户 ngx_http_gzip_module 压缩模块 ngx_http_gzip_static_modul…

Java 学习和实践笔记(19):this的使用方法

this用来指向当前对象的地址。 this的用法&#xff1a; 1&#xff09;在普通方法中&#xff0c;this总是指向调用该方法的对象。在普通方法中&#xff0c;它是作为一种隐式参数一直就存在着&#xff08;这句话的意思&#xff0c;就是其实在普通方法中&#xff0c;编译器一直就…

【前端素材】推荐优质后台管理系统Be admin平台模板(附源码)

一、需求分析 后台管理系统&#xff08;或称作管理后台、管理系统、后台管理平台&#xff09;是一种专门用于管理网站、应用程序或系统后台运营的软件系统。它通常由一系列功能模块组成&#xff0c;为管理员提供了管理、监控和控制网站或应用程序的各个方面的工具和界面。以下…

从零开始学逆向:理解ret2syscall

1.题目信息 链接&#xff1a;https://pan.baidu.com/s/19ymHlZZmVGsJHFmmlwww0w 提取码&#xff1a;r4el 首先checksec 看一下保护机制 2.原理 ret2syscall 即控制程序执行系统调用来获取 shell 什么是系统调用&#xff1f; 操作系统提供给用户的编程接口是提供访问操作系统…

电路设计(28)——交通灯控制器的multisim仿真

1.功能设定 南北、东西两道的红灯时间、绿灯时间均为24S&#xff0c;数码管显示倒计时。在绿灯的最后5S内&#xff0c;黄灯闪烁。有夜间模式&#xff1a;按下按键进入夜间模式。在夜间模式下&#xff0c;数码管显示计数最大值&#xff0c;两个方向的黄灯不停闪烁。 2.电路设计 …

【k8s资源调度-StatefulSet】

1、部署对象StatefulSet资源&#xff08;无状态应用&#xff09; StatefulSet针对的是有状态应用&#xff0c;有状态应用会对我们的当前pod的网络、文件系统等有关联。 2、配置文件如下 StatefulSet资源的配置文件粗略如下&#xff0c;如下的配置信息包含了数据卷&#xff0c;…

uniapp_微信小程序自定义顶部导航栏和右侧胶囊对齐(不对齐来打我)

一、想要的效果 思路首先开启自定义导航栏&#xff0c;取消自带的导航栏&#xff0c;然后计算胶囊的高度和标题对齐 二、成品代码 1、首先再你需要居中的代码添加以下style <view class"header":style"{paddingTop:navBarTop px,height:navBarHeight px,…

GitLab代码库提交量统计工具

1.说明 统计公司所有项目的提交情况&#xff0c;可指定分支和时间段&#xff0c;返回每个人的提交新增数、删除数和总数。 2.API 文档地址&#xff1a;http://公司gitlab域名/help/api/README.md 项目列表查询 返回示例&#xff1a; [{"id": 1, //项目ID"http…