jack 1 month ago
parent a9ec2702db
commit 99732b44d9
  1. 249
      rpc_batch_fetch_dataset/rpc_batch_fetch_dataset.py
  2. 79
      rpc_fetch_final_prompt/check.py
  3. 420
      rpc_fetch_final_prompt/rpc_fetch_final_prompt.py

@ -0,0 +1,249 @@
import xmlrpc.client
import time
import sys
# Odoo 连接配置
ODOO_URL = "http://192.168.31.41:32000"
DB_NAME = "quantify"
USERNAME = "rpc"
PASSWORD = "aaaAAA111"
class OdooClient:
def __init__(self, url, db, username, password):
self.url = url
self.db = db
self.username = username
self.password = password
self.uid = None
self.models = None
self._connect()
def _connect(self):
"""建立 XML-RPC 连接"""
try:
common = xmlrpc.client.ServerProxy(f"{self.url}/xmlrpc/2/common")
self.uid = common.authenticate(self.db, self.username, self.password, {})
if not self.uid:
raise Exception("认证失败,请检查用户名和密码")
self.models = xmlrpc.client.ServerProxy(f"{self.url}/xmlrpc/2/object")
print(f"[INFO] 连接成功,UID: {self.uid}")
except Exception as e:
print(f"[ERROR] 连接失败: {e}")
sys.exit(1)
def search_draft_records(self):
"""搜索所有状态为 draft 的 alpha.datasets 记录"""
try:
ids = self.models.execute_kw(
self.db, self.uid, self.password,
'alpha.datasets', 'search',
[[('status', '=', 'draft')]]
)
print(f"[INFO] 找到 {len(ids)} 条 draft 记录: {ids}")
return ids
except xmlrpc.client.Fault as e:
print(f"[ERROR] XML-RPC Fault 搜索记录失败: {e.faultCode} - {e.faultString}")
return []
except Exception as e:
print(f"[ERROR] 搜索 draft 记录失败: {e}")
return []
def get_record_status(self, record_id):
"""获取单条记录的状态"""
try:
records = self.models.execute_kw(
self.db, self.uid, self.password,
'alpha.datasets', 'read',
[[record_id], ['status', 'result_message', 'datasets_id', 'name']]
)
if records:
return records[0]
return None
except xmlrpc.client.Fault as e:
print(f"[ERROR] XML-RPC Fault 获取记录 {record_id} 状态失败: {e.faultCode} - {e.faultString}")
return None
except Exception as e:
print(f"[ERROR] 获取记录 {record_id} 状态失败: {e}")
return None
def trigger_btn_get_datasets(self, record_id):
"""
调用 btn_get_datasets 方法
返回: (success, message)
"""
try:
result = self.models.execute_kw(
self.db, self.uid, self.password,
'alpha.datasets', 'btn_get_datasets',
[[record_id]]
)
# 处理不同的返回值
if result is True:
print(f"[INFO] 记录 {record_id} 的 btn_get_datasets 调用成功")
return True, "调用成功"
elif isinstance(result, dict) and result.get('type') == 'ir.actions.client':
# 返回的是 notification 字典
message = result.get('params', {}).get('message', '')
msg_type = result.get('params', {}).get('type', 'info')
if msg_type == 'danger':
print(f"[WARN] 记录 {record_id} 返回错误通知: {message}")
return False, message
else:
print(f"[INFO] 记录 {record_id} 返回通知: {message}")
return True, message
else:
print(f"[INFO] 记录 {record_id} 的 btn_get_datasets 调用完成,返回: {result}")
return True, "调用成功"
except xmlrpc.client.Fault as e:
error_msg = f"XML-RPC Fault: {e.faultCode} - {e.faultString}"
print(f"[ERROR] 调用记录 {record_id} 的 btn_get_datasets 失败: {error_msg}")
return False, error_msg
except Exception as e:
error_msg = f"Exception: {str(e)}"
print(f"[ERROR] 调用记录 {record_id} 的 btn_get_datasets 失败: {error_msg}")
return False, error_msg
def wait_for_status_change(self, record_id, check_interval=5, max_wait_minutes=30):
"""
轮询等待记录状态变为 done failed
返回: (status, result_message)
"""
max_attempts = (max_wait_minutes * 60) // check_interval
attempt = 0
while attempt < max_attempts:
record = self.get_record_status(record_id)
if not record:
return 'unknown', '无法获取记录状态'
status = record.get('status')
result_message = record.get('result_message', '')
datasets_id = record.get('datasets_id', 'N/A')
name = record.get('name', 'N/A')
if status in ['done', 'failed']:
print(f"[INFO] 记录 {record_id} (name={name}, datasets_id={datasets_id}) 状态变为: {status}")
if status == 'failed':
print(f"[WARN] 失败原因: {result_message}")
return status, result_message
print(f"[INFO] 记录 {record_id} 当前状态: {status},等待 {check_interval} 秒后重试...")
time.sleep(check_interval)
attempt += 1
print(f"[WARN] 记录 {record_id} 等待超时 ({max_wait_minutes} 分钟)")
return 'timeout', '等待超时'
def main():
"""主函数"""
print("=" * 60)
print("Odoo 批量处理 draft 数据集脚本")
print("=" * 60)
# 初始化客户端
client = OdooClient(ODOO_URL, DB_NAME, USERNAME, PASSWORD)
# 统计信息
total_processed = 0
success_count = 0
failed_count = 0
timeout_count = 0
while True:
# 搜索所有 draft 记录
draft_ids = client.search_draft_records()
if not draft_ids:
print("[INFO] 没有更多 draft 记录,处理完成!")
break
print(f"\n[INFO] 开始处理 {len(draft_ids)} 条 draft 记录...")
for record_id in draft_ids:
print(f"\n--- 处理记录 ID: {record_id} ---")
# 再次确认状态(防止在搜索后状态被改变)
current_record = client.get_record_status(record_id)
if not current_record:
print(f"[ERROR] 无法获取记录 {record_id} 的信息,跳过")
failed_count += 1
total_processed += 1
continue
if current_record.get('status') != 'draft':
print(f"[INFO] 记录 {record_id} 状态已不是 draft (当前: {current_record.get('status')}),跳过")
total_processed += 1
continue
datasets_id = current_record.get('datasets_id', 'N/A')
name = current_record.get('name', 'N/A')
print(f"[INFO] 数据集名称: {name}")
print(f"[INFO] 数据集 ID: {datasets_id}")
# 触发 btn_get_datasets
success, message = client.trigger_btn_get_datasets(record_id)
if not success:
print(f"[ERROR] 触发失败: {message},跳过记录 {record_id}")
failed_count += 1
total_processed += 1
# 更新记录状态为 failed(如果触发失败)
try:
client.models.execute_kw(
client.db, client.uid, client.password,
'alpha.datasets', 'write',
[[record_id], {
'status': 'failed',
'result_message': f'Trigger failed: {message}'
}]
)
except Exception as e:
print(f"[WARN] 无法更新记录状态: {e}")
continue
# 等待状态变化
status, result_msg = client.wait_for_status_change(record_id)
if status == 'done':
success_count += 1
print(f"[SUCCESS] 记录 {record_id} 处理成功")
elif status == 'failed':
failed_count += 1
print(f"[FAILED] 记录 {record_id} 处理失败: {result_msg}")
elif status == 'timeout':
timeout_count += 1
failed_count += 1
print(f"[TIMEOUT] 记录 {record_id} 处理超时")
else:
failed_count += 1
print(f"[UNKNOWN] 记录 {record_id} 状态未知: {status}")
total_processed += 1
# 短暂延迟,避免请求过快
time.sleep(1)
# 输出统计
print("\n" + "=" * 60)
print("处理完成统计:")
print(f" 总处理记录数: {total_processed}")
print(f" 成功: {success_count}")
print(f" 失败: {failed_count - timeout_count}")
print(f" 超时: {timeout_count}")
print("=" * 60)
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\n[INFO] 用户中断脚本")
sys.exit(0)
except Exception as e:
print(f"[ERROR] 脚本异常: {e}")
sys.exit(1)

@ -0,0 +1,79 @@
# -*- coding: utf-8 -*-
import xmlrpc.client
from datetime import datetime
# Odoo 连接配置
ODOO_URL = "http://192.168.31.41:32000"
DB_NAME = "quantify"
USERNAME = "rpc"
PASSWORD = "aaaAAA111"
# 连接
common = xmlrpc.client.ServerProxy(f"{ODOO_URL}/xmlrpc/2/common")
uid = common.authenticate(DB_NAME, USERNAME, PASSWORD, {})
models = xmlrpc.client.ServerProxy(f"{ODOO_URL}/xmlrpc/2/object")
# 获取今天的日期字符串
today = datetime.now()
today_str = today.strftime('%Y-%m-%d')
print(f"脚本执行时间(本地): {today_str}")
# 查询今天创建的所有记录
print("\n" + "="*60)
print("查询今天创建的所有记录:")
print("="*60)
domain = [('create_date', '=', today_str)]
record_ids = models.execute_kw(DB_NAME, uid, PASSWORD, 'alpha.idea', 'search', [domain])
records = models.execute_kw(DB_NAME, uid, PASSWORD, 'alpha.idea', 'read',
[record_ids, ['id', 'name', 'status', 'create_date']])
print(f"找到 {len(records)} 条记录:")
for record in records:
print(f" ID: {record['id']}, Name: {record['name']}, Status: {record['status']}, Create Date: {record['create_date']}")
# 查询所有状态分布
print("\n" + "="*60)
print("今天所有记录的状态分布:")
print("="*60)
status_count = {}
for record in records:
status = record.get('status')
status_count[status] = status_count.get(status, 0) + 1
for status, count in status_count.items():
print(f" {status}: {count}")
# 测试日期比较的不同方式
print("\n" + "="*60)
print("测试日期比较方式:")
print("="*60)
# 方式1: 直接使用字符串比较
test_domain_1 = [('create_date', '=', today_str)]
test_ids_1 = models.execute_kw(DB_NAME, uid, PASSWORD, 'alpha.idea', 'search', [test_domain_1])
print(f"方式1 (create_date = '{today_str}'): 找到 {len(test_ids_1)}")
# 方式2: 使用日期范围
test_domain_2 = [('create_date', '>=', today_str), ('create_date', '<', f"{today_str} 23:59:59")]
test_ids_2 = models.execute_kw(DB_NAME, uid, PASSWORD, 'alpha.idea', 'search', [test_domain_2])
print(f"方式2 (create_date >= '{today_str}' AND < '{today_str} 23:59:59'): 找到 {len(test_ids_2)}")
# 方式3: 使用日期函数(如果支持)
test_domain_3 = [('create_date', '>=', today_str)]
test_ids_3 = models.execute_kw(DB_NAME, uid, PASSWORD, 'alpha.idea', 'search', [test_domain_3])
print(f"方式3 (create_date >= '{today_str}'): 找到 {len(test_ids_3)}")
# 查看最近创建的5条记录,看看日期格式
print("\n" + "="*60)
print("最近创建的5条记录:")
print("="*60)
recent_ids = models.execute_kw(DB_NAME, uid, PASSWORD, 'alpha.idea', 'search',
[[]], {'limit': 5, 'order': 'create_date desc'})
recent_records = models.execute_kw(DB_NAME, uid, PASSWORD, 'alpha.idea', 'read',
[recent_ids, ['id', 'name', 'status', 'create_date']])
for record in recent_records:
print(f" ID: {record['id']}, Status: {record['status']}, Create Date: {record['create_date']}")

@ -0,0 +1,420 @@
import xmlrpc.client
import os
import sys
import time
from datetime import datetime, timedelta
# Odoo 连接配置
ODOO_URL = "http://192.168.31.41:32000"
DB_NAME = "quantify"
USERNAME = "rpc"
PASSWORD = "aaaAAA111"
class OdooClient:
def __init__(self, url, db, username, password):
self.url = url
self.db = db
self.username = username
self.password = password
self.uid = None
self.models = None
self._connect()
def _connect(self):
"""建立 XML-RPC 连接"""
try:
common = xmlrpc.client.ServerProxy(f"{self.url}/xmlrpc/2/common")
self.uid = common.authenticate(self.db, self.username, self.password, {})
if not self.uid:
raise Exception("认证失败,请检查用户名和密码")
self.models = xmlrpc.client.ServerProxy(f"{self.url}/xmlrpc/2/object")
print(f"[INFO] 连接成功,UID: {self.uid}")
except Exception as e:
print(f"[ERROR] 连接失败: {e}")
sys.exit(1)
def get_today_date_str(self):
"""获取今天的日期字符串 (YYYY-MM-DD)"""
return datetime.now().strftime('%Y-%m-%d')
def get_today_start(self):
"""获取今天的开始时间 (YYYY-MM-DD 00:00:00)"""
return datetime.now().strftime('%Y-%m-%d 00:00:00')
def get_today_end(self):
"""获取今天的结束时间 (YYYY-MM-DD 23:59:59)"""
return datetime.now().strftime('%Y-%m-%d 23:59:59')
def get_tomorrow_start(self):
"""获取明天的开始时间 (YYYY-MM-DD 00:00:00)"""
tomorrow = datetime.now() + timedelta(days=1)
return tomorrow.strftime('%Y-%m-%d 00:00:00')
# ==================== 步骤1: 清理历史数据 ====================
def cancel_old_non_terminal_records(self):
"""
步骤1: 取消非今天的非终态记录
将状态不是 done/failed/cancel 且创建日期 < 今天的记录设为 cancel
"""
today_start = self.get_today_start()
# 搜索条件:状态不是终态,且创建日期小于今天开始时间
domain = [
('status', 'not in', ['done', 'failed', 'cancel']),
('create_date', '<', today_start)
]
try:
record_ids = self.models.execute_kw(
self.db, self.uid, self.password,
'alpha.idea', 'search',
[domain]
)
if not record_ids:
print(f"[INFO] 没有需要取消的历史记录")
return 0
print(f"[INFO] 找到 {len(record_ids)} 条历史记录需要取消(创建日期 < {self.get_today_date_str()}")
# 批量更新状态为 cancel
self.models.execute_kw(
self.db, self.uid, self.password,
'alpha.idea', 'write',
[record_ids, {'status': 'cancel'}]
)
print(f"[INFO] 成功将 {len(record_ids)} 条历史记录状态更新为 cancel")
return len(record_ids)
except xmlrpc.client.Fault as e:
print(f"[ERROR] XML-RPC Fault 取消记录失败: {e.faultCode} - {e.faultString}")
return 0
except Exception as e:
print(f"[ERROR] 取消记录失败: {e}")
return 0
# ==================== 通用方法: 获取指定状态的记录 ====================
def fetch_records_by_status(self, status, fields=None):
"""
获取今天指定状态的记录
:param status: 状态值 'draft', 'fetched_data', 'generated_prompt'
:param fields: 需要读取的字段列表默认读取 ['id', 'name', 'status']
"""
today_start = self.get_today_start()
tomorrow_start = self.get_tomorrow_start()
if fields is None:
fields = ['id', 'name', 'status']
# 使用日期范围查询当天的记录
domain = [
('create_date', '>=', today_start),
('create_date', '<', tomorrow_start),
('status', '=', status)
]
try:
record_ids = self.models.execute_kw(
self.db, self.uid, self.password,
'alpha.idea', 'search',
[domain]
)
if not record_ids:
print(f"[INFO] 没有找到今天的 {status} 状态记录")
return []
print(f"[INFO] 找到 {len(record_ids)} 条今天的 {status} 状态记录")
records = self.models.execute_kw(
self.db, self.uid, self.password,
'alpha.idea', 'read',
[record_ids, fields]
)
return records
except xmlrpc.client.Fault as e:
print(f"[ERROR] XML-RPC Fault 获取 {status} 记录失败: {e.faultCode} - {e.faultString}")
return []
except Exception as e:
print(f"[ERROR] 获取 {status} 记录失败: {e}")
return []
# ==================== 通用方法: 调用按钮并等待状态变化 ====================
def call_button_and_wait(self, record_id, button_name, target_statuses, check_interval=5, max_wait_minutes=30):
"""
调用指定按钮并等待状态变为目标状态
:param record_id: 记录ID
:param button_name: 按钮方法名 'btn_check_and_fetch_data'
:param target_statuses: 目标状态列表 ['generated_prompt', 'failed']
:param check_interval: 检查间隔
:param max_wait_minutes: 最大等待时间分钟
:return: (最终状态, 结果消息)
"""
# 调用按钮
try:
result = self.models.execute_kw(
self.db, self.uid, self.password,
'alpha.idea', button_name,
[[record_id]]
)
print(f"[INFO] 记录 {record_id}{button_name} 已调用")
except xmlrpc.client.Fault as e:
error_msg = f"XML-RPC Fault: {e.faultCode} - {e.faultString}"
print(f"[ERROR] 调用 {button_name} 失败: {error_msg}")
return 'failed', error_msg
except Exception as e:
error_msg = f"Exception: {str(e)}"
print(f"[ERROR] 调用 {button_name} 失败: {error_msg}")
return 'failed', error_msg
# 等待状态变化
return self.wait_for_status_change(record_id, target_statuses, check_interval, max_wait_minutes)
def wait_for_status_change(self, record_id, target_statuses, check_interval=5, max_wait_minutes=30):
"""
轮询等待记录状态变为目标状态之一
:return: (current_status, result_message)
"""
max_attempts = (max_wait_minutes * 60) // check_interval
attempt = 0
# 获取初始状态
record = self.get_record_status(record_id)
if not record:
return 'unknown', '无法获取记录状态'
current_status = record.get('status')
print(f"[INFO] 记录 {record_id} 初始状态: {current_status}")
while attempt < max_attempts:
if current_status in target_statuses:
print(f"[INFO] 记录 {record_id} 状态变为目标状态: {current_status}")
return current_status, record.get('result_message', '')
print(f"[INFO] 记录 {record_id} 当前状态: {current_status},等待 {check_interval} 秒后重试...")
time.sleep(check_interval)
attempt += 1
record = self.get_record_status(record_id)
if record:
current_status = record.get('status')
else:
print(f"[WARN] 无法获取记录 {record_id} 状态")
print(f"[WARN] 记录 {record_id} 等待超时 ({max_wait_minutes} 分钟)")
return current_status, '等待超时'
def get_record_status(self, record_id):
"""获取单条记录的状态和 result_message"""
try:
records = self.models.execute_kw(
self.db, self.uid, self.password,
'alpha.idea', 'read',
[[record_id], ['status', 'result_message', 'name']]
)
if records:
return records[0]
return None
except Exception as e:
print(f"[ERROR] 获取记录 {record_id} 状态失败: {e}")
return None
# ==================== 步骤2: 处理 draft 记录 ====================
def process_draft_records(self):
"""
步骤2: 处理今天的 draft 状态记录
调用 btn_check_and_fetch_data等待状态变为 fetched_data failed
"""
print("\n[步骤2] 处理今天的 draft 记录...")
print("-" * 40)
draft_records = self.fetch_records_by_status('draft')
if not draft_records:
print("[INFO] 没有需要处理的 draft 记录")
return 0
success_count = 0
failed_count = 0
for record in draft_records:
record_id = record.get('id')
name = record.get('name')
print(f"\n处理 draft 记录: {name} (ID: {record_id})")
# 调用 btn_check_and_fetch_data,等待状态变为 fetched_data 或 failed
target_statuses = ['fetched_data', 'failed', 'cancel', 'done']
final_status, message = self.call_button_and_wait(
record_id,
'btn_check_and_fetch_data',
target_statuses,
check_interval=5,
max_wait_minutes=30
)
if final_status == 'fetched_data':
print(f"[SUCCESS] 记录 {record_id} 成功变为 fetched_data 状态")
success_count += 1
else:
print(f"[FAILED] 记录 {record_id} 最终状态为 {final_status},失败原因: {message}")
failed_count += 1
print(f"\n[步骤2完成] 成功: {success_count}, 失败: {failed_count}")
return success_count
# ==================== 步骤3: 处理 fetched_data 记录 ====================
def process_fetched_data_records(self):
"""
步骤3: 处理今天的 fetched_data 状态记录
调用 btn_generate_final_prompt等待状态变为 generated_prompt failed
"""
print("\n[步骤3] 处理今天的 fetched_data 记录...")
print("-" * 40)
fetched_records = self.fetch_records_by_status('fetched_data')
if not fetched_records:
print("[INFO] 没有需要处理的 fetched_data 记录")
return 0
success_count = 0
failed_count = 0
for record in fetched_records:
record_id = record.get('id')
name = record.get('name')
print(f"\n处理 fetched_data 记录: {name} (ID: {record_id})")
# 调用 btn_generate_final_prompt,等待状态变为 generated_prompt 或 failed
target_statuses = ['generated_prompt', 'failed', 'cancel', 'done']
final_status, message = self.call_button_and_wait(
record_id,
'btn_generate_final_prompt',
target_statuses,
check_interval=5,
max_wait_minutes=30
)
if final_status == 'generated_prompt':
print(f"[SUCCESS] 记录 {record_id} 成功变为 generated_prompt 状态")
success_count += 1
else:
print(f"[FAILED] 记录 {record_id} 最终状态为 {final_status},失败原因: {message}")
failed_count += 1
print(f"\n[步骤3完成] 成功: {success_count}, 失败: {failed_count}")
return success_count
# ==================== 步骤4: 下载 final_prompt ====================
def download_final_prompts(self):
"""
步骤4: 获取今天的 generated_prompt 状态记录下载 final_prompt 到本地文件
"""
print("\n[步骤4] 下载今天的 final_prompt...")
print("-" * 40)
generated_records = self.fetch_records_by_status('generated_prompt', ['id', 'name', 'final_prompt'])
if not generated_records:
print("[INFO] 没有需要下载的 generated_prompt 记录")
return 0
# 创建当天日期文件夹
today_folder = self.get_today_date_str()
output_dir = os.path.join(os.getcwd(), today_folder)
print(f"[INFO] 文件将保存到: {output_dir}")
success_count = 0
failed_count = 0
for record in generated_records:
record_id = record.get('id')
name = record.get('name')
final_prompt = record.get('final_prompt', '')
print(f"\n处理记录: {name} (ID: {record_id})")
# 检查 final_prompt 是否为空
if not final_prompt or not final_prompt.strip():
print(f"[WARN] 记录 {name} 的 final_prompt 为空,跳过")
failed_count += 1
continue
# 保存文件
if self.save_prompt_to_md(name, final_prompt, output_dir):
success_count += 1
else:
failed_count += 1
print(f"\n[步骤4完成] 成功保存: {success_count}, 失败: {failed_count}")
return success_count
def save_prompt_to_md(self, name, final_prompt, output_dir):
"""将 final_prompt 保存为 Markdown 文件"""
try:
os.makedirs(output_dir, exist_ok=True)
filename = f"{name}.md"
filepath = os.path.join(output_dir, filename)
with open(filepath, 'w', encoding='utf-8') as f:
f.write(final_prompt)
print(f"[SUCCESS] 已保存文件: {filepath}")
return True
except Exception as e:
print(f"[ERROR] 保存文件失败 {name}.md: {e}")
return False
def main():
"""主函数"""
print("=" * 60)
print("Odoo Alpha Idea 处理脚本")
print(f"执行时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print("=" * 60)
# 初始化客户端
client = OdooClient(ODOO_URL, DB_NAME, USERNAME, PASSWORD)
# 步骤1: 清理历史数据(创建日期 < 今天的非终态记录设为 cancel)
print("\n[步骤1] 清理历史数据...")
print("-" * 40)
canceled_count = client.cancel_old_non_terminal_records()
print(f"[步骤1完成] 已取消 {canceled_count} 条历史记录")
# 步骤2: 处理今天的 draft 记录
draft_success = client.process_draft_records()
# 步骤3: 处理今天的 fetched_data 记录
fetched_success = client.process_fetched_data_records()
# 步骤4: 下载今天的 final_prompt
downloaded_count = client.download_final_prompts()
# 输出统计
print("\n" + "=" * 60)
print("处理完成统计:")
print(f" 步骤1 - 取消的历史记录: {canceled_count}")
print(f" 步骤2 - 处理的 draft 记录: {draft_success}")
print(f" 步骤3 - 处理的 fetched_data 记录: {fetched_success}")
print(f" 步骤4 - 下载的 prompt 文件: {downloaded_count}")
print(f" 文件保存路径: {os.path.join(os.getcwd(), client.get_today_date_str())}")
print("=" * 60)
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\n[INFO] 用户中断脚本")
sys.exit(0)
except Exception as e:
print(f"[ERROR] 脚本异常: {e}")
sys.exit(1)
Loading…
Cancel
Save