提交 065ffcc3 authored 作者: 贺阳's avatar 贺阳

定时清理向导生成的临时附件

上级 d9d75008
......@@ -25,5 +25,18 @@
<field name="active" eval="True"/>
</record>
<!-- 清理向导生成的临时附件-->
<record id="cron_cleanup_temp_attachments" model="ir.cron">
<field name="name">清理向导临时附件</field>
<field name="model_id" ref="model_batch_get_pod_info_wizard"/>
<field name="state">code</field>
<field name="code">model.cron_cleanup_temp_attachments()</field>
<field name='interval_number'>1</field>
<field name='interval_type'>days</field>
<field name="nextcall" eval="(DateTime.now().replace(hour=0, minute=0) + timedelta(days=1)).strftime('%Y-%m-%d %H:%M:%S')" />
<field name="numbercall">-1</field>
<field name="active" eval="True"/>
</record>
</data>
</odoo>
\ No newline at end of file
......@@ -32,8 +32,7 @@ class AIImageEditService:
start_time = time.time()
_logger.info(f"开始AI图片编辑,目标文字: {text_to_remove}")
print(f"开始AI图片编辑,目标文字: {text_to_remove}") # 添加print输出
try:
# 根据要移除的文字构建不同的提示词,强调保持清晰度
if "AGN" in text_to_remove and "UCLINK" in text_to_remove:
......@@ -70,23 +69,18 @@ class AIImageEditService:
if rsp.status_code == HTTPStatus.OK:
# 检查返回结果结构
_logger.info(f"API响应结构: {rsp}")
print(f"API响应结构: {rsp}")
# 检查任务状态
if hasattr(rsp, 'output') and hasattr(rsp.output, 'task_status'):
task_status = rsp.output.task_status
_logger.info(f"AI任务状态: {task_status}")
print(f"AI任务状态: {task_status}")
if task_status == "FAILED":
error_code = getattr(rsp.output, 'code', 'Unknown')
error_message = getattr(rsp.output, 'message', 'Unknown error')
_logger.error(f"AI任务失败 - 错误码: {error_code}, 错误信息: {error_message}")
print(f"AI任务失败 - 错误码: {error_code}, 错误信息: {error_message}")
return None
elif task_status != "SUCCEEDED":
_logger.warning(f"AI任务状态异常: {task_status}")
print(f"AI任务状态异常: {task_status}")
return None
# 安全地获取处理后图片的URL
......@@ -94,35 +88,23 @@ class AIImageEditService:
if hasattr(rsp, 'output') and hasattr(rsp.output, 'results') and len(rsp.output.results) > 0:
image_url = rsp.output.results[0].url
_logger.info(f"AI图片编辑成功,图片URL: {image_url}")
print(f"AI图片编辑成功,图片URL: {image_url}") # 添加print输出
# 下载图片并转换为base64
download_start_time = time.time()
edited_image_base64 = self.download_and_convert_to_base64(image_url)
download_end_time = time.time()
download_time = download_end_time - download_start_time
_logger.info(f"图片下载耗时: {download_time:.2f}秒")
total_time = time.time() - start_time
_logger.info(f"AI图片编辑总耗时: {total_time:.2f}秒")
print(f"AI图片编辑总耗时: {total_time:.2f}秒") # 添加print输出
return edited_image_base64
else:
_logger.error(f"API返回结果结构异常: {rsp}")
print(f"API返回结果结构异常: {rsp}")
return None
except (IndexError, AttributeError) as e:
_logger.error(f"解析API返回结果失败: {str(e)}")
_logger.error(f"完整响应: {rsp}")
print(f"解析API返回结果失败: {str(e)}")
print(f"完整响应: {rsp}")
return None
else:
_logger.error(f"AI图片编辑失败,HTTP返回码:{rsp.status_code}")
_logger.error(f"错误码:{rsp.code}")
_logger.error(f"错误信息:{rsp.message}")
print(f"AI图片编辑失败,HTTP返回码:{rsp.status_code}") # 添加print输出
return None
except Exception as e:
......
......@@ -8,10 +8,10 @@ import logging
import time
import requests
from odoo import models, fields, _
from odoo import models, fields, api, _
from odoo.exceptions import ValidationError
from .ai_image_edit_service import AIImageEditService
from datetime import datetime, timedelta
_logger = logging.getLogger(__name__)
......@@ -19,6 +19,82 @@ class BatchGetPodInfoWizard(models.TransientModel):
_name = 'batch.get.pod.info.wizard'
_description = 'Batch Get POD Info Wizard' # 批量获取POD信息向导
@api.model
def cron_cleanup_temp_attachments(self):
"""
定时清理向导生成的临时附件
每天早上8点执行,删除1天之前创建的temp_pod_开头的附件
"""
try:
# 计算1天前的时间(前一天23:59:59)
today = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
one_day_ago = today - timedelta(seconds=1) # 前一天23:59:59
_logger.info(f"开始执行定时清理临时附件任务,清理时间点: {one_day_ago.strftime('%Y-%m-%d %H:%M:%S')}")
# 使用SQL查询查找1天之前创建的临时附件
_logger.info("使用SQL查询查找临时附件")
# 构建SQL查询
sql_query = """
SELECT id, name, res_model, res_id, create_date, store_fname
FROM ir_attachment
WHERE res_model = 'batch.get.pod.info.wizard'
AND create_date < '%s'
ORDER BY create_date DESC
""" % (one_day_ago.strftime('%Y-%m-%d %H:%M:%S'))
# 执行SQL查询
self.env.cr.execute(sql_query)
sql_results = self.env.cr.fetchall()
# 将SQL结果转换为Odoo记录集
if sql_results:
attachment_ids = [result[0] for result in sql_results]
temp_attachments = self.env['ir.attachment'].sudo().browse(attachment_ids)
attachment_count = len(temp_attachments)
attachment_names = [att.name for att in temp_attachments]
_logger.info(f"找到 {attachment_count} 个{one_day_ago.strftime('%Y-%m-%d')}之前创建的临时附件,开始清理")
# 删除物理文件
for attachment in temp_attachments:
try:
# 获取附件的物理文件路径
if hasattr(attachment, 'store_fname') and attachment.store_fname:
# Odoo 12+ 使用 store_fname
file_path = attachment.store_fname
elif hasattr(attachment, 'datas_fname') and attachment.datas_fname:
# 旧版本使用 datas_fname
file_path = attachment.datas_fname
else:
# 尝试从 name 字段构建路径
file_path = attachment.name
# 构建完整的文件路径
import os
from odoo.tools import config
# 获取 Odoo 数据目录
data_dir = config.filestore(self.env.cr.dbname)
if data_dir and file_path:
full_path = os.path.join(data_dir, file_path)
if os.path.exists(full_path):
os.remove(full_path)
_logger.info(f"已删除物理文件: {full_path}")
else:
_logger.warning(f"物理文件不存在: {full_path}")
except Exception as file_e:
_logger.warning(f"删除物理文件失败 {attachment.name}: {str(file_e)}")
# 删除数据库记录
temp_attachments.unlink()
_logger.info(f"定时清理完成,共删除 {attachment_count} 个{one_day_ago.strftime('%Y-%m-%d')}之前创建的临时附件: {', '.join(attachment_names[:5])}{'...' if len(attachment_names) > 5 else ''}")
else:
_logger.info(f"没有找到{one_day_ago.strftime('%Y-%m-%d')}之前创建的临时附件需要清理")
except Exception as e:
_logger.error(f"定时清理临时附件失败: {str(e)}")
def get_order(self):
"""
得到单据
......@@ -201,7 +277,7 @@ class BatchGetPodInfoWizard(models.TransientModel):
}
# 回写到附件信息
if processed_files:
if processed_files and (self.sync_last_mile_pod or self.sync_match_node):
logging.info(f"回写PDF文件到清关文件,共 {len(processed_files)} 个文件")
# 回写PDF文件到清关文件
self._write_pdf_file(processed_files)
......@@ -817,33 +893,10 @@ class BatchGetPodInfoWizard(models.TransientModel):
mat = fitz.Matrix(3.0, 3.0) # 进一步提高分辨率,从2.0提升到3.0
pix = page.get_pixmap(matrix=mat)
img_data = pix.tobytes("png")
# 转换为base64
img_base64 = base64.b64encode(img_data).decode('utf-8')
# 保存AI转换前的图片用于对比
try:
import os
from datetime import datetime
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
before_ai_filename = f"before_ai_{bl_no}_page{page_num + 1}_{timestamp}.png"
# 创建保存目录
save_dir = os.path.join(os.getcwd(), "ai_comparison_images")
if not os.path.exists(save_dir):
os.makedirs(save_dir)
before_ai_path = os.path.join(save_dir, before_ai_filename)
# 保存原始图片
with open(before_ai_path, 'wb') as f:
f.write(img_data)
_logger.info(f"已保存AI转换前的图片: {before_ai_path}")
print(f"已保存AI转换前的图片: {before_ai_path}") # 添加print输出
except Exception as e:
_logger.warning(f"保存AI转换前图片失败: {str(e)}")
print(f"保存AI转换前图片失败: {str(e)}") # 添加print输出
# 使用AI编辑图片,移除指定文字
ai_start_time = time.time()
edited_img_base64 = ai_service.edit_image_remove_text(
......@@ -856,21 +909,6 @@ class BatchGetPodInfoWizard(models.TransientModel):
if edited_img_base64:
# 解码base64图片数据
edited_img_data = base64.b64decode(edited_img_base64)
# 保存AI转换后的图片用于对比
try:
after_ai_filename = f"after_ai_{bl_no}_page{page_num + 1}_{timestamp}.png"
after_ai_path = os.path.join(save_dir, after_ai_filename)
# 保存AI处理后的图片
with open(after_ai_path, 'wb') as f:
f.write(edited_img_data)
_logger.info(f"已保存AI转换后的图片: {after_ai_path}")
print(f"已保存AI转换后的图片: {after_ai_path}") # 添加print输出
except Exception as e:
_logger.warning(f"保存AI转换后图片失败: {str(e)}")
print(f"保存AI转换后图片失败: {str(e)}") # 添加print输出
# 保存处理后的图片数据
processed_pages.append({
'img_data': edited_img_data,
......
......@@ -28,16 +28,16 @@
<div class="alert alert-info" role="alert">
<strong>Description:</strong> <!-- 说明: -->
<ul>
<li>
<li attrs="{'invisible': [('pdf_file', '!=', False)]}">
<strong>Sync Last Mile POD:</strong>
Synchronize POD (Proof of Delivery) attachment information with TK system, including
big package quantities and container numbers
</li> <!-- 同步尾程POD:向TK同步尾程交接POD(待大包数量和箱号)的附件信息 -->
<li>
<li attrs="{'invisible': ['|',('pdf_file', '=', False),('show_error_message', '!=', False)]}">
<strong>Remove Specified Text:</strong>
Remove specified text (AGN, UCLINK LOGISITICS LTD) from PDF files
</li> <!-- 涂抹指定文字:对PDF文件中的指定文字进行涂抹处理 -->
<li>
<li attrs="{'invisible': ['|',('pdf_file', '=', False),('show_error_message', '!=', False)]}">
<strong>Sync Push Match Node:</strong>
Synchronize and push matched node information based on POD file, extract time from
red boxes as node operation time
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论