From 076fc65b00bcad68dfa1462d90f19200de2e5dbe Mon Sep 17 00:00:00 2001 From: Andrew Brower Date: Tue, 29 Oct 2024 16:04:01 -0400 Subject: [PATCH 1/2] add locks around api key usage to allow updating --- src/openai_leap.nim | 45 ++++++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/src/openai_leap.nim b/src/openai_leap.nim index 87bec0b..cb16bea 100644 --- a/src/openai_leap.nim +++ b/src/openai_leap.nim @@ -1,5 +1,5 @@ import - std/[os, osproc, json, options, strutils, strformat, tables], + std/[os, locks, osproc, json, options, strutils, strformat, tables], curly, jsony, webby ## OpenAI Api Reference: https://platform.openai.com/docs/api-reference/introduction @@ -11,6 +11,7 @@ import type OpenAiApiObj* = object curly: Curly + lock: Lock # lock for modifying the openai api object baseUrl: string curlTimeout: int apiKey: string @@ -271,11 +272,24 @@ proc newOpenAiApi*( result = cast[OpenAiApi](allocShared0(sizeof(OpenAiApiObj))) result.curly = newCurly(maxInFlight) + initLock(result.lock) result.baseUrl = baseUrl result.curlTimeout = curlTimeout result.apiKey = apiKeyVar result.organization = organization +template sync*(a: Lock, body: untyped) = + acquire(a) + try: + body + finally: + release(a) + +proc updateApiKey*(api: OpenAiApi, apiKey: string) = + ## Update the API key for the OpenAI API client. + api.lock.sync: + api.apiKey = apiKey + proc close*(api: OpenAiApi) = ## Clean up the OpenAPI API client. api.curly.close() @@ -285,14 +299,15 @@ proc get(api: OpenAiApi, path: string): Response = ## Make a GET request to the OpenAI API. var headers: curly.HttpHeaders headers["Content-Type"] = "application/json" - headers["Authorization"] = "Bearer " & api.apiKey + api.lock.sync: + headers["Authorization"] = "Bearer " & api.apiKey if api.organization != "": headers["Organization"] = api.organization let resp = api.curly.get(api.baseUrl & path, headers, api.curlTimeout) if resp.code != 200: raise newException( OpenAiError, - &"OpenAi call {path} failed: {resp.code} {resp.body}" + &"API call {path} failed: {resp.code} {resp.body}" ) result = resp @@ -300,7 +315,8 @@ proc post(api: OpenAiApi, path: string, body: string): Response = ## Make a POST request to the OpenAI API. var headers: curly.HttpHeaders headers["Content-Type"] = "application/json" - headers["Authorization"] = "Bearer " & api.apiKey + api.lock.sync: + headers["Authorization"] = "Bearer " & api.apiKey if api.organization != "": headers["Organization"] = api.organization let resp = api.curly.post( @@ -312,7 +328,7 @@ proc post(api: OpenAiApi, path: string, body: string): Response = if resp.code != 200: raise newException( OpenAiError, - &"OpenAi call {path} failed: {resp.code} {resp.body}" + &"API call {path} failed: {resp.code} {resp.body}" ) result = resp @@ -320,7 +336,8 @@ proc postStream(api: OpenAiApi, path: string, body: string): ResponseStream = ## Make a streaming POST request to the OpenAI API. var headers: curly.HttpHeaders headers["Content-Type"] = "application/json" - headers["Authorization"] = "Bearer " & api.apiKey + api.lock.sync: + headers["Authorization"] = "Bearer " & api.apiKey if api.organization != "": headers["Organization"] = api.organization @@ -333,7 +350,7 @@ proc postStream(api: OpenAiApi, path: string, body: string): ResponseStream = if resp.code != 200: raise newException( OpenAiError, - &"OpenAi call {path} failed: {resp.code}" + &"API call {path} failed: {resp.code}" ) result = resp @@ -344,7 +361,8 @@ proc post( ): Response = ## Make a POST request to the OpenAI API. var headers: curly.HttpHeaders - headers["Authorization"] = "Bearer " & api.apiKey + api.lock.sync: + headers["Authorization"] = "Bearer " & api.apiKey if api.organization != "": headers["Organization"] = api.organization let (contentType, body) = encodeMultipart(entries) @@ -358,7 +376,7 @@ proc post( if resp.code != 200: raise newException( OpenAiError, - &"OpenAi call {path} failed: {resp.code} {resp.body}" + &"API call {path} failed: {resp.code} {resp.body}" ) result = resp @@ -366,14 +384,15 @@ proc delete(api: OpenAiApi, path: string): Response = ## Make a DELETE request to the OpenAI API. var headers: curly.HttpHeaders headers["Content-Type"] = "application/json" - headers["Authorization"] = "Bearer " & api.apiKey + api.lock.sync: + headers["Authorization"] = "Bearer " & api.apiKey if api.organization != "": headers["Organization"] = api.organization let resp = api.curly.delete(api.baseUrl & path, headers, api.curlTimeout) if resp.code != 200: raise newException( OpenAiError, - &"OpenAi call {path} failed: {resp.code} {resp.body}" + &"API call {path} failed: {resp.code} {resp.body}" ) result = resp @@ -534,8 +553,8 @@ proc createFineTuneDataset*(api: OpenAiApi, filepath: string): OpenAIFile = if not fileExists(filepath): raise newException(OpenAiError, "File does not exist: " & filepath) - - let auth = "Bearer " & api.apiKey + api.lock.sync: + let auth = "Bearer " & api.apiKey var orgLine = "" if api.organization != "": orgLine = "-H \"Organization: " & api.organization & "\"" From 2fcc37ec7f72cb200b75f1b6217d05771e7ddae9 Mon Sep 17 00:00:00 2001 From: Andrew Brower Date: Tue, 29 Oct 2024 16:05:18 -0400 Subject: [PATCH 2/2] bump version and fix mistake --- openai_leap.nimble | 2 +- src/openai_leap.nim | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/openai_leap.nimble b/openai_leap.nimble index 5e29d96..f5e83e0 100644 --- a/openai_leap.nimble +++ b/openai_leap.nimble @@ -1,4 +1,4 @@ -version = "2.0.7" +version = "2.0.8" author = "Andrew Brower" description = "OpenAI API for Nim" license = "MIT" diff --git a/src/openai_leap.nim b/src/openai_leap.nim index cb16bea..1329556 100644 --- a/src/openai_leap.nim +++ b/src/openai_leap.nim @@ -553,14 +553,15 @@ proc createFineTuneDataset*(api: OpenAiApi, filepath: string): OpenAIFile = if not fileExists(filepath): raise newException(OpenAiError, "File does not exist: " & filepath) + var authToken: string api.lock.sync: - let auth = "Bearer " & api.apiKey + authToken = "Bearer " & api.apiKey var orgLine = "" if api.organization != "": orgLine = "-H \"Organization: " & api.organization & "\"" let curlUploadCmd = &""" curl -s https://api.openai.com/v1/files \ - -H "Authorization: {auth}" \ + -H "Authorization: {authToken}" \ {orgLine} \ -F purpose="fine-tune" \ -F file="@{filepath}"