-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcallOpenAI.scala
127 lines (112 loc) · 4.18 KB
/
callOpenAI.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import cats.effect.IOApp
import java.util.Base64.Decoder
import org.http4s.EntityDecoder
import cats.effect.IO
import org.http4s.ember.client.EmberClientBuilder
import org.http4s.Request
import org.http4s.syntax.all.*
import org.http4s.Method
import ciris.*
import org.http4s.Header
import org.http4s.Headers.*
import org.http4s.Headers
import org.http4s.MediaType
import org.http4s.headers.Authorization
import org.http4s.Credentials
import org.http4s.AuthScheme
import javax.swing.text.AbstractDocument.Content
import org.http4s.headers.`Content-Type`
import org.http4s.client.middleware.Logger
import org.http4s.client.Client
import cats.effect.kernel.Resource
import io.circe.*
import io.circe.parser.*
import org.typelevel.ci.CIStringSyntax
import javax.print.attribute.standard.Media
import org.http4s.circe.*
import io.circe.literal.*
import ujson.circe.CirceJson
import upickle.core.LinkedHashMap
import org.http4s.headers.Accept
object Main extends IOApp.Simple:
val key = env("OPEN_API_TOKEN").as[String].load[IO].toResource
// Generate this from `smithyGPTool`
val toolInfo = ujson.read("""[
{
"name": "get_current_weather",
"description": "Get the current weather in a given location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA"
},
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
},
"required": ["location"]
}
}
]""")
val messages = ujson.Arr(
ujson.Obj(
"role" -> "system",
"content" -> "You are a helpful assistent. "
),
ujson.Obj(
"role" -> "user",
"content" -> "Tell me the forecast for today, I'm in Zurich switzerland."
)
)
val basicBody = ujson.Obj(
"messages" -> messages,
"model" -> "gpt-3.5-turbo-0613",
"temperature" -> 0,
"functions" -> toolInfo
)
val logger = (cIn: Client[IO]) =>
Logger(logBody = true, logHeaders = true, _ => false, Some((x: String) => IO.println(x)))(cIn)
val clientR: Resource[cats.effect.IO, Client[cats.effect.IO]] = EmberClientBuilder.default[IO].build.map(logger(_))
def run =
clientR.both(key).use { (client, token) =>
val body: Json = CirceJson(basicBody)
def request: Request[IO] = Request(
Method.POST,
uri"https://api.openai.com/v1/chat/completions",
headers = Headers(
Header("Authorization", "Bearer " + token),
Accept(MediaType.application.json),
Accept(MediaType.text.plain),
)
)
val tmp = client
.expect[Json](request.withEntity(body))
.flatMap: s =>
val raw = ujson.read(s.toString)
val check = raw("choices")(0)("message").objOpt.flatMap(_.get("function_call"))
check match
case Some(value) =>
// dispatch to `smithyGPT` here
println(value.toString())
val fakeFunctResult = ujson.Obj(
// it is seriously weird, that it needs the JSON ... encoded as a string. Quite the footgun.
"content" -> ujson.Str("""{"location" : "Zurich, Switerland", "unit" : "celsius", "temperature" : "27", "forecast" : ["sunny", "windy"]}"""),
"name" -> "get_current_weather",
"role" -> "function"
)
val newMessages = messages.arr :+ raw("choices")(0)("message") :+ fakeFunctResult
// In realz, recursive, but for now, just do it once
val bodyTwo = ujson.Obj(
"model" -> "gpt-3.5-turbo-0613",
"messages" -> newMessages,
"temperature" -> 0
)
println(ujson.write(bodyTwo))
IO.println("------------------") >>
client.expect[Json](request.withEntity(CirceJson(bodyTwo))) >>
IO.println("------------------")
case None => IO.println("no function")
tmp
}
end run
end Main