{-# OPTIONS_GHC -cpp -pgmPcpphs -optP--cpp #-}
{-# LANGUAGE CPP #-}
module OpenAI.Client
  ( -- * Basics
    ApiKey, OpenAIClient, makeOpenAIClient, ClientError(..)
    -- * Helper types
  , TimeStamp(..), OpenAIList(..)
    -- * Engine
  , EngineId(..), Engine(..)
  , listEngines
  , getEngine
    -- * Text completion
  , TextCompletionId(..), TextCompletionChoice(..), TextCompletion(..), TextCompletionCreate(..)
  , defaultTextCompletionCreate
  , completeText
    -- * Searching
  , SearchResult(..), SearchResultCreate(..)
  , searchDocuments
  )
where

import OpenAI.Api
import OpenAI.Client.Internal.Helpers
import OpenAI.Resources

import Data.Proxy
import Network.HTTP.Client (Manager)
import Servant.API
import Servant.Client
import qualified Data.Text as T
import qualified Data.Text.Encoding as T

-- | Your OpenAI API key. Can be obtained from the OpenAI dashboard. Format: @sk-<redacted>@
type ApiKey = T.Text

-- | Holds a 'Manager' and your API key.
data OpenAIClient
  = OpenAIClient
  { OpenAIClient -> BasicAuthData
scBasicAuthData :: BasicAuthData
  , OpenAIClient -> Manager
scManager :: Manager
  , OpenAIClient -> Int
scMaxRetries :: Int
  }

-- | Construct a 'OpenAIClient'. Note that the passed 'Manager' must support https (e.g. via @http-client-tls@)
makeOpenAIClient ::
  ApiKey
  -> Manager
  -> Int
  -- ^ Number of automatic retries the library should attempt.
  -> OpenAIClient
makeOpenAIClient :: ApiKey -> Manager -> Int -> OpenAIClient
makeOpenAIClient ApiKey
k = BasicAuthData -> Manager -> Int -> OpenAIClient
OpenAIClient (ByteString -> ByteString -> BasicAuthData
BasicAuthData ByteString
"" (ApiKey -> ByteString
T.encodeUtf8 ApiKey
k))

api :: Proxy OpenAIApi
api :: Proxy OpenAIApi
api = Proxy OpenAIApi
forall k (t :: k). Proxy t
Proxy

openaiBaseUrl :: BaseUrl
openaiBaseUrl :: BaseUrl
openaiBaseUrl = Scheme -> String -> Int -> String -> BaseUrl
BaseUrl Scheme
Https String
"api.openai.com" Int
443 String
""

#define EP0(N, R) \
    N##' :: BasicAuthData -> ClientM R;\
    N :: OpenAIClient -> IO (Either ClientError R);\
    N sc = runRequest (scMaxRetries sc) 0 $ runClientM (N##' (scBasicAuthData sc)) (mkClientEnv (scManager sc) openaiBaseUrl)

#define EP(N, ARG, R) \
    N##' :: BasicAuthData -> ARG -> ClientM R;\
    N :: OpenAIClient -> ARG -> IO (Either ClientError R);\
    N sc a = runRequest (scMaxRetries sc) 0 $ runClientM (N##' (scBasicAuthData sc) a) (mkClientEnv (scManager sc) openaiBaseUrl)

#define EP2(N, ARG, ARG2, R) \
    N##' :: BasicAuthData -> ARG -> ARG2 -> ClientM R;\
    N :: OpenAIClient -> ARG -> ARG2 -> IO (Either ClientError R);\
    N sc a b = runRequest (scMaxRetries sc) 0 $ runClientM (N##' (scBasicAuthData sc) a b) (mkClientEnv (scManager sc) openaiBaseUrl)

EP2(completeText, EngineId, TextCompletionCreate, TextCompletion)
EP2(searchDocuments, EngineId, SearchResultCreate, (OpenAIList SearchResult))

EP0(listEngines, (OpenAIList Engine))
EP(getEngine, EngineId, Engine)

BasicAuthData -> ClientM (OpenAIList Engine)
listEngines'
  :<|> BasicAuthData -> EngineId -> ClientM Engine
getEngine'
  :<|> BasicAuthData
-> EngineId -> TextCompletionCreate -> ClientM TextCompletion
completeText'
  :<|> BasicAuthData
-> EngineId
-> SearchResultCreate
-> ClientM (OpenAIList SearchResult)
searchDocuments'
  = Proxy OpenAIApi -> Client ClientM OpenAIApi
forall api.
HasClient ClientM api =>
Proxy api -> Client ClientM api
client Proxy OpenAIApi
api