|
|
|
import uuid
|
|
|
|
from langchain_community.embeddings import DashScopeEmbeddings
|
|
|
|
from langchain_community.document_loaders import TextLoader
|
|
|
|
from langchain_text_splitters import RecursiveCharacterTextSplitter
|
|
|
|
from qwen_agent.agents import Assistant
|
|
|
|
import json_repair
|
|
|
|
import json
|
|
|
|
embeddings = DashScopeEmbeddings(dashscope_api_key="sk-ea89cf04431645b185990b8af8c9bb13")
|
|
|
|
device_id=0
|
|
|
|
import re
|
|
|
|
import time
|
|
|
|
from docx import Document
|
|
|
|
import shutil
|
|
|
|
from docx.opc.pkgreader import _SerializedRelationships, _SerializedRelationship
|
|
|
|
from docx.opc.oxml import parse_xml
|
|
|
|
import logging
|
|
|
|
import logging.config
|
|
|
|
import requests
|
|
|
|
from collections import defaultdict
|
|
|
|
|
|
|
|
userLog=None
|
|
|
|
def load_from_xml_v2(baseURI, rels_item_xml):
|
|
|
|
"""
|
|
|
|
Return |_SerializedRelationships| instance loaded with the
|
|
|
|
relationships contained in *rels_item_xml*. Returns an empty
|
|
|
|
collection if *rels_item_xml* is |None|.
|
|
|
|
"""
|
|
|
|
srels = _SerializedRelationships()
|
|
|
|
if rels_item_xml is not None:
|
|
|
|
rels_elm = parse_xml(rels_item_xml)
|
|
|
|
for rel_elm in rels_elm.Relationship_lst:
|
|
|
|
if rel_elm.target_ref in ('../NULL', 'NULL'):
|
|
|
|
continue
|
|
|
|
srels._srels.append(_SerializedRelationship(baseURI, rel_elm))
|
|
|
|
return srels
|
|
|
|
|
|
|
|
|
|
|
|
_SerializedRelationships.load_from_xml = load_from_xml_v2
|
|
|
|
# 记录程序开始的时间戳
|
|
|
|
def getOutlineLevel(inputXml):
|
|
|
|
"""
|
|
|
|
功能 从xml字段中提取出<w:outlineLvl w:val="number"/>中的数字number
|
|
|
|
参数 inputXml
|
|
|
|
返回 number
|
|
|
|
"""
|
|
|
|
start_index = inputXml.find('<w:outlineLvl')
|
|
|
|
end_index = inputXml.find('>', start_index)
|
|
|
|
number = inputXml[start_index:end_index + 1]
|
|
|
|
number = re.search("\d+", number).group()
|
|
|
|
return number
|
|
|
|
|
|
|
|
|
|
|
|
def isTitle(paragraph):
|
|
|
|
"""
|
|
|
|
功能 判断该段落是否设置了大纲等级
|
|
|
|
参数 paragraph:段落
|
|
|
|
返回 None:普通正文,没有大纲级别 0:一级标题 1:二级标题 2:三级标题
|
|
|
|
"""
|
|
|
|
# 如果是空行,直接返回None
|
|
|
|
if paragraph.text.strip() == '':
|
|
|
|
return None
|
|
|
|
|
|
|
|
# 如果该段落是直接在段落里设置大纲级别的,根据xml判断大纲级别
|
|
|
|
paragraphXml = paragraph._p.xml
|
|
|
|
if paragraphXml.find('<w:outlineLvl') >= 0:
|
|
|
|
return getOutlineLevel(paragraphXml)
|
|
|
|
# 如果该段落是通过样式设置大纲级别的,逐级检索样式及其父样式,判断大纲级别
|
|
|
|
targetStyle = paragraph.style
|
|
|
|
while targetStyle is not None:
|
|
|
|
# 如果在该级style中找到了大纲级别,返回
|
|
|
|
if targetStyle.element.xml.find('<w:outlineLvl') >= 0:
|
|
|
|
return getOutlineLevel(targetStyle.element.xml)
|
|
|
|
else:
|
|
|
|
targetStyle = targetStyle.base_style
|
|
|
|
# 如果在段落、样式里都没有找到大纲级别,返回None
|
|
|
|
return None
|
|
|
|
|
|
|
|
#寻找标题名称
|
|
|
|
def findTitleName(docxPath):
|
|
|
|
yield '文档相似性检查----检查是否存在详细设计方案'
|
|
|
|
loopCount = 0
|
|
|
|
while True:
|
|
|
|
loopCount+=1
|
|
|
|
if(loopCount>=15):
|
|
|
|
raise Exception("文档读取超时,或文档存在问题无法读取")
|
|
|
|
break
|
|
|
|
try:
|
|
|
|
document = Document(docxPath)
|
|
|
|
break
|
|
|
|
except Exception as e:
|
|
|
|
time.sleep(1)
|
|
|
|
pass
|
|
|
|
# 逐段读取docx文档的内容
|
|
|
|
titleWords=[]
|
|
|
|
firstTitle = 0
|
|
|
|
secondTitle = 0
|
|
|
|
sanjiTitle = 0
|
|
|
|
for paragraph in document.paragraphs:
|
|
|
|
# 判断该段落的标题级别
|
|
|
|
# 这里用isTitle()临时代表,具体见下文介绍的方法
|
|
|
|
text = paragraph.text
|
|
|
|
if text.strip():#非空判断
|
|
|
|
level = isTitle(paragraph)
|
|
|
|
if level=="0":
|
|
|
|
firstTitle+=1
|
|
|
|
secondTitle = 0
|
|
|
|
if(text.find("附件")>=0):
|
|
|
|
continue
|
|
|
|
titleWords.append("一级标题:".format(firstTitle)+text)
|
|
|
|
elif level=="1":
|
|
|
|
secondTitle+=1
|
|
|
|
sanjiTitle=0
|
|
|
|
# words.append("\t"+"{}.{}".format(firstTitle,secondTitle)+text)
|
|
|
|
# titleWords.append("第{}章的二级标题:".format(firstTitle,firstTitle,secondTitle)+text)
|
|
|
|
elif level=="2":
|
|
|
|
sanjiTitle += 1
|
|
|
|
# words.append("\t"+"{}.{}".format(firstTitle,secondTitle)+text)
|
|
|
|
# titleWords.append("第{}章的三级标题".format(firstTitle, secondTitle,firstTitle, secondTitle,sanjiTitle) + text)
|
|
|
|
findTitleName_llm_cfg = {
|
|
|
|
#'model': 'qwen1.5-72b-chat',
|
|
|
|
'model':"qwen2-72b",
|
|
|
|
'model_server': 'http://127.0.0.1:1025/v1', # base_url, also known as api_base
|
|
|
|
# 'api_key': 'sk-ea89cf04431645b185990b8af8c9bb13',
|
|
|
|
}
|
|
|
|
findTitleName_bot = Assistant(llm=findTitleName_llm_cfg,
|
|
|
|
name='Assistant',
|
|
|
|
# system_message='1:这样的是一级标题。1.1:这样的是二级标题。1.1.1:这样的是三级标题'
|
|
|
|
)
|
|
|
|
prompt='''\n是文档的大纲,一级标题组成,哪一章存在与方案相关的内容
|
|
|
|
类似详细设计方案,详细服务方案,详细建设方案为最相关的,优先选择
|
|
|
|
类似设计方案,服务方案,建设方案为次相关,次级选择
|
|
|
|
类似方案是最后选择
|
|
|
|
按照这样的顺序选择最合适的
|
|
|
|
你只能从这两个答案中选择一个:{"name":"一级标题名称","answer":"存在"}或{"name":"","answer":"不存在"},不做过多的解释,严格按回答格式作答
|
|
|
|
'''
|
|
|
|
# print("\n".join(titleWords)+prompt)
|
|
|
|
messages = [({'role': 'user', 'content': "\n".join(titleWords)+prompt})]
|
|
|
|
runList=[]
|
|
|
|
for rsp in findTitleName_bot.run(messages):
|
|
|
|
runList.append(rsp)
|
|
|
|
data = runList[len(runList) - 1][0]["content"]
|
|
|
|
parsed_data = json_repair.loads(data.replace('`', ''))
|
|
|
|
if(parsed_data["answer"]=="存在"):
|
|
|
|
yield parsed_data["name"]
|
|
|
|
else:
|
|
|
|
yield "文档相似性检查----未找到与详细设计方案相关内容,无法进行相似性比较"
|
|
|
|
|
|
|
|
def merge_chapters(words):
|
|
|
|
merged_text = {}
|
|
|
|
for line in words:
|
|
|
|
if ":" in line:
|
|
|
|
key, value = line.split(":", 1) # 根据第一个冒号分割
|
|
|
|
if key in merged_text:
|
|
|
|
merged_text[key].append(value.strip()) # 添加到列表
|
|
|
|
else:
|
|
|
|
merged_text[key] = [value.strip()] # 初始化列表
|
|
|
|
else:
|
|
|
|
logging.warning(f"Skipping line without key-value pair: {line}")
|
|
|
|
|
|
|
|
# 合并结果格式化为列表输出
|
|
|
|
merged_words = []
|
|
|
|
for key, values in merged_text.items():
|
|
|
|
combined_value = ",".join(values) # 将内容合并
|
|
|
|
merged_words.append(f"{key}:{combined_value}")
|
|
|
|
return merged_words
|
|
|
|
#获取文档中 详细设计方案 章节的所有内容
|
|
|
|
def getDocxToText(docxPath, titleName, vector_store_path):
|
|
|
|
loopCount = 0
|
|
|
|
while True:
|
|
|
|
loopCount += 1
|
|
|
|
if loopCount >= 15:
|
|
|
|
raise Exception("文档读取超时,或文档存在问题无法读取")
|
|
|
|
break
|
|
|
|
try:
|
|
|
|
document = Document(docxPath)
|
|
|
|
break
|
|
|
|
except Exception as e:
|
|
|
|
time.sleep(1)
|
|
|
|
pass
|
|
|
|
|
|
|
|
# 逐段读取docx文档的内容
|
|
|
|
levelList = []
|
|
|
|
words = []
|
|
|
|
addStart = False
|
|
|
|
title_counter = [] # 用于存储当前标题的计数
|
|
|
|
title_texts = [] # 用于存储当前各级标题的文本
|
|
|
|
i = 0
|
|
|
|
|
|
|
|
for paragraph in document.paragraphs:
|
|
|
|
text = paragraph.text.strip()
|
|
|
|
if text: # 非空判断
|
|
|
|
level = isTitle(paragraph) # 确保这个函数在代码中定义
|
|
|
|
|
|
|
|
# 当前标题的层级
|
|
|
|
current_level = int(level) if level is not None else -1
|
|
|
|
|
|
|
|
if current_level >= 0: # 标题段落
|
|
|
|
# 确保标题计数器足够长
|
|
|
|
while len(title_counter) <= current_level:
|
|
|
|
title_counter.append(0) # 初始化新级别的标题计数
|
|
|
|
title_texts.append('') # 初始化对应的标题文本
|
|
|
|
|
|
|
|
# 更新当前级别及以下的标题计数和标题文本
|
|
|
|
title_counter[current_level] += 1 # 当前级别计数加1
|
|
|
|
title_counter = title_counter[:current_level+1]
|
|
|
|
title_texts[current_level] = text # 保存当前级别的标题文本
|
|
|
|
title_texts = title_texts[:current_level+1]
|
|
|
|
|
|
|
|
# 重置更低级别的计数和标题文本
|
|
|
|
for idx in range(current_level + 1, len(title_counter)):
|
|
|
|
title_counter[idx] = 0
|
|
|
|
title_texts[idx] = ''
|
|
|
|
|
|
|
|
# 检查是否与 titleName 匹配
|
|
|
|
if current_level == 0:
|
|
|
|
addStart = titleName in text # 检查是否与 titleName 匹配
|
|
|
|
|
|
|
|
else: # 非标题段落
|
|
|
|
if addStart:
|
|
|
|
if len(text) > 30: # 仅记录长度大于30的内容
|
|
|
|
i += 1
|
|
|
|
# 获取当前完整的标题编号和标题名称
|
|
|
|
levelText = ".".join(map(str, title_counter))
|
|
|
|
# 使用非空的标题名称
|
|
|
|
current_title = title_texts[-1] if title_texts else ''
|
|
|
|
words.append(f"{levelText}-{current_title}:{text}")
|
|
|
|
|
|
|
|
if len(words) == 0:
|
|
|
|
raise Exception("checkRepeatText,获取长度为0")
|
|
|
|
|
|
|
|
# 使用封装的合并函数
|
|
|
|
merged_words = merge_chapters(words)
|
|
|
|
|
|
|
|
# 将合并后的内容写入 txt 文件
|
|
|
|
with open("checkRepeatText.txt", 'w') as txt_file:
|
|
|
|
for line in merged_words:
|
|
|
|
txt_file.write(f"{line}\n")
|
|
|
|
|
|
|
|
time.sleep(3)
|
|
|
|
|
|
|
|
# 加载文本
|
|
|
|
loader = TextLoader(file_path='checkRepeatText.txt')
|
|
|
|
docs = loader.load()
|
|
|
|
|
|
|
|
# 创建唯一标识符
|
|
|
|
uuids = []
|
|
|
|
for _ in range(len(merged_words)):
|
|
|
|
uuids.append(str(uuid.uuid4()))
|
|
|
|
logging.info(f"checkRepeatTextuuidLen{len(uuids)}")
|
|
|
|
|
|
|
|
return merged_words, uuids
|
|
|
|
|
|
|
|
|
|
|
|
# @app.route('/checkRepeatText/<filename>', methods=['GET'])
|
|
|
|
def checkRepeatText(filename):
|
|
|
|
yield "文档相似性检查---启动中...."
|
|
|
|
vector_store_path="vector_store"+str(uuid.uuid4())
|
|
|
|
for titleName in findTitleName(filename):
|
|
|
|
yield titleName
|
|
|
|
if(titleName!="文档相似性检查----未找到与详细设计方案相关内容,无法进行相似性比较"):
|
|
|
|
yield "文档相似性检查----文档内容解析中"
|
|
|
|
words,uuids=getDocxToText(filename,titleName,vector_store_path)
|
|
|
|
# 记录程序开始的时间戳‘
|
|
|
|
reslist = []
|
|
|
|
count = 0
|
|
|
|
standard = {
|
|
|
|
"清晰性": """对软件功能描述的完整性主要体现在以下两个方面:
|
|
|
|
a. 功能描述是否简洁明了,避免使用过于复杂或专业的术语,使得用户能够轻松理解。
|
|
|
|
b. 是否明确指出了功能的具体作用,没有模糊不清或含糊其辞的表述。
|
|
|
|
如果要将软件功能描述的清晰性划分为优秀、良好、一般、差四个从高到低的等级,每个等级的评判标准是什么?
|
|
|
|
将软件功能描述的清晰性划分为优秀、良好、一般、差四个等级时,每个等级的评判标准可以如下定义:
|
|
|
|
优秀(90~100分)
|
|
|
|
简洁明了:功能描述极其精炼,没有多余的词汇,每个字都承载着必要的信息。
|
|
|
|
通俗易懂:完全避免了专业术语或行业黑话,即使是非专业用户也能轻松理解。
|
|
|
|
具体明确:功能的作用、范围、限制以及用户期望的结果都被清晰、准确地阐述,没有任何模糊或含糊的表述。
|
|
|
|
良好(70分~90分,不包含90分)
|
|
|
|
较为简洁:功能描述相对简短,但可能包含一些必要的细节或背景信息。
|
|
|
|
易于理解:大部分术语都是通俗易懂的,对于少数专业术语,提供了简短的解释或上下文。
|
|
|
|
明确具体:功能的主要作用、范围和用户期望的结果都被明确阐述,但可能在某些细节上稍显模糊。
|
|
|
|
一般(60~70分,不包含70分)
|
|
|
|
稍显冗长:功能描述可能包含一些不必要的细节或重复信息,导致用户需要花费更多时间来理解。
|
|
|
|
有一定难度:使用了一些专业术语或行业黑话,但没有提供足够的解释或上下文,导致非专业用户可能难以理解。
|
|
|
|
基本明确:功能的主要作用被阐述,但在范围、限制或用户期望的结果上可能存在一些模糊或含糊的表述。
|
|
|
|
差(60分以下,不包含60分)
|
|
|
|
冗长复杂:功能描述过于详细和复杂,包含大量不必要的细节和背景信息,导致用户难以抓住重点。
|
|
|
|
难以理解:大量使用专业术语或行业黑话,且没有提供任何解释或上下文,使得大部分用户都难以理解。
|
|
|
|
模糊不清:功能的作用、范围、限制以及用户期望的结果都没有被明确阐述,存在大量的模糊和含糊表述。
|
|
|
|
评估的提示词举例:
|
|
|
|
根据这些评判标准,对下面的软件功能描述的清晰性进行客观的评价,给出优秀、良好、一般、差四个等级之一的评价,并给出具体得分。并在此基础上润色和完善,使之达到优秀的等级。
|
|
|
|
""",
|
|
|
|
"完整性": """对软件功能描述的完整性主要体现在以下两个方面:
|
|
|
|
a. 是否涵盖了功能的所有重要方面,包括输入、输出、处理过程等。
|
|
|
|
b. 是否提供了足够的信息,以便用户能够全面了解功能的工作原理和用途。
|
|
|
|
如果要将软件功能描述的完整性划分为优秀、良好、一般、差四个从高到低的等级,每个等级的评判标准是什么?
|
|
|
|
将软件功能描述的完整性划分为优秀、良好、一般、差四个等级时,每个等级的评判标准可以如下定义:
|
|
|
|
优秀:(90~100分)
|
|
|
|
描述全面涵盖了功能的所有重要方面,包括但不限于输入、输出、处理过程、异常处理等。
|
|
|
|
提供了详尽的信息,用户能够清晰地了解功能的工作原理、用途以及在不同场景下的表现。
|
|
|
|
包含了必要的示例、图表或流程图,以直观展示功能的工作流程和效果。
|
|
|
|
没有遗漏任何对用户理解和使用功能至关重要的信息。
|
|
|
|
良好:(70分~90分,不包含90分)
|
|
|
|
描述基本涵盖了功能的主要方面,但可能有个别不太重要的细节未提及。
|
|
|
|
提供了足够的信息,用户能够较好地理解功能的工作原理和用途,但在某些复杂场景下可能需要额外说明。
|
|
|
|
可能包含一些示例或图表,但可能不如优秀等级那么全面或详细。
|
|
|
|
一般:(60~70分,不包含70分)
|
|
|
|
描述涵盖了功能的一部分重要方面,但存在较明显的遗漏或不足。
|
|
|
|
提供的信息有限,用户可能只能对功能有一个大致的了解,无法深入了解其工作原理和详细用途。
|
|
|
|
可能缺乏示例、图表或流程图等辅助材料,导致用户难以理解功能的某些复杂部分。
|
|
|
|
差:(60分以下,不包含60分)
|
|
|
|
描述严重缺失,未涵盖功能的关键方面,甚至可能误导用户。
|
|
|
|
提供的信息极少,用户无法全面了解功能的工作原理和用途。
|
|
|
|
可能存在错误或矛盾的信息,导致用户无法准确理解功能。
|
|
|
|
根据这些评判标准,对下面的软件功能描述的完整性进行客观的评价,给出优秀、良好、一般、差四个等级之一的评价。并在此基础上润色和完善,使之达到优秀的等级。
|
|
|
|
""",
|
|
|
|
"可测试性": """软件功能描述的可测试性主要体现为以下方面:
|
|
|
|
a. 功能描述是否具体、明确,以便能够进行功能测试和验证。
|
|
|
|
b. 是否提供了足够的细节,以便开发人员和测试人员能够准确理解和实现功能。
|
|
|
|
如果要将软件功能描述的可测试性划分为优秀、良好、一般、差四个从高到低的等级,每个等级的评判标准是什么?
|
|
|
|
将软件功能描述的可测试性划分为优秀、良好、一般、差四个等级时,每个等级的评判标准可以如下定义:
|
|
|
|
优秀:(90~100分)
|
|
|
|
功能描述非常具体和明确,能够直接转化为测试用例。
|
|
|
|
提供了详尽的细节,包括输入、输出、边界条件、异常处理等。
|
|
|
|
开发人员和测试人员能够轻松理解和实现功能,无需额外澄清或假设。
|
|
|
|
功能描述中包含了预期的行为和非预期的行为,有助于全面覆盖测试场景。
|
|
|
|
良好:(70分~90分,不包含90分)
|
|
|
|
功能描述相对具体和明确,大部分内容可以直接用于测试。
|
|
|
|
提供了足够的细节,但可能需要一些额外的解释或澄清才能完全理解。
|
|
|
|
开发人员和测试人员能够基于描述实现和测试功能,但可能需要一些额外的沟通和协调。
|
|
|
|
功能描述中基本涵盖了主要的行为和边界条件,但可能缺少对某些异常情况的详细描述。
|
|
|
|
一般:(60~70分,不包含70分)
|
|
|
|
功能描述较为笼统,需要较多的解释和澄清才能用于测试和开发。
|
|
|
|
细节不够充分,可能导致开发人员和测试人员在实现和测试过程中产生误解或遗漏。
|
|
|
|
需要较多的沟通和协调来确保功能的正确实现和测试。
|
|
|
|
功能描述中可能只涵盖了主要的行为,对边界条件和异常情况的描述较为模糊或缺失。
|
|
|
|
差:(60分以下,不包含60分)
|
|
|
|
功能描述非常模糊和笼统,无法直接用于测试和开发。
|
|
|
|
缺乏必要的细节,导致开发人员和测试人员无法准确理解和实现功能。
|
|
|
|
需要大量的沟通和协调,甚至可能需要重新编写功能描述才能进行有效的测试和开发。
|
|
|
|
功能描述中可能只提到了大致的目标或意图,没有具体的行为描述、边界条件或异常处理。
|
|
|
|
根据这些评判标准,对下面的软件功能描述的可测试性进行客观的评价,给出优秀、良好、一般、差四个等级之一的评价。并在此基础上润色和完善,使之达到优秀的等级。
|
|
|
|
""",
|
|
|
|
"详细性": """软件功能详细性主要体现在:
|
|
|
|
a. 功能描述是否详细,可以根据功能描述进行功能点评价,计算出ILF、EIF、EI、EO、EQ的数量;
|
|
|
|
如果要将软件功能描述的详细性划分为优秀、良好、一般、差四个从高到低的等级,每个等级的评判标准是什么?
|
|
|
|
将软件功能描述的详细性划分为优秀、良好、一般、差四个等级时,每个等级的评判标准可以如下定义:
|
|
|
|
优秀:(90~100分)
|
|
|
|
功能描述非常详尽,包含了所有必要的信息,使得评估者能够轻松地根据描述进行功能点评价。
|
|
|
|
ILF、EIF、EI、EO、EQ的数量可以明确且无误地计算出来,没有遗漏或模糊之处。
|
|
|
|
描述中不仅包含了功能的正常操作,还涵盖了异常处理、边界条件等特殊情况。
|
|
|
|
使用了具体的例子、流程图或伪代码来进一步阐明功能。
|
|
|
|
良好:(70分~90分,不包含90分)
|
|
|
|
功能描述相对详细,提供了足够的信息来进行功能点评价。
|
|
|
|
ILF、EIF、EI、EO、EQ的数量可以大致计算出来,但可能需要一些额外的解释或澄清。
|
|
|
|
描述中基本涵盖了功能的各个方面,但对某些细节或特殊情况可能描述不够充分。
|
|
|
|
整体而言,描述是清晰和准确的,但还有改进的空间。
|
|
|
|
一般:(60~70分,不包含70分)
|
|
|
|
功能描述较为笼统,缺乏具体的细节。
|
|
|
|
ILF、EIF、EI、EO、EQ的数量计算可能存在一定的困难或不确定性,需要较多的假设或推测。
|
|
|
|
描述中只涵盖了功能的主要方面,对细节和特殊情况的处理描述不足。
|
|
|
|
可能需要额外的沟通或澄清才能准确理解功能需求。
|
|
|
|
差:(60分以下,不包含60分)
|
|
|
|
功能描述非常模糊,缺乏必要的信息和细节。
|
|
|
|
无法根据描述进行准确的功能点评价,ILF、EIF、EI、EO、EQ的数量无法确定。
|
|
|
|
描述中可能只提到了功能的大致目标或意图,没有具体的实现细节或操作步骤。
|
|
|
|
需要大量的额外信息或澄清才能理解功能需求,甚至可能需要重新编写功能描述。
|
|
|
|
根据这些评判标准,对下面的软件功能描述的详细性进行客观的评价,给出优秀、良好、一般、差四个等级之一的评价。并在此基础上润色和完善,使之达到优秀的等级。
|
|
|
|
""",
|
|
|
|
}
|
|
|
|
weight = {
|
|
|
|
"清晰性" : 0.4,
|
|
|
|
"完整性" : 0.3,
|
|
|
|
"可测试性" : 0.2,
|
|
|
|
"详细性" : 0.1,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
findTitleName_llm_cfg = {
|
|
|
|
'model': "qwen2-72b",
|
|
|
|
'model_server': 'http://127.0.0.1:1025/v1',
|
|
|
|
}
|
|
|
|
findTitleName_bot = Assistant(llm=findTitleName_llm_cfg, name='Assistant')
|
|
|
|
for i in words:
|
|
|
|
count += 1
|
|
|
|
yield f"文档相似性检查--对{titleName}章节,进行文档内容检查中{count}/{len(words)}"
|
|
|
|
chapter, rest = i.split('-', 1)
|
|
|
|
title, text = rest.split(':', 1)
|
|
|
|
|
|
|
|
# 生成字典
|
|
|
|
example = {
|
|
|
|
"chapter": chapter.strip(),
|
|
|
|
"title": title.strip(),
|
|
|
|
"text": text.strip()
|
|
|
|
}
|
|
|
|
result = {
|
|
|
|
"title": title.strip(),
|
|
|
|
"text": text.strip()
|
|
|
|
}
|
|
|
|
# 循环提取键和值
|
|
|
|
weighted_score = 0
|
|
|
|
for key, value in standard.items():
|
|
|
|
prompt_score = f"""对软件功能{key}的定义:
|
|
|
|
{value}
|
|
|
|
模块名称:【{example['title']}】
|
|
|
|
模块描述:【{example['text']}】
|
|
|
|
回答格式为:{{"模块名称":"{example['text']}",
|
|
|
|
"等级":"优秀/良好/一般/差",
|
|
|
|
"得分":"0~100",
|
|
|
|
"理由及扣分原因":"理由及扣分原因",
|
|
|
|
}},不做过多的解释,严格按回答格式作答,只给出一个回答。
|
|
|
|
"""
|
|
|
|
|
|
|
|
messages = [({'role': 'user', 'content': prompt_score})]
|
|
|
|
runList = []
|
|
|
|
for rsp in findTitleName_bot.run(messages):
|
|
|
|
runList.append(rsp)
|
|
|
|
data = runList[len(runList) - 1][0]["content"]
|
|
|
|
parsed_data = json_repair.loads(data.replace('`', ''))
|
|
|
|
if isinstance(parsed_data, list): # 检查parsed_data是否为列表
|
|
|
|
parsed_data = parsed_data[0] # 取第一个元素
|
|
|
|
else:
|
|
|
|
parsed_data = parsed_data
|
|
|
|
result[f"{key}等级"] = parsed_data['等级']
|
|
|
|
result[f"{key}得分"] = parsed_data['得分']
|
|
|
|
score = int(parsed_data['得分']) # 假设 '得分' 是字符串,需要转换为整数
|
|
|
|
key_weight = weight.get(key, 0) # 根据键获取权重,如果没有匹配的权重,默认为 0
|
|
|
|
# 计算加权得分并累加
|
|
|
|
weighted_score += score * key_weight
|
|
|
|
result["加权得分"] = round(weighted_score, 2) # 保留两位小数
|
|
|
|
answer = f"{example['text']}"
|
|
|
|
for key, value in standard.items():
|
|
|
|
prompt_answer = f"""对软件功能{key}的定义:\n
|
|
|
|
{value}\n
|
|
|
|
模块名称:【{example['title']}】\n
|
|
|
|
模块描述:f【{answer}】\n
|
|
|
|
回答格式为:{{"模块名称":"{example['text']}",
|
|
|
|
"改进后的描述":"改进后的描述",
|
|
|
|
}},不做过多的解释,严格按回答格式作答。
|
|
|
|
"""
|
|
|
|
messages = [({'role': 'user', 'content': prompt_answer})]
|
|
|
|
runList = []
|
|
|
|
for rsp in findTitleName_bot.run(messages):
|
|
|
|
runList.append(rsp)
|
|
|
|
data = runList[len(runList) - 1][0]["content"]
|
|
|
|
parsed_data = json_repair.loads(data.replace('`', ''))
|
|
|
|
answer = parsed_data['改进后的描述']
|
|
|
|
result["改进后的描述"] = answer
|
|
|
|
textTag = i.split(":")[0]
|
|
|
|
breakpoint()
|
|
|
|
# vectorstore.delete(ids=uuids)
|
|
|
|
shutil.rmtree(vector_store_path)
|
|
|
|
resInfo=f"对{titleName}章节,发现相似内容:<br>"
|
|
|
|
if(len(reslist)>0):
|
|
|
|
for res in reslist:
|
|
|
|
resInfo+="【在**"+res["yuanwen1"][:res["yuanwen1"].find(':')]+"**下包含:"+res["yuanwen1"][res["yuanwen1"].find(':') + 1:]+"<br>在**"+res["yuanwen2"][:res["yuanwen2"].find(':')]+"**下包含:"+res["yuanwen2"][res["yuanwen2"].find(':') + 1:]+"<br>以上两段内容***相似度***:"+'{:.2f}'.format(res['similarity'])+"】<br>"
|
|
|
|
yield resInfo
|
|
|
|
else:
|
|
|
|
yield "**未发现相似内容**"
|
|
|
|
userLog.info("文档相似性检查----未发现相似内容**")
|
|
|
|
|
|
|
|
for i in checkRepeatText("./北仑区综合行政执法局协同监管系统项目建设方案_20240824.docx"):
|
|
|
|
print(i)
|