packages feed

openai-1.0.0: src/OpenAI/V1/Threads/Messages.hs

-- | @\/v1\/threads/:thread_id/messages@
module OpenAI.V1.Threads.Messages
    ( -- * Main types
        MessageID(..)
      , Message(..)
      , ModifyMessage(..)
      , _ModifyMessage
      , MessageObject(..)

      -- * Other types
      , Status(..)
      , IncompleteDetails(..)
      , File(..)
      , Annotation(..)
      , TextObject(..)

      -- * Servant
      , API
    ) where

import OpenAI.Prelude
import OpenAI.V1.Assistants (AssistantID)
import OpenAI.V1.DeletionStatus
import OpenAI.V1.Files (FileID)
import OpenAI.V1.ListOf
import OpenAI.V1.Message
import OpenAI.V1.Threads (ThreadID)
import OpenAI.V1.Threads.Runs (RunID)

-- | Message ID
newtype MessageID = MessageID{ text :: Text }
    deriving newtype (FromJSON, IsString, Show, ToHttpApiData, ToJSON)

-- | Request body for @\/v1\/threads\/:thread_id\/messages\/:message_id@
data ModifyMessage = ModifyMessage
    { metadata :: Maybe (Map Text Text)
    } deriving stock (Generic, Show)

instance ToJSON ModifyMessage where
    toJSON = genericToJSON aesonOptions

-- | Default `ModifyMessage`
_ModifyMessage :: ModifyMessage
_ModifyMessage = ModifyMessage
    { metadata = Nothing
    }

-- | The status of the message
data Status = In_Progress | Incomplete | Completed
    deriving stock (Generic, Show)

instance FromJSON Status where
    parseJSON = genericParseJSON aesonOptions

-- | On an incomplete message, details about why the message is incomplete.
data IncompleteDetails = IncompleteDetails
    { reason :: Text
    } deriving (Generic, Show)
      deriving anyclass (FromJSON)

-- | File
data File = File
    { file_id :: FileID
    } deriving stock (Generic, Show)
      deriving anyclass (FromJSON)

-- | An annotation
data Annotation
    = File_Citation
        { text :: Text
        , file_citation :: File
        , start_index :: Natural
        , end_index :: Natural
        }
    | File_Path
        { text :: Text
        , file_path :: File
        , start_index :: Natural
        , end_index :: Natural
        }
    deriving stock (Generic, Show)

instance FromJSON Annotation where
    parseJSON = genericParseJSON aesonOptions
        { sumEncoding =
            TaggedObject{ tagFieldName = "type", contentsFieldName = "" }

        , tagSingleConstructors = True
        }

-- | The text content that is part of a message.
data TextObject = TextObject
    { value :: Text
    , annotations :: Vector Annotation
    } deriving stock (Generic, Show)
      deriving anyclass (FromJSON)

instance IsString TextObject where
    fromString string =
        TextObject{ value = fromString string, annotations = [] }

-- | Represents a message within a thread.
data MessageObject = MessageObject
    { id :: MessageID
    , object :: Text
    , created_at :: POSIXTime
    , thread_id :: ThreadID
    , status :: Maybe Status
    , incomplete_details :: Maybe IncompleteDetails
    , completed_at :: Maybe POSIXTime
    , incomplete_at :: Maybe POSIXTime
    , role :: Text
    , content :: Vector (Content TextObject)
    , assistant_id :: Maybe AssistantID
    , run_id :: Maybe RunID
    , attachments :: Maybe (Vector Attachment)
    , metadata :: Map Text Text
    } deriving (Generic, Show)
      deriving anyclass (FromJSON)

-- | Servant API
type API =
        Header' '[Required, Strict] "OpenAI-Beta" Text
    :>  "threads"
    :>  (         Capture "thread_id" ThreadID
              :>  "messages"
              :>  ReqBody '[JSON] Message
              :>  Post '[JSON] MessageObject
        :<|>      Capture "thread_id" ThreadID
              :>  "messages"
              :>  Get '[JSON] (ListOf MessageObject)
        :<|>      Capture "thread_id" ThreadID
              :>  "messages"
              :>  Capture "message_id" MessageID
              :>  Get '[JSON] MessageObject
        :<|>      Capture "thread_id" ThreadID
              :>  "messages"
              :>  Capture "message_id" MessageID
              :>  ReqBody '[JSON] ModifyMessage
              :>  Post '[JSON] MessageObject
        :<|>      Capture "thread_id" ThreadID
              :>  "messages"
              :>  Capture "message_id" MessageID
              :>  Delete '[JSON] DeletionStatus
        )