openai.lua 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. --[[
  2. @module openai
  3. @summary 对接OpenAI兼容的平台,例如deepseek
  4. @version 1.0
  5. @date 2025.1.27
  6. @author wendal
  7. @tag LUAT_USE_NETWORK
  8. @demo openai
  9. @usage
  10. -- 对接deepseek演示 请阅demo/openai
  11. -- 本API正在积极设计中
  12. ]] local openai = {
  13. conf = {}
  14. }
  15. -- 定义默认参数表
  16. local defaultOpts = {
  17. apikey = "123456",
  18. apiurl = "https://api.deepseek.com",
  19. model = "deepseek-chat"
  20. }
  21. --比较传入的table和默认table,如果传入的值里少了某个值,默认table顶上去
  22. local function mergeWithDefaults(opts, defaults)
  23. -- 创建一个新的表来存储合并结果
  24. local mergedOpts = {}
  25. -- 先加载默认值
  26. for k, v in pairs(defaults) do
  27. mergedOpts[k] = v
  28. end
  29. -- 使用传入的 opts 表覆盖默认值
  30. for k, v in pairs(opts) do
  31. mergedOpts[k] = v
  32. end
  33. return mergedOpts
  34. end
  35. local function talk(self, msg)
  36. local rheaders = {
  37. ['Content-Type'] = "application/json",
  38. ['Accept'] = "application/json",
  39. ['Authorization'] = "Bearer " .. self.opts.apikey
  40. }
  41. if not msg then
  42. return
  43. end
  44. if type(msg) == "table" then
  45. table.insert(self.msgs, msg)
  46. else
  47. table.insert(self.msgs, {
  48. role = "user",
  49. content = msg
  50. })
  51. end
  52. local rbody = {
  53. model = self.opts.model,
  54. messages = self.msgs,
  55. stream = false
  56. }
  57. local url = self.opts.apiurl .. "/chat/completions"
  58. -- log.info("openai", "request", url, json.encode(rheaders), json.encode(rbody))
  59. local code, headers, body = http.request("POST", url, rheaders, (json.encode(rbody)), {
  60. timeout = 60 * 1000
  61. }).wait()
  62. local tag = ""
  63. -- log.info("openai", code, json.encode(headers) or "", body or "")
  64. if code == 200 then
  65. -- log.info("openai", "执行完成!!!")
  66. local jdata = json.decode(body)
  67. if jdata and jdata.choices and #jdata.choices > 0 then
  68. -- 自动选用第一个回应
  69. local ch = jdata.choices[1].message
  70. table.insert(self.msgs, {
  71. role = ch.role,
  72. content = ch.content
  73. })
  74. return ch
  75. end
  76. elseif code == 400 then
  77. tag = "请求体格式错误,请根据错误信息提示修改请求体"
  78. log.warn(tag)
  79. elseif code == 401 then
  80. tag = "API key错误,认证失败,请检查您的API key是否正确,如没有API key,请先创建API key"
  81. log.warn(tag)
  82. elseif code == 402 then
  83. tag = "账号余额不足,请充值"
  84. log.warn(tag)
  85. elseif code == 422 then
  86. tag = "请求体参数错误,请根据错误信息提示修改请求体"
  87. log.warn(tag)
  88. elseif code == 429 then
  89. tag = "请求速率(TPM 或 RPM)达到上限,请稍后再试"
  90. log.warn(tag)
  91. elseif code == 500 then
  92. tag = "服务器内部故障,请等待后重试,若问题一直存在,请联系deepseek官方解决"
  93. log.warn(tag)
  94. elseif code == 503 then
  95. tag = "服务器负载过高,请稍后重试您的请求"
  96. log.warn(tag)
  97. elseif code < 0 then
  98. tag = "异常,大概率是服务器问题" .. code
  99. if code == -8 then
  100. tag = "链接服务超时或读取数据超时" .. code
  101. end
  102. end
  103. log.info("openai", code, json.encode(headers) or "", body or "")
  104. return tag
  105. end
  106. --[[
  107. 创建一个对话
  108. @api openai.completions(opts, prompt)
  109. @table 调用选项,有必填参数,请看实例
  110. @string 起始提示语,可选
  111. @return 对话实例
  112. @usage
  113. -- 以deepseek为例, 请填充真实的apikey
  114. sys = require "sys"
  115. require "sysplus"
  116. openai = require "openai"
  117. local opts = {
  118. apikey = "sk-123456",
  119. apiurl = "https://api.deepseek.com",
  120. model = "deepseek-chat"
  121. }
  122. local chat = openai.completions(opts)
  123. sys.taskInit(function()
  124. sys.waitUntil("IP_READY")
  125. sys.wait(100)
  126. -- 固定问答演示
  127. local resp = chat:talk("你好,请问LuatOS是什么软件?应该如何学习呢?")
  128. if resp then
  129. log.info("deepseek回复", resp.content)
  130. else
  131. log.info("deepseek执行失败")
  132. end
  133. end)
  134. ]]
  135. function openai.completions(opts, prompt)
  136. opts = mergeWithDefaults(opts, defaultOpts)
  137. local chat = {
  138. opts = opts,
  139. talk = talk,
  140. msgs = {prompt and {
  141. role = "system",
  142. content = prompt
  143. }}
  144. }
  145. return chat
  146. end
  147. return openai