Qanything 2 0源码解析系列4 图片解析逻辑

Qanything 2.0源码解析系列4: 图片解析逻辑

文章转载自:https://www.feifeixu.top/article/8bb8401b-9689-453f-ab86-e3ecae414e12

qanything_kernel/core/retriever/general_document.py文件中LocalFileForInsert 类的split_file_to_docs 方法的这一段。

        elif self.file_path.lower().endswith(".jpg") or self.file_path.lower().endswith(".png") or self.file_path.lower().endswith(".jpeg"):txt_file_path = self.image_ocr_txt(filepath=self.file_path)loader = TextLoader(txt_file_path, autodetect_encoding=True)docs = loader.load()

核心是两块:

  1. 将图片内容进行ocr识别
  2. 识别的文字内容组装成Document 类型的doc

📝 ocr识别

核心方法

引用的话语

def image_ocr_txt(filepath, dir_path="tmp_files"):'''filepath = '/tmp/pycharm_project_419/QANY_DB/content/feifeixu__1234/KBb17bd2d168604a84a59abe24e855d574_240625/9770b07842994e628d92558777f9ac98/9.png'full_dir_path = '/tmp/pycharm_project_419/QANY_DB/content/feifeixu__1234/KBb17bd2d168604a84a59abe24e855d574_240625/9770b07842994e628d92558777f9ac98/tmp_files''''full_dir_path = os.path.join(os.path.dirname(filepath), dir_path)# 如果full_dir_path文件夹不存在,则创建if not os.path.exists(full_dir_path):os.makedirs(full_dir_path)# 拿到filename 是 9.pngfilename = os.path.split(filepath)[-1]# 读取图片img_np = open(filepath, 'rb').read()# base64编解码img_data = {"img64": base64.b64encode(img_np).decode("utf-8"),}# 调用ocr服务,拿到ocr识别的结果result = get_ocr_result_sync(img_data)# 去除空行,所有行内容存到list中ocr_result = [line for line in result if line]# 行与行之间用\n拼成一个大strocr_result = '\n'.join(ocr_result)insert_logger.info(f'ocr_res[:100]: {ocr_result[:100]}')# 写入结果到文本文件txt_file_path = os.path.join(full_dir_path, "%s.txt" % (filename))with open(txt_file_path, 'w', encoding='utf-8') as fout:fout.write(ocr_result)# 返回文件路径return txt_file_path

get_ocr_result_sync方法

def get_ocr_result_sync(image_data):try:response = requests.post(f"http://{LOCAL_OCR_SERVICE_URL}/ocr", data=image_data, timeout=120)response.raise_for_status()  # 如果请求返回了错误状态码,将会抛出异常ocr_res = response.textocr_res = json.loads(ocr_res)return ocr_res['result']except Exception as e:insert_logger.warning(f"ocr error: {traceback.format_exc()}")return None

ocr服务启动

执行上述方法之前,应先将ocr服务启动起来,不然直接异常报错了。

在项目scripts/entrypoint.sh文件中看到ocr的启动命令是:

nohup python3 -u qanything_kernel/dependent_server/ocr_server/ocr_server.py > /workspace/QAnything/logs/debug_logs/ocr_server.log 2>&1 &

模型文件下载:https://github.com/netease-youdao/QAnything/tree/v1.4.1/qanything_kernel/dependent_server/ocr_server/ocr_models

存放路径:qanything_kernel/dependent_server/ocr_server/ocr_models下

对于这样一张图片:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

ocr识别的结果为:

押金,自如与出租人另行结算。承租人同意自如返还押金时有权抵扣承租人应付自如的款
项。若上述款项尚在自如的监管或托管账户的,自如应在15日内退还。
(四)承租人续租、换租或转租房屋的,租金以届时自如和出租人商定的报价为准。
(五)房租发票由房屋出租人开具,自如予以相应协助。如果在租赁期内承租人索要了相关
发票,办理服务费及房租退费时,承租人须按照税法规定配合自如进行发票红冲手
续,包括但不限于承租人自双方办理完毕解约之日(含当日)起1个月内,依据税法要
求将其此前取得的增值税普通发票或增值税专用发票原件(如有)交还自如或配合自
如进行红字发票处理,否则自如有权代出租人拒绝向承租人退还服务费或房租且不承
担任何违约责任。
(六)生活费用的品类及价格详见物业交割补充协议:
1.租赁期限内,承租人需配合自如定期上门查表(包括但不限于协助自如拍摄示数照
片)。
2.后付费的生活费用由自如定期生成相应账单,承租人应及时支付。预付费的生活费用,
承租人应根据实际使用情况自行合理购买,并及时与房屋其他实际使用人结清,否则造
成的损失和后果由承租人自行承担。
3.非出租人及自如原因导致无法上门查表或生活费用收费单位未定时生成相应账单的,自
如有权代出租人通过预估的形式生成生活费用账单,后期按照承租人的实际使用情况多
退少补。
4.承租人应承担的生活费用计算方式为:按使用示数或使用时长计算的生活费用总额除以
房屋实际居住户数。
5.本合同约定的生活费用单价仅供参考,具体以实际收费标准为准。
第四条房屋维护与维修
(一)自如受出租人委托,如房屋及原有物品、设备设施在租赁期限内因老化产生的维护、维
修事宜由自如承担;如发生人为损坏的,应按照附件三及物业交割补充协议的标准进行赔偿
或维修;若附件三及物业交割补充协议未有明确约定的,依据“谁导致谁承担”的原则处理。
(二)租赁期限内,承租人对房屋具有一般性保管义务,如有房屋设施设备损毁或发生故障情
况,应及时通知自如,否则由此造成的财产损失、人身损害等由承租人承担。
第五条转租及换租
(一)转租:合同起租日后,承租人向自如提出转租申请的,经自如及出租人同意后的45日
内,可将所租赁的房屋重新上架并租给第三方。转租期间改为解约申请的,以提出转租申请
日为解约申请日。
(二)换租:本合同生效后,经协商一致,承租人可换租至自如管理的其他房屋(换租不支
持由整租换成非整租产品)。承租人应先与该房屋的出租人就拟换租的房屋签订租赁期限
不少于90天的租赁合同,该合同起租后60日内(不含60日,含起租日当日)应办理本
合同的退租手续,否则自如有权拒绝办理换租。本合同租金计算至退租完成日。
(三)三天不满意无理由换租:
1.对新签合同(不含转租、换租),承租人享有一次在本合同生效日起3日内(含生
3/20

组装doc

def lazy_load(self) -> Iterator[Document]:"""Load from file path."""text = ""try:# 读取ocr返回的文件的文字内容with open(self.file_path, encoding=self.encoding) as f:text = f.read()except UnicodeDecodeError as e:xxxmetadata = {"source": str(self.file_path)}# 生成一个doc,一张图片的整个ocr结果作为一个doc进行返回yield Document(page_content=text, metadata=metadata)

为每个doc注入元数据(不重要)

主要是为doc注入file_id,kb_id之类的元数据,还有个操作是合并短的doc,对pdf、doc这类文件起作用,对图片类文件不起作用,因为一个图片只有一个doc。所以下面这个方法可以忽略。

def inject_metadata(self, docs: List[Document]):# 这里给每个docs片段的metadata里注入file_idnew_docs = []for doc in docs:page_content = re.sub(r'\t+', ' ', doc.page_content)  # 将制表符替换为单个空格page_content = re.sub(r'\n{3,}', '\n\n', page_content)  # 将三个或更多换行符替换为两个page_content = page_content.strip()  # 去除首尾空白字符new_doc = Document(page_content=page_content)new_doc.metadata["user_id"] = self.user_idnew_doc.metadata["kb_id"] = self.kb_idnew_doc.metadata["file_id"] = self.file_idnew_doc.metadata["file_name"] = self.file_namenew_doc.metadata["nos_key"] = self.file_locationnew_doc.metadata["file_url"] = self.file_urlnew_doc.metadata["title_lst"] = doc.metadata.get("title_lst", [])new_doc.metadata["has_table"] = doc.metadata.get("has_table", False)# 从文本中提取图片数量:![figure](x-figure-x.jpg)new_doc.metadata["images"] = re.findall(r'!\[figure]\(\d+-figure-\d+.jpg.*?\)', page_content)new_doc.metadata["page_id"] = doc.metadata.get("page_id", 0)kb_name = self.mysql_client.get_knowledge_base_name([self.kb_id])[0][2]metadata_infos = {"知识库名": kb_name, '文件名': self.file_name}new_doc.metadata['headers'] = metadata_infosif 'faq_dict' not in doc.metadata:new_doc.metadata['faq_dict'] = {}else:new_doc.metadata['faq_dict'] = doc.metadata['faq_dict']new_docs.append(new_doc)if new_docs:insert_logger.info('langchain analysis content head: %s', new_docs[0].page_content[:100])else:insert_logger.info('langchain analysis docs is empty!')# merge short docsinsert_logger.info(f"before merge doc lens: {len(new_docs)}")child_chunk_size = min(DEFAULT_CHILD_CHUNK_SIZE, int(self.chunk_size / 2))merged_docs = []for doc_idx, doc in enumerate(new_docs):if not merged_docs:merged_docs.append(doc)else:last_doc = merged_docs[-1]# insert_logger.info(f"doc_idx: {doc_idx}, doc_content: {doc.page_content[:100]}")# insert_logger.info(f"last_doc_len: {num_tokens_embed(last_doc.page_content)}, doc_len: {num_tokens_embed(doc.page_content)}")if num_tokens_embed(last_doc.page_content) + num_tokens_embed(doc.page_content) <= child_chunk_size or \num_tokens_embed(doc.page_content) < child_chunk_size / 4:tmp_content_slices = doc.page_content.split('\n')# print(last_doc.metadata['title_lst'], tmp_content)tmp_content_slices_clear = [line for line in tmp_content_slices if clear_string(line) not in[clear_string(t) for t in last_doc.metadata['title_lst']]]tmp_content = '\n'.join(tmp_content_slices_clear)# for title in last_doc.metadata['title_lst']:#     tmp_content = tmp_content.replace(title, '')last_doc.page_content += '\n\n' + tmp_content# for title in last_doc.metadata['title_lst']:#     last_doc.page_content = self.remove_substring_after_first(last_doc.page_content, '![figure]')last_doc.metadata['title_lst'] += doc.metadata.get('title_lst', [])last_doc.metadata['has_table'] = last_doc.metadata.get('has_table', False) or doc.metadata.get('has_table', False)last_doc.metadata['images'] += doc.metadata.get('images', [])else:merged_docs.append(doc)insert_logger.info(f"after merge doc lens: {len(merged_docs)}")self.docs = merged_docs

存milvus向量数据库

  1. 先用num_tokens_embed这个方法判断一下这个doc的tokenizer后长度有没有超过800,不超过不做处理,超过的话需要对doc切分(split)。
embedding_tokenizer = AutoTokenizer.from_pretrained(LOCAL_EMBED_PATH, local_files_only=True)def num_tokens_embed(text: str) -> int:"""Return the number of tokens in a string."""return len(embedding_tokenizer.encode(text, add_special_tokens=True))
  1. split用的是这个

DEFAULT_PARENT_CHUNK_SIZE=800, chunk_overlap=0

init_parent_splitter = RecursiveCharacterTextSplitter(separators=["\n\n", "\n", "。", "!", "!", "?", "?", ";", ";", "……", "…", "、", ",", ",", " ", ""],chunk_size=DEFAULT_PARENT_CHUNK_SIZE,chunk_overlap=0,length_function=num_tokens_embed)
押金,自如与出租人另行结算。承租人同意自如返还押金时有权抵扣承租人应付自如的款
项。若上述款项尚在自如的监管或托管账户的,自如应在15日内退还。
(四)承租人续租、换租或转租房屋的,租金以届时自如和出租人商定的报价为准。
(五)房租发票由房屋出租人开具,自如予以相应协助。如果在租赁期内承租人索要了相关
发票,办理服务费及房租退费时,承租人须按照税法规定配合自如进行发票红冲手
续,包括但不限于承租人自双方办理完毕解约之日(含当日)起1个月内,依据税法要
求将其此前取得的增值税普通发票或增值税专用发票原件(如有)交还自如或配合自
如进行红字发票处理,否则自如有权代出租人拒绝向承租人退还服务费或房租且不承
担任何违约责任。
(六)生活费用的品类及价格详见物业交割补充协议:
1.租赁期限内,承租人需配合自如定期上门查表(包括但不限于协助自如拍摄示数照
片)。
2.后付费的生活费用由自如定期生成相应账单,承租人应及时支付。预付费的生活费用,
承租人应根据实际使用情况自行合理购买,并及时与房屋其他实际使用人结清,否则造
成的损失和后果由承租人自行承担。
3.非出租人及自如原因导致无法上门查表或生活费用收费单位未定时生成相应账单的,自
如有权代出租人通过预估的形式生成生活费用账单,后期按照承租人的实际使用情况多
退少补。
4.承租人应承担的生活费用计算方式为:按使用示数或使用时长计算的生活费用总额除以
房屋实际居住户数。
5.本合同约定的生活费用单价仅供参考,具体以实际收费标准为准。
第四条房屋维护与维修
(一)自如受出租人委托,如房屋及原有物品、设备设施在租赁期限内因老化产生的维护、维
修事宜由自如承担;如发生人为损坏的,应按照附件三及物业交割补充协议的标准进行赔偿
或维修;若附件三及物业交割补充协议未有明确约定的,依据“谁导致谁承担”的原则处理。
(二)租赁期限内,承租人对房屋具有一般性保管义务,如有房屋设施设备损毁或发生故障情
况,应及时通知自如,否则由此造成的财产损失、人身损害等由承租人承担。
第五条转租及换租
(一)转租:合同起租日后,承租人向自如提出转租申请的,经自如及出租人同意后的45日
内,可将所租赁的房屋重新上架并租给第三方。转租期间改为解约申请的,以提出转租申请
日为解约申请日。
(二)换租:本合同生效后,经协商一致,承租人可换租至自如管理的其他房屋(换租不支
持由整租换成非整租产品)。承租人应先与该房屋的出租人就拟换租的房屋签订租赁期限
不少于90天的租赁合同,该合同起租后60日内(不含60日,含起租日当日)应办理本
合同的退租手续,否则自如有权拒绝办理换租。本合同租金计算至退租完成日。
(三)三天不满意无理由换租:
1.对新签合同(不含转租、换租),承租人享有一次在本合同生效日起3日内(含生
3/20
  1. 对于这样一个text,先从separators=[“\n\n”, “\n”, “。”, “!”, “!”, “?”, “?”, “;”, “;”, “……”, “…”, “、”, “,”, “,”, " ", “”]中从左都有判断哪个符号可以对这个text进行拆分,\n\n不行,\n可以。

  2. 按照\n对text进行拆分,然后每个句子和前面的\n进行合并,处理完就变成了一个列表。

    ['押金,自如与出租人另行结算。承租人同意自如返还押金时有权抵扣承租人应付自如的款', '\n项。若上述款项尚在自如的监管或托管账户的,自如应在15日内退还。', '\n(四)承租人续租、换租或转租房屋的,租金以届时自如和出租人商定的报价为准。', '\n(五)房租发票由房屋出租人开具,自如予以相应协助。如果在租赁期内承租人索要了相关', '\n发票,办理服务费及房租退费时,承租人须按照税法规定配合自如进行发票红冲手', '\n续,包括但不限于承租人自双方办理完毕解约之日(含当日)起1个月内,依据税法要', '\n求将其此前取得的增值税普通发票或增值税专用发票原件(如有)交还自如或配合自', '\n如进行红字发票处理,否则自如有权代出租人拒绝向承租人退还服务费或房租且不承', '\n担任何违约责任。', '\n(六)生活费用的品类及价格详见物业交割补充协议:', '\n1.租赁期限内,承租人需配合自如定期上门查表(包括但不限于协助自如拍摄示数照', '\n片)。', '\n2.后付费的生活费用由自如定期生成相应账单,承租人应及时支付。预付费的生活费用,', '\n承租人应根据实际使用情况自行合理购买,并及时与房屋其他实际使用人结清,否则造', '\n成的损失和后果由承租人自行承担。', '\n3.非出租人及自如原因导致无法上门查表或生活费用收费单位未定时生成相应账单的,自', '\n如有权代出租人通过预估的形式生成生活费用账单,后期按照承租人的实际使用情况多', '\n退少补。', '\n4.承租人应承担的生活费用计算方式为:按使用示数或使用时长计算的生活费用总额除以', '\n房屋实际居住户数。', '\n5.本合同约定的生活费用单价仅供参考,具体以实际收费标准为准。', '\n第四条房屋维护与维修', '\n(一)自如受出租人委托,如房屋及原有物品、设备设施在租赁期限内因老化产生的维护、维', '\n修事宜由自如承担;如发生人为损坏的,应按照附件三及物业交割补充协议的标准进行赔偿', '\n或维修;若附件三及物业交割补充协议未有明确约定的,依据“谁导致谁承担”的原则处理。', '\n(二)租赁期限内,承租人对房屋具有一般性保管义务,如有房屋设施设备损毁或发生故障情', '\n况,应及时通知自如,否则由此造成的财产损失、人身损害等由承租人承担。', '\n第五条转租及换租', '\n(一)转租:合同起租日后,承租人向自如提出转租申请的,经自如及出租人同意后的45日', '\n内,可将所租赁的房屋重新上架并租给第三方。转租期间改为解约申请的,以提出转租申请', '\n日为解约申请日。', '\n(二)换租:本合同生效后,经协商一致,承租人可换租至自如管理的其他房屋(换租不支', '\n持由整租换成非整租产品)。承租人应先与该房屋的出租人就拟换租的房屋签订租赁期限', '\n不少于90天的租赁合同,该合同起租后60日内(不含60日,含起租日当日)应办理本', '\n合同的退租手续,否则自如有权拒绝办理换租。本合同租金计算至退租完成日。', '\n(三)三天不满意无理由换租:', '\n1.对新签合同(不含转租、换租),承租人享有一次在本合同生效日起3日内(含生', '\n3/20']
    
  3. 遍历上述列表,看看是不是还有长度超过800的chunk,如果有,\n已经用过了,用\n后面的符号按照上述流程,继续拆分这个chunk。这也就是RecursiveCharacterTextSplitter这个名字的来源,递归的去处理。

    遍历的过程中如果发现这个chunk的长度小于800,将其添加到_good_splits 列表中,直到遇到大于800的chunk。遇到之后两步操作:

    • 如果_good_splits 不为空,则将_good_splits列表内容进行merge
    • 继续按照上述逻辑递归的处理这个chunk

    如果遍历完这个列表都没遇到大于800的chunk,最终对_good_splits 进行一遍merge操作。

  4. merge的逻辑

    以我们这个text为例,执行完c步骤后,_good_splits 的内容和b步骤的列表是一模一样的,总共是38行,所以列表长度也是38,因为所有chunk的长度都小于800,不涉及递归的操作。

    遍历这个_good_splits,定义一个total统计遍历过的所有chunk的总长度,直到遍历到当前的chunk,发现总长度超过800,则对当前chunk之前的所有chunk进行merge(不包含当前chunk)。合并逻辑直接按照切分符号拼接成字符串,一个大chunk(切分符号是空字符串)。

    chunk_overlap的逻辑也在merge的逻辑内:

    为了提高文档检索以及提高大模型问答的效果,一般都会设置一个overlap,增加每个document(简称doc)的上下文关联。

    举个例子,比如对于这样一个splits,设置了chunk_overlap那么每个doc开头都会和上一个doc的末尾有重叠,这样就增加了每个doc的上下文关联。

    ['押金,自如与出租人另行结算。承租人同意自如返还押金时有权抵扣承租人应付自如的款', '\n项。若上述款项尚在自如的监管或托管账户的,自如应在15日内退还。', '\n(四)承租人续租、换租或转租房屋的,租金以届时自如和出租人商定的报价为准。', '\n(五)房租发票由房屋出租人开具,自如予以相应协助。如果在租赁期内承租人索要了相关', '\n发票,办理服务费及房租退费时,承租人须按照税法规定配合自如进行发票红冲手']比如设置了chunk_overlap=20,merge完的doc长度设置为50,最终的doc列表会变成:
    ['押金,自如与出租人另行结算。承租人同意自如返还押金时有权抵扣承租人应付自如的款\n项。若上述款项尚在自如的监管或托管账户的,自如应在15日内退还。', '\n项。若上述款项尚在自如的监管或托管账户的,自如应在15日内退还。\n(四)承租人续租、换租或转租房屋的,租金以届时自如和出租人商定的报价为准。', '\n(四)承租人续租、换租或转租房屋的,租金以届时自如和出租人商定的报价为准。\n(五)房租发票由房屋出租人开具,自如予以相应协助。如果在租赁期内承租人索要了相关', '\n(五)房租发票由房屋出租人开具,自如予以相应协助。如果在租赁期内承租人索要了相关\n发票,办理服务费及房租退费时,承租人须按照税法规定配合自如进行发票红冲手', '\n发票,办理服务费及房租退费时,承租人须按照税法规定配合自如进行发票红冲手']
    

    merge逻辑的源代码:

    # splits:长度为38的列表, separator: ''
    def _merge_splits(self, splits: Iterable[str], separator: str) -> List[str]:# We now want to combine these smaller pieces into medium size# chunks to send to the LLM.separator_len = self._length_function(separator)docs = []current_doc: List[str] = []total = 0# 遍历每个chunkfor d in splits:# 使用tokenizer计算长度_len = self._length_function(d)# 如果当前chunk的长度加上之前累计的chunk的长度>800了,最长的chunk长度是800,说明改进行merge了。if (total + _len + (separator_len if len(current_doc) > 0 else 0)> self._chunk_size):if total > self._chunk_size:logger.warning(f"Created a chunk of size {total}, "f"which is longer than the specified {self._chunk_size}")if len(current_doc) > 0:# 使用separator进行列表内容拼接doc = self._join_docs(current_doc, separator)if doc is not None:docs.append(doc)# Keep on popping if:# - we have a larger chunk than in the chunk overlap# - or if we still have any chunks and the length is long# 留在current_doc列表中的chunk的长度刚好大于_chunk_overlap,在这里是0,表示不留。如果_chunk_overlap是200,则留下几个chunk,使其长度大于_chunk_overlapwhile total > self._chunk_overlap or (total + _len + (separator_len if len(current_doc) > 0 else 0)> self._chunk_sizeand total > 0):# 每次减去current_doc的第一个chunk的长度total -= self._length_function(current_doc[0]) + (separator_len if len(current_doc) > 1 else 0)# 更新current_doc列表,丢弃第0个chunk,列表是有一个从左到右顺序,列表右边的chunk和后续的chunk才能连贯起来,所以是从左到右删。current_doc = current_doc[1:]# 将当前chunk添加到current_doc列表中current_doc.append(d)# 计算累计chunk的长度total += _len + (separator_len if len(current_doc) > 1 else 0)doc = self._join_docs(current_doc, separator)if doc is not None:docs.append(doc)return docs
    

    c步骤的结果经d步骤处理完之后变成了两个doc,每个doc长度都在800内,且没有overlap。

    [Document(page_content='押金,自如与出租人另行结算。承租人同意自如返还押金时有权抵扣承租人应付自如的款\n项。若上述款项尚在自如的监管或托管账户的,自如应在15日内退还。\n(四)承租人续租、换租或转租房屋的,租金以届时自如和出租人商定的报价为准。\n(五)房租发票由房屋出租人开具,自如予以相应协助。如果在租赁期内承租人索要了相关\n发票,办理服务费及房租退费时,承租人须按照税法规定配合自如进行发票红冲手\n续,包括但不限于承租人自双方办理完毕解约之日(含当日)起1个月内,依据税法要\n求将其此前取得的增值税普通发票或增值税专用发票原件(如有)交还自如或配合自\n如进行红字发票处理,否则自如有权代出租人拒绝向承租人退还服务费或房租且不承\n担任何违约责任。\n(六)生活费用的品类及价格详见物业交割补充协议:\n1.租赁期限内,承租人需配合自如定期上门查表(包括但不限于协助自如拍摄示数照\n片)。\n2.后付费的生活费用由自如定期生成相应账单,承租人应及时支付。预付费的生活费用,\n承租人应根据实际使用情况自行合理购买,并及时与房屋其他实际使用人结清,否则造\n成的损失和后果由承租人自行承担。\n3.非出租人及自如原因导致无法上门查表或生活费用收费单位未定时生成相应账单的,自\n如有权代出租人通过预估的形式生成生活费用账单,后期按照承租人的实际使用情况多\n退少补。\n4.承租人应承担的生活费用计算方式为:按使用示数或使用时长计算的生活费用总额除以\n房屋实际居住户数。\n5.本合同约定的生活费用单价仅供参考,具体以实际收费标准为准。\n第四条房屋维护与维修\n(一)自如受出租人委托,如房屋及原有物品、设备设施在租赁期限内因老化产生的维护、维\n修事宜由自如承担;如发生人为损坏的,应按照附件三及物业交割补充协议的标准进行赔偿\n或维修;若附件三及物业交割补充协议未有明确约定的,依据“谁导致谁承担”的原则处理。\n(二)租赁期限内,承租人对房屋具有一般性保管义务,如有房屋设施设备损毁或发生故障情\n况,应及时通知自如,否则由此造成的财产损失、人身损害等由承租人承担。\n第五条转租及换租\n(一)转租:合同起租日后,承租人向自如提出转租申请的,经自如及出租人同意后的45日', metadata={'user_id': 'feifeixu__1234', 'kb_id': 'KBb17bd2d168604a84a59abe24e855d574_240625', 'file_id': 'e1368aa4c0cf4d88bda9874ae3686811', 'file_name': '9.png', 'nos_key': '/tmp/pycharm_project_419/QANY_DB/content/feifeixu__1234/KBb17bd2d168604a84a59abe24e855d574_240625/e1368aa4c0cf4d88bda9874ae3686811/9.png', 'file_url': '', 'title_lst': [], 'has_table': False, 'images': [], 'page_id': 0, 'headers': {'知识库名': 'qanything2.0', '文件名': '9.png'}, 'faq_dict': {}}), Document(page_content='内,可将所租赁的房屋重新上架并租给第三方。转租期间改为解约申请的,以提出转租申请\n日为解约申请日。\n(二)换租:本合同生效后,经协商一致,承租人可换租至自如管理的其他房屋(换租不支\n持由整租换成非整租产品)。承租人应先与该房屋的出租人就拟换租的房屋签订租赁期限\n不少于90天的租赁合同,该合同起租后60日内(不含60日,含起租日当日)应办理本\n合同的退租手续,否则自如有权拒绝办理换租。本合同租金计算至退租完成日。\n(三)三天不满意无理由换租:\n1.对新签合同(不含转租、换租),承租人享有一次在本合同生效日起3日内(含生\n3/20', metadata={'user_id': 'feifeixu__1234', 'kb_id': 'KBb17bd2d168604a84a59abe24e855d574_240625', 'file_id': 'e1368aa4c0cf4d88bda9874ae3686811', 'file_name': '9.png', 'nos_key': '/tmp/pycharm_project_419/QANY_DB/content/feifeixu__1234/KBb17bd2d168604a84a59abe24e855d574_240625/e1368aa4c0cf4d88bda9874ae3686811/9.png', 'file_url': '', 'title_lst': [], 'has_table': False, 'images': [], 'page_id': 0, 'headers': {'知识库名': 'qanything2.0', '文件名': '9.png'}, 'faq_dict': {}})]
    

3.为每个doc注入doc_id

这里有两个doc,每个doc长度都在800内,且没有overlap。

这个很简单,就是file_id + ‘_’ + doc的位置
doc_ids = [file_id + '_' + str(i) for i, _ in enumerate(documents)]

  1. 对前面生成的两个doc继续split。

这个split和前面的split参数有些不同,DEFAULT_CHILD_CHUNK_SIZE=400,chunk_overlap=100.

init_child_splitter = RecursiveCharacterTextSplitter(separators=["\n\n", "\n", "。", "!", "!", "?", "?", ";", ";", "……", "…", "、", ",", ",", " ", ""],chunk_size=DEFAULT_CHILD_CHUNK_SIZE,chunk_overlap=int(DEFAULT_CHILD_CHUNK_SIZE / 4),length_function=num_tokens_embed)

为每个子doc注入doc_id:

前面生成了两个doc,以第一个doc生成的子doc为例,子doc的长度是400左右,且个其他子doc之间有100个token的重复。子doc的doc_id都是e1368aa4c0cf4d88bda9874ae3686811_0。

[Document(page_content="[headers]({'知识库名': 'qanything2.0', '文件名': '9.png'})\n押金,自如与出租人另行结算。承租人同意自如返还押金时有权抵扣承租人应付自如的款\n项。若上述款项尚在自如的监管或托管账户的,自如应在15日内退还。\n(四)承租人续租、换租或转租房屋的,租金以届时自如和出租人商定的报价为准。\n(五)房租发票由房屋出租人开具,自如予以相应协助。如果在租赁期内承租人索要了相关\n发票,办理服务费及房租退费时,承租人须按照税法规定配合自如进行发票红冲手\n续,包括但不限于承租人自双方办理完毕解约之日(含当日)起1个月内,依据税法要\n求将其此前取得的增值税普通发票或增值税专用发票原件(如有)交还自如或配合自\n如进行红字发票处理,否则自如有权代出租人拒绝向承租人退还服务费或房租且不承\n担任何违约责任。\n(六)生活费用的品类及价格详见物业交割补充协议:\n1.租赁期限内,承租人需配合自如定期上门查表(包括但不限于协助自如拍摄示数照\n片)。\n2.后付费的生活费用由自如定期生成相应账单,承租人应及时支付。预付费的生活费用,", metadata={'user_id': 'feifeixu__1234', 'kb_id': 'KBb17bd2d168604a84a59abe24e855d574_240625', 'file_id': 'e1368aa4c0cf4d88bda9874ae3686811', 'file_name': '9.png', 'nos_key': '/tmp/pycharm_project_419/QANY_DB/content/feifeixu__1234/KBb17bd2d168604a84a59abe24e855d574_240625/e1368aa4c0cf4d88bda9874ae3686811/9.png', 'file_url': '', 'title_lst': [], 'has_table': False, 'images': [], 'page_id': 0, 'headers': {'知识库名': 'qanything2.0', '文件名': '9.png'}, 'faq_dict': {}, 'doc_id': 'e1368aa4c0cf4d88bda9874ae3686811_0'}), Document(page_content="[headers]({'知识库名': 'qanything2.0', '文件名': '9.png'})\n(六)生活费用的品类及价格详见物业交割补充协议:\n1.租赁期限内,承租人需配合自如定期上门查表(包括但不限于协助自如拍摄示数照\n片)。\n2.后付费的生活费用由自如定期生成相应账单,承租人应及时支付。预付费的生活费用,\n承租人应根据实际使用情况自行合理购买,并及时与房屋其他实际使用人结清,否则造\n成的损失和后果由承租人自行承担。\n3.非出租人及自如原因导致无法上门查表或生活费用收费单位未定时生成相应账单的,自\n如有权代出租人通过预估的形式生成生活费用账单,后期按照承租人的实际使用情况多\n退少补。\n4.承租人应承担的生活费用计算方式为:按使用示数或使用时长计算的生活费用总额除以\n房屋实际居住户数。\n5.本合同约定的生活费用单价仅供参考,具体以实际收费标准为准。\n第四条房屋维护与维修\n(一)自如受出租人委托,如房屋及原有物品、设备设施在租赁期限内因老化产生的维护、维\n修事宜由自如承担;如发生人为损坏的,应按照附件三及物业交割补充协议的标准进行赔偿\n或维修;若附件三及物业交割补充协议未有明确约定的,依据“谁导致谁承担”的原则处理。", metadata={'user_id': 'feifeixu__1234', 'kb_id': 'KBb17bd2d168604a84a59abe24e855d574_240625', 'file_id': 'e1368aa4c0cf4d88bda9874ae3686811', 'file_name': '9.png', 'nos_key': '/tmp/pycharm_project_419/QANY_DB/content/feifeixu__1234/KBb17bd2d168604a84a59abe24e855d574_240625/e1368aa4c0cf4d88bda9874ae3686811/9.png', 'file_url': '', 'title_lst': [], 'has_table': False, 'images': [], 'page_id': 0, 'headers': {'知识库名': 'qanything2.0', '文件名': '9.png'}, 'faq_dict': {}, 'doc_id': 'e1368aa4c0cf4d88bda9874ae3686811_0'}), Document(page_content="[headers]({'知识库名': 'qanything2.0', '文件名': '9.png'})\n(一)自如受出租人委托,如房屋及原有物品、设备设施在租赁期限内因老化产生的维护、维\n修事宜由自如承担;如发生人为损坏的,应按照附件三及物业交割补充协议的标准进行赔偿\n或维修;若附件三及物业交割补充协议未有明确约定的,依据“谁导致谁承担”的原则处理。\n(二)租赁期限内,承租人对房屋具有一般性保管义务,如有房屋设施设备损毁或发生故障情\n况,应及时通知自如,否则由此造成的财产损失、人身损害等由承租人承担。\n第五条转租及换租\n(一)转租:合同起租日后,承租人向自如提出转租申请的,经自如及出租人同意后的45日", metadata={'user_id': 'feifeixu__1234', 'kb_id': 'KBb17bd2d168604a84a59abe24e855d574_240625', 'file_id': 'e1368aa4c0cf4d88bda9874ae3686811', 'file_name': '9.png', 'nos_key': '/tmp/pycharm_project_419/QANY_DB/content/feifeixu__1234/KBb17bd2d168604a84a59abe24e855d574_240625/e1368aa4c0cf4d88bda9874ae3686811/9.png', 'file_url': '', 'title_lst': [], 'has_table': False, 'images': [], 'page_id': 0, 'headers': {'知识库名': 'qanything2.0', '文件名': '9.png'}, 'faq_dict': {}, 'doc_id': 'e1368aa4c0cf4d88bda9874ae3686811_0'})]
  1. 子doc向量化并存入milvus向量数据库

本来有两个doc,第一个doc产生了三个子doc,第二个doc产生了一个子doc,总共4个子doc,现在要对着4个子doc进行操作。4个doc如下,删除了一些无用的属性。

[Document(page_content="[headers]({'知识库名': 'qanything2.0', '文件名': '9.png'})\n押金,自如与出租人另行结算。承租人同意自如返还押金时有权抵扣承租人应付自如的款\n项。若上述款项尚在自如的监管或托管账户的,自如应在15日内退还。\n(四)承租人续租、换租或转租房屋的,租金以届时自如和出租人商定的报价为准。\n(五)房租发票由房屋出租人开具,自如予以相应协助。如果在租赁期内承租人索要了相关\n发票,办理服务费及房租退费时,承租人须按照税法规定配合自如进行发票红冲手\n续,包括但不限于承租人自双方办理完毕解约之日(含当日)起1个月内,依据税法要\n求将其此前取得的增值税普通发票或增值税专用发票原件(如有)交还自如或配合自\n如进行红字发票处理,否则自如有权代出租人拒绝向承租人退还服务费或房租且不承\n担任何违约责任。\n(六)生活费用的品类及价格详见物业交割补充协议:\n1.租赁期限内,承租人需配合自如定期上门查表(包括但不限于协助自如拍摄示数照\n片)。\n2.后付费的生活费用由自如定期生成相应账单,承租人应及时支付。预付费的生活费用,", metadata={'user_id': 'feifeixu__1234', 'kb_id': 'KBb17bd2d168604a84a59abe24e855d574_240625', 'file_id': 'e1368aa4c0cf4d88bda9874ae3686811', 'file_url': '', 'headers': {'知识库名': 'qanything2.0', '文件名': '9.png'}, 'doc_id': 'e1368aa4c0cf4d88bda9874ae3686811_0'}), Document(page_content="[headers]({'知识库名': 'qanything2.0', '文件名': '9.png'})\n(六)生活费用的品类及价格详见物业交割补充协议:\n1.租赁期限内,承租人需配合自如定期上门查表(包括但不限于协助自如拍摄示数照\n片)。\n2.后付费的生活费用由自如定期生成相应账单,承租人应及时支付。预付费的生活费用,\n承租人应根据实际使用情况自行合理购买,并及时与房屋其他实际使用人结清,否则造\n成的损失和后果由承租人自行承担。\n3.非出租人及自如原因导致无法上门查表或生活费用收费单位未定时生成相应账单的,自\n如有权代出租人通过预估的形式生成生活费用账单,后期按照承租人的实际使用情况多\n退少补。\n4.承租人应承担的生活费用计算方式为:按使用示数或使用时长计算的生活费用总额除以\n房屋实际居住户数。\n5.本合同约定的生活费用单价仅供参考,具体以实际收费标准为准。\n第四条房屋维护与维修\n(一)自如受出租人委托,如房屋及原有物品、设备设施在租赁期限内因老化产生的维护、维\n修事宜由自如承担;如发生人为损坏的,应按照附件三及物业交割补充协议的标准进行赔偿\n或维修;若附件三及物业交割补充协议未有明确约定的,依据“谁导致谁承担”的原则处理。", metadata={'user_id': 'feifeixu__1234', 'kb_id': 'KBb17bd2d168604a84a59abe24e855d574_240625', 'file_id': 'e1368aa4c0cf4d88bda9874ae3686811', 'file_url': '', 'headers': {'知识库名': 'qanything2.0', '文件名': '9.png'}, 'doc_id': 'e1368aa4c0cf4d88bda9874ae3686811_0'}), Document(page_content="[headers]({'知识库名': 'qanything2.0', '文件名': '9.png'})\n(一)自如受出租人委托,如房屋及原有物品、设备设施在租赁期限内因老化产生的维护、维\n修事宜由自如承担;如发生人为损坏的,应按照附件三及物业交割补充协议的标准进行赔偿\n或维修;若附件三及物业交割补充协议未有明确约定的,依据“谁导致谁承担”的原则处理。\n(二)租赁期限内,承租人对房屋具有一般性保管义务,如有房屋设施设备损毁或发生故障情\n况,应及时通知自如,否则由此造成的财产损失、人身损害等由承租人承担。\n第五条转租及换租\n(一)转租:合同起租日后,承租人向自如提出转租申请的,经自如及出租人同意后的45日", metadata={'user_id': 'feifeixu__1234', 'kb_id': 'KBb17bd2d168604a84a59abe24e855d574_240625', 'file_id': 'e1368aa4c0cf4d88bda9874ae3686811', 'file_url': '', 'headers': {'知识库名': 'qanything2.0', '文件名': '9.png'}, 'doc_id': 'e1368aa4c0cf4d88bda9874ae3686811_0'}), Document(page_content="[headers]({'知识库名': 'qanything2.0', '文件名': '9.png'})\n内,可将所租赁的房屋重新上架并租给第三方。转租期间改为解约申请的,以提出转租申请\n日为解约申请日。\n(二)换租:本合同生效后,经协商一致,承租人可换租至自如管理的其他房屋(换租不支\n持由整租换成非整租产品)。承租人应先与该房屋的出租人就拟换租的房屋签订租赁期限\n不少于90天的租赁合同,该合同起租后60日内(不含60日,含起租日当日)应办理本\n合同的退租手续,否则自如有权拒绝办理换租。本合同租金计算至退租完成日。\n(三)三天不满意无理由换租:\n1.对新签合同(不含转租、换租),承租人享有一次在本合同生效日起3日内(含生\n3/20", metadata={'user_id': 'feifeixu__1234', 'kb_id': 'KBb17bd2d168604a84a59abe24e855d574_240625', 'file_id': 'e1368aa4c0cf4d88bda9874ae3686811', 'file_url': '', 'headers': {'知识库名': 'qanything2.0', '文件名': '9.png'}, 'doc_id': 'e1368aa4c0cf4d88bda9874ae3686811_1'})]
  1. 起bce-embedding的服务,得到四个doc的embedding向量
nohup python3 -u qanything_kernel/dependent_server/embedding_server/embedding_server.py > /workspace/QAnything/logs/debug_logs/embedding_server.log 2>&1 &

b. 存milvus向量数据库。

🤗 总结归纳

以上就是图片解析逻辑的全部流程了。

  1. 图片ocr识别文字,这些文字注入元数据,组成一个doc
  2. 对doc进行split并merge,doc和doc之间的chunk_overlap为0,也就是没有overlap,每个doc长度在800内
  3. 对每个doc再split并merge,doc的子doc之间有100的chunk_overlap,子doc长度400内
  4. 对所有的子doc使用bce-embedding向量化并存入milvus向量数据库

📎 参考文章

  • Qanything v2.0源码

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

FreeMarker 禁止自动转义标签-noautoesc

&#x1f496;简介 FreeMarker 是一个用 Java 语言编写的模板引擎&#xff0c;它被设计用来生成文本输出&#xff08;HTML 网页、电子邮件、配置文件等&#xff09;。在 FreeMarker 中&#xff0c;默认情况下&#xff0c;当你在模板中输出变量时&#xff0c;如果这些变量包含 …

shardingjdbc介绍

文章目录 1、shardingjdbc介绍1.1、读写分离、数据分片&#xff08;分库分表&#xff09;中间件&#xff1a;1.1.1、shardingsphere1.1.2、mycat 2、shardingjdbc-demo搭建2.1、创建项目2.2、添加依赖2.3、application.yml2.4、创建实体类 User2.5、创建 UserMapper2.6、创建测…

DNA亲和纯化测序(DAP-seq)、组蛋白甲基化修饰(H3K4me3 ChlP-seq)

&#x1f31f; 教授团队领衔&#xff0c;全方位服务&#xff01; &#x1f680; 从实验设计到论文发表&#xff0c;一站式解决方案&#xff01; &#x1f4c8; 选择我们&#xff0c;加速您的科研进程&#xff0c;让成果不再等待&#xff01; &#x1f4dd; 专业分析 定制服…

19_Python中的上下文管理器

Python中的上下文管理器 在Python中&#xff0c;上下文管理器&#xff08;Context Manager&#xff09;是一种用于资源管理的技术&#xff0c;它可以确保资源在使用后被正确释放&#xff0c;例如文件、网络连接或锁。 上下文管理器&#xff08;Context Manager&#xff09;是…

GB28181语音对讲协议详解

GB28181-2016语音对讲流程如下图1所示&#xff1a; 图1.语音对讲流程。 其中, 信令 1 、2 、 3 、 4 为语音广播通知、 语音广播应答消息流程; 信令 5 、 1 2 、 1 3 、 1 4 、 1 5 、 1 6 为 S I P 服务器接收到客户端的呼叫请求通过 B 2 B UA 代理方式建立语音流接收者与媒…

计算机毕业设计之:基于微信小程序的电费缴费系统(源码+文档+讲解)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

MatrixOne助力一道创新打造高性能智能制造AIOT系统

客户简介 深圳一道创新&#xff08;ETAO Innovation&#xff09;成立于2012年&#xff0c;是一家创新型软件及信息技术服务商&#xff0c;致力于制造戏份行业—电子制造业的数字转型服务&#xff0c;构建万物互联的智能工程。一道创新致力于把先进的软件系统、数字平台、人工智…

QT中添加资源文件

什么是资源文件 项目中经常需要添加图片、‌音频、‌视频、翻译文件等文件&#xff0c;在QT中&#xff0c;这些文件会放在 .qrc 文件中来被使用。 .qrc 文件是一个XML格式的资源集合描述文件&#xff0c;是Qt中用于定义和管理资源的关键文件 如何使用 创建资源文件 在你的Qt项…

C++之STL—string容器

本质&#xff1a;类 class 封装了很多方法&#xff1a;查找find&#xff0c;拷贝copy&#xff0c;删除delete 替换replace&#xff0c;插入insert 构造函数 赋值操作 assign&#xff1a; 字符串拼接 &#xff0b; append&#xff1a; string查找和替换 没查找到&#xff0c;po…

石头剪刀布手势识别系统源码分享

石头剪刀布手势识别检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Comput…

Qt系统相关——QThread

文章目录 QThread的API使用示例客户端多线程应用场景互斥锁QMutexQMutexLockerQReadWriteLocker、QReadLocker、QWriteLocker 条件变量和信号量 QThread的API Qt中的多线程和Linux中的线程&#xff0c;本质上是一个东西 Linux线程概念 Linux多线程——线程控制 Linux多线程——…

[干货] [非基础警告] Unity 发布-订阅模式下的事件中心设计

本文师承于唐老师&#xff0c;但是修改了一些代码&#xff0c;采用更加方便理解的方式设计 1.什么是事件中心 2.可以比喻成冒险者工会的任务板子 任务板子上面有发布任务和任务完成两种基础情况 2.1 发布任务 来个冒险者发布一个任务&#xff0c;就执行Pulishtask方法 这…

记一次 RabbitMQ 消费者莫名消失问题的排查

问题回顾 某天下午&#xff0c;生产监控告警&#xff1a;消息积压&#xff0c;队列 xxx 消息数超过 100&#xff1b;我第一时间想到的是应用服务是不是停了&#xff0c;但应用服务存活监控又没有告警&#xff0c;但我还是找值班运维同事帮忙确认了下&#xff0c;确认结果是服务…

GitHub上图像超分开源项目推荐【持续更新】

RAISR 介绍&#xff1a;RAISR&#xff08;Rapid and Accurate Image Super-Resolution&#xff09;是一种由Google开发的图像超分辨率技术&#xff0c;它利用机器学习算法来提高低分辨率图像的质量&#xff0c;使其看起来更加清晰和细致。这项技术可以在移动设备上实时运行&am…

uni-app快速入门

目录 一、什么是 uni-app二、快速创建 uni-app 项目1.创建 uni-app2.运行 uni-app 三、uni-app 相对传统 H5 的变化1.网络模型的变化2.文件类型变化3.文件内代码架构的变化4.外部文件引用方式变化5.组件/标签的变化6.js的变化&#xff08;1&#xff09;运行环境从浏览器变成v8引…

java项目之基于springboot框架开发的景区民宿预约系统的设计与实现(源码+文档)

项目简介 基于springboot框架开发的景区民宿预约系统的设计与实现的主要使用者分为&#xff1a; 管理员的功能有&#xff1a;用户信息的查询管理&#xff0c;可以删除用户信息、修改用户信息、新增用户信息&#xff0c;根据公告信息进行新增、修改、查询操作等等。。 &#x1…

最新版Visual Studio安装教程(超详细,新手必看)

一、官网下载 这里奉上Visual Studio官方下载地址&#xff1a; https://visualstudio.microsoft.com/zh-hans/downloads/https://visualstudio.microsoft.com/zh-hans/downloads/ 对于我们学习来说&#xff0c;下载第一个社区免费版即可&#xff0c;点击下载。 下载完成以后是…

Conda虚拟环境配置常见问题记录

搞深度学习的&#xff0c;总有被虚拟环境搞得头大的时候&#xff0c;特别是涉及到CUDA&#xff0c;Torch &#xff0c;Torchvision 版本适配的问题。这两天因为在原来的环境中装了几个包&#xff0c;导致原来的环境崩了&#xff0c;搞了一天的时间又重新配了环境&#xff0c;中…

18 基于51单片机的心率体温监测报警系统(包括程序、仿真、原理图、流程图)

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于51单片机 ds18B20读取温度&#xff0c; 设置初始心率65 设置温度阈值38 心率阈值60 100 如果超过阈值&#xff0c;蜂鸣器报警&#xff0c;led灯亮 二、硬件资源 基于KEIL5编写C代码&#xf…

BOE(京东方)重磅亮相世界制造业大会 科技创新引领现代化产业体系建设新未来

9月20日-23日&#xff0c;备受瞩目的2024世界制造业大会在合肥盛大召开&#xff0c;汇聚全球行业领袖、专家学者、知名企业&#xff0c;共同探讨现代化产业体系建设的新技术、新趋势、新机遇。作为积极推动实体经济与数字经济融合发展的产业领军企业&#xff0c;BOE&#xff08…