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

@@ -14,6 +14,10 @@ from datetime import datetime
DB_PATH = os.getenv("DB_PATH", "/app/data/insightflow.db") DB_PATH = os.getenv("DB_PATH", "/app/data/insightflow.db")
# Constants
UUID_LENGTH = 8 # UUID 截断长度
@dataclass @dataclass
class Project: class Project:
id: str id: str
@@ -22,6 +26,7 @@ class Project:
created_at: str = "" created_at: str = ""
updated_at: str = "" updated_at: str = ""
@dataclass @dataclass
class Entity: class Entity:
id: str id: str
@@ -42,6 +47,7 @@ class Entity:
if self.attributes is None: if self.attributes is None:
self.attributes = {} self.attributes = {}
@dataclass @dataclass
class AttributeTemplate: class AttributeTemplate:
"""属性模板定义""" """属性模板定义"""
@@ -62,6 +68,7 @@ class AttributeTemplate:
if self.options is None: if self.options is None:
self.options = [] self.options = []
@dataclass @dataclass
class EntityAttribute: class EntityAttribute:
"""实体属性值""" """实体属性值"""
@@ -82,6 +89,7 @@ class EntityAttribute:
if self.options is None: if self.options is None:
self.options = [] self.options = []
@dataclass @dataclass
class AttributeHistory: class AttributeHistory:
"""属性变更历史""" """属性变更历史"""
@@ -95,6 +103,7 @@ class AttributeHistory:
changed_at: str = "" changed_at: str = ""
change_reason: str = "" change_reason: str = ""
@dataclass @dataclass
class EntityMention: class EntityMention:
id: str id: str
@@ -105,6 +114,7 @@ class EntityMention:
text_snippet: str text_snippet: str
confidence: float = 1.0 confidence: float = 1.0
class DatabaseManager: class DatabaseManager:
def __init__(self, db_path: str = DB_PATH): def __init__(self, db_path: str = DB_PATH):
self.db_path = db_path self.db_path = db_path
@@ -321,15 +331,14 @@ class DatabaseManager:
conn.execute( conn.execute(
"""INSERT INTO entity_mentions (id, entity_id, transcript_id, start_pos, end_pos, text_snippet, confidence) """INSERT INTO entity_mentions (id, entity_id, transcript_id, start_pos, end_pos, text_snippet, confidence)
VALUES (?, ?, ?, ?, ?, ?, ?)""", VALUES (?, ?, ?, ?, ?, ?, ?)""",
( (mention.id,
mention.id, mention.entity_id,
mention.entity_id, mention.transcript_id,
mention.transcript_id, mention.start_pos,
mention.start_pos, mention.end_pos,
mention.end_pos, mention.text_snippet,
mention.text_snippet, mention.confidence,
mention.confidence, ),
),
) )
conn.commit() conn.commit()
conn.close() conn.close()
@@ -358,7 +367,12 @@ class DatabaseManager:
now = datetime.now().isoformat() now = datetime.now().isoformat()
conn.execute( conn.execute(
"INSERT INTO transcripts (id, project_id, filename, full_text, type, created_at) VALUES (?, ?, ?, ?, ?, ?)", "INSERT INTO transcripts (id, project_id, filename, full_text, type, created_at) VALUES (?, ?, ?, ?, ?, ?)",
(transcript_id, project_id, filename, full_text, transcript_type, now), (transcript_id,
project_id,
filename,
full_text,
transcript_type,
now),
) )
conn.commit() conn.commit()
conn.close() conn.close()
@@ -401,7 +415,7 @@ class DatabaseManager:
transcript_id: str = "", transcript_id: str = "",
): ):
conn = self.get_conn() conn = self.get_conn()
relation_id = str(uuid.uuid4())[:8] relation_id = str(uuid.uuid4())[:UUID_LENGTH]
now = datetime.now().isoformat() now = datetime.now().isoformat()
conn.execute( conn.execute(
"""INSERT INTO entity_relations """INSERT INTO entity_relations
@@ -485,7 +499,7 @@ class DatabaseManager:
conn.close() conn.close()
return existing["id"] return existing["id"]
term_id = str(uuid.uuid4())[:8] term_id = str(uuid.uuid4())[:UUID_LENGTH]
conn.execute( conn.execute(
"INSERT INTO glossary (id, project_id, term, pronunciation, frequency) VALUES (?, ?, ?, ?, ?)", "INSERT INTO glossary (id, project_id, term, pronunciation, frequency) VALUES (?, ?, ?, ?, ?)",
(term_id, project_id, term, pronunciation, 1), (term_id, project_id, term, pronunciation, 1),
@@ -836,7 +850,7 @@ class DatabaseManager:
(id, entity_id, template_id, old_value, new_value, changed_by, changed_at, change_reason) (id, entity_id, template_id, old_value, new_value, changed_by, changed_at, change_reason)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)""", VALUES (?, ?, ?, ?, ?, ?, ?, ?)""",
( (
str(uuid.uuid4())[:8], str(uuid.uuid4())[:UUID_LENGTH],
attr.entity_id, attr.entity_id,
attr.template_id, attr.template_id,
old_value, old_value,
@@ -915,7 +929,7 @@ class DatabaseManager:
(id, entity_id, template_id, old_value, new_value, changed_by, changed_at, change_reason) (id, entity_id, template_id, old_value, new_value, changed_by, changed_at, change_reason)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)""", VALUES (?, ?, ?, ?, ?, ?, ?, ?)""",
( (
str(uuid.uuid4())[:8], str(uuid.uuid4())[:UUID_LENGTH],
entity_id, entity_id,
template_id, template_id,
old_row["value"], old_row["value"],
@@ -1387,9 +1401,11 @@ class DatabaseManager:
conn.close() conn.close()
return stats return stats
# Singleton instance # Singleton instance
_db_manager = None _db_manager = None
def get_db_manager() -> DatabaseManager: def get_db_manager() -> DatabaseManager:
global _db_manager global _db_manager
if _db_manager is None: if _db_manager is None:

View File

@@ -456,7 +456,7 @@ class GrowthManager:
await client.post( await client.post(
"https://api.mixpanel.com/track", headers=headers, json=[payload], timeout=10.0 "https://api.mixpanel.com/track", headers=headers, json=[payload], timeout=10.0
) )
except Exception as e: except (RuntimeError, ValueError, TypeError) as e:
print(f"Failed to send to Mixpanel: {e}") print(f"Failed to send to Mixpanel: {e}")
async def _send_to_amplitude(self, event: AnalyticsEvent): async def _send_to_amplitude(self, event: AnalyticsEvent):
@@ -484,7 +484,7 @@ class GrowthManager:
json=payload, json=payload,
timeout=10.0, timeout=10.0,
) )
except Exception as e: except (RuntimeError, ValueError, TypeError) as e:
print(f"Failed to send to Amplitude: {e}") print(f"Failed to send to Amplitude: {e}")
async def _update_user_profile( async def _update_user_profile(

View File

@@ -10,6 +10,9 @@ import os
import uuid import uuid
from dataclasses import dataclass from dataclasses import dataclass
# Constants
UUID_LENGTH = 8 # UUID 截断长度
# 尝试导入图像处理库 # 尝试导入图像处理库
try: try:
from PIL import Image, ImageEnhance, ImageFilter from PIL import Image, ImageEnhance, ImageFilter
@@ -369,7 +372,7 @@ class ImageProcessor:
Returns: Returns:
图片处理结果 图片处理结果
""" """
image_id = image_id or str(uuid.uuid4())[:8] image_id = image_id or str(uuid.uuid4())[:UUID_LENGTH]
if not PIL_AVAILABLE: if not PIL_AVAILABLE:
return ImageProcessingResult( return ImageProcessingResult(

View File

@@ -15,11 +15,13 @@ import httpx
KIMI_API_KEY = os.getenv("KIMI_API_KEY", "") KIMI_API_KEY = os.getenv("KIMI_API_KEY", "")
KIMI_BASE_URL = os.getenv("KIMI_BASE_URL", "https://api.kimi.com/coding") KIMI_BASE_URL = os.getenv("KIMI_BASE_URL", "https://api.kimi.com/coding")
@dataclass @dataclass
class ChatMessage: class ChatMessage:
role: str role: str
content: str content: str
@dataclass @dataclass
class EntityExtractionResult: class EntityExtractionResult:
name: str name: str
@@ -27,6 +29,7 @@ class EntityExtractionResult:
definition: str definition: str
confidence: float confidence: float
@dataclass @dataclass
class RelationExtractionResult: class RelationExtractionResult:
source: str source: str
@@ -34,6 +37,7 @@ class RelationExtractionResult:
type: str type: str
confidence: float confidence: float
class LLMClient: class LLMClient:
"""Kimi API 客户端""" """Kimi API 客户端"""
@@ -163,7 +167,7 @@ class LLMClient:
for r in data.get("relations", []) for r in data.get("relations", [])
] ]
return entities, relations return entities, relations
except Exception as e: except (RuntimeError, ValueError, TypeError) as e:
print(f"Parse extraction result failed: {e}") print(f"Parse extraction result failed: {e}")
return [], [] return [], []
@@ -254,9 +258,11 @@ class LLMClient:
messages = [ChatMessage(role="user", content=prompt)] messages = [ChatMessage(role="user", content=prompt)]
return await self.chat(messages, temperature=0.3) return await self.chat(messages, temperature=0.3)
# Singleton instance # Singleton instance
_llm_client = None _llm_client = None
def get_llm_client() -> LLMClient: def get_llm_client() -> LLMClient:
global _llm_client global _llm_client
if _llm_client is None: if _llm_client is None:

View File

@@ -38,6 +38,14 @@ from pydantic import BaseModel, Field
# Configure logger # Configure logger
logger = logging.getLogger(__name__) 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 # Add backend directory to path for imports
backend_dir = os.path.dirname(os.path.abspath(__file__)) backend_dir = os.path.dirname(os.path.abspath(__file__))
if backend_dir not in sys.path: if backend_dir not in sys.path:
@@ -101,7 +109,7 @@ except ImportError:
REASONER_AVAILABLE = False REASONER_AVAILABLE = False
try: try:
from export_manager import ExportEntity, ExportRelation, ExportTranscript, get_export_manager from export_manager import get_export_manager
EXPORT_AVAILABLE = True EXPORT_AVAILABLE = True
except ImportError: 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: if x_api_key and x_api_key == MASTER_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]}" limit_key = f"master:{x_api_key[:16]}"
elif hasattr(request.state, "api_key") and request.state.api_key: elif hasattr(request.state, "api_key") and request.state.api_key:
# 使用 API Key 的限流配置 # 使用 API Key 的限流配置
@@ -500,7 +508,7 @@ async def rate_limit_middleware(request: Request, call_next):
else: else:
# IP 限流(未认证用户) # IP 限流(未认证用户)
client_ip = request.client.host if request.client else "unknown" 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}" 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 "", ip_address=request.client.host if request.client else "",
user_agent=request.headers.get("User-Agent", ""), 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}") print(f"Failed to log API call: {e}")
@@ -1062,7 +1070,7 @@ async def create_manual_entity(
if existing: if existing:
return {"id": existing.id, "name": existing.name, "type": existing.type, "existed": True} 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( new_entity = db.create_entity(
Entity( Entity(
id=entity_id, id=entity_id,
@@ -1079,7 +1087,7 @@ async def create_manual_entity(
if transcript: if transcript:
text = transcript["full_text"] text = transcript["full_text"]
mention = EntityMention( mention = EntityMention(
id=str(uuid.uuid4())[:8], id=str(uuid.uuid4())[:UUID_LENGTH],
entity_id=entity_id, entity_id=entity_id,
transcript_id=entity.transcript_id, transcript_id=entity.transcript_id,
start_pos=entity.start_pos, 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") raise HTTPException(status_code=500, detail="Database not available")
db = get_db_manager() 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) p = db.create_project(project_id, project.name, project.description)
return {"id": p.id, "name": p.name, "description": p.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"]) 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( db.save_transcript(
transcript_id=transcript_id, transcript_id=transcript_id,
project_id=project_id, project_id=project_id,
@@ -1290,7 +1298,7 @@ async def upload_audio(project_id: str, file: UploadFile = File(...), _=Depends(
else: else:
new_ent = db.create_entity( new_ent = db.create_entity(
Entity( Entity(
id=str(uuid.uuid4())[:8], id=str(uuid.uuid4())[:UUID_LENGTH],
project_id=project_id, project_id=project_id,
name=raw_ent["name"], name=raw_ent["name"],
type=raw_ent.get("type", "OTHER"), type=raw_ent.get("type", "OTHER"),
@@ -1313,7 +1321,7 @@ async def upload_audio(project_id: str, file: UploadFile = File(...), _=Depends(
if pos == -1: if pos == -1:
break break
mention = EntityMention( mention = EntityMention(
id=str(uuid.uuid4())[:8], id=str(uuid.uuid4())[:UUID_LENGTH],
entity_id=entity_name_to_id[name], entity_id=entity_name_to_id[name],
transcript_id=transcript_id, transcript_id=transcript_id,
start_pos=pos, start_pos=pos,
@@ -1374,11 +1382,11 @@ async def upload_document(project_id: str, file: UploadFile = File(...), _=Depen
processor = get_doc_processor() processor = get_doc_processor()
try: try:
result = processor.process(content, file.filename) 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)}") 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( db.save_transcript(
transcript_id=transcript_id, transcript_id=transcript_id,
project_id=project_id, project_id=project_id,
@@ -1411,7 +1419,7 @@ async def upload_document(project_id: str, file: UploadFile = File(...), _=Depen
else: else:
new_ent = db.create_entity( new_ent = db.create_entity(
Entity( Entity(
id=str(uuid.uuid4())[:8], id=str(uuid.uuid4())[:UUID_LENGTH],
project_id=project_id, project_id=project_id,
name=raw_ent["name"], name=raw_ent["name"],
type=raw_ent.get("type", "OTHER"), type=raw_ent.get("type", "OTHER"),
@@ -1437,7 +1445,7 @@ async def upload_document(project_id: str, file: UploadFile = File(...), _=Depen
if pos == -1: if pos == -1:
break break
mention = EntityMention( mention = EntityMention(
id=str(uuid.uuid4())[:8], id=str(uuid.uuid4())[:UUID_LENGTH],
entity_id=entity_name_to_id[name], entity_id=entity_name_to_id[name],
transcript_id=transcript_id, transcript_id=transcript_id,
start_pos=pos, start_pos=pos,
@@ -2282,7 +2290,7 @@ async def create_attribute_template_endpoint(
raise HTTPException(status_code=404, detail="Project not found") raise HTTPException(status_code=404, detail="Project not found")
new_template = AttributeTemplate( new_template = AttributeTemplate(
id=str(uuid.uuid4())[:8], id=str(uuid.uuid4())[:UUID_LENGTH],
project_id=project_id, project_id=project_id,
name=template.name, name=template.name,
type=template.type, 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) (id, entity_id, attribute_name, old_value, new_value, changed_by, changed_at, change_reason)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)""", VALUES (?, ?, ?, ?, ?, ?, ?, ?)""",
( (
str(uuid.uuid4())[:8], str(uuid.uuid4())[:UUID_LENGTH],
entity_id, entity_id,
attr.name, attr.name,
existing["value"], existing["value"],
@@ -2444,7 +2452,7 @@ async def set_entity_attribute_endpoint(
attr_id = existing["id"] attr_id = existing["id"]
else: else:
# 创建 # 创建
attr_id = str(uuid.uuid4())[:8] attr_id = str(uuid.uuid4())[:UUID_LENGTH]
conn.execute( conn.execute(
"""INSERT INTO entity_attributes """INSERT INTO entity_attributes
(id, entity_id, template_id, name, type, value, options, created_at, updated_at) (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) (id, entity_id, attribute_name, old_value, new_value, changed_by, changed_at, change_reason)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)""", VALUES (?, ?, ?, ?, ?, ?, ?, ?)""",
( (
str(uuid.uuid4())[:8], str(uuid.uuid4())[:UUID_LENGTH],
entity_id, entity_id,
attr.name, attr.name,
None, None,
@@ -2499,7 +2507,7 @@ async def batch_set_entity_attributes_endpoint(
template = db.get_attribute_template(attr_data.template_id) template = db.get_attribute_template(attr_data.template_id)
if template: if template:
new_attr = EntityAttribute( new_attr = EntityAttribute(
id=str(uuid.uuid4())[:8], id=str(uuid.uuid4())[:UUID_LENGTH],
entity_id=entity_id, entity_id=entity_id,
template_id=attr_data.template_id, template_id=attr_data.template_id,
value=attr_data.value, 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() reasoner = get_knowledge_reasoner()
summary_result = reasoner.generate_project_summary(project_id, db) summary_result = reasoner.generate_project_summary(project_id, db)
summary = summary_result.get("summary", "") summary = summary_result.get("summary", "")
except Exception: except (RuntimeError, ValueError, TypeError):
pass pass
export_mgr = get_export_manager() export_mgr = get_export_manager()
@@ -3113,7 +3121,7 @@ async def neo4j_status(_=Depends(verify_api_key)):
"uri": manager.uri if connected else None, "uri": manager.uri if connected else None,
"message": "Connected" if connected else "Not connected", "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)} return {"available": True, "connected": False, "message": str(e)}
@app.post("/api/v1/neo4j/sync") @app.post("/api/v1/neo4j/sync")
@@ -3658,7 +3666,7 @@ async def create_workflow_endpoint(request: WorkflowCreate, _=Depends(verify_api
try: try:
workflow = Workflow( workflow = Workflow(
id=str(uuid.uuid4())[:8], id=str(uuid.uuid4())[:UUID_LENGTH],
name=request.name, name=request.name,
description=request.description, description=request.description,
workflow_type=request.workflow_type, workflow_type=request.workflow_type,
@@ -3847,7 +3855,7 @@ async def trigger_workflow_endpoint(
) )
except ValueError as e: except ValueError as e:
raise HTTPException(status_code=404, detail=str(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)) raise HTTPException(status_code=500, detail=str(e))
@app.get( @app.get(
@@ -3924,7 +3932,7 @@ async def create_webhook_endpoint(request: WebhookCreate, _=Depends(verify_api_k
try: try:
webhook = WebhookConfig( webhook = WebhookConfig(
id=str(uuid.uuid4())[:8], id=str(uuid.uuid4())[:UUID_LENGTH],
name=request.name, name=request.name,
webhook_type=request.webhook_type, webhook_type=request.webhook_type,
url=request.url, url=request.url,
@@ -4175,7 +4183,7 @@ async def upload_video_endpoint(
processor = get_multimodal_processor(frame_interval=extract_interval) 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) result = processor.process_video(video_data, file.filename, project_id, video_id)
if not result.success: if not result.success:
@@ -4252,7 +4260,7 @@ async def upload_video_endpoint(
else: else:
new_ent = db.create_entity( new_ent = db.create_entity(
Entity( Entity(
id=str(uuid.uuid4())[:8], id=str(uuid.uuid4())[:UUID_LENGTH],
project_id=project_id, project_id=project_id,
name=raw_ent["name"], name=raw_ent["name"],
type=raw_ent.get("type", "OTHER"), 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) (id, project_id, entity_id, modality, source_id, source_type, text_snippet, confidence, created_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)""", VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)""",
( (
str(uuid.uuid4())[:8], str(uuid.uuid4())[:UUID_LENGTH],
project_id, project_id,
entity_name_to_id[raw_ent["name"]], entity_name_to_id[raw_ent["name"]],
"video", "video",
@@ -4356,7 +4364,7 @@ async def upload_image_endpoint(
processor = get_image_processor() 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) result = processor.process_image(image_data, file.filename, image_id, detect_type)
if not result.success: if not result.success:
@@ -4406,7 +4414,7 @@ async def upload_image_endpoint(
if not existing: if not existing:
new_ent = db.create_entity( new_ent = db.create_entity(
Entity( Entity(
id=str(uuid.uuid4())[:8], id=str(uuid.uuid4())[:UUID_LENGTH],
project_id=project_id, project_id=project_id,
name=entity.name, name=entity.name,
type=entity.type, 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) (id, project_id, entity_id, modality, source_id, source_type, text_snippet, confidence, created_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)""", VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)""",
( (
str(uuid.uuid4())[:8], str(uuid.uuid4())[:UUID_LENGTH],
project_id, project_id,
entity_id, entity_id,
"image", "image",
@@ -5156,7 +5164,7 @@ async def create_plugin_endpoint(request: PluginCreate, _=Depends(verify_api_key
manager = get_plugin_manager_instance() manager = get_plugin_manager_instance()
plugin = Plugin( plugin = Plugin(
id=str(uuid.uuid4())[:8], id=str(uuid.uuid4())[:UUID_LENGTH],
name=request.name, name=request.name,
plugin_type=request.plugin_type, plugin_type=request.plugin_type,
project_id=request.project_id, project_id=request.project_id,
@@ -8056,7 +8064,7 @@ async def create_tenant(
"status": tenant.status, "status": tenant.status,
"created_at": tenant.created_at.isoformat(), "created_at": tenant.created_at.isoformat(),
} }
except Exception as e: except (RuntimeError, ValueError, TypeError) as e:
raise HTTPException(status_code=400, detail=str(e)) raise HTTPException(status_code=400, detail=str(e))
@app.get("/api/v1/tenants", tags=["Tenants"]) @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, "verification_instructions": instructions,
"created_at": domain.created_at.isoformat(), "created_at": domain.created_at.isoformat(),
} }
except Exception as e: except (RuntimeError, ValueError, TypeError) as e:
raise HTTPException(status_code=400, detail=str(e)) raise HTTPException(status_code=400, detail=str(e))
@app.get("/api/v1/tenants/{tenant_id}/domains", tags=["Tenants"]) @app.get("/api/v1/tenants/{tenant_id}/domains", tags=["Tenants"])
@@ -8313,7 +8321,7 @@ async def invite_member(
"status": member.status, "status": member.status,
"invited_at": member.invited_at.isoformat(), "invited_at": member.invited_at.isoformat(),
} }
except Exception as e: except (RuntimeError, ValueError, TypeError) as e:
raise HTTPException(status_code=400, detail=str(e)) raise HTTPException(status_code=400, detail=str(e))
@app.get("/api/v1/tenants/{tenant_id}/members", tags=["Tenants"]) @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, "trial_end": subscription.trial_end.isoformat() if subscription.trial_end else None,
"created_at": subscription.created_at.isoformat(), "created_at": subscription.created_at.isoformat(),
} }
except Exception as e: except (RuntimeError, ValueError, TypeError) as e:
raise HTTPException(status_code=400, detail=str(e)) raise HTTPException(status_code=400, detail=str(e))
@app.get("/api/v1/tenants/{tenant_id}/subscription", tags=["Subscriptions"]) @app.get("/api/v1/tenants/{tenant_id}/subscription", tags=["Subscriptions"])
@@ -9259,7 +9267,7 @@ async def change_subscription_plan(
"status": updated.status, "status": updated.status,
"message": "Plan changed successfully", "message": "Plan changed successfully",
} }
except Exception as e: except (RuntimeError, ValueError, TypeError) as e:
raise HTTPException(status_code=400, detail=str(e)) raise HTTPException(status_code=400, detail=str(e))
@app.post("/api/v1/tenants/{tenant_id}/subscription/cancel", tags=["Subscriptions"]) @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, "canceled_at": updated.canceled_at.isoformat() if updated.canceled_at else None,
"message": "Subscription cancelled", "message": "Subscription cancelled",
} }
except Exception as e: except (RuntimeError, ValueError, TypeError) as e:
raise HTTPException(status_code=400, detail=str(e)) raise HTTPException(status_code=400, detail=str(e))
# Usage APIs # Usage APIs
@@ -9498,7 +9506,7 @@ async def request_refund(
"status": refund.status, "status": refund.status,
"requested_at": refund.requested_at.isoformat(), "requested_at": refund.requested_at.isoformat(),
} }
except Exception as e: except (RuntimeError, ValueError, TypeError) as e:
raise HTTPException(status_code=400, detail=str(e)) raise HTTPException(status_code=400, detail=str(e))
@app.get("/api/v1/tenants/{tenant_id}/refunds", tags=["Subscriptions"]) @app.get("/api/v1/tenants/{tenant_id}/refunds", tags=["Subscriptions"])
@@ -9636,7 +9644,7 @@ async def create_stripe_checkout(
) )
return session return session
except Exception as e: except (RuntimeError, ValueError, TypeError) as e:
raise HTTPException(status_code=400, detail=str(e)) raise HTTPException(status_code=400, detail=str(e))
@app.post("/api/v1/tenants/{tenant_id}/checkout/alipay", tags=["Subscriptions"]) @app.post("/api/v1/tenants/{tenant_id}/checkout/alipay", tags=["Subscriptions"])
@@ -9658,7 +9666,7 @@ async def create_alipay_order(
) )
return order return order
except Exception as e: except (RuntimeError, ValueError, TypeError) as e:
raise HTTPException(status_code=400, detail=str(e)) raise HTTPException(status_code=400, detail=str(e))
@app.post("/api/v1/tenants/{tenant_id}/checkout/wechat", tags=["Subscriptions"]) @app.post("/api/v1/tenants/{tenant_id}/checkout/wechat", tags=["Subscriptions"])
@@ -9680,7 +9688,7 @@ async def create_wechat_order(
) )
return order return order
except Exception as e: except (RuntimeError, ValueError, TypeError) as e:
raise HTTPException(status_code=400, detail=str(e)) raise HTTPException(status_code=400, detail=str(e))
# Webhook Handlers # Webhook Handlers
@@ -9876,7 +9884,7 @@ async def create_sso_config_endpoint(
"default_role": sso_config.default_role, "default_role": sso_config.default_role,
"created_at": sso_config.created_at.isoformat(), "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)) raise HTTPException(status_code=400, detail=str(e))
@app.get("/api/v1/tenants/{tenant_id}/sso-configs", tags=["Enterprise"]) @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, "sync_interval_minutes": scim_config.sync_interval_minutes,
"created_at": scim_config.created_at.isoformat(), "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)) raise HTTPException(status_code=400, detail=str(e))
@app.get("/api/v1/tenants/{tenant_id}/scim-configs", tags=["Enterprise"]) @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, "expires_at": export.expires_at.isoformat() if export.expires_at else None,
"created_at": export.created_at.isoformat(), "created_at": export.created_at.isoformat(),
} }
except Exception as e: except (RuntimeError, ValueError, TypeError) as e:
raise HTTPException(status_code=400, detail=str(e)) raise HTTPException(status_code=400, detail=str(e))
@app.get("/api/v1/tenants/{tenant_id}/audit-exports", tags=["Enterprise"]) @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, "is_active": new_policy.is_active,
"created_at": new_policy.created_at.isoformat(), "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)) raise HTTPException(status_code=400, detail=str(e))
@app.get("/api/v1/tenants/{tenant_id}/retention-policies", tags=["Enterprise"]) @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()} 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)) raise HTTPException(status_code=500, detail=str(e))
@app.get("/api/v1/analytics/dashboard/{tenant_id}", tags=["Growth & Analytics"]) @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, "variants": experiment.variants,
"created_at": experiment.created_at, "created_at": experiment.created_at,
} }
except Exception as e: except (RuntimeError, ValueError, TypeError) as e:
raise HTTPException(status_code=400, detail=str(e)) raise HTTPException(status_code=400, detail=str(e))
@app.get("/api/v1/experiments", tags=["Growth & Analytics"]) @app.get("/api/v1/experiments", tags=["Growth & Analytics"])
@@ -12231,7 +12239,7 @@ async def create_email_template_endpoint(request: CreateEmailTemplateRequest):
"variables": template.variables, "variables": template.variables,
"created_at": template.created_at, "created_at": template.created_at,
} }
except Exception as e: except (RuntimeError, ValueError, TypeError) as e:
raise HTTPException(status_code=400, detail=str(e)) raise HTTPException(status_code=400, detail=str(e))
@app.get("/api/v1/email/templates", tags=["Growth & Analytics"]) @app.get("/api/v1/email/templates", tags=["Growth & Analytics"])

View File

@@ -8,6 +8,9 @@ import uuid
from dataclasses import dataclass from dataclasses import dataclass
from difflib import SequenceMatcher from difflib import SequenceMatcher
# Constants
UUID_LENGTH = 8 # UUID 截断长度
# 尝试导入embedding库 # 尝试导入embedding库
try: try:
NUMPY_AVAILABLE = True NUMPY_AVAILABLE = True
@@ -247,7 +250,7 @@ class MultimodalEntityLinker:
if result and result.matched_entity_id: if result and result.matched_entity_id:
link = EntityLink( link = EntityLink(
id=str(uuid.uuid4())[:8], id=str(uuid.uuid4())[:UUID_LENGTH],
project_id=project_id, project_id=project_id,
source_entity_id=ent1.get("id"), source_entity_id=ent1.get("id"),
target_entity_id=result.matched_entity_id, target_entity_id=result.matched_entity_id,
@@ -461,7 +464,7 @@ class MultimodalEntityLinker:
多模态实体记录 多模态实体记录
""" """
return MultimodalEntity( return MultimodalEntity(
id=str(uuid.uuid4())[:8], id=str(uuid.uuid4())[:UUID_LENGTH],
entity_id=entity_id, entity_id=entity_id,
project_id=project_id, project_id=project_id,
name="", # 将在后续填充 name="", # 将在后续填充

View File

@@ -12,6 +12,9 @@ import uuid
from dataclasses import dataclass from dataclasses import dataclass
from pathlib import Path from pathlib import Path
# Constants
UUID_LENGTH = 8 # UUID 截断长度
# 尝试导入OCR库 # 尝试导入OCR库
try: try:
import pytesseract import pytesseract
@@ -340,7 +343,7 @@ class MultimodalProcessor:
Returns: Returns:
视频处理结果 视频处理结果
""" """
video_id = video_id or str(uuid.uuid4())[:8] video_id = video_id or str(uuid.uuid4())[:UUID_LENGTH]
try: try:
# 保存视频文件 # 保存视频文件
@@ -375,7 +378,7 @@ class MultimodalProcessor:
ocr_text, confidence = self.perform_ocr(frame_path) ocr_text, confidence = self.perform_ocr(frame_path)
frame = VideoFrame( frame = VideoFrame(
id=str(uuid.uuid4())[:8], id=str(uuid.uuid4())[:UUID_LENGTH],
video_id=video_id, video_id=video_id,
frame_number=frame_number, frame_number=frame_number,
timestamp=timestamp, timestamp=timestamp,

View File

@@ -111,7 +111,7 @@ class Neo4jManager:
# 验证连接 # 验证连接
self._driver.verify_connectivity() self._driver.verify_connectivity()
logger.info(f"Connected to Neo4j at {self.uri}") logger.info(f"Connected to Neo4j at {self.uri}")
except Exception as e: except (RuntimeError, ValueError, TypeError) as e:
logger.error(f"Failed to connect to Neo4j: {e}") logger.error(f"Failed to connect to Neo4j: {e}")
self._driver = None self._driver = None

View File

@@ -11,7 +11,6 @@ import json
import os import os
import sqlite3 import sqlite3
import time import time
import urllib.parse
import uuid import uuid
from dataclasses import dataclass, field from dataclasses import dataclass, field
from datetime import datetime from datetime import datetime
@@ -20,6 +19,9 @@ from typing import Any
import httpx import httpx
# Constants
UUID_LENGTH = 8 # UUID 截断长度
# WebDAV 支持 # WebDAV 支持
try: try:
import webdav4.client as webdav_client import webdav4.client as webdav_client
@@ -318,7 +320,7 @@ class PluginManager:
) )
config_id = existing["id"] config_id = existing["id"]
else: else:
config_id = str(uuid.uuid4())[:8] config_id = str(uuid.uuid4())[:UUID_LENGTH]
conn.execute( conn.execute(
"""INSERT INTO plugin_configs """INSERT INTO plugin_configs
(id, plugin_id, config_key, config_value, is_encrypted, created_at, updated_at) (id, plugin_id, config_key, config_value, is_encrypted, created_at, updated_at)
@@ -400,7 +402,7 @@ class ChromeExtensionHandler:
expires_days: int = None, expires_days: int = None,
) -> ChromeExtensionToken: ) -> ChromeExtensionToken:
"""创建 Chrome 扩展令牌""" """创建 Chrome 扩展令牌"""
token_id = str(uuid.uuid4())[:8] token_id = str(uuid.uuid4())[:UUID_LENGTH]
# 生成随机令牌 # 生成随机令牌
raw_token = f"if_ext_{base64.urlsafe_b64encode(os.urandom(32)).decode('utf-8').rstrip('=')}" raw_token = f"if_ext_{base64.urlsafe_b64encode(os.urandom(32)).decode('utf-8').rstrip('=')}"
@@ -563,7 +565,7 @@ class ChromeExtensionHandler:
return {"success": False, "error": "Insufficient permissions"} return {"success": False, "error": "Insufficient permissions"}
# 创建转录记录(将网页作为文档处理) # 创建转录记录(将网页作为文档处理)
transcript_id = str(uuid.uuid4())[:8] transcript_id = str(uuid.uuid4())[:UUID_LENGTH]
now = datetime.now().isoformat() now = datetime.now().isoformat()
# 构建完整文本 # 构建完整文本
@@ -604,7 +606,7 @@ class BotHandler:
secret: str = "", secret: str = "",
) -> BotSession: ) -> BotSession:
"""创建机器人会话""" """创建机器人会话"""
bot_id = str(uuid.uuid4())[:8] bot_id = str(uuid.uuid4())[:UUID_LENGTH]
now = datetime.now().isoformat() now = datetime.now().isoformat()
conn = self.pm.db.get_conn() conn = self.pm.db.get_conn()
@@ -932,7 +934,7 @@ class WebhookIntegration:
trigger_events: list[str] = None, trigger_events: list[str] = None,
) -> WebhookEndpoint: ) -> WebhookEndpoint:
"""创建 Webhook 端点""" """创建 Webhook 端点"""
endpoint_id = str(uuid.uuid4())[:8] endpoint_id = str(uuid.uuid4())[:UUID_LENGTH]
now = datetime.now().isoformat() now = datetime.now().isoformat()
conn = self.pm.db.get_conn() conn = self.pm.db.get_conn()
@@ -1155,7 +1157,7 @@ class WebDAVSyncManager:
sync_interval: int = 3600, sync_interval: int = 3600,
) -> WebDAVSync: ) -> WebDAVSync:
"""创建 WebDAV 同步配置""" """创建 WebDAV 同步配置"""
sync_id = str(uuid.uuid4())[:8] sync_id = str(uuid.uuid4())[:UUID_LENGTH]
now = datetime.now().isoformat() now = datetime.now().isoformat()
conn = self.pm.db.get_conn() conn = self.pm.db.get_conn()

View File

@@ -12,6 +12,7 @@ from collections.abc import Callable
from dataclasses import dataclass from dataclasses import dataclass
from functools import wraps from functools import wraps
@dataclass @dataclass
class RateLimitConfig: class RateLimitConfig:
"""限流配置""" """限流配置"""
@@ -20,6 +21,7 @@ class RateLimitConfig:
burst_size: int = 10 # 突发请求数 burst_size: int = 10 # 突发请求数
window_size: int = 60 # 窗口大小(秒) window_size: int = 60 # 窗口大小(秒)
@dataclass @dataclass
class RateLimitInfo: class RateLimitInfo:
"""限流信息""" """限流信息"""
@@ -29,6 +31,7 @@ class RateLimitInfo:
reset_time: int # 重置时间戳 reset_time: int # 重置时间戳
retry_after: int # 需要等待的秒数 retry_after: int # 需要等待的秒数
class SlidingWindowCounter: class SlidingWindowCounter:
"""滑动窗口计数器""" """滑动窗口计数器"""
@@ -60,6 +63,7 @@ class SlidingWindowCounter:
for k in old_keys: for k in old_keys:
self.requests.pop(k, None) self.requests.pop(k, None)
class RateLimiter: class RateLimiter:
"""API 限流器""" """API 限流器"""
@@ -155,9 +159,11 @@ class RateLimiter:
self.counters.clear() self.counters.clear()
self.configs.clear() self.configs.clear()
# 全局限流器实例 # 全局限流器实例
_rate_limiter: RateLimiter | None = None _rate_limiter: RateLimiter | None = None
def get_rate_limiter() -> RateLimiter: def get_rate_limiter() -> RateLimiter:
"""获取限流器实例""" """获取限流器实例"""
global _rate_limiter global _rate_limiter
@@ -166,6 +172,8 @@ def get_rate_limiter() -> RateLimiter:
return _rate_limiter return _rate_limiter
# 限流装饰器(用于函数级别限流) # 限流装饰器(用于函数级别限流)
def rate_limit(requests_per_minute: int = 60, key_func: Callable | None = None) -> None: def rate_limit(requests_per_minute: int = 60, key_func: Callable | None = None) -> None:
""" """
限流装饰器 限流装饰器
@@ -208,5 +216,6 @@ def rate_limit(requests_per_minute: int = 60, key_func: Callable | None = None)
return decorator return decorator
class RateLimitExceeded(Exception): class RateLimitExceeded(Exception):
"""限流异常""" """限流异常"""

View File

@@ -395,7 +395,7 @@ class TenantManager:
conn.commit() conn.commit()
logger.info("Tenant tables initialized successfully") logger.info("Tenant tables initialized successfully")
except Exception as e: except (RuntimeError, ValueError, TypeError) as e:
logger.error(f"Error initializing tenant tables: {e}") logger.error(f"Error initializing tenant tables: {e}")
raise raise
finally: finally:
@@ -760,7 +760,7 @@ class TenantManager:
return is_verified return is_verified
except Exception as e: except (RuntimeError, ValueError, TypeError) as e:
logger.error(f"Error verifying domain: {e}") logger.error(f"Error verifying domain: {e}")
return False return False
finally: finally:

View File

@@ -8,6 +8,7 @@ import time
from datetime import datetime from datetime import datetime
from typing import Any from typing import Any
class TingwuClient: class TingwuClient:
def __init__(self): def __init__(self):
self.access_key = os.getenv("ALI_ACCESS_KEY", "") self.access_key = os.getenv("ALI_ACCESS_KEY", "")
@@ -67,7 +68,7 @@ class TingwuClient:
# Fallback: 使用 mock # Fallback: 使用 mock
print("Tingwu SDK not available, using mock") print("Tingwu SDK not available, using mock")
return f"mock_task_{int(time.time())}" return f"mock_task_{int(time.time())}"
except Exception as e: except (RuntimeError, ValueError, TypeError) as e:
print(f"Tingwu API error: {e}") print(f"Tingwu API error: {e}")
return f"mock_task_{int(time.time())}" return f"mock_task_{int(time.time())}"
@@ -107,7 +108,7 @@ class TingwuClient:
except ImportError: except ImportError:
print("Tingwu SDK not available, using mock result") print("Tingwu SDK not available, using mock result")
return self._mock_result() return self._mock_result()
except Exception as e: except (RuntimeError, ValueError, TypeError) as e:
print(f"Get result error: {e}") print(f"Get result error: {e}")
return self._mock_result() return self._mock_result()

View File

@@ -15,7 +15,6 @@ import hashlib
import hmac import hmac
import json import json
import logging import logging
import urllib.parse
import uuid import uuid
from collections.abc import Callable from collections.abc import Callable
from dataclasses import dataclass, field from dataclasses import dataclass, field
@@ -29,6 +28,12 @@ from apscheduler.schedulers.asyncio import AsyncIOScheduler
from apscheduler.triggers.cron import CronTrigger from apscheduler.triggers.cron import CronTrigger
from apscheduler.triggers.interval import IntervalTrigger from apscheduler.triggers.interval import IntervalTrigger
# Constants
UUID_LENGTH = 8 # UUID 截断长度
DEFAULT_TIMEOUT = 300 # 默认超时时间(秒)
DEFAULT_RETRY_COUNT = 3 # 默认重试次数
DEFAULT_RETRY_DELAY = 5 # 默认重试延迟(秒)
# Configure logging # Configure logging
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -1073,7 +1078,7 @@ class WorkflowManager:
# 创建工作流执行日志 # 创建工作流执行日志
log = WorkflowLog( log = WorkflowLog(
id=str(uuid.uuid4())[:8], id=str(uuid.uuid4())[:UUID_LENGTH],
workflow_id=workflow_id, workflow_id=workflow_id,
status=TaskStatus.RUNNING.value, status=TaskStatus.RUNNING.value,
start_time=now, start_time=now,
@@ -1200,7 +1205,7 @@ class WorkflowManager:
# 创建任务日志 # 创建任务日志
task_log = WorkflowLog( task_log = WorkflowLog(
id=str(uuid.uuid4())[:8], id=str(uuid.uuid4())[:UUID_LENGTH],
workflow_id=task.workflow_id, workflow_id=task.workflow_id,
task_id=task.id, task_id=task.id,
status=TaskStatus.RUNNING.value, status=TaskStatus.RUNNING.value,