# 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 ```