update_n8n_cohere_credential.py 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. """
  2. 更新 n8n 中的 Cohere API Key 凭证
  3. 用于修复 "Forbidden" 错误,重新配置凭证
  4. """
  5. import os
  6. import sys
  7. import json
  8. from typing import Optional, Dict, Any
  9. import requests
  10. from loguru import logger
  11. # 添加项目根目录到路径
  12. sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
  13. from app.config.config import BaseConfig
  14. # 配置日志(避免 emoji 编码问题)
  15. logger.remove()
  16. logger.add(
  17. sys.stdout,
  18. level="INFO",
  19. format="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {message}",
  20. )
  21. def update_cohere_credential(
  22. credential_id: str,
  23. api_url: Optional[str] = None,
  24. api_key: Optional[str] = None,
  25. cohere_api_key: str = "4pLcF0CGE7LeDmAudBQHdvAxGaKwNOKfxUGkHb5C",
  26. credential_name: Optional[str] = None,
  27. ) -> Dict[str, Any]:
  28. """
  29. 更新 n8n 中的 Cohere 凭证
  30. Args:
  31. credential_id: 凭证 ID
  32. api_url: n8n API 地址
  33. api_key: n8n API Key
  34. cohere_api_key: Cohere API Key 值
  35. credential_name: 凭证名称(可选)
  36. Returns:
  37. 更新结果
  38. """
  39. # 获取配置
  40. if api_url is None or api_key is None:
  41. config = BaseConfig()
  42. api_url = api_url or config.N8N_API_URL
  43. api_key = api_key or config.N8N_API_KEY
  44. base_url = api_url.rstrip("/")
  45. headers = {
  46. "X-N8N-API-KEY": api_key,
  47. "Content-Type": "application/json",
  48. "Accept": "application/json",
  49. }
  50. # 先获取现有凭证信息
  51. logger.info(f"获取凭证信息: {credential_id}")
  52. try:
  53. get_response = requests.get(
  54. f"{base_url}/api/v1/credentials/{credential_id}",
  55. headers=headers,
  56. timeout=30,
  57. )
  58. if get_response.status_code == 200:
  59. existing_credential = get_response.json()
  60. logger.info(f"现有凭证名称: {existing_credential.get('name')}")
  61. credential_name = credential_name or existing_credential.get("name", "Cohere API Key")
  62. else:
  63. logger.warning(f"无法获取现有凭证: {get_response.status_code}")
  64. credential_name = credential_name or "Cohere API Key"
  65. except Exception as e:
  66. logger.warning(f"获取凭证信息失败: {str(e)}")
  67. credential_name = credential_name or "Cohere API Key"
  68. # 准备更新数据
  69. # 注意: n8n 凭证更新可能需要特定的数据格式
  70. update_data = {
  71. "name": credential_name,
  72. "type": "cohereApi",
  73. "data": {
  74. "apiKey": cohere_api_key,
  75. },
  76. }
  77. logger.info(f"更新凭证: {credential_id}")
  78. logger.info(f"API Key (前8位): {cohere_api_key[:8]}...")
  79. try:
  80. # 尝试更新凭证
  81. response = requests.put(
  82. f"{base_url}/api/v1/credentials/{credential_id}",
  83. headers=headers,
  84. json=update_data,
  85. timeout=30,
  86. )
  87. logger.debug(f"响应状态码: {response.status_code}")
  88. logger.debug(f"响应内容: {response.text[:500]}")
  89. if response.status_code == 200:
  90. result = response.json()
  91. logger.success(f"凭证更新成功: {result.get('name')}")
  92. return {
  93. "success": True,
  94. "message": "凭证更新成功",
  95. "data": result,
  96. }
  97. elif response.status_code == 401:
  98. logger.error("API 认证失败,请检查 n8n API Key")
  99. return {
  100. "success": False,
  101. "message": "API 认证失败,请检查 n8n API Key",
  102. "error": "Unauthorized",
  103. }
  104. elif response.status_code == 403:
  105. logger.error("API 权限不足,凭证更新可能需要 Owner 权限")
  106. return {
  107. "success": False,
  108. "message": "API 权限不足,请使用 Web UI 手动更新",
  109. "error": "Forbidden",
  110. }
  111. elif response.status_code == 404:
  112. logger.error(f"凭证不存在: {credential_id}")
  113. return {
  114. "success": False,
  115. "message": f"凭证不存在: {credential_id}",
  116. "error": "Not Found",
  117. }
  118. else:
  119. logger.warning(f"更新失败: {response.status_code} - {response.text[:200]}")
  120. return {
  121. "success": False,
  122. "message": f"更新失败: {response.status_code}",
  123. "error": response.text[:200],
  124. "status_code": response.status_code,
  125. }
  126. except requests.exceptions.RequestException as e:
  127. logger.error(f"请求异常: {str(e)}")
  128. return {
  129. "success": False,
  130. "message": f"请求失败: {str(e)}",
  131. "error": str(e),
  132. }
  133. def delete_and_recreate_credential(
  134. credential_id: Optional[str] = None,
  135. api_url: Optional[str] = None,
  136. api_key: Optional[str] = None,
  137. cohere_api_key: str = "4pLcF0CGE7LeDmAudBQHdvAxGaKwNOKfxUGkHb5C",
  138. ) -> Dict[str, Any]:
  139. """
  140. 删除旧凭证并重新创建
  141. Args:
  142. credential_id: 要删除的凭证 ID(如果为 None,则只创建新凭证)
  143. api_url: n8n API 地址
  144. api_key: n8n API Key
  145. cohere_api_key: Cohere API Key 值
  146. Returns:
  147. 操作结果
  148. """
  149. # 获取配置
  150. if api_url is None or api_key is None:
  151. config = BaseConfig()
  152. api_url = api_url or config.N8N_API_URL
  153. api_key = api_key or config.N8N_API_KEY
  154. base_url = api_url.rstrip("/")
  155. headers = {
  156. "X-N8N-API-KEY": api_key,
  157. "Content-Type": "application/json",
  158. "Accept": "application/json",
  159. }
  160. # 删除旧凭证(如果提供)
  161. if credential_id:
  162. logger.info(f"删除旧凭证: {credential_id}")
  163. try:
  164. delete_response = requests.delete(
  165. f"{base_url}/api/v1/credentials/{credential_id}",
  166. headers=headers,
  167. timeout=30,
  168. )
  169. if delete_response.status_code in [200, 204]:
  170. logger.success("旧凭证已删除")
  171. else:
  172. logger.warning(f"删除凭证失败: {delete_response.status_code}")
  173. except Exception as e:
  174. logger.warning(f"删除凭证异常: {str(e)}")
  175. # 创建新凭证
  176. logger.info("创建新凭证...")
  177. credential_data = {
  178. "name": "Cohere API Key",
  179. "type": "cohereApi",
  180. "data": {
  181. "apiKey": cohere_api_key,
  182. },
  183. }
  184. try:
  185. response = requests.post(
  186. f"{base_url}/api/v1/credentials",
  187. headers=headers,
  188. json=credential_data,
  189. timeout=30,
  190. )
  191. if response.status_code in [200, 201]:
  192. result = response.json()
  193. logger.success(f"新凭证创建成功: {result.get('id')}")
  194. return {
  195. "success": True,
  196. "message": "凭证重新创建成功",
  197. "data": result,
  198. "credential_id": result.get("id"),
  199. }
  200. else:
  201. logger.error(f"创建凭证失败: {response.status_code} - {response.text[:200]}")
  202. return {
  203. "success": False,
  204. "message": f"创建凭证失败: {response.status_code}",
  205. "error": response.text[:200],
  206. }
  207. except requests.exceptions.RequestException as e:
  208. logger.error(f"请求异常: {str(e)}")
  209. return {
  210. "success": False,
  211. "message": f"请求失败: {str(e)}",
  212. "error": str(e),
  213. }
  214. def main():
  215. """主函数"""
  216. import argparse
  217. parser = argparse.ArgumentParser(description="更新 n8n Cohere API Key 凭证")
  218. parser.add_argument(
  219. "--credential-id",
  220. type=str,
  221. help="要更新的凭证 ID(如果不提供,将创建新凭证)",
  222. )
  223. parser.add_argument(
  224. "--recreate",
  225. action="store_true",
  226. help="删除旧凭证并重新创建",
  227. )
  228. parser.add_argument(
  229. "--api-key",
  230. type=str,
  231. help="Cohere API Key(默认使用配置中的值)",
  232. default="4pLcF0CGE7LeDmAudBQHdvAxGaKwNOKfxUGkHb5C",
  233. )
  234. args = parser.parse_args()
  235. logger.info("开始更新 n8n Cohere API Key 凭证...")
  236. if args.recreate:
  237. result = delete_and_recreate_credential(
  238. credential_id=args.credential_id,
  239. cohere_api_key=args.api_key,
  240. )
  241. elif args.credential_id:
  242. result = update_cohere_credential(
  243. credential_id=args.credential_id,
  244. cohere_api_key=args.api_key,
  245. )
  246. else:
  247. logger.error("请提供 --credential-id 或使用 --recreate 选项")
  248. return 1
  249. print("\n" + "=" * 60)
  250. print("执行结果:")
  251. print("=" * 60)
  252. print(json.dumps(result, indent=2, ensure_ascii=False))
  253. if result.get("success"):
  254. if "credential_id" in result:
  255. print(f"\n新凭证 ID: {result.get('credential_id')}")
  256. print("\n请在工作流中使用更新后的凭证。")
  257. else:
  258. print("\n" + "=" * 60)
  259. print("建议:")
  260. print("=" * 60)
  261. print("如果 API 更新失败,请使用 Web UI 手动更新:")
  262. print("1. 访问: https://n8n.citupro.com/home/credentials")
  263. print("2. 找到 Cohere API Key 凭证")
  264. print("3. 点击编辑,重新输入 API Key")
  265. print("4. 确保 API Key 没有多余的空格或换行")
  266. return 0 if result.get("success") else 1
  267. if __name__ == "__main__":
  268. sys.exit(main())