{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
module Data.Ollama.Generate
(
generate
, defaultGenerateOps
, generateJson
, GenerateOps (..)
, GenerateResponse (..)
) where
import Control.Exception (try)
import Data.Aeson
import Data.ByteString.Char8 qualified as BS
import Data.ByteString.Lazy.Char8 qualified as BSL
import Data.Maybe
import Data.Ollama.Common.Utils as CU
import Data.Ollama.Common.Types (Format(..))
import Data.Text (Text)
import Data.Text qualified as T
import Data.Text.Encoding qualified as T
import Data.Time (UTCTime)
import GHC.Int (Int64)
import Network.HTTP.Client
data GenerateOps = GenerateOps
{ GenerateOps -> Text
modelName :: Text
, GenerateOps -> Text
prompt :: Text
, GenerateOps -> Maybe Text
suffix :: Maybe Text
, GenerateOps -> Maybe [Text]
images :: Maybe [Text]
, GenerateOps -> Maybe Format
format :: Maybe Format
, GenerateOps -> Maybe Text
system :: Maybe Text
, GenerateOps -> Maybe Text
template :: Maybe Text
, GenerateOps -> Maybe (GenerateResponse -> IO (), IO ())
stream :: Maybe (GenerateResponse -> IO (), IO ())
, GenerateOps -> Maybe Bool
raw :: Maybe Bool
, GenerateOps -> Maybe Text
keepAlive :: Maybe Text
, GenerateOps -> Maybe Text
hostUrl :: Maybe Text
, GenerateOps -> Maybe Int
responseTimeOut :: Maybe Int
, GenerateOps -> Maybe Value
options :: Maybe Value
}
instance Show GenerateOps where
show :: GenerateOps -> String
show GenerateOps {Maybe Bool
Maybe Int
Maybe [Text]
Maybe (GenerateResponse -> IO (), IO ())
Maybe Value
Maybe Text
Maybe Format
Text
$sel:modelName:GenerateOps :: GenerateOps -> Text
$sel:prompt:GenerateOps :: GenerateOps -> Text
$sel:suffix:GenerateOps :: GenerateOps -> Maybe Text
$sel:images:GenerateOps :: GenerateOps -> Maybe [Text]
$sel:format:GenerateOps :: GenerateOps -> Maybe Format
$sel:system:GenerateOps :: GenerateOps -> Maybe Text
$sel:template:GenerateOps :: GenerateOps -> Maybe Text
$sel:stream:GenerateOps :: GenerateOps -> Maybe (GenerateResponse -> IO (), IO ())
$sel:raw:GenerateOps :: GenerateOps -> Maybe Bool
$sel:keepAlive:GenerateOps :: GenerateOps -> Maybe Text
$sel:hostUrl:GenerateOps :: GenerateOps -> Maybe Text
$sel:responseTimeOut:GenerateOps :: GenerateOps -> Maybe Int
$sel:options:GenerateOps :: GenerateOps -> Maybe Value
modelName :: Text
prompt :: Text
suffix :: Maybe Text
images :: Maybe [Text]
format :: Maybe Format
system :: Maybe Text
template :: Maybe Text
stream :: Maybe (GenerateResponse -> IO (), IO ())
raw :: Maybe Bool
keepAlive :: Maybe Text
hostUrl :: Maybe Text
responseTimeOut :: Maybe Int
options :: Maybe Value
..} =
String
"GenerateOps { "
String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
"model : "
String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Text -> String
T.unpack Text
modelName
String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
", prompt : "
String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Text -> String
T.unpack Text
prompt
String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
", suffix : "
String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Maybe Text -> String
forall a. Show a => a -> String
show Maybe Text
suffix
String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
", images : "
String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Maybe [Text] -> String
forall a. Show a => a -> String
show Maybe [Text]
images
String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
", format : "
String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Maybe Format -> String
forall a. Show a => a -> String
show Maybe Format
format
String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
", system : "
String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Maybe Text -> String
forall a. Show a => a -> String
show Maybe Text
system
String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
", template : "
String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Maybe Text -> String
forall a. Show a => a -> String
show Maybe Text
template
String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
", stream : "
String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
"Stream functions"
String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
", raw : "
String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Maybe Bool -> String
forall a. Show a => a -> String
show Maybe Bool
raw
String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
", keepAlive : "
String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Maybe Text -> String
forall a. Show a => a -> String
show Maybe Text
keepAlive
String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
", options : "
String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Maybe Value -> String
forall a. Show a => a -> String
show Maybe Value
options
instance Eq GenerateOps where
== :: GenerateOps -> GenerateOps -> Bool
(==) GenerateOps
a GenerateOps
b =
GenerateOps -> Text
modelName GenerateOps
a Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== GenerateOps -> Text
modelName GenerateOps
b
Bool -> Bool -> Bool
&& GenerateOps -> Text
prompt GenerateOps
a Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== GenerateOps -> Text
prompt GenerateOps
b
Bool -> Bool -> Bool
&& GenerateOps -> Maybe Text
suffix GenerateOps
a Maybe Text -> Maybe Text -> Bool
forall a. Eq a => a -> a -> Bool
== GenerateOps -> Maybe Text
suffix GenerateOps
b
Bool -> Bool -> Bool
&& GenerateOps -> Maybe [Text]
images GenerateOps
a Maybe [Text] -> Maybe [Text] -> Bool
forall a. Eq a => a -> a -> Bool
== GenerateOps -> Maybe [Text]
images GenerateOps
b
Bool -> Bool -> Bool
&& GenerateOps -> Maybe Format
format GenerateOps
a Maybe Format -> Maybe Format -> Bool
forall a. Eq a => a -> a -> Bool
== GenerateOps -> Maybe Format
format GenerateOps
b
Bool -> Bool -> Bool
&& GenerateOps -> Maybe Text
system GenerateOps
a Maybe Text -> Maybe Text -> Bool
forall a. Eq a => a -> a -> Bool
== GenerateOps -> Maybe Text
system GenerateOps
b
Bool -> Bool -> Bool
&& GenerateOps -> Maybe Text
template GenerateOps
a Maybe Text -> Maybe Text -> Bool
forall a. Eq a => a -> a -> Bool
== GenerateOps -> Maybe Text
template GenerateOps
b
Bool -> Bool -> Bool
&& GenerateOps -> Maybe Bool
raw GenerateOps
a Maybe Bool -> Maybe Bool -> Bool
forall a. Eq a => a -> a -> Bool
== GenerateOps -> Maybe Bool
raw GenerateOps
b
Bool -> Bool -> Bool
&& GenerateOps -> Maybe Text
keepAlive GenerateOps
a Maybe Text -> Maybe Text -> Bool
forall a. Eq a => a -> a -> Bool
== GenerateOps -> Maybe Text
keepAlive GenerateOps
b
Bool -> Bool -> Bool
&& GenerateOps -> Maybe Value
options GenerateOps
a Maybe Value -> Maybe Value -> Bool
forall a. Eq a => a -> a -> Bool
== GenerateOps -> Maybe Value
options GenerateOps
b
data GenerateResponse = GenerateResponse
{ GenerateResponse -> Text
model :: Text
, GenerateResponse -> UTCTime
createdAt :: UTCTime
, GenerateResponse -> Text
response_ :: Text
, GenerateResponse -> Bool
done :: Bool
, GenerateResponse -> Maybe Int64
totalDuration :: Maybe Int64
, GenerateResponse -> Maybe Int64
loadDuration :: Maybe Int64
, GenerateResponse -> Maybe Int64
promptEvalCount :: Maybe Int64
, GenerateResponse -> Maybe Int64
promptEvalDuration :: Maybe Int64
, GenerateResponse -> Maybe Int64
evalCount :: Maybe Int64
, GenerateResponse -> Maybe Int64
evalDuration :: Maybe Int64
}
deriving (Int -> GenerateResponse -> ShowS
[GenerateResponse] -> ShowS
GenerateResponse -> String
(Int -> GenerateResponse -> ShowS)
-> (GenerateResponse -> String)
-> ([GenerateResponse] -> ShowS)
-> Show GenerateResponse
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> GenerateResponse -> ShowS
showsPrec :: Int -> GenerateResponse -> ShowS
$cshow :: GenerateResponse -> String
show :: GenerateResponse -> String
$cshowList :: [GenerateResponse] -> ShowS
showList :: [GenerateResponse] -> ShowS
Show, GenerateResponse -> GenerateResponse -> Bool
(GenerateResponse -> GenerateResponse -> Bool)
-> (GenerateResponse -> GenerateResponse -> Bool)
-> Eq GenerateResponse
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: GenerateResponse -> GenerateResponse -> Bool
== :: GenerateResponse -> GenerateResponse -> Bool
$c/= :: GenerateResponse -> GenerateResponse -> Bool
/= :: GenerateResponse -> GenerateResponse -> Bool
Eq)
instance ToJSON GenerateOps where
toJSON :: GenerateOps -> Value
toJSON
( GenerateOps
Text
model
Text
prompt
Maybe Text
suffix
Maybe [Text]
images
Maybe Format
format
Maybe Text
system
Maybe Text
template
Maybe (GenerateResponse -> IO (), IO ())
stream
Maybe Bool
raw
Maybe Text
keepAlive
Maybe Text
_
Maybe Int
_
Maybe Value
options
) =
[Pair] -> Value
object
[ Key
"model" Key -> Text -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Text
model
, Key
"prompt" Key -> Text -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Text
prompt
, Key
"suffix" Key -> Maybe Text -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Maybe Text
suffix
, Key
"images" Key -> Maybe [Text] -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Maybe [Text]
images
, Key
"format" Key -> Maybe Format -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Maybe Format
format
, Key
"system" Key -> Maybe Text -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Maybe Text
system
, Key
"template" Key -> Maybe Text -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Maybe Text
template
, Key
"stream" Key -> Maybe Bool -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= if Maybe (GenerateResponse -> IO (), IO ()) -> Bool
forall a. Maybe a -> Bool
isNothing Maybe (GenerateResponse -> IO (), IO ())
stream then Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False else Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True
, Key
"raw" Key -> Maybe Bool -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Maybe Bool
raw
, Key
"keep_alive" Key -> Maybe Text -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Maybe Text
keepAlive
, Key
"options" Key -> Maybe Value -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Maybe Value
options
]
instance FromJSON GenerateResponse where
parseJSON :: Value -> Parser GenerateResponse
parseJSON = String
-> (Object -> Parser GenerateResponse)
-> Value
-> Parser GenerateResponse
forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"GenerateResponse" ((Object -> Parser GenerateResponse)
-> Value -> Parser GenerateResponse)
-> (Object -> Parser GenerateResponse)
-> Value
-> Parser GenerateResponse
forall a b. (a -> b) -> a -> b
$ \Object
v ->
Text
-> UTCTime
-> Text
-> Bool
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> GenerateResponse
GenerateResponse
(Text
-> UTCTime
-> Text
-> Bool
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> GenerateResponse)
-> Parser Text
-> Parser
(UTCTime
-> Text
-> Bool
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> GenerateResponse)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
v Object -> Key -> Parser Text
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"model"
Parser
(UTCTime
-> Text
-> Bool
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> GenerateResponse)
-> Parser UTCTime
-> Parser
(Text
-> Bool
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> GenerateResponse)
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
v Object -> Key -> Parser UTCTime
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"created_at"
Parser
(Text
-> Bool
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> GenerateResponse)
-> Parser Text
-> Parser
(Bool
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> GenerateResponse)
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
v Object -> Key -> Parser Text
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"response"
Parser
(Bool
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> GenerateResponse)
-> Parser Bool
-> Parser
(Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> GenerateResponse)
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
v Object -> Key -> Parser Bool
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"done"
Parser
(Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> GenerateResponse)
-> Parser (Maybe Int64)
-> Parser
(Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> GenerateResponse)
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
v Object -> Key -> Parser (Maybe Int64)
forall a. FromJSON a => Object -> Key -> Parser (Maybe a)
.:? Key
"total_duration"
Parser
(Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> Maybe Int64
-> GenerateResponse)
-> Parser (Maybe Int64)
-> Parser
(Maybe Int64
-> Maybe Int64 -> Maybe Int64 -> Maybe Int64 -> GenerateResponse)
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
v Object -> Key -> Parser (Maybe Int64)
forall a. FromJSON a => Object -> Key -> Parser (Maybe a)
.:? Key
"load_duration"
Parser
(Maybe Int64
-> Maybe Int64 -> Maybe Int64 -> Maybe Int64 -> GenerateResponse)
-> Parser (Maybe Int64)
-> Parser
(Maybe Int64 -> Maybe Int64 -> Maybe Int64 -> GenerateResponse)
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
v Object -> Key -> Parser (Maybe Int64)
forall a. FromJSON a => Object -> Key -> Parser (Maybe a)
.:? Key
"prompt_eval_count"
Parser
(Maybe Int64 -> Maybe Int64 -> Maybe Int64 -> GenerateResponse)
-> Parser (Maybe Int64)
-> Parser (Maybe Int64 -> Maybe Int64 -> GenerateResponse)
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
v Object -> Key -> Parser (Maybe Int64)
forall a. FromJSON a => Object -> Key -> Parser (Maybe a)
.:? Key
"prompt_eval_duration"
Parser (Maybe Int64 -> Maybe Int64 -> GenerateResponse)
-> Parser (Maybe Int64) -> Parser (Maybe Int64 -> GenerateResponse)
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
v Object -> Key -> Parser (Maybe Int64)
forall a. FromJSON a => Object -> Key -> Parser (Maybe a)
.:? Key
"eval_count"
Parser (Maybe Int64 -> GenerateResponse)
-> Parser (Maybe Int64) -> Parser GenerateResponse
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
v Object -> Key -> Parser (Maybe Int64)
forall a. FromJSON a => Object -> Key -> Parser (Maybe a)
.:? Key
"eval_duration"
defaultGenerateOps :: GenerateOps
defaultGenerateOps :: GenerateOps
defaultGenerateOps =
GenerateOps
{ $sel:modelName:GenerateOps :: Text
modelName = Text
"llama3.2"
, $sel:prompt:GenerateOps :: Text
prompt = Text
"what is 2+2"
, $sel:suffix:GenerateOps :: Maybe Text
suffix = Maybe Text
forall a. Maybe a
Nothing
, $sel:images:GenerateOps :: Maybe [Text]
images = Maybe [Text]
forall a. Maybe a
Nothing
, $sel:format:GenerateOps :: Maybe Format
format = Maybe Format
forall a. Maybe a
Nothing
, $sel:system:GenerateOps :: Maybe Text
system = Maybe Text
forall a. Maybe a
Nothing
, $sel:template:GenerateOps :: Maybe Text
template = Maybe Text
forall a. Maybe a
Nothing
, $sel:stream:GenerateOps :: Maybe (GenerateResponse -> IO (), IO ())
stream = Maybe (GenerateResponse -> IO (), IO ())
forall a. Maybe a
Nothing
, $sel:raw:GenerateOps :: Maybe Bool
raw = Maybe Bool
forall a. Maybe a
Nothing
, $sel:keepAlive:GenerateOps :: Maybe Text
keepAlive = Maybe Text
forall a. Maybe a
Nothing
, $sel:hostUrl:GenerateOps :: Maybe Text
hostUrl = Maybe Text
forall a. Maybe a
Nothing
, $sel:responseTimeOut:GenerateOps :: Maybe Int
responseTimeOut = Maybe Int
forall a. Maybe a
Nothing
, $sel:options:GenerateOps :: Maybe Value
options = Maybe Value
forall a. Maybe a
Nothing
}
generate :: GenerateOps -> IO (Either String GenerateResponse)
generate :: GenerateOps -> IO (Either String GenerateResponse)
generate GenerateOps
genOps = do
let url :: Text
url = Text -> Maybe Text -> Text
forall a. a -> Maybe a -> a
fromMaybe Text
defaultOllamaUrl (GenerateOps -> Maybe Text
hostUrl GenerateOps
genOps)
responseTimeout :: Int
responseTimeout = Int -> Maybe Int -> Int
forall a. a -> Maybe a -> a
fromMaybe Int
15 (GenerateOps -> Maybe Int
responseTimeOut GenerateOps
genOps)
Manager
manager <-
ManagerSettings -> IO Manager
newManager
ManagerSettings
defaultManagerSettings
{ managerResponseTimeout = responseTimeoutMicro (responseTimeout * 60 * 1000000)
}
Either HttpException Request
eInitialRequest <-
IO Request -> IO (Either HttpException Request)
forall e a. Exception e => IO a -> IO (Either e a)
try (IO Request -> IO (Either HttpException Request))
-> IO Request -> IO (Either HttpException Request)
forall a b. (a -> b) -> a -> b
$ String -> IO Request
forall (m :: * -> *). MonadThrow m => String -> m Request
parseRequest (String -> IO Request) -> String -> IO Request
forall a b. (a -> b) -> a -> b
$ Text -> String
T.unpack (Text
url Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"/api/generate") :: IO (Either HttpException Request)
case Either HttpException Request
eInitialRequest of
Left HttpException
e -> do
Either String GenerateResponse
-> IO (Either String GenerateResponse)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String GenerateResponse
-> IO (Either String GenerateResponse))
-> Either String GenerateResponse
-> IO (Either String GenerateResponse)
forall a b. (a -> b) -> a -> b
$ String -> Either String GenerateResponse
forall a b. a -> Either a b
Left (String -> Either String GenerateResponse)
-> String -> Either String GenerateResponse
forall a b. (a -> b) -> a -> b
$ HttpException -> String
forall a. Show a => a -> String
show HttpException
e
Right Request
initialRequest -> do
let reqBody :: GenerateOps
reqBody = GenerateOps
genOps
request :: Request
request =
Request
initialRequest
{ method = "POST"
, requestBody = RequestBodyLBS $ encode reqBody
}
Either HttpException (Either String GenerateResponse)
eRes <-
IO (Either String GenerateResponse)
-> IO (Either HttpException (Either String GenerateResponse))
forall e a. Exception e => IO a -> IO (Either e a)
try (Request
-> Manager
-> (Response BodyReader -> IO (Either String GenerateResponse))
-> IO (Either String GenerateResponse)
forall a.
Request -> Manager -> (Response BodyReader -> IO a) -> IO a
withResponse Request
request Manager
manager ((Response BodyReader -> IO (Either String GenerateResponse))
-> IO (Either String GenerateResponse))
-> (Response BodyReader -> IO (Either String GenerateResponse))
-> IO (Either String GenerateResponse)
forall a b. (a -> b) -> a -> b
$ GenerateOps
-> Response BodyReader -> IO (Either String GenerateResponse)
handleRequest GenerateOps
genOps) ::
IO (Either HttpException (Either String GenerateResponse))
case Either HttpException (Either String GenerateResponse)
eRes of
Left HttpException
e -> do
Either String GenerateResponse
-> IO (Either String GenerateResponse)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String GenerateResponse
-> IO (Either String GenerateResponse))
-> Either String GenerateResponse
-> IO (Either String GenerateResponse)
forall a b. (a -> b) -> a -> b
$ String -> Either String GenerateResponse
forall a b. a -> Either a b
Left (String -> Either String GenerateResponse)
-> String -> Either String GenerateResponse
forall a b. (a -> b) -> a -> b
$ String
"HTTP error occured: " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> HttpException -> String
forall a. Show a => a -> String
show HttpException
e
Right Either String GenerateResponse
r -> Either String GenerateResponse
-> IO (Either String GenerateResponse)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Either String GenerateResponse
r
handleRequest :: GenerateOps -> Response BodyReader -> IO (Either String GenerateResponse)
handleRequest :: GenerateOps
-> Response BodyReader -> IO (Either String GenerateResponse)
handleRequest GenerateOps
genOps Response BodyReader
response = do
let streamResponse :: (GenerateResponse -> IO a)
-> IO a -> IO (Either String GenerateResponse)
streamResponse GenerateResponse -> IO a
sendChunk IO a
flush = do
ByteString
bs <- BodyReader -> BodyReader
brRead (BodyReader -> BodyReader) -> BodyReader -> BodyReader
forall a b. (a -> b) -> a -> b
$ Response BodyReader -> BodyReader
forall body. Response body -> body
responseBody Response BodyReader
response
if ByteString -> Bool
BS.null ByteString
bs
then String -> IO ()
putStrLn String
"" IO ()
-> IO (Either String GenerateResponse)
-> IO (Either String GenerateResponse)
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Either String GenerateResponse
-> IO (Either String GenerateResponse)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (String -> Either String GenerateResponse
forall a b. a -> Either a b
Left String
"")
else do
let eRes :: Either String GenerateResponse
eRes = ByteString -> Either String GenerateResponse
forall a. FromJSON a => ByteString -> Either String a
eitherDecode (ByteString -> ByteString
BSL.fromStrict ByteString
bs) :: Either String GenerateResponse
case Either String GenerateResponse
eRes of
Left String
e -> Either String GenerateResponse
-> IO (Either String GenerateResponse)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (String -> Either String GenerateResponse
forall a b. a -> Either a b
Left String
e)
Right GenerateResponse
r -> do
a
_ <- GenerateResponse -> IO a
sendChunk GenerateResponse
r
a
_ <- IO a
flush
if GenerateResponse -> Bool
done GenerateResponse
r then Either String GenerateResponse
-> IO (Either String GenerateResponse)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (GenerateResponse -> Either String GenerateResponse
forall a b. b -> Either a b
Right GenerateResponse
r) else (GenerateResponse -> IO a)
-> IO a -> IO (Either String GenerateResponse)
streamResponse GenerateResponse -> IO a
sendChunk IO a
flush
let genResponse :: ByteString -> IO (Either String GenerateResponse)
genResponse ByteString
op = do
ByteString
bs <- BodyReader -> BodyReader
brRead (BodyReader -> BodyReader) -> BodyReader -> BodyReader
forall a b. (a -> b) -> a -> b
$ Response BodyReader -> BodyReader
forall body. Response body -> body
responseBody Response BodyReader
response
if ByteString
bs ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== ByteString
""
then do
let eRes0 :: Either String GenerateResponse
eRes0 = ByteString -> Either String GenerateResponse
forall a. FromJSON a => ByteString -> Either String a
eitherDecode (ByteString -> ByteString
BSL.fromStrict ByteString
op) :: Either String GenerateResponse
case Either String GenerateResponse
eRes0 of
Left String
e -> Either String GenerateResponse
-> IO (Either String GenerateResponse)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (String -> Either String GenerateResponse
forall a b. a -> Either a b
Left String
e)
Right GenerateResponse
r -> Either String GenerateResponse
-> IO (Either String GenerateResponse)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (GenerateResponse -> Either String GenerateResponse
forall a b. b -> Either a b
Right GenerateResponse
r)
else ByteString -> IO (Either String GenerateResponse)
genResponse (ByteString
op ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
bs)
case GenerateOps -> Maybe (GenerateResponse -> IO (), IO ())
stream GenerateOps
genOps of
Maybe (GenerateResponse -> IO (), IO ())
Nothing -> ByteString -> IO (Either String GenerateResponse)
genResponse ByteString
""
Just (GenerateResponse -> IO ()
sendChunk, IO ()
flush) -> (GenerateResponse -> IO ())
-> IO () -> IO (Either String GenerateResponse)
forall {a} {a}.
(GenerateResponse -> IO a)
-> IO a -> IO (Either String GenerateResponse)
streamResponse GenerateResponse -> IO ()
sendChunk IO ()
flush
generateJson ::
(ToJSON jsonResult, FromJSON jsonResult) =>
GenerateOps ->
jsonResult ->
Maybe Int ->
IO (Either String jsonResult)
generateJson :: forall jsonResult.
(ToJSON jsonResult, FromJSON jsonResult) =>
GenerateOps
-> jsonResult -> Maybe Int -> IO (Either String jsonResult)
generateJson genOps :: GenerateOps
genOps@GenerateOps {Maybe Bool
Maybe Int
Maybe [Text]
Maybe (GenerateResponse -> IO (), IO ())
Maybe Value
Maybe Text
Maybe Format
Text
$sel:modelName:GenerateOps :: GenerateOps -> Text
$sel:prompt:GenerateOps :: GenerateOps -> Text
$sel:suffix:GenerateOps :: GenerateOps -> Maybe Text
$sel:images:GenerateOps :: GenerateOps -> Maybe [Text]
$sel:format:GenerateOps :: GenerateOps -> Maybe Format
$sel:system:GenerateOps :: GenerateOps -> Maybe Text
$sel:template:GenerateOps :: GenerateOps -> Maybe Text
$sel:stream:GenerateOps :: GenerateOps -> Maybe (GenerateResponse -> IO (), IO ())
$sel:raw:GenerateOps :: GenerateOps -> Maybe Bool
$sel:keepAlive:GenerateOps :: GenerateOps -> Maybe Text
$sel:hostUrl:GenerateOps :: GenerateOps -> Maybe Text
$sel:responseTimeOut:GenerateOps :: GenerateOps -> Maybe Int
$sel:options:GenerateOps :: GenerateOps -> Maybe Value
modelName :: Text
prompt :: Text
suffix :: Maybe Text
images :: Maybe [Text]
format :: Maybe Format
system :: Maybe Text
template :: Maybe Text
stream :: Maybe (GenerateResponse -> IO (), IO ())
raw :: Maybe Bool
keepAlive :: Maybe Text
hostUrl :: Maybe Text
responseTimeOut :: Maybe Int
options :: Maybe Value
..} jsonResult
jsonStructure Maybe Int
mMaxRetries = do
let jsonHelperPrompt :: Text
jsonHelperPrompt =
Text
"You are an AI that returns only JSON object. \n"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"* Your output should be a JSON object that matches the following schema: \n"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> ByteString -> Text
T.decodeUtf8 (ByteString -> ByteString
BSL.toStrict (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ jsonResult -> ByteString
forall a. ToJSON a => a -> ByteString
encode jsonResult
jsonStructure)
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
prompt
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"# How to treat the task:\n"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"* Stricly follow the schema for the output.\n"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"* Never return anything other than a JSON object.\n"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"* Do not talk to the user.\n"
Either String GenerateResponse
generatedResponse <- GenerateOps -> IO (Either String GenerateResponse)
generate GenerateOps
genOps {prompt = jsonHelperPrompt}
case Either String GenerateResponse
generatedResponse of
Left String
err -> Either String jsonResult -> IO (Either String jsonResult)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String jsonResult -> IO (Either String jsonResult))
-> Either String jsonResult -> IO (Either String jsonResult)
forall a b. (a -> b) -> a -> b
$ String -> Either String jsonResult
forall a b. a -> Either a b
Left String
err
Right GenerateResponse
r -> do
case ByteString -> Maybe jsonResult
forall a. FromJSON a => ByteString -> Maybe a
decode (ByteString -> ByteString
BSL.fromStrict (ByteString -> ByteString)
-> (Text -> ByteString) -> Text -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
T.encodeUtf8 (Text -> ByteString) -> Text -> ByteString
forall a b. (a -> b) -> a -> b
$ GenerateResponse -> Text
response_ GenerateResponse
r) of
Maybe jsonResult
Nothing -> do
case Maybe Int
mMaxRetries of
Maybe Int
Nothing -> Either String jsonResult -> IO (Either String jsonResult)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String jsonResult -> IO (Either String jsonResult))
-> Either String jsonResult -> IO (Either String jsonResult)
forall a b. (a -> b) -> a -> b
$ String -> Either String jsonResult
forall a b. a -> Either a b
Left String
"Decoding Failed :("
Just Int
n ->
if Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
1
then Either String jsonResult -> IO (Either String jsonResult)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String jsonResult -> IO (Either String jsonResult))
-> Either String jsonResult -> IO (Either String jsonResult)
forall a b. (a -> b) -> a -> b
$ String -> Either String jsonResult
forall a b. a -> Either a b
Left String
"Decoding failed :("
else GenerateOps
-> jsonResult -> Maybe Int -> IO (Either String jsonResult)
forall jsonResult.
(ToJSON jsonResult, FromJSON jsonResult) =>
GenerateOps
-> jsonResult -> Maybe Int -> IO (Either String jsonResult)
generateJson GenerateOps
genOps jsonResult
jsonStructure (Int -> Maybe Int
forall a. a -> Maybe a
Just (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1))
Just jsonResult
resultInType -> Either String jsonResult -> IO (Either String jsonResult)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String jsonResult -> IO (Either String jsonResult))
-> Either String jsonResult -> IO (Either String jsonResult)
forall a b. (a -> b) -> a -> b
$ jsonResult -> Either String jsonResult
forall a b. b -> Either a b
Right jsonResult
resultInType