fix: auto-fix code issues (cron)

- 修复重复导入/字段
- 修复异常处理 (将裸 except Exception 改为具体异常类型)
- 修复PEP8格式问题
- 清理未使用导入
- 添加 UUID_LENGTH 常量替代魔法数字
- 添加 DEFAULT_RATE_LIMIT, MASTER_KEY_RATE_LIMIT, IP_RATE_LIMIT 常量
- 添加 MAX_TEXT_LENGTH, DEFAULT_TIMEOUT 常量

涉及文件:
- backend/main.py
- backend/db_manager.py
- backend/llm_client.py
- backend/neo4j_manager.py
- backend/tingwu_client.py
- backend/tenant_manager.py
- backend/growth_manager.py
- backend/workflow_manager.py
- backend/image_processor.py
- backend/multimodal_entity_linker.py
- backend/multimodal_processor.py
- backend/plugin_manager.py
- backend/rate_limiter.py
This commit is contained in:
OpenClaw Bot
2026-03-01 03:06:06 +08:00
parent ea58b6fe43
commit 1f33d203e8
13 changed files with 141 additions and 85 deletions

View File

@@ -38,6 +38,14 @@ from pydantic import BaseModel, Field
# Configure logger
logger = logging.getLogger(__name__)
# Constants
DEFAULT_RATE_LIMIT = 60 # 默认每分钟请求限制
MASTER_KEY_RATE_LIMIT = 1000 # Master key 限流
IP_RATE_LIMIT = 10 # IP 限流
MAX_TEXT_LENGTH = 3000 # 最大文本长度
UUID_LENGTH = 8 # UUID 截断长度
DEFAULT_TIMEOUT = 60.0 # 默认超时时间
# Add backend directory to path for imports
backend_dir = os.path.dirname(os.path.abspath(__file__))
if backend_dir not in sys.path:
@@ -101,7 +109,7 @@ except ImportError:
REASONER_AVAILABLE = False
try:
from export_manager import ExportEntity, ExportRelation, ExportTranscript, get_export_manager
from export_manager import get_export_manager
EXPORT_AVAILABLE = True
except ImportError:
@@ -490,7 +498,7 @@ async def rate_limit_middleware(request: Request, call_next):
if x_api_key and x_api_key == MASTER_KEY:
# Master key 有更高的限流
config = RateLimitConfig(requests_per_minute=1000)
config = RateLimitConfig(requests_per_minute=MASTER_KEY_RATE_LIMIT)
limit_key = f"master:{x_api_key[:16]}"
elif hasattr(request.state, "api_key") and request.state.api_key:
# 使用 API Key 的限流配置
@@ -500,7 +508,7 @@ async def rate_limit_middleware(request: Request, call_next):
else:
# IP 限流(未认证用户)
client_ip = request.client.host if request.client else "unknown"
config = RateLimitConfig(requests_per_minute=10)
config = RateLimitConfig(requests_per_minute=IP_RATE_LIMIT)
limit_key = f"ip:{client_ip}"
# 检查限流
@@ -547,7 +555,7 @@ async def rate_limit_middleware(request: Request, call_next):
ip_address=request.client.host if request.client else "",
user_agent=request.headers.get("User-Agent", ""),
)
except Exception as e:
except (RuntimeError, ValueError, TypeError) as e:
# 日志记录失败不应影响主流程
print(f"Failed to log API call: {e}")
@@ -1062,7 +1070,7 @@ async def create_manual_entity(
if existing:
return {"id": existing.id, "name": existing.name, "type": existing.type, "existed": True}
entity_id = str(uuid.uuid4())[:8]
entity_id = str(uuid.uuid4())[:UUID_LENGTH]
new_entity = db.create_entity(
Entity(
id=entity_id,
@@ -1079,7 +1087,7 @@ async def create_manual_entity(
if transcript:
text = transcript["full_text"]
mention = EntityMention(
id=str(uuid.uuid4())[:8],
id=str(uuid.uuid4())[:UUID_LENGTH],
entity_id=entity_id,
transcript_id=entity.transcript_id,
start_pos=entity.start_pos,
@@ -1227,7 +1235,7 @@ async def create_project(project: ProjectCreate, _=Depends(verify_api_key)):
raise HTTPException(status_code=500, detail="Database not available")
db = get_db_manager()
project_id = str(uuid.uuid4())[:8]
project_id = str(uuid.uuid4())[:UUID_LENGTH]
p = db.create_project(project_id, project.name, project.description)
return {"id": p.id, "name": p.name, "description": p.description}
@@ -1263,7 +1271,7 @@ async def upload_audio(project_id: str, file: UploadFile = File(...), _=Depends(
raw_entities, raw_relations = extract_entities_with_llm(tw_result["full_text"])
# 保存转录记录
transcript_id = str(uuid.uuid4())[:8]
transcript_id = str(uuid.uuid4())[:UUID_LENGTH]
db.save_transcript(
transcript_id=transcript_id,
project_id=project_id,
@@ -1290,7 +1298,7 @@ async def upload_audio(project_id: str, file: UploadFile = File(...), _=Depends(
else:
new_ent = db.create_entity(
Entity(
id=str(uuid.uuid4())[:8],
id=str(uuid.uuid4())[:UUID_LENGTH],
project_id=project_id,
name=raw_ent["name"],
type=raw_ent.get("type", "OTHER"),
@@ -1313,7 +1321,7 @@ async def upload_audio(project_id: str, file: UploadFile = File(...), _=Depends(
if pos == -1:
break
mention = EntityMention(
id=str(uuid.uuid4())[:8],
id=str(uuid.uuid4())[:UUID_LENGTH],
entity_id=entity_name_to_id[name],
transcript_id=transcript_id,
start_pos=pos,
@@ -1374,11 +1382,11 @@ async def upload_document(project_id: str, file: UploadFile = File(...), _=Depen
processor = get_doc_processor()
try:
result = processor.process(content, file.filename)
except Exception as e:
except (ValueError, TypeError, RuntimeError, IOError) as e:
raise HTTPException(status_code=400, detail=f"Document processing failed: {str(e)}")
# 保存文档转录记录
transcript_id = str(uuid.uuid4())[:8]
transcript_id = str(uuid.uuid4())[:UUID_LENGTH]
db.save_transcript(
transcript_id=transcript_id,
project_id=project_id,
@@ -1411,7 +1419,7 @@ async def upload_document(project_id: str, file: UploadFile = File(...), _=Depen
else:
new_ent = db.create_entity(
Entity(
id=str(uuid.uuid4())[:8],
id=str(uuid.uuid4())[:UUID_LENGTH],
project_id=project_id,
name=raw_ent["name"],
type=raw_ent.get("type", "OTHER"),
@@ -1437,7 +1445,7 @@ async def upload_document(project_id: str, file: UploadFile = File(...), _=Depen
if pos == -1:
break
mention = EntityMention(
id=str(uuid.uuid4())[:8],
id=str(uuid.uuid4())[:UUID_LENGTH],
entity_id=entity_name_to_id[name],
transcript_id=transcript_id,
start_pos=pos,
@@ -2282,7 +2290,7 @@ async def create_attribute_template_endpoint(
raise HTTPException(status_code=404, detail="Project not found")
new_template = AttributeTemplate(
id=str(uuid.uuid4())[:8],
id=str(uuid.uuid4())[:UUID_LENGTH],
project_id=project_id,
name=template.name,
type=template.type,
@@ -2423,7 +2431,7 @@ async def set_entity_attribute_endpoint(
(id, entity_id, attribute_name, old_value, new_value, changed_by, changed_at, change_reason)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)""",
(
str(uuid.uuid4())[:8],
str(uuid.uuid4())[:UUID_LENGTH],
entity_id,
attr.name,
existing["value"],
@@ -2444,7 +2452,7 @@ async def set_entity_attribute_endpoint(
attr_id = existing["id"]
else:
# 创建
attr_id = str(uuid.uuid4())[:8]
attr_id = str(uuid.uuid4())[:UUID_LENGTH]
conn.execute(
"""INSERT INTO entity_attributes
(id, entity_id, template_id, name, type, value, options, created_at, updated_at)
@@ -2458,7 +2466,7 @@ async def set_entity_attribute_endpoint(
(id, entity_id, attribute_name, old_value, new_value, changed_by, changed_at, change_reason)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)""",
(
str(uuid.uuid4())[:8],
str(uuid.uuid4())[:UUID_LENGTH],
entity_id,
attr.name,
None,
@@ -2499,7 +2507,7 @@ async def batch_set_entity_attributes_endpoint(
template = db.get_attribute_template(attr_data.template_id)
if template:
new_attr = EntityAttribute(
id=str(uuid.uuid4())[:8],
id=str(uuid.uuid4())[:UUID_LENGTH],
entity_id=entity_id,
template_id=attr_data.template_id,
value=attr_data.value,
@@ -2937,7 +2945,7 @@ async def export_report_pdf_endpoint(project_id: str, _=Depends(verify_api_key))
reasoner = get_knowledge_reasoner()
summary_result = reasoner.generate_project_summary(project_id, db)
summary = summary_result.get("summary", "")
except Exception:
except (RuntimeError, ValueError, TypeError):
pass
export_mgr = get_export_manager()
@@ -3113,7 +3121,7 @@ async def neo4j_status(_=Depends(verify_api_key)):
"uri": manager.uri if connected else None,
"message": "Connected" if connected else "Not connected",
}
except Exception as e:
except (RuntimeError, ValueError, TypeError, ConnectionError) as e:
return {"available": True, "connected": False, "message": str(e)}
@app.post("/api/v1/neo4j/sync")
@@ -3658,7 +3666,7 @@ async def create_workflow_endpoint(request: WorkflowCreate, _=Depends(verify_api
try:
workflow = Workflow(
id=str(uuid.uuid4())[:8],
id=str(uuid.uuid4())[:UUID_LENGTH],
name=request.name,
description=request.description,
workflow_type=request.workflow_type,
@@ -3847,7 +3855,7 @@ async def trigger_workflow_endpoint(
)
except ValueError as e:
raise HTTPException(status_code=404, detail=str(e))
except Exception as e:
except (RuntimeError, TypeError, ConnectionError) as e:
raise HTTPException(status_code=500, detail=str(e))
@app.get(
@@ -3924,7 +3932,7 @@ async def create_webhook_endpoint(request: WebhookCreate, _=Depends(verify_api_k
try:
webhook = WebhookConfig(
id=str(uuid.uuid4())[:8],
id=str(uuid.uuid4())[:UUID_LENGTH],
name=request.name,
webhook_type=request.webhook_type,
url=request.url,
@@ -4175,7 +4183,7 @@ async def upload_video_endpoint(
processor = get_multimodal_processor(frame_interval=extract_interval)
# 处理视频
video_id = str(uuid.uuid4())[:8]
video_id = str(uuid.uuid4())[:UUID_LENGTH]
result = processor.process_video(video_data, file.filename, project_id, video_id)
if not result.success:
@@ -4252,7 +4260,7 @@ async def upload_video_endpoint(
else:
new_ent = db.create_entity(
Entity(
id=str(uuid.uuid4())[:8],
id=str(uuid.uuid4())[:UUID_LENGTH],
project_id=project_id,
name=raw_ent["name"],
type=raw_ent.get("type", "OTHER"),
@@ -4268,7 +4276,7 @@ async def upload_video_endpoint(
(id, project_id, entity_id, modality, source_id, source_type, text_snippet, confidence, created_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)""",
(
str(uuid.uuid4())[:8],
str(uuid.uuid4())[:UUID_LENGTH],
project_id,
entity_name_to_id[raw_ent["name"]],
"video",
@@ -4356,7 +4364,7 @@ async def upload_image_endpoint(
processor = get_image_processor()
# 处理图片
image_id = str(uuid.uuid4())[:8]
image_id = str(uuid.uuid4())[:UUID_LENGTH]
result = processor.process_image(image_data, file.filename, image_id, detect_type)
if not result.success:
@@ -4406,7 +4414,7 @@ async def upload_image_endpoint(
if not existing:
new_ent = db.create_entity(
Entity(
id=str(uuid.uuid4())[:8],
id=str(uuid.uuid4())[:UUID_LENGTH],
project_id=project_id,
name=entity.name,
type=entity.type,
@@ -4424,7 +4432,7 @@ async def upload_image_endpoint(
(id, project_id, entity_id, modality, source_id, source_type, text_snippet, confidence, created_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)""",
(
str(uuid.uuid4())[:8],
str(uuid.uuid4())[:UUID_LENGTH],
project_id,
entity_id,
"image",
@@ -5156,7 +5164,7 @@ async def create_plugin_endpoint(request: PluginCreate, _=Depends(verify_api_key
manager = get_plugin_manager_instance()
plugin = Plugin(
id=str(uuid.uuid4())[:8],
id=str(uuid.uuid4())[:UUID_LENGTH],
name=request.name,
plugin_type=request.plugin_type,
project_id=request.project_id,
@@ -8056,7 +8064,7 @@ async def create_tenant(
"status": tenant.status,
"created_at": tenant.created_at.isoformat(),
}
except Exception as e:
except (RuntimeError, ValueError, TypeError) as e:
raise HTTPException(status_code=400, detail=str(e))
@app.get("/api/v1/tenants", tags=["Tenants"])
@@ -8162,7 +8170,7 @@ async def add_domain(tenant_id: str, request: AddDomainRequest, _=Depends(verify
"verification_instructions": instructions,
"created_at": domain.created_at.isoformat(),
}
except Exception as e:
except (RuntimeError, ValueError, TypeError) as e:
raise HTTPException(status_code=400, detail=str(e))
@app.get("/api/v1/tenants/{tenant_id}/domains", tags=["Tenants"])
@@ -8313,7 +8321,7 @@ async def invite_member(
"status": member.status,
"invited_at": member.invited_at.isoformat(),
}
except Exception as e:
except (RuntimeError, ValueError, TypeError) as e:
raise HTTPException(status_code=400, detail=str(e))
@app.get("/api/v1/tenants/{tenant_id}/members", tags=["Tenants"])
@@ -9193,7 +9201,7 @@ async def create_subscription(
"trial_end": subscription.trial_end.isoformat() if subscription.trial_end else None,
"created_at": subscription.created_at.isoformat(),
}
except Exception as e:
except (RuntimeError, ValueError, TypeError) as e:
raise HTTPException(status_code=400, detail=str(e))
@app.get("/api/v1/tenants/{tenant_id}/subscription", tags=["Subscriptions"])
@@ -9259,7 +9267,7 @@ async def change_subscription_plan(
"status": updated.status,
"message": "Plan changed successfully",
}
except Exception as e:
except (RuntimeError, ValueError, TypeError) as e:
raise HTTPException(status_code=400, detail=str(e))
@app.post("/api/v1/tenants/{tenant_id}/subscription/cancel", tags=["Subscriptions"])
@@ -9288,7 +9296,7 @@ async def cancel_subscription(
"canceled_at": updated.canceled_at.isoformat() if updated.canceled_at else None,
"message": "Subscription cancelled",
}
except Exception as e:
except (RuntimeError, ValueError, TypeError) as e:
raise HTTPException(status_code=400, detail=str(e))
# Usage APIs
@@ -9498,7 +9506,7 @@ async def request_refund(
"status": refund.status,
"requested_at": refund.requested_at.isoformat(),
}
except Exception as e:
except (RuntimeError, ValueError, TypeError) as e:
raise HTTPException(status_code=400, detail=str(e))
@app.get("/api/v1/tenants/{tenant_id}/refunds", tags=["Subscriptions"])
@@ -9636,7 +9644,7 @@ async def create_stripe_checkout(
)
return session
except Exception as e:
except (RuntimeError, ValueError, TypeError) as e:
raise HTTPException(status_code=400, detail=str(e))
@app.post("/api/v1/tenants/{tenant_id}/checkout/alipay", tags=["Subscriptions"])
@@ -9658,7 +9666,7 @@ async def create_alipay_order(
)
return order
except Exception as e:
except (RuntimeError, ValueError, TypeError) as e:
raise HTTPException(status_code=400, detail=str(e))
@app.post("/api/v1/tenants/{tenant_id}/checkout/wechat", tags=["Subscriptions"])
@@ -9680,7 +9688,7 @@ async def create_wechat_order(
)
return order
except Exception as e:
except (RuntimeError, ValueError, TypeError) as e:
raise HTTPException(status_code=400, detail=str(e))
# Webhook Handlers
@@ -9876,7 +9884,7 @@ async def create_sso_config_endpoint(
"default_role": sso_config.default_role,
"created_at": sso_config.created_at.isoformat(),
}
except Exception as e:
except (RuntimeError, ValueError, TypeError) as e:
raise HTTPException(status_code=400, detail=str(e))
@app.get("/api/v1/tenants/{tenant_id}/sso-configs", tags=["Enterprise"])
@@ -10036,7 +10044,7 @@ async def create_scim_config_endpoint(
"sync_interval_minutes": scim_config.sync_interval_minutes,
"created_at": scim_config.created_at.isoformat(),
}
except Exception as e:
except (RuntimeError, ValueError, TypeError) as e:
raise HTTPException(status_code=400, detail=str(e))
@app.get("/api/v1/tenants/{tenant_id}/scim-configs", tags=["Enterprise"])
@@ -10174,7 +10182,7 @@ async def create_audit_export_endpoint(
"expires_at": export.expires_at.isoformat() if export.expires_at else None,
"created_at": export.created_at.isoformat(),
}
except Exception as e:
except (RuntimeError, ValueError, TypeError) as e:
raise HTTPException(status_code=400, detail=str(e))
@app.get("/api/v1/tenants/{tenant_id}/audit-exports", tags=["Enterprise"])
@@ -10309,7 +10317,7 @@ async def create_retention_policy_endpoint(
"is_active": new_policy.is_active,
"created_at": new_policy.created_at.isoformat(),
}
except Exception as e:
except (RuntimeError, ValueError, TypeError) as e:
raise HTTPException(status_code=400, detail=str(e))
@app.get("/api/v1/tenants/{tenant_id}/retention-policies", tags=["Enterprise"])
@@ -11885,7 +11893,7 @@ async def track_event_endpoint(request: TrackEventRequest):
)
return {"success": True, "event_id": event.id, "timestamp": event.timestamp.isoformat()}
except Exception as e:
except (RuntimeError, ValueError, TypeError) as e:
raise HTTPException(status_code=500, detail=str(e))
@app.get("/api/v1/analytics/dashboard/{tenant_id}", tags=["Growth & Analytics"])
@@ -12052,7 +12060,7 @@ async def create_experiment_endpoint(request: CreateExperimentRequest, created_b
"variants": experiment.variants,
"created_at": experiment.created_at,
}
except Exception as e:
except (RuntimeError, ValueError, TypeError) as e:
raise HTTPException(status_code=400, detail=str(e))
@app.get("/api/v1/experiments", tags=["Growth & Analytics"])
@@ -12231,7 +12239,7 @@ async def create_email_template_endpoint(request: CreateEmailTemplateRequest):
"variables": template.variables,
"created_at": template.created_at,
}
except Exception as e:
except (RuntimeError, ValueError, TypeError) as e:
raise HTTPException(status_code=400, detail=str(e))
@app.get("/api/v1/email/templates", tags=["Growth & Analytics"])