# Haskell - call OpenAI API
```haskell
{-# LANGUAGE OverloadedStrings #-}
module Main (main) where
import System.Environment (getArgs, getEnv)
import qualified Data.Text as T
import qualified Data.Text.Encoding as TE
import Data.Aeson
import Data.Aeson.Types (parseMaybe)
import qualified Data.Vector as V
import Network.HTTP.Req
import System.IO (isEOF, hIsTerminalDevice, stdin)
-- | Extract content from OpenAI API response
getContent :: Value -> Maybe String
getContent = parseMaybe $ \v -> do
obj <- parseJSON v
choices <- obj .: "choices"
firstChoice <- case choices of
Array arr -> case V.toList arr of
(x:_) -> parseJSON x
[] -> fail "Empty choices array"
_ -> fail "Expected choices to be an array"
message <- firstChoice .: "message"
message .: "content"
-- | Create chat completion request payload
createPayload :: String -> String -> Value
createPayload msg input = object
[ "model" .= ("gpt-4o" :: String)
, "messages" .= messages
, "temperature" .= (0.7 :: Float)
]
where
messages = if null input
then toJSONList [object [ "role" .= ("user" :: String), "content" .= msg]]
else toJSONList [object [ "role" .= ("user" :: String), "content" .= msg]
, object [ "role" .= ("user" :: String), "content" .= input]
]
-- | Make API request to OpenAI
makeRequest :: String -> String -> String -> Req (Maybe String)
makeRequest apiKey msg input = do
let apiKeyBytes = TE.encodeUtf8 . T.pack $ apiKey
let url = https "api.openai.com" /: "v1" /: "chat" /: "completions"
r <- req POST url
(ReqBodyJson $ createPayload msg input)
jsonResponse
(header "Authorization" $ "Bearer " <> apiKeyBytes)
return $ getContent (responseBody r :: Value)
-- | Get content from stdin only if it's from a pipe
getInputContent :: IO String
getInputContent = do
isTerm <- hIsTerminalDevice stdin
if isTerm
then return ""
else do
empty <- isEOF
if empty
then return ""
else getContents
-- | Main program
main :: IO ()
main = do
args <- getArgs
case args of
(msg:_) -> do
input <- getInputContent
apiKey <- getEnv "OPENAI_API_KEY"
response <- runReq defaultHttpConfig $ makeRequest apiKey msg input
case response of
Just content -> putStrLn $ "[GPT]: " ++ content
Nothing -> putStrLn "[APP]: Content not found"
[] -> putStrLn "[APP]: Please provide a message as a command line argument"
```
```sh
cabal build
```
```sh
./gpt "Hello"
```
```sh
cat app/Main.hs | ./gpt "Explain this code" | glow
```