openai 2.4.0 → 2.5.0
raw patch · 7 files changed
+80/−59 lines, 7 files
Files
- CHANGELOG.md +4/−0
- examples/chat-completions-stream-example/Main.hs +3/−2
- openai.cabal +2/−1
- src/OpenAI/V1.hs +3/−2
- src/OpenAI/V1/Chat/Completions.hs +2/−50
- src/OpenAI/V1/Chat/Completions/Stream.hs +62/−0
- tasty/Main.hs +4/−4
CHANGELOG.md view
@@ -1,3 +1,7 @@+2.5.0:++- **BREAKING (streaming imports):** move chat-completion streaming payload types (`ChatCompletionChunk`, `ChunkChoice`, `Delta`, `ChatCompletionStreamEvent`) from `OpenAI.V1.Chat.Completions` to `OpenAI.V1.Chat.Completions.Stream` to avoid selector ambiguity on `choices`/`usage` in non-streaming imports.+ 2.4.0: - Add Structured Outputs support to the Responses API (`TextConfig`, `TextFormat`, `TextFormat_JSON_Schema`).
examples/chat-completions-stream-example/Main.hs view
@@ -12,6 +12,7 @@ import qualified Data.Text.IO as TIO import qualified OpenAI.V1 as V1 import qualified OpenAI.V1.Chat.Completions as Chat+import qualified OpenAI.V1.Chat.Completions.Stream as ChatStream main :: IO () main = do@@ -23,10 +24,10 @@ let onEvent (Left err) = hPutStrLn stderr ("stream error: " <> T.unpack err) onEvent (Right chunk) = case chunk of -- Print content deltas as they arrive- Chat.ChatCompletionChunk{ Chat.choices = cs } ->+ ChatStream.ChatCompletionChunk{ ChatStream.choices = cs } -> mapM_ printChoice cs where- printChoice Chat.ChunkChoice{ Chat.delta = d } = case Chat.delta_content d of+ printChoice ChatStream.ChunkChoice{ ChatStream.delta = d } = case ChatStream.delta_content d of Just content -> TIO.putStr content >> hFlush stdout Nothing -> pure ()
openai.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name: openai-version: 2.4.0+version: 2.5.0 synopsis: Servant bindings to OpenAI description: This package provides comprehensive and type-safe bindings to OpenAI, providing both a Servant interface and@@ -53,6 +53,7 @@ OpenAI.V1.AutoOr OpenAI.V1.Batches OpenAI.V1.Chat.Completions+ OpenAI.V1.Chat.Completions.Stream OpenAI.V1.ChatKit OpenAI.V1.ChunkingStrategy OpenAI.V1.DeletionStatus
src/OpenAI/V1.hs view
@@ -134,6 +134,7 @@ import qualified OpenAI.V1.Audio as Audio import qualified OpenAI.V1.Batches as Batches import qualified OpenAI.V1.Chat.Completions as Chat.Completions+import qualified OpenAI.V1.Chat.Completions.Stream as Chat.Completions.Stream import qualified OpenAI.V1.ChatKit as ChatKit import qualified OpenAI.V1.Embeddings as Embeddings import qualified OpenAI.V1.Files as Files@@ -362,7 +363,7 @@ createChatCompletionStreamTyped :: CreateChatCompletion- -> (Either Text Chat.Completions.ChatCompletionStreamEvent -> IO ())+ -> (Either Text Chat.Completions.Stream.ChatCompletionStreamEvent -> IO ()) -> IO () createChatCompletionStreamTyped req onEvent = createChatCompletionStream req $ \ev -> case ev of@@ -531,7 +532,7 @@ -> IO () , createChatCompletionStreamTyped :: CreateChatCompletion- -> (Either Text Chat.Completions.ChatCompletionStreamEvent -> IO ())+ -> (Either Text Chat.Completions.Stream.ChatCompletionStreamEvent -> IO ()) -> IO () , createResponse :: CreateResponse -> IO ResponseObject , createResponseStream
src/OpenAI/V1/Chat/Completions.hs view
@@ -1,6 +1,7 @@ -- | @\/v1\/chat\/completions@ ----- Streaming is not implemented here;+-- Streaming payload types are available in+-- "OpenAI.V1.Chat.Completions.Stream". module OpenAI.V1.Chat.Completions ( -- * Main types CreateChatCompletion(..)@@ -10,11 +11,6 @@ , Message(..) , messageToContent , Content(..)- -- * Streaming types- , ChatCompletionChunk(..)- , ChunkChoice(..)- , Delta(..)- , ChatCompletionStreamEvent -- * Stream options , ChatCompletionStreamOptions(..) , _ChatCompletionStreamOptions@@ -429,50 +425,6 @@ , usage :: Usage CompletionTokensDetails PromptTokensDetails } deriving stock (Generic, Show) deriving anyclass (FromJSON, ToJSON)---- | Delta message content for streaming-data Delta = Delta- { delta_content :: Maybe Text- , delta_refusal :: Maybe Text- , delta_role :: Maybe Text- , delta_tool_calls :: Maybe (Vector ToolCall)- } deriving stock (Generic, Show)--deltaOptions :: Options-deltaOptions = aesonOptions- { fieldLabelModifier = stripPrefix "delta_"- }--instance FromJSON Delta where- parseJSON = genericParseJSON deltaOptions--instance ToJSON Delta where- toJSON = genericToJSON deltaOptions---- | A streaming choice chunk-data ChunkChoice = ChunkChoice- { delta :: Delta- , finish_reason :: Maybe Text- , index :: Natural- , logprobs :: Maybe LogProbs- } deriving stock (Generic, Show)- deriving anyclass (FromJSON, ToJSON)---- | Chat completion chunk (streaming response)-data ChatCompletionChunk = ChatCompletionChunk- { id :: Text- , choices :: Vector ChunkChoice- , created :: POSIXTime- , model :: Model- , service_tier :: Maybe ServiceTier- , system_fingerprint :: Maybe Text- , object :: Text- , usage :: Maybe (Usage CompletionTokensDetails PromptTokensDetails)- } deriving stock (Generic, Show)- deriving anyclass (FromJSON, ToJSON)---- | Type alias for streaming events (currently just chunks)-type ChatCompletionStreamEvent = ChatCompletionChunk -- | Servant API type API =
+ src/OpenAI/V1/Chat/Completions/Stream.hs view
@@ -0,0 +1,62 @@+-- | Streaming payload types for @/v1/chat/completions@.+module OpenAI.V1.Chat.Completions.Stream+ ( ChatCompletionChunk(..)+ , ChunkChoice(..)+ , Delta(..)+ , ChatCompletionStreamEvent+ ) where++import OpenAI.Prelude+import OpenAI.V1.Chat.Completions (LogProbs, ServiceTier)+import OpenAI.V1.Models (Model)+import OpenAI.V1.ToolCall (ToolCall)+import OpenAI.V1.Usage+ ( CompletionTokensDetails+ , PromptTokensDetails+ , Usage+ )+import Prelude hiding (id)++-- | Delta message content for streaming+data Delta = Delta+ { delta_content :: Maybe Text+ , delta_refusal :: Maybe Text+ , delta_role :: Maybe Text+ , delta_tool_calls :: Maybe (Vector ToolCall)+ } deriving stock (Generic, Show)++deltaOptions :: Options+deltaOptions = aesonOptions+ { fieldLabelModifier = stripPrefix "delta_"+ }++instance FromJSON Delta where+ parseJSON = genericParseJSON deltaOptions++instance ToJSON Delta where+ toJSON = genericToJSON deltaOptions++-- | A streaming choice chunk+data ChunkChoice = ChunkChoice+ { delta :: Delta+ , finish_reason :: Maybe Text+ , index :: Natural+ , logprobs :: Maybe LogProbs+ } deriving stock (Generic, Show)+ deriving anyclass (FromJSON, ToJSON)++-- | Chat completion chunk (streaming response)+data ChatCompletionChunk = ChatCompletionChunk+ { id :: Text+ , choices :: Vector ChunkChoice+ , created :: POSIXTime+ , model :: Model+ , service_tier :: Maybe ServiceTier+ , system_fingerprint :: Maybe Text+ , object :: Text+ , usage :: Maybe (Usage CompletionTokensDetails PromptTokensDetails)+ } deriving stock (Generic, Show)+ deriving anyclass (FromJSON, ToJSON)++-- | Type alias for streaming events (currently just chunks)+type ChatCompletionStreamEvent = ChatCompletionChunk
tasty/Main.hs view
@@ -17,7 +17,7 @@ import OpenAI.V1.Audio.Translations (CreateTranslation(..)) import OpenAI.V1.AutoOr (AutoOr(..)) import OpenAI.V1.Batches (BatchObject(..), CreateBatch(..))-import OpenAI.V1.Chat.Completions (CreateChatCompletion(..), Modality(..), ChatCompletionChunk(..), ChunkChoice(..), delta_content)+import OpenAI.V1.Chat.Completions (CreateChatCompletion(..), Modality(..)) import OpenAI.V1.Embeddings (CreateEmbeddings(..), EncodingFormat(..)) import OpenAI.V1.Files (FileObject(..), Order(..), UploadFile(..)) import OpenAI.V1.Images.Edits (CreateImageEdit(..))@@ -60,6 +60,7 @@ import qualified Network.HTTP.Client.TLS as TLS import qualified OpenAI.V1 as V1 import qualified OpenAI.V1.Chat.Completions as Completions+import qualified OpenAI.V1.Chat.Completions.Stream as ChatStream import qualified OpenAI.V1.Files as Files import qualified OpenAI.V1.FineTuning.Jobs as Jobs import qualified OpenAI.V1.Images.ResponseFormat as ResponseFormat@@ -356,10 +357,10 @@ let onEvent (Left _err) = Concurrent.putMVar done () onEvent (Right ev) = case ev of- ChatCompletionChunk{ choices = cs } ->+ ChatStream.ChatCompletionChunk{ ChatStream.choices = cs } -> mapM_ accChoice cs where- accChoice ChunkChoice{ delta = d } = case delta_content d of+ accChoice ChatStream.ChunkChoice{ ChatStream.delta = d } = case ChatStream.delta_content d of Just content -> IORef.modifyIORef' acc (<> content) Nothing -> Concurrent.putMVar done () @@ -1203,7 +1204,6 @@ fineTuningTest, batchesTest, uploadsTest,- createImageMinimalTest, createImageMaximalTest, createImageEditMinimalTest, createImageEditMaximalTest,