chore: auto release commit (2026-09-14 15:11:41)
All checks were successful
技能自动化发布 / release (push) Successful in 9s
All checks were successful
技能自动化发布 / release (push) Successful in 9s
This commit is contained in:
@@ -697,3 +697,292 @@ def cmd_stats() -> int:
|
||||
log.exception("task_failed task_type=stats")
|
||||
print("ERROR:QUERY_FAILED 统计查询异常,详见统一日志")
|
||||
return 1
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# RPA 命令:发票信息提取
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def cmd_extract_invoices(
|
||||
username: str,
|
||||
password: str,
|
||||
profile_dir: str,
|
||||
headless: bool = False,
|
||||
detail_mode: bool = False,
|
||||
) -> int:
|
||||
"""从网站提取发票信息。"""
|
||||
log = _get_task_logger()
|
||||
task_type = "extract_invoices"
|
||||
|
||||
with job_context(skill=SKILL_SLUG):
|
||||
log.info(
|
||||
"task_start task_type=%s username=%s detail_mode=%s",
|
||||
task_type,
|
||||
username[:3] + "***",
|
||||
detail_mode,
|
||||
)
|
||||
emit("开始提取发票信息", skill=SKILL_SLUG, stage="rpa_start")
|
||||
|
||||
try:
|
||||
ok, reason = check_entitlement(SKILL_SLUG)
|
||||
if not ok:
|
||||
log.warning(
|
||||
"entitlement_failed task_type=%s stage=auth error_code=ENTITLEMENT_DENIED",
|
||||
task_type,
|
||||
)
|
||||
emit("鉴权失败,已记录诊断信息", type="warn", skill=SKILL_SLUG, stage="auth")
|
||||
finish(
|
||||
status="failed",
|
||||
message=reason,
|
||||
skill=SKILL_SLUG,
|
||||
error_code="ENTITLEMENT_DENIED",
|
||||
stage="auth",
|
||||
)
|
||||
print(f"ERROR:ENTITLEMENT_DENIED {reason}")
|
||||
return 1
|
||||
|
||||
log.info("entitlement_ok task_type=%s stage=auth", task_type)
|
||||
|
||||
# 导入RPA模块
|
||||
from service.rpa import run_invoice_rpa_with_video
|
||||
|
||||
# 运行RPA
|
||||
result = asyncio.run(
|
||||
run_invoice_rpa_with_video(
|
||||
username=username,
|
||||
password=password,
|
||||
profile_dir=profile_dir,
|
||||
skill_slug=SKILL_SLUG,
|
||||
skill_data_dir=get_skill_root(),
|
||||
headless=headless,
|
||||
detail_mode=detail_mode,
|
||||
title="开始提取发票信息",
|
||||
closing_title="发票信息提取完成",
|
||||
)
|
||||
)
|
||||
|
||||
if result.success:
|
||||
invoice_count = result.data.get("total_count", 0)
|
||||
log.info(
|
||||
"rpa_success task_type=%s invoice_count=%s stage=extraction",
|
||||
task_type,
|
||||
invoice_count,
|
||||
)
|
||||
emit(f"成功提取 {invoice_count} 张发票信息", skill=SKILL_SLUG, stage="rpa_complete")
|
||||
|
||||
# 保存到数据库
|
||||
try:
|
||||
from service.rpa_invoice_service import save_rpa_invoice_data
|
||||
|
||||
batch_id = uuid.uuid4().hex[:12]
|
||||
record_id = save_rpa_invoice_data(
|
||||
batch_id=batch_id,
|
||||
source_url="https://sandbox.jc2009.com/industries/campus/smartcampus/app/finance/invoice-precheck",
|
||||
invoice_data=result.data,
|
||||
username=username,
|
||||
status="extracted",
|
||||
)
|
||||
|
||||
log.info(
|
||||
"rpa_data_saved record_id=%s batch_id=%s",
|
||||
record_id,
|
||||
batch_id,
|
||||
)
|
||||
|
||||
# 添加记录ID到结果中
|
||||
result.data["record_id"] = record_id
|
||||
result.data["batch_id"] = batch_id
|
||||
|
||||
except Exception as save_error:
|
||||
log.warning("rpa_data_save_failed error=%s", str(save_error))
|
||||
# 即使保存失败,也继续输出结果
|
||||
|
||||
# 输出结果
|
||||
_print_json(result.data)
|
||||
|
||||
finish(
|
||||
status="success",
|
||||
message=f"成功提取 {invoice_count} 张发票信息",
|
||||
skill=SKILL_SLUG,
|
||||
stage="extraction",
|
||||
)
|
||||
return 0
|
||||
else:
|
||||
log.warning(
|
||||
"rpa_failed task_type=%s error=%s stage=%s",
|
||||
task_type,
|
||||
result.error,
|
||||
result.stage,
|
||||
)
|
||||
emit("发票信息提取失败", type="warn", skill=SKILL_SLUG, stage="rpa_failed")
|
||||
|
||||
finish(
|
||||
status="failed",
|
||||
message=result.error or "发票信息提取失败",
|
||||
skill=SKILL_SLUG,
|
||||
error_code="RPA_FAILED",
|
||||
stage=result.stage or "unknown",
|
||||
)
|
||||
print(f"ERROR:RPA_FAILED {result.error}")
|
||||
return 1
|
||||
|
||||
except JobStopped:
|
||||
raise
|
||||
except Exception:
|
||||
log.exception(
|
||||
"task_failed task_type=%s",
|
||||
task_type,
|
||||
)
|
||||
emit("任务失败,已记录诊断信息", type="warn", skill=SKILL_SLUG, stage="rpa_error")
|
||||
finish(
|
||||
status="failed",
|
||||
message="发票信息提取异常,详见统一日志",
|
||||
skill=SKILL_SLUG,
|
||||
stage="rpa_error",
|
||||
)
|
||||
return 1
|
||||
|
||||
|
||||
def cmd_list_rpa_invoices(
|
||||
limit: int = 20,
|
||||
batch_id: Optional[str] = None,
|
||||
username: Optional[str] = None,
|
||||
status: Optional[str] = None,
|
||||
) -> int:
|
||||
"""查询RPA提取的发票数据。"""
|
||||
log = _get_task_logger()
|
||||
task_type = "list_rpa_invoices"
|
||||
|
||||
with job_context(skill=SKILL_SLUG):
|
||||
log.info(
|
||||
"task_start task_type=%s limit=%s batch_id=%s username=%s status=%s",
|
||||
task_type,
|
||||
limit,
|
||||
batch_id,
|
||||
username,
|
||||
status,
|
||||
)
|
||||
|
||||
try:
|
||||
from service.rpa_invoice_service import list_rpa_invoices
|
||||
|
||||
records = list_rpa_invoices(
|
||||
limit=limit,
|
||||
batch_id=batch_id,
|
||||
username=username,
|
||||
status=status,
|
||||
)
|
||||
|
||||
_print_json({
|
||||
"ok": True,
|
||||
"count": len(records),
|
||||
"records": records,
|
||||
})
|
||||
|
||||
return 0
|
||||
|
||||
except Exception as e:
|
||||
log.exception("task_failed task_type=%s", task_type)
|
||||
print(f"ERROR:QUERY_FAILED 查询RPA提取数据失败: {str(e)}")
|
||||
return 1
|
||||
|
||||
|
||||
def cmd_show_rpa_invoice(record_id: int) -> int:
|
||||
"""查看RPA提取的发票数据详情。"""
|
||||
log = _get_task_logger()
|
||||
task_type = "show_rpa_invoice"
|
||||
|
||||
with job_context(skill=SKILL_SLUG):
|
||||
log.info("task_start task_type=%s record_id=%s", task_type, record_id)
|
||||
|
||||
try:
|
||||
from service.rpa_invoice_service import get_rpa_invoice_data
|
||||
|
||||
record = get_rpa_invoice_data(record_id)
|
||||
if not record:
|
||||
print(f"ERROR:RECORD_NOT_FOUND 未找到记录 ID={record_id}")
|
||||
return 1
|
||||
|
||||
_print_json(record)
|
||||
return 0
|
||||
|
||||
except Exception as e:
|
||||
log.exception("task_failed task_type=%s", task_type)
|
||||
print(f"ERROR:QUERY_FAILED 查询RPA发票详情失败: {str(e)}")
|
||||
return 1
|
||||
|
||||
|
||||
def cmd_rpa_invoice_stats() -> int:
|
||||
"""获取RPA提取统计信息。"""
|
||||
log = _get_task_logger()
|
||||
task_type = "rpa_invoice_stats"
|
||||
|
||||
with job_context(skill=SKILL_SLUG):
|
||||
log.info("task_start task_type=%s", task_type)
|
||||
|
||||
try:
|
||||
from service.rpa_invoice_service import get_rpa_invoice_stats
|
||||
|
||||
stats = get_rpa_invoice_stats()
|
||||
_print_json(stats)
|
||||
return 0
|
||||
|
||||
except Exception as e:
|
||||
log.exception("task_failed task_type=%s", task_type)
|
||||
print(f"ERROR:QUERY_FAILED 获取RPA统计失败: {str(e)}")
|
||||
return 1
|
||||
|
||||
|
||||
def cmd_test_rpa_connection(
|
||||
username: str,
|
||||
password: str,
|
||||
profile_dir: str,
|
||||
) -> int:
|
||||
"""测试RPA连接和登录。"""
|
||||
log = _get_task_logger()
|
||||
task_type = "test_rpa_connection"
|
||||
|
||||
with job_context(skill=SKILL_SLUG):
|
||||
log.info(
|
||||
"task_start task_type=%s username=%s",
|
||||
task_type,
|
||||
username[:3] + "***",
|
||||
)
|
||||
emit("测试RPA连接", skill=SKILL_SLUG, stage="test_start")
|
||||
|
||||
try:
|
||||
# 导入RPA模块
|
||||
from service.rpa import close_browser_context, start_browser_session
|
||||
from service.rpa.login_handler import login_if_needed
|
||||
|
||||
# 启动浏览器
|
||||
pw, context, page = asyncio.run(
|
||||
start_browser_session(profile_dir, headless=False)
|
||||
)
|
||||
|
||||
# 测试登录
|
||||
login_success = asyncio.run(
|
||||
login_if_needed(page, username, password, wait_sec=30)
|
||||
)
|
||||
|
||||
# 关闭浏览器
|
||||
asyncio.run(close_browser_context(pw, context))
|
||||
|
||||
if login_success:
|
||||
log.info("rpa_connection_test_success task_type=%s", task_type)
|
||||
emit("RPA连接测试成功", skill=SKILL_SLUG, stage="test_success")
|
||||
_print_json({"success": True, "message": "连接和登录测试成功"})
|
||||
finish(status="success", message="RPA连接测试成功", skill=SKILL_SLUG, stage="test")
|
||||
return 0
|
||||
else:
|
||||
log.warning("rpa_connection_test_failed task_type=%s", task_type)
|
||||
emit("RPA连接测试失败", type="warn", skill=SKILL_SLUG, stage="test_failed")
|
||||
_print_json({"success": False, "message": "登录失败"})
|
||||
finish(status="failed", message="登录失败", skill=SKILL_SLUG, stage="test")
|
||||
return 1
|
||||
|
||||
except Exception as e:
|
||||
log.exception("task_failed task_type=%s", task_type)
|
||||
emit("RPA连接测试异常", type="warn", skill=SKILL_SLUG, stage="test_error")
|
||||
finish(status="failed", message=f"测试异常: {str(e)}", skill=SKILL_SLUG, stage="test")
|
||||
return 1
|
||||
|
||||
Reference in New Issue
Block a user