fix: auto-fix code issues (cron)

- 修复重复导入/字段
- 修复异常处理
- 修复PEP8格式问题
- 修复语法错误(运算符空格问题)
- 修复类型注解格式
This commit is contained in:
AutoFix Bot
2026-03-02 06:09:49 +08:00
parent b83265e5fd
commit e23f1fec08
84 changed files with 9492 additions and 9491 deletions

View File

@@ -14,9 +14,9 @@ from typing import Any
try:
import pandas as pd
PANDAS_AVAILABLE = True
PANDAS_AVAILABLE = True
except ImportError:
PANDAS_AVAILABLE = False
PANDAS_AVAILABLE = False
try:
from reportlab.lib import colors
@@ -32,9 +32,9 @@ try:
TableStyle,
)
REPORTLAB_AVAILABLE = True
REPORTLAB_AVAILABLE = True
except ImportError:
REPORTLAB_AVAILABLE = False
REPORTLAB_AVAILABLE = False
@dataclass
@@ -71,8 +71,8 @@ class ExportTranscript:
class ExportManager:
"""导出管理器 - 处理各种导出需求"""
def __init__(self, db_manager=None):
self.db = db_manager
def __init__(self, db_manager = None) -> None:
self.db = db_manager
def export_knowledge_graph_svg(
self, project_id: str, entities: list[ExportEntity], relations: list[ExportRelation]
@@ -84,21 +84,21 @@ class ExportManager:
SVG 字符串
"""
# 计算布局参数
width = 1200
height = 800
center_x = width / 2
center_y = height / 2
radius = 300
width = 1200
height = 800
center_x = width / 2
center_y = height / 2
radius = 300
# 按类型分组实体
entities_by_type = {}
entities_by_type = {}
for e in entities:
if e.type not in entities_by_type:
entities_by_type[e.type] = []
entities_by_type[e.type] = []
entities_by_type[e.type].append(e)
# 颜色映射
type_colors = {
type_colors = {
"PERSON": "#FF6B6B",
"ORGANIZATION": "#4ECDC4",
"LOCATION": "#45B7D1",
@@ -110,110 +110,110 @@ class ExportManager:
}
# 计算实体位置
entity_positions = {}
angle_step = 2 * 3.14159 / max(len(entities), 1)
entity_positions = {}
angle_step = 2 * 3.14159 / max(len(entities), 1)
for i, entity in enumerate(entities):
i * angle_step
x = center_x + radius * 0.8 * (i % 3 - 1) * 150 + (i // 3) * 50
y = center_y + radius * 0.6 * ((i % 6) - 3) * 80
entity_positions[entity.id] = (x, y)
x = center_x + radius * 0.8 * (i % 3 - 1) * 150 + (i // 3) * 50
y = center_y + radius * 0.6 * ((i % 6) - 3) * 80
entity_positions[entity.id] = (x, y)
# 生成 SVG
svg_parts = [
f'<svg xmlns="http://www.w3.org/2000/svg" width="{width}" height="{height}" '
f'viewBox="0 0 {width} {height}">',
svg_parts = [
f'<svg xmlns = "http://www.w3.org/2000/svg" width = "{width}" height = "{height}" '
f'viewBox = "0 0 {width} {height}">',
"<defs>",
' <marker id="arrowhead" markerWidth="10" markerHeight="7" '
'refX="9" refY="3.5" orient="auto">',
' <polygon points="0 0, 10 3.5, 0 7" fill="#7f8c8d"/>',
' <marker id = "arrowhead" markerWidth = "10" markerHeight = "7" '
'refX = "9" refY = "3.5" orient = "auto">',
' <polygon points = "0 0, 10 3.5, 0 7" fill = "#7f8c8d"/>',
" </marker>",
"</defs>",
f'<rect width="{width}" height="{height}" fill="#f8f9fa"/>',
f'<text x="{center_x}" y="30" text-anchor="middle" font-size="20" '
f'font-weight="bold" fill="#2c3e50">知识图谱 - {project_id}</text>',
f'<rect width = "{width}" height = "{height}" fill = "#f8f9fa"/>',
f'<text x = "{center_x}" y = "30" text-anchor = "middle" font-size = "20" '
f'font-weight = "bold" fill = "#2c3e50">知识图谱 - {project_id}</text>',
]
# 绘制关系连线
for rel in relations:
if rel.source in entity_positions and rel.target in entity_positions:
x1, y1 = entity_positions[rel.source]
x2, y2 = entity_positions[rel.target]
x1, y1 = entity_positions[rel.source]
x2, y2 = entity_positions[rel.target]
# 计算箭头终点(避免覆盖节点)
dx = x2 - x1
dy = y2 - y1
dist = (dx**2 + dy**2) ** 0.5
dx = x2 - x1
dy = y2 - y1
dist = (dx**2 + dy**2) ** 0.5
if dist > 0:
offset = 40
x2 = x2 - dx * offset / dist
y2 = y2 - dy * offset / dist
offset = 40
x2 = x2 - dx * offset / dist
y2 = y2 - dy * offset / dist
svg_parts.append(
f'<line x1="{x1}" y1="{y1}" x2="{x2}" y2="{y2}" '
f'stroke="#7f8c8d" stroke-width="2" marker-end="url(#arrowhead)" opacity="0.6"/>'
f'<line x1 = "{x1}" y1 = "{y1}" x2 = "{x2}" y2 = "{y2}" '
f'stroke = "#7f8c8d" stroke-width = "2" marker-end = "url(#arrowhead)" opacity = "0.6"/>'
)
# 关系标签
mid_x = (x1 + x2) / 2
mid_y = (y1 + y2) / 2
mid_x = (x1 + x2) / 2
mid_y = (y1 + y2) / 2
svg_parts.append(
f'<rect x="{mid_x - 30}" y="{mid_y - 10}" width="60" height="20" '
f'fill="white" stroke="#bdc3c7" rx="3"/>'
f'<rect x = "{mid_x - 30}" y = "{mid_y - 10}" width = "60" height = "20" '
f'fill = "white" stroke = "#bdc3c7" rx = "3"/>'
)
svg_parts.append(
f'<text x="{mid_x}" y="{mid_y + 5}" text-anchor="middle" '
f'font-size="10" fill="#2c3e50">{rel.relation_type}</text>'
f'<text x = "{mid_x}" y = "{mid_y + 5}" text-anchor = "middle" '
f'font-size = "10" fill = "#2c3e50">{rel.relation_type}</text>'
)
# 绘制实体节点
for entity in entities:
if entity.id in entity_positions:
x, y = entity_positions[entity.id]
color = type_colors.get(entity.type, type_colors["default"])
x, y = entity_positions[entity.id]
color = type_colors.get(entity.type, type_colors["default"])
# 节点圆圈
svg_parts.append(
f'<circle cx="{x}" cy="{y}" r="35" fill="{color}" stroke="white" stroke-width="3"/>'
f'<circle cx = "{x}" cy = "{y}" r = "35" fill = "{color}" stroke = "white" stroke-width = "3"/>'
)
# 实体名称
svg_parts.append(
f'<text x="{x}" y="{y + 5}" text-anchor="middle" font-size="12" '
f'font-weight="bold" fill="white">{entity.name[:8]}</text>'
f'<text x = "{x}" y = "{y + 5}" text-anchor = "middle" font-size = "12" '
f'font-weight = "bold" fill = "white">{entity.name[:8]}</text>'
)
# 实体类型
svg_parts.append(
f'<text x="{x}" y="{y + 55}" text-anchor="middle" font-size="10" '
f'fill="#7f8c8d">{entity.type}</text>'
f'<text x = "{x}" y = "{y + 55}" text-anchor = "middle" font-size = "10" '
f'fill = "#7f8c8d">{entity.type}</text>'
)
# 图例
legend_x = width - 150
legend_y = 80
rect_x = legend_x - 10
rect_y = legend_y - 20
rect_height = len(type_colors) * 25 + 10
legend_x = width - 150
legend_y = 80
rect_x = legend_x - 10
rect_y = legend_y - 20
rect_height = len(type_colors) * 25 + 10
svg_parts.append(
f'<rect x="{rect_x}" y="{rect_y}" width="140" height="{rect_height}" '
f'fill="white" stroke="#bdc3c7" rx="5"/>'
f'<rect x = "{rect_x}" y = "{rect_y}" width = "140" height = "{rect_height}" '
f'fill = "white" stroke = "#bdc3c7" rx = "5"/>'
)
svg_parts.append(
f'<text x="{legend_x}" y="{legend_y}" font-size="12" font-weight="bold" '
f'fill="#2c3e50">实体类型</text>'
f'<text x = "{legend_x}" y = "{legend_y}" font-size = "12" font-weight = "bold" '
f'fill = "#2c3e50">实体类型</text>'
)
for i, (etype, color) in enumerate(type_colors.items()):
if etype != "default":
y_pos = legend_y + 25 + i * 20
y_pos = legend_y + 25 + i * 20
svg_parts.append(
f'<circle cx="{legend_x + 10}" cy="{y_pos}" r="8" fill="{color}"/>'
f'<circle cx = "{legend_x + 10}" cy = "{y_pos}" r = "8" fill = "{color}"/>'
)
text_y = y_pos + 4
text_y = y_pos + 4
svg_parts.append(
f'<text x="{legend_x + 25}" y="{text_y}" font-size="10" '
f'fill="#2c3e50">{etype}</text>'
f'<text x = "{legend_x + 25}" y = "{text_y}" font-size = "10" '
f'fill = "#2c3e50">{etype}</text>'
)
svg_parts.append("</svg>")
@@ -231,12 +231,12 @@ class ExportManager:
try:
import cairosvg
svg_content = self.export_knowledge_graph_svg(project_id, entities, relations)
png_bytes = cairosvg.svg2png(bytestring=svg_content.encode("utf-8"))
svg_content = self.export_knowledge_graph_svg(project_id, entities, relations)
png_bytes = cairosvg.svg2png(bytestring = svg_content.encode("utf-8"))
return png_bytes
except ImportError:
# 如果没有 cairosvg返回 SVG 的 base64
svg_content = self.export_knowledge_graph_svg(project_id, entities, relations)
svg_content = self.export_knowledge_graph_svg(project_id, entities, relations)
return base64.b64encode(svg_content.encode("utf-8"))
def export_entities_excel(self, entities: list[ExportEntity]) -> bytes:
@@ -250,9 +250,9 @@ class ExportManager:
raise ImportError("pandas is required for Excel export")
# 准备数据
data = []
data = []
for e in entities:
row = {
row = {
"ID": e.id,
"名称": e.name,
"类型": e.type,
@@ -262,29 +262,29 @@ class ExportManager:
}
# 添加属性
for attr_name, attr_value in e.attributes.items():
row[f"属性:{attr_name}"] = attr_value
row[f"属性:{attr_name}"] = attr_value
data.append(row)
df = pd.DataFrame(data)
df = pd.DataFrame(data)
# 写入 Excel
output = io.BytesIO()
with pd.ExcelWriter(output, engine="openpyxl") as writer:
df.to_excel(writer, sheet_name="实体列表", index=False)
output = io.BytesIO()
with pd.ExcelWriter(output, engine = "openpyxl") as writer:
df.to_excel(writer, sheet_name = "实体列表", index = False)
# 调整列宽
worksheet = writer.sheets["实体列表"]
worksheet = writer.sheets["实体列表"]
for column in worksheet.columns:
max_length = 0
column_letter = column[0].column_letter
max_length = 0
column_letter = column[0].column_letter
for cell in column:
try:
if len(str(cell.value)) > max_length:
max_length = len(str(cell.value))
max_length = len(str(cell.value))
except (AttributeError, TypeError, ValueError):
pass
adjusted_width = min(max_length + 2, 50)
worksheet.column_dimensions[column_letter].width = adjusted_width
adjusted_width = min(max_length + 2, 50)
worksheet.column_dimensions[column_letter].width = adjusted_width
return output.getvalue()
@@ -295,24 +295,24 @@ class ExportManager:
Returns:
CSV 字符串
"""
output = io.StringIO()
output = io.StringIO()
# 收集所有可能的属性列
all_attrs = set()
all_attrs = set()
for e in entities:
all_attrs.update(e.attributes.keys())
# 表头
headers = ["ID", "名称", "类型", "定义", "别名", "提及次数"] + [
headers = ["ID", "名称", "类型", "定义", "别名", "提及次数"] + [
f"属性:{a}" for a in sorted(all_attrs)
]
writer = csv.writer(output)
writer = csv.writer(output)
writer.writerow(headers)
# 数据行
for e in entities:
row = [e.id, e.name, e.type, e.definition, ", ".join(e.aliases), e.mention_count]
row = [e.id, e.name, e.type, e.definition, ", ".join(e.aliases), e.mention_count]
for attr in sorted(all_attrs):
row.append(e.attributes.get(attr, ""))
writer.writerow(row)
@@ -327,8 +327,8 @@ class ExportManager:
CSV 字符串
"""
output = io.StringIO()
writer = csv.writer(output)
output = io.StringIO()
writer = csv.writer(output)
writer.writerow(["ID", "源实体", "目标实体", "关系类型", "置信度", "证据"])
for r in relations:
@@ -345,7 +345,7 @@ class ExportManager:
Returns:
Markdown 字符串
"""
lines = [
lines = [
f"# {transcript.name}",
"",
f"**类型**: {transcript.type}",
@@ -369,10 +369,10 @@ class ExportManager:
]
)
for seg in transcript.segments:
speaker = seg.get("speaker", "Unknown")
start = seg.get("start", 0)
end = seg.get("end", 0)
text = seg.get("text", "")
speaker = seg.get("speaker", "Unknown")
start = seg.get("start", 0)
end = seg.get("end", 0)
text = seg.get("text", "")
lines.append(f"**[{start:.1f}s - {end:.1f}s] {speaker}**: {text}")
lines.append("")
@@ -387,12 +387,12 @@ class ExportManager:
]
)
for mention in transcript.entity_mentions:
entity_id = mention.get("entity_id", "")
entity = entities_map.get(entity_id)
entity_name = entity.name if entity else mention.get("entity_name", "Unknown")
entity_type = entity.type if entity else "Unknown"
position = mention.get("position", "")
context = mention.get("context", "")[:50] + "..." if mention.get("context") else ""
entity_id = mention.get("entity_id", "")
entity = entities_map.get(entity_id)
entity_name = entity.name if entity else mention.get("entity_name", "Unknown")
entity_type = entity.type if entity else "Unknown"
position = mention.get("position", "")
context = mention.get("context", "")[:50] + "..." if mention.get("context") else ""
lines.append(f"| {entity_name} | {entity_type} | {position} | {context} |")
return "\n".join(lines)
@@ -404,7 +404,7 @@ class ExportManager:
entities: list[ExportEntity],
relations: list[ExportRelation],
transcripts: list[ExportTranscript],
summary: str = "",
summary: str = "",
) -> bytes:
"""
导出项目报告为 PDF 格式
@@ -415,29 +415,29 @@ class ExportManager:
if not REPORTLAB_AVAILABLE:
raise ImportError("reportlab is required for PDF export")
output = io.BytesIO()
doc = SimpleDocTemplate(
output, pagesize=A4, rightMargin=72, leftMargin=72, topMargin=72, bottomMargin=18
output = io.BytesIO()
doc = SimpleDocTemplate(
output, pagesize = A4, rightMargin = 72, leftMargin = 72, topMargin = 72, bottomMargin = 18
)
# 样式
styles = getSampleStyleSheet()
title_style = ParagraphStyle(
styles = getSampleStyleSheet()
title_style = ParagraphStyle(
"CustomTitle",
parent=styles["Heading1"],
fontSize=24,
spaceAfter=30,
textColor=colors.HexColor("#2c3e50"),
parent = styles["Heading1"],
fontSize = 24,
spaceAfter = 30,
textColor = colors.HexColor("#2c3e50"),
)
heading_style = ParagraphStyle(
heading_style = ParagraphStyle(
"CustomHeading",
parent=styles["Heading2"],
fontSize=16,
spaceAfter=12,
textColor=colors.HexColor("#34495e"),
parent = styles["Heading2"],
fontSize = 16,
spaceAfter = 12,
textColor = colors.HexColor("#34495e"),
)
story = []
story = []
# 标题页
story.append(Paragraph("InsightFlow 项目报告", title_style))
@@ -452,7 +452,7 @@ class ExportManager:
# 统计概览
story.append(Paragraph("项目概览", heading_style))
stats_data = [
stats_data = [
["指标", "数值"],
["实体数量", str(len(entities))],
["关系数量", str(len(relations))],
@@ -460,14 +460,14 @@ class ExportManager:
]
# 按类型统计实体
type_counts = {}
type_counts = {}
for e in entities:
type_counts[e.type] = type_counts.get(e.type, 0) + 1
type_counts[e.type] = type_counts.get(e.type, 0) + 1
for etype, count in sorted(type_counts.items()):
stats_data.append([f"{etype} 实体", str(count)])
stats_table = Table(stats_data, colWidths=[3 * inch, 2 * inch])
stats_table = Table(stats_data, colWidths = [3 * inch, 2 * inch])
stats_table.setStyle(
TableStyle(
[
@@ -496,8 +496,8 @@ class ExportManager:
story.append(PageBreak())
story.append(Paragraph("实体列表", heading_style))
entity_data = [["名称", "类型", "提及次数", "定义"]]
for e in sorted(entities, key=lambda x: x.mention_count, reverse=True)[
entity_data = [["名称", "类型", "提及次数", "定义"]]
for e in sorted(entities, key = lambda x: x.mention_count, reverse = True)[
:50
]: # 限制前50个
entity_data.append(
@@ -509,8 +509,8 @@ class ExportManager:
]
)
entity_table = Table(
entity_data, colWidths=[1.5 * inch, 1 * inch, 1 * inch, 2.5 * inch]
entity_table = Table(
entity_data, colWidths = [1.5 * inch, 1 * inch, 1 * inch, 2.5 * inch]
)
entity_table.setStyle(
TableStyle(
@@ -534,12 +534,12 @@ class ExportManager:
story.append(PageBreak())
story.append(Paragraph("关系列表", heading_style))
relation_data = [["源实体", "关系", "目标实体", "置信度"]]
relation_data = [["源实体", "关系", "目标实体", "置信度"]]
for r in relations[:100]: # 限制前100个
relation_data.append([r.source, r.relation_type, r.target, f"{r.confidence:.2f}"])
relation_table = Table(
relation_data, colWidths=[2 * inch, 1.5 * inch, 2 * inch, 1 * inch]
relation_table = Table(
relation_data, colWidths = [2 * inch, 1.5 * inch, 2 * inch, 1 * inch]
)
relation_table.setStyle(
TableStyle(
@@ -574,7 +574,7 @@ class ExportManager:
Returns:
JSON 字符串
"""
data = {
data = {
"project_id": project_id,
"project_name": project_name,
"export_time": datetime.now().isoformat(),
@@ -613,16 +613,16 @@ class ExportManager:
],
}
return json.dumps(data, ensure_ascii=False, indent=2)
return json.dumps(data, ensure_ascii = False, indent = 2)
# 全局导出管理器实例
_export_manager = None
_export_manager = None
def get_export_manager(db_manager=None) -> None:
def get_export_manager(db_manager = None) -> None:
"""获取导出管理器实例"""
global _export_manager
if _export_manager is None:
_export_manager = ExportManager(db_manager)
_export_manager = ExportManager(db_manager)
return _export_manager