-- Test OpenAI.API and OpenAI.Types modules
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
module Main where
import Test.Hspec
import OpenAI.API
import OpenAI.Types
--import Data.Aeson.Decoding
import Data.Aeson
import Data.Maybe (fromMaybe)
import Data.Function ((&))
import Data.List (stripPrefix)
import qualified Data.Char as Char
import qualified Data.Text as T
uncapitalize :: String -> String
uncapitalize (first:rest) = Char.toLower first : rest
uncapitalize [] = []
removeFieldLabelPrefix :: Bool -> String -> Options
removeFieldLabelPrefix forParsing prefix =
defaultOptions
{ omitNothingFields = True
, fieldLabelModifier = uncapitalize . fromMaybe (error ("did not find prefix " ++ prefix)) . stripPrefix prefix . replaceSpecialChars
}
where
replaceSpecialChars field = foldl (&) field (map mkCharReplacement specialChars)
specialChars =
[ ("$", "'Dollar")
, ("^", "'Caret")
, ("|", "'Pipe")
, ("=", "'Equal")
, ("*", "'Star")
, ("-", "'Dash")
, ("&", "'Ampersand")
, ("%", "'Percent")
, ("#", "'Hash")
, ("@", "'At")
, ("!", "'Exclamation")
, ("+", "'Plus")
, (":", "'Colon")
, (";", "'Semicolon")
, (">", "'GreaterThan")
, ("<", "'LessThan")
, (".", "'Period")
, ("_", "Underscore")
, ("?", "'Question_Mark")
, (",", "'Comma")
, ("'", "'Quote")
, ("/", "'Slash")
, ("(", "'Left_Parenthesis")
, (")", "'Right_Parenthesis")
, ("{", "'Left_Curly_Bracket")
, ("}", "'Right_Curly_Bracket")
, ("[", "'Left_Square_Bracket")
, ("]", "'Right_Square_Bracket")
, ("~", "'Tilde")
, ("`", "'Backtick")
, ("<=", "'Less_Than_Or_Equal_To")
, (">=", "'Greater_Than_Or_Equal_To")
, ("!=", "'Not_Equal")
, ("<>", "'Not_Equal")
, ("~=", "'Tilde_Equal")
, ("\\", "'Back_Slash")
, ("\"", "'Double_Quote")
]
mkCharReplacement (replaceStr, searchStr) = T.unpack . replacer (T.pack searchStr) (T.pack replaceStr) . T.pack
replacer =
if forParsing
then flip T.replace
else T.replace
main :: IO ()
main = hspec $ do
describe "OpenAI API" $ do
it "Encode labels of CompletionUsage" $ do
let options = removeFieldLabelPrefix False "completionUsage"
replace = fieldLabelModifier options
replace "completionUsagePromptUnderscoretokens" `shouldBe` "prompt_tokens"
it "Decode labels of CompletionUsage" $ do
let options = removeFieldLabelPrefix False "completionUsage"
replace = fieldLabelModifier options
replace "completionUsagePromptUnderscoretokens" `shouldBe` "prompt_tokens"
it "Encode CompletionUsage" $ do
let usage = CompletionUsage 8 9 17
encode usage `shouldBe` "{\"completion_tokens\":8,\"prompt_tokens\":9,\"total_tokens\":17}"
it "Decode CompletionUsage" $ do
let jsonData = "{\n \"prompt_tokens\": 9,\n \"completion_tokens\": 8,\n \"total_tokens\": 17\n}"
let response = eitherDecode jsonData :: Either String CompletionUsage
response `shouldBe` (Right $ CompletionUsage 8 9 17)
it "Encode Request" $ do
let jsonData = "{\"messages\":[{\"content\":\"Hello\",\"role\":\"user\"}],\"model\":\"gpt-3.5-turbo\",\"seed\":0}"
request = eitherDecode jsonData :: Either String CreateChatCompletionRequest
request `shouldBe` Right (CreateChatCompletionRequest
{ createChatCompletionRequestMessages = [
ChatCompletionRequestMessage
{ chatCompletionRequestMessageContent = Just $ ChatCompletionRequestMessageContentText "Hello"
-- 'User' is not one of ['system', 'assistant', 'user', 'function']
, chatCompletionRequestMessageRole = "user"
, chatCompletionRequestMessageName = Nothing
, chatCompletionRequestMessageToolUnderscorecalls = Nothing
, chatCompletionRequestMessageFunctionUnderscorecall = Nothing
, chatCompletionRequestMessageToolUnderscorecallUnderscoreid = Nothing
}
]
, createChatCompletionRequestModel = CreateChatCompletionRequestModel "gpt-3.5-turbo"
, createChatCompletionRequestFrequencyUnderscorepenalty = Nothing
, createChatCompletionRequestLogitUnderscorebias = Nothing
, createChatCompletionRequestLogprobs = Nothing
, createChatCompletionRequestTopUnderscorelogprobs = Nothing
, createChatCompletionRequestMaxUnderscoretokens = Nothing
, createChatCompletionRequestN = Nothing
, createChatCompletionRequestPresenceUnderscorepenalty = Nothing
, createChatCompletionRequestResponseUnderscoreformat = Nothing
, createChatCompletionRequestSeed = Just 0
, createChatCompletionRequestStop = Nothing
, createChatCompletionRequestStream = Nothing
, createChatCompletionRequestTemperature = Nothing
, createChatCompletionRequestTopUnderscorep = Nothing
, createChatCompletionRequestTools = Nothing
, createChatCompletionRequestToolUnderscorechoice = Nothing
, createChatCompletionRequestUser = Nothing
, createChatCompletionRequestFunctionUnderscorecall = Nothing
, createChatCompletionRequestFunctions = Nothing
} )
it "Load and save response types" $ do
let jsonData = "{\n \"id\": \"chatcmpl-8zKzKZVra3d7t082fFoB8ZAFxLSWf\",\n \"object\": \"chat.completion\",\n \"created\": 1709629378,\n \"model\": \"gpt-3.5-turbo-0125\",\n \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": \"assistant\",\n \"content\": \"Hello! How can I assist you today?\"\n },\n \"logprobs\": null,\n \"finish_reason\": \"stop\"\n }\n ],\n \"usage\": {\n \"prompt_tokens\": 8,\n \"completion_tokens\": 9,\n \"total_tokens\": 17\n },\n \"system_fingerprint\": \"fp_b9d4cef803\"\n}\n"
let response = eitherDecode jsonData :: Either String CreateChatCompletionResponse
response `shouldBe` (Right (
CreateChatCompletionResponse
{ createChatCompletionResponseId = "chatcmpl-8zKzKZVra3d7t082fFoB8ZAFxLSWf"
, createChatCompletionResponseObject = "chat.completion"
, createChatCompletionResponseCreated = 1709629378
, createChatCompletionResponseModel = "gpt-3.5-turbo-0125"
, createChatCompletionResponseChoices = [
CreateChatCompletionResponseChoicesInner
{ createChatCompletionResponseChoicesInnerIndex = 0
, createChatCompletionResponseChoicesInnerMessage = ChatCompletionResponseMessage
{ chatCompletionResponseMessageRole = "assistant"
, chatCompletionResponseMessageContent = Just "Hello! How can I assist you today?"
, chatCompletionResponseMessageToolUnderscorecalls = Nothing
, chatCompletionResponseMessageFunctionUnderscorecall = Nothing
}
, createChatCompletionResponseChoicesInnerLogprobs = Nothing
, createChatCompletionResponseChoicesInnerFinishUnderscorereason = "stop"
}
]
, createChatCompletionResponseUsage = Just $ CompletionUsage
{ completionUsagePromptUnderscoretokens = 8
, completionUsageCompletionUnderscoretokens = 9
, completionUsageTotalUnderscoretokens = 17
}
, createChatCompletionResponseSystemUnderscorefingerprint = Just "fp_b9d4cef803"
}
))