Skip to content

Commit 2d15ea9

Browse files
committed
prompt caching model and serialization/deserialization
1 parent 29e403e commit 2d15ea9

File tree

4 files changed

+67
-37
lines changed

4 files changed

+67
-37
lines changed

anthropic-client/src/main/scala/io/cequence/openaiscala/anthropic/JsonFormats.scala

Lines changed: 52 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import io.cequence.openaiscala.anthropic.domain.response.{
2222
import io.cequence.openaiscala.anthropic.domain.{CacheControl, ChatRole, Content, Message}
2323
import io.cequence.wsclient.JsonUtil
2424
import play.api.libs.functional.syntax._
25+
import play.api.libs.json.JsonNaming.SnakeCase
2526
import play.api.libs.json._
2627

2728
object JsonFormats extends JsonFormats
@@ -45,9 +46,15 @@ trait JsonFormats {
4546
implicit lazy val contentBlocksFormat: Format[ContentBlocks] = Json.format[ContentBlocks]
4647

4748
// implicit lazy val textBlockWrites: Writes[TextBlock] = Json.writes[TextBlock]
48-
implicit lazy val textBlockReads: Reads[TextBlock] = Json.reads[TextBlock]
49+
implicit lazy val textBlockReads: Reads[TextBlock] = {
50+
implicit val config: JsonConfiguration = JsonConfiguration(SnakeCase)
51+
Json.reads[TextBlock]
52+
}
4953

50-
implicit lazy val textBlockWrites: Writes[TextBlock] = Json.writes[TextBlock]
54+
implicit lazy val textBlockWrites: Writes[TextBlock] = {
55+
implicit val config: JsonConfiguration = JsonConfiguration(SnakeCase)
56+
Json.writes[TextBlock]
57+
}
5158
implicit lazy val imageBlockWrites: Writes[ImageBlock] =
5259
(block: ImageBlock) =>
5360
Json.obj(
@@ -105,43 +112,57 @@ trait JsonFormats {
105112
}
106113
}
107114

108-
// implicit lazy val baseMessageWrites: Writes[Message] = new Writes[Message] {
109-
// def writes(message: Message): JsValue = message match {
110-
// case UserMessage(content) => Json.obj("role" -> "user", "content" -> content)
111-
// case UserMessageContent(content) =>
112-
// Json.obj(
113-
// "role" -> "user",
114-
// "content" -> content.map(Json.toJson(_)(contentBlockWrites))
115-
// )
116-
// case AssistantMessage(content) => Json.obj("role" -> "assistant", "content" -> content)
117-
// case AssistantMessageContent(content) =>
118-
// Json.obj(
119-
// "role" -> "assistant",
120-
// "content" -> content.map(Json.toJson(_)(contentBlockWrites))
121-
// )
122-
// // Add cases for other subclasses if necessary
123-
// }
124-
// }
115+
implicit lazy val baseMessageWrites: Writes[Message] = new Writes[Message] {
116+
def writes(message: Message): JsValue = message match {
117+
case UserMessage(content, cacheControl) =>
118+
val baseObj = Json.obj("role" -> "user", "content" -> content)
119+
cacheControl.fold(baseObj)(cc => baseObj + ("cache_control" -> Json.toJson(cc)))
120+
121+
case UserMessageContent(content) =>
122+
Json.obj(
123+
"role" -> "user",
124+
"content" -> content.map(Json.toJson(_)(contentBlockWrites))
125+
)
126+
127+
case AssistantMessage(content, cacheControl) =>
128+
val baseObj = Json.obj("role" -> "assistant", "content" -> content)
129+
cacheControl.fold(baseObj)(cc => baseObj + ("cache_control" -> Json.toJson(cc)))
130+
131+
case AssistantMessageContent(content) =>
132+
Json.obj(
133+
"role" -> "assistant",
134+
"content" -> content.map(Json.toJson(_)(contentBlockWrites))
135+
)
136+
// Add cases for other subclasses if necessary
137+
}
138+
}
125139

126140
implicit lazy val baseMessageReads: Reads[Message] = (
127141
(__ \ "role").read[String] and
128142
(__ \ "content").read[JsValue] and
129143
(__ \ "cache_control").readNullable[CacheControl]
130144
).tupled.flatMap {
131145
case ("user", JsString(str), cacheControl) => Reads.pure(UserMessage(str, cacheControl))
132-
case ("user", json @ JsArray(_), cacheControl) => {
133-
val contentBlocks = Json.fromJson[Seq[ContentBlock]](json).map(ContentBlocks(_))
134-
146+
case ("user", json @ JsArray(_), _) => {
147+
Json.fromJson[Seq[ContentBlock]](json) match {
148+
case JsSuccess(contentBlocks, _) =>
149+
Reads.pure(UserMessageContent(contentBlocks))
150+
case JsError(errors) =>
151+
Reads(_ => JsError(errors))
152+
}
135153
}
136-
137-
// case ("user", SingleString(text), None) => Reads.pure(UserMessage(text))
138-
// case ("user", SingleString(text), Some(cacheControl)) => Reads.pure(UserMessage(text))
139-
// case ("user", ContentBlocks(blocks), None) => Reads.pure(UserMessageContent(blocks))
140-
// case ("user", ContentBlocks(blocks), Some(cacheControl)) =>
141-
// Reads.pure(UserMessageContent(blocks))
142-
// case ("assistant", SingleString(text)) => Reads.pure(AssistantMessage(text))
143-
// case ("assistant", ContentBlocks(blocks)) => Reads.pure(AssistantMessageContent(blocks))
144-
// case _ => Reads(_ => JsError("Unsupported role or content type"))
154+
case ("assistant", JsString(str), cacheControl) =>
155+
Reads.pure(AssistantMessage(str, cacheControl))
156+
157+
case ("assistant", json @ JsArray(_), _) => {
158+
Json.fromJson[Seq[ContentBlock]](json) match {
159+
case JsSuccess(contentBlocks, _) =>
160+
Reads.pure(AssistantMessageContent(contentBlocks))
161+
case JsError(errors) =>
162+
Reads(_ => JsError(errors))
163+
}
164+
}
165+
case _ => Reads(_ => JsError("Unsupported role or content type"))
145166
}
146167

147168
implicit lazy val createMessageResponseReads: Reads[CreateMessageResponse] = (

anthropic-client/src/main/scala/io/cequence/openaiscala/anthropic/domain/Message.scala

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,19 @@ sealed abstract class Message private (
1313

1414
object Message {
1515

16-
case class UserMessage(contentString: String, cacheControl: Option[CacheControl] = None)
17-
extends Message(ChatRole.User, SingleString(contentString, cacheControl))
16+
case class UserMessage(
17+
contentString: String,
18+
cacheControl: Option[CacheControl] = None
19+
) extends Message(ChatRole.User, SingleString(contentString, cacheControl))
20+
1821
case class UserMessageContent(contentBlocks: Seq[ContentBlock])
1922
extends Message(ChatRole.User, ContentBlocks(contentBlocks))
20-
case class AssistantMessage(contentString: String)
21-
extends Message(ChatRole.Assistant, SingleString(contentString))
23+
24+
case class AssistantMessage(
25+
contentString: String,
26+
cacheControl: Option[CacheControl] = None
27+
) extends Message(ChatRole.Assistant, SingleString(contentString, cacheControl))
28+
2229
case class AssistantMessageContent(contentBlocks: Seq[ContentBlock])
2330
extends Message(ChatRole.Assistant, ContentBlocks(contentBlocks))
2431
}

openai-examples/src/main/scala/io/cequence/openaiscala/examples/nonopenai/AnthropicCreateMessage.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ object AnthropicCreateMessage extends ExampleBase[AnthropicService] {
3030
.map(printMessageContent)
3131

3232
private def printMessageContent(response: CreateMessageResponse) = {
33-
val text = response.content.blocks.collect { case TextBlock(text) => text }.mkString(" ")
33+
val text =
34+
response.content.blocks.collect { case TextBlock(text, _) => text }.mkString(" ")
3435
println(text)
3536
}
3637
}

openai-examples/src/main/scala/io/cequence/openaiscala/examples/nonopenai/AnthropicCreateMessageWithImage.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ object AnthropicCreateMessageWithImage extends ExampleBase[AnthropicService] {
6262
}
6363

6464
private def printMessageContent(response: CreateMessageResponse) = {
65-
val text = response.content.blocks.collect { case TextBlock(text) => text }.mkString(" ")
65+
val text =
66+
response.content.blocks.collect { case TextBlock(text, _) => text }.mkString(" ")
6667
println(text)
6768
}
6869
}

0 commit comments

Comments
 (0)