-
-
Notifications
You must be signed in to change notification settings - Fork 26
/
openai.clj
120 lines (111 loc) · 5.84 KB
/
openai.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
(ns ^:no-doc wkok.openai-clojure.openai
(:require
[clojure.java.io :as io]
[martian.hato :as martian-http]
[martian.core :as martian]
[martian.openapi :as openapi]
[martian.yaml :as yaml]
[wkok.openai-clojure.sse :as sse]
[wkok.openai-clojure.interceptors :as openai-interceptors]
[martian.encoders :as encoders]
[martian.interceptors :as interceptors]
[schema.core :as s]))
(def add-headers
{:name ::add-headers
:enter (fn [ctx]
(let [api-key (or (-> ctx :params :wkok.openai-clojure.core/options :api-key)
(System/getenv "OPENAI_API_KEY"))
organization (or (-> ctx :params :wkok.openai-clojure.core/options :organization)
(System/getenv "OPENAI_ORGANIZATION"))
openai-beta (-> ctx :params :wkok.openai-clojure.core/options :openai-beta)]
(update-in ctx [:request :headers]
(fn [headers]
(cond-> headers
(not-empty api-key) (assoc "Authorization" (str "Bearer " api-key))
(not-empty organization) (assoc "OpenAI-Organization" organization)
(not-empty openai-beta) (assoc "OpenAI-Beta" openai-beta))))))})
(defn override-api-endpoint
[base-url]
{:name ::override-api-endpoint
:enter (fn [ctx]
(update-in ctx [:request :url]
(fn [url]
(let [endpoint (or (-> ctx :params :wkok.openai-clojure.core/options :api-endpoint)
(System/getenv "OPENAI_API_ENDPOINT")
base-url)]
(str endpoint (subs url (count base-url)))))))})
(defn- multipart-form-data?
[handler]
(-> handler :openapi-definition :requestBody :content :multipart/form-data))
(defn- param->multipart-entry
[[param content]]
{:name (name param)
:content (if (or (instance? java.io.File content)
(instance? java.io.InputStream content)
(bytes? content))
content
(str content))})
(def multipart-form-data
{:name ::multipart-form-data
:enter (fn [{:keys [handler params] :as ctx}]
(let [params' (dissoc params :wkok.openai-clojure.core/options)]
(if (multipart-form-data? handler)
(-> (assoc-in ctx [:request :multipart]
(map param->multipart-entry params'))
(update-in [:request :headers] dissoc "Content-Type")
(update :request dissoc :body))
ctx)))})
(defn update-file-schema
[m operation-id field-name]
(martian/update-handler m operation-id assoc-in [:body-schema :body field-name] java.io.File))
(defn update-file-schemas
[m]
(-> m
(update-file-schema :create-transcription :file)
(update-file-schema :create-translation :file)
(update-file-schema :create-file :file)
(update-file-schema :create-image-edit :image)
(update-file-schema :create-image-edit (schema.core/optional-key :mask))
(update-file-schema :create-image-variation :image)))
(defn bootstrap-openapi
"Bootstrap the martian from a local copy of the openai swagger spec"
[]
(let [definition (yaml/yaml->edn (slurp (io/resource "openapi.yaml")))
base-url (openapi/base-url nil nil definition)
encoders (assoc (encoders/default-encoders)
"multipart/form-data" nil
"application/octet-stream" nil)
opts (update martian-http/default-opts
:interceptors (fn [interceptors]
(-> interceptors
(interceptors/inject
add-headers
:after
:martian.interceptors/header-params)
(interceptors/inject
multipart-form-data
:after
::add-headers)
(interceptors/inject
openai-interceptors/set-request-options
:before
:martian.hato/perform-request)
(interceptors/inject
(override-api-endpoint base-url)
:before
:martian.hato/perform-request)
(interceptors/inject
sse/perform-sse-capable-request
:replace
:martian.hato/perform-request)
(interceptors/inject
(interceptors/encode-body encoders)
:replace
:martian.interceptors/encode-body)
(interceptors/inject
(interceptors/coerce-response encoders)
:replace
:martian.interceptors/coerce-response))))]
(-> (martian/bootstrap-openapi base-url definition opts)
update-file-schemas)))
(def m (delay (bootstrap-openapi)))