You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
256 lines
7.9 KiB
256 lines
7.9 KiB
# -*- coding: utf-8 -*-
|
|
import time
|
|
|
|
import httpx
|
|
import json
|
|
|
|
|
|
def fetch_llm_generate_task(odoo_base_url="http://localhost:8069"):
|
|
"""
|
|
从 Odoo 接口获取待生成的 LLM 任务数据
|
|
|
|
Args:
|
|
odoo_base_url: Odoo 服务地址,默认 http://localhost:8069
|
|
|
|
Returns:
|
|
dict or None: 返回获取到的任务数据,包含以下字段:
|
|
- id: 记录ID
|
|
- final_prompt: 最终提示词
|
|
- system_prompt: 系统提示词
|
|
- user_prompt: 用户提示词
|
|
如果没有待生成的任务,返回 None
|
|
"""
|
|
url = f"{odoo_base_url}/api/local-llm-generate/fetch"
|
|
|
|
headers = {
|
|
"Content-Type": "application/json"
|
|
}
|
|
|
|
payload = {}
|
|
|
|
try:
|
|
print(f"[INFO] 正在请求 Odoo 接口: {url}")
|
|
response = httpx.post(
|
|
url,
|
|
headers=headers,
|
|
json=payload,
|
|
timeout=30
|
|
)
|
|
response.raise_for_status()
|
|
|
|
data = response.json()
|
|
# print(f"[INFO] 接口返回数据: {json.dumps(data, ensure_ascii=False, indent=2)}")
|
|
|
|
# 检查是否返回了 {"data": null}(没有待生成任务)
|
|
if isinstance(data, dict) and 'data' in data and data['data'] is None:
|
|
print("[INFO] 当前没有待生成的 LLM 任务")
|
|
exit(1)
|
|
|
|
# 返回获取到的任务数据(包含 id, final_prompt, system_prompt, user_prompt)
|
|
if isinstance(data, dict) and 'id' in data:
|
|
print(f"[SUCCESS] 获取到任务数据, record_id={data['id']}")
|
|
return data
|
|
|
|
print(f"[WARNING] 返回数据格式不符合预期: {data}")
|
|
return None
|
|
|
|
except httpx.TimeoutException:
|
|
print("[ERROR] 请求超时")
|
|
return None
|
|
except httpx.ConnectError as e:
|
|
print(f"[ERROR] 连接错误: {e}")
|
|
return None
|
|
except httpx.HTTPStatusError as e:
|
|
print(f"[ERROR] HTTP 错误: {e}")
|
|
return None
|
|
except Exception as e:
|
|
print(f"[ERROR] 发生未知错误: {e}")
|
|
return None
|
|
|
|
|
|
def call_llm_generate(task_data, max_retries=3):
|
|
"""
|
|
调用本地 Ollama LLM 生成内容
|
|
|
|
Args:
|
|
task_data: 包含 final_prompt, system_prompt, user_prompt 的字典
|
|
max_retries: 最大重试次数,默认 max_retries 次
|
|
|
|
Returns:
|
|
str: 生成的内容,如果失败返回 "failed"
|
|
"""
|
|
if task_data is None:
|
|
print("[ERROR] task_data 为 None,无法调用 LLM")
|
|
return "failed"
|
|
|
|
# 提取 task_data 中的字段
|
|
final_prompt = task_data.get('final_prompt', '')
|
|
system_prompt = task_data.get('system_prompt', '')
|
|
user_prompt = task_data.get('user_prompt', '')
|
|
record_id = task_data.get('id', 'unknown')
|
|
|
|
print(f"[INFO] 开始为 record_id={record_id} 调用本地 Ollama")
|
|
|
|
# Ollama API 地址
|
|
ollama_url = "http://localhost:11434/v1/chat/completions"
|
|
|
|
# 组装 messages
|
|
messages = []
|
|
if system_prompt:
|
|
messages.append({"role": "system", "content": system_prompt})
|
|
if final_prompt:
|
|
messages.append({"role": "user", "content": final_prompt})
|
|
|
|
# 请求体
|
|
payload = {
|
|
"model": "kimi-k2.5:cloud",
|
|
"messages": messages,
|
|
"stream": False
|
|
}
|
|
|
|
# 重试机制
|
|
for attempt in range(1, max_retries + 1):
|
|
try:
|
|
print(f"[INFO] 第 {attempt} 次尝试调用 Ollama...")
|
|
|
|
response = httpx.post(
|
|
ollama_url,
|
|
json=payload,
|
|
timeout=600
|
|
)
|
|
response.raise_for_status()
|
|
|
|
result = response.json()
|
|
|
|
# 提取生成的内容
|
|
if "choices" in result and len(result["choices"]) > 0:
|
|
generated_content = result["choices"][0].get("message", {}).get("content", "")
|
|
if generated_content:
|
|
print(f"[SUCCESS] 第 {attempt} 次尝试成功,生成长度: {len(generated_content)} 字符")
|
|
return generated_content
|
|
else:
|
|
print(f"[WARNING] 第 {attempt} 次尝试返回空内容")
|
|
else:
|
|
print(f"[WARNING] 第 {attempt} 次尝试返回格式异常: {result}")
|
|
|
|
except httpx.TimeoutException:
|
|
print(f"[ERROR] 第 {attempt} 次尝试超时")
|
|
except httpx.ConnectError as e:
|
|
print(f"[ERROR] 第 {attempt} 次尝试连接错误: {e}")
|
|
except httpx.HTTPStatusError as e:
|
|
print(f"[ERROR] 第 {attempt} 次尝试 HTTP 错误: {e}")
|
|
except Exception as e:
|
|
print(f"[ERROR] 第 {attempt} 次尝试发生未知错误: {e}")
|
|
|
|
# 如果不是最后一次尝试,等待后继续
|
|
if attempt < max_retries:
|
|
import time
|
|
print(f"[INFO] 等待 2 秒后重试...")
|
|
time.sleep(2)
|
|
|
|
# 所有重试都失败了
|
|
print(f"[FAILED] 经过 {max_retries} 次尝试后仍然失败")
|
|
return "failed"
|
|
|
|
|
|
def upload_llm_result(odoo_base_url, upload_data):
|
|
"""
|
|
上传 LLM 生成结果到 Odoo
|
|
|
|
Args:
|
|
odoo_base_url: Odoo 服务地址
|
|
upload_data: 包含以下字段的字典:
|
|
- record_id: int, 记录ID
|
|
- status: str, "success" 或 "failed"
|
|
- result: str, 成功时的生成内容
|
|
- error_message: str, 失败时的错误信息
|
|
|
|
Returns:
|
|
bool: 上传成功返回 True,失败返回 False
|
|
"""
|
|
url = f"{odoo_base_url}/api/alpha-idea/result"
|
|
|
|
headers = {
|
|
"Content-Type": "application/json"
|
|
}
|
|
|
|
try:
|
|
print(f"[INFO] 正在上传结果到 Odoo: {url}")
|
|
print(f"[INFO] 上传数据: {json.dumps(upload_data, ensure_ascii=False)}")
|
|
|
|
response = httpx.post(
|
|
url,
|
|
headers=headers,
|
|
json=upload_data,
|
|
timeout=30
|
|
)
|
|
response.raise_for_status()
|
|
|
|
result = response.json()
|
|
print(f"[INFO] 上传结果接口返回: {json.dumps(result, ensure_ascii=False)}")
|
|
|
|
# 检查返回结果
|
|
if isinstance(result, dict):
|
|
if result.get('status') == 'success' or result.get('success') is True:
|
|
print(f"[SUCCESS] 结果上传成功")
|
|
return True
|
|
|
|
print(f"[WARNING] 结果上传可能失败: {result}")
|
|
return False
|
|
|
|
except httpx.TimeoutException:
|
|
print("[ERROR] 上传结果超时")
|
|
return False
|
|
except httpx.ConnectError as e:
|
|
print(f"[ERROR] 上传结果连接错误: {e}")
|
|
return False
|
|
except httpx.HTTPStatusError as e:
|
|
print(f"[ERROR] 上传结果 HTTP 错误: {e}")
|
|
return False
|
|
except Exception as e:
|
|
print(f"[ERROR] 上传结果发生未知错误: {e}")
|
|
return False
|
|
|
|
|
|
if __name__ == "__main__":
|
|
# 配置 Odoo 服务地址
|
|
ODOO_BASE_URL = "https://quantify.erhe.top"
|
|
|
|
print("开始获取 LLM 生成任务...")
|
|
|
|
while True:
|
|
# 获取任务数据
|
|
task_data = fetch_llm_generate_task(odoo_base_url=ODOO_BASE_URL)
|
|
|
|
if not task_data:
|
|
break
|
|
|
|
llm_generate_result = call_llm_generate(task_data)
|
|
|
|
print(llm_generate_result)
|
|
|
|
if llm_generate_result != "failed":
|
|
print("开始上传 LLM 生成结果...")
|
|
upload_data = {
|
|
'record_id': task_data['id'],
|
|
'status': 'success',
|
|
'result': llm_generate_result
|
|
}
|
|
else:
|
|
print("开始上传 LLM 生成结果失败...")
|
|
upload_data = {
|
|
'record_id': task_data['id'],
|
|
'status': 'failed',
|
|
'result': '',
|
|
'error_message': 'generate failed'
|
|
}
|
|
|
|
# 上传结果到 Odoo
|
|
upload_success = upload_llm_result(ODOO_BASE_URL, upload_data)
|
|
if upload_success:
|
|
print("[SUCCESS] 整个流程完成")
|
|
else:
|
|
print("[FAILED] 结果上传失败")
|
|
|
|
time.sleep(60)
|
|
|
|
|