Dies ist ein sachlicher Async Scala-Client für OpenAI-API, der alle verfügbaren Endpunkte und Parameter wie Streaming , die neuesten Chat-Abschluss- , Vision- und Sprachroutinen (wie hier definiert) unterstützt, die in einem einzigen, bequemen Service namens OpenAiservice bereitgestellt werden. Die unterstützten Anrufe sind:
Beachten Sie, dass die Service -Funktionsnamen genau den API -Endpunkttiteln/-beschreibungen mit Camelcase übereinstimmen, um mit der OpenAI -API -Benennungsnamen übereinzustimmen. Außerdem zielten wir an play-ws-standalone-json
dass die LIB mit den wenigsten Abhängigkeiten in sich geschlossen ist play-ahc-ws-standalone
Wenn eine Abhängigkeitsinjektion erforderlich ist, verwenden wir außerdem auch scala-guice
-Bibliothek.
Keine Zeit, ein langes Tutorial zu lesen? Klar, wir hören dich! Schauen Sie sich die Beispiele an, um zu sehen, wie die LIB in der Praxis verwendet wird.
Zusätzlich zur OpenAI-API unterstützt diese Bibliothek API-kompatible Anbieter (siehe Beispiele), wie z. B.:
Hintergrundinformationen finden Sie einen Artikel über den LIB/Client auf Medium.
Probieren Sie auch unseren Scala -Client für die Pnecone -Vektor -Datenbank aus oder verwenden Sie beide Clients zusammen! Dieses Demo-Projekt zeigt, wie OpenAI-Einbettungen (mit text-embedding-ada-002
-Modell) in Tinecone generiert und gespeichert werden und sie anschließend abfragen. Die OpenAI + Pinecone -Kombination wird üblicherweise für autonome KI -Agenten wie Babyagi und Autogpt verwendet.
✔️ WICHTIG : Dies ist eine "in der Gemeinschaft gepflegte" Bibliothek und hat daher keinen Zusammenhang mit der OpenAI-Firma.
Die derzeit unterstützten Scala -Versionen sind 2,12, 2,13 und 3 .
Um die Bibliothek zu installieren, fügen Sie Ihrem Build.SBT die folgende Abhängigkeit hinzu
"io.cequence" %% "openai-scala-client" % "1.1.0"
oder pom.xml (wenn Sie Maven verwenden)
<dependency>
<groupId>io.cequence</groupId>
<artifactId>openai-scala-client_2.12</artifactId>
<version>1.1.0</version>
</dependency>
Wenn Sie Streaming-Unterstützung wünschen, verwenden Sie stattdessen "io.cequence" %% "openai-scala-client-stream" % "1.1.0"
.
OPENAI_SCALA_CLIENT_API_KEY
und optional auch OPENAI_SCALA_CLIENT_ORG_ID
(wenn Sie eine haben)I. Openaiservice erhalten
Zuerst müssen Sie einen implizite Ausführungskontext sowie Akka Materializer, z. B. AS, bereitstellen
implicit val ec = ExecutionContext .global
implicit val materializer = Materializer ( ActorSystem ())
Dann können Sie einen Dienst auf eine der folgenden Arten erhalten.
Config
definierten Variablen festgelegt wird) val service = OpenAIServiceFactory ()
val config = ConfigFactory .load( " path_to_my_custom_config " )
val service = OpenAIServiceFactory (config)
val service = OpenAIServiceFactory (
apiKey = " your_api_key " ,
orgId = Some ( " your_org_id " ) // if you have one
)
val service = OpenAIServiceFactory .forAzureWithApiKey(
resourceName = " your-resource-name " ,
deploymentId = " your-deployment-id " , // usually model name such as "gpt-35-turbo"
apiVersion = " 2023-05-15 " , // newest version
apiKey = " your_api_key "
)
OpenAICoreService
unterstützt listModels
, createCompletion
, createChatCompletion
und createEmbeddings
-Anrufe - Bereitstellung von z. B. nach Fastchat -Dienst, der auf dem Port 8000 ausgeführt wird val service = OpenAICoreServiceFactory ( " http://localhost:8000/v1/ " )
OpenAIChatCompletionService
, die nur createChatCompletion
bereitstellen val service = OpenAIChatCompletionServiceFactory .forAzureAI(
endpoint = sys.env( " AZURE_AI_COHERE_R_PLUS_ENDPOINT " ),
region = sys.env( " AZURE_AI_COHERE_R_PLUS_REGION " ),
accessToken = sys.env( " AZURE_AI_COHERE_R_PLUS_ACCESS_KEY " )
)
openai-scala-anthropic-client
-Lib und ANTHROPIC_API_KEY
val service = AnthropicServiceFactory .asOpenAI()
openai-scala-google-vertexai-client
Lib und VERTEXAI_LOCATION
+ VERTEXAI_PROJECT_ID
val service = VertexAIServiceFactory .asOpenAI()
GROQ_API_KEY"
val service = OpenAIChatCompletionServiceFactory ( ChatProviderSettings .groq)
// or with streaming
val service = OpenAIChatCompletionServiceFactory .withStreaming( ChatProviderSettings .groq)
GROK_API_KEY"
val service = OpenAIChatCompletionServiceFactory ( ChatProviderSettings .grok)
// or with streaming
val service = OpenAIChatCompletionServiceFactory .withStreaming( ChatProviderSettings .grok)
FIREWORKS_API_KEY"
val service = OpenAIChatCompletionServiceFactory ( ChatProviderSettings .fireworks)
// or with streaming
val service = OpenAIChatCompletionServiceFactory .withStreaming( ChatProviderSettings .fireworks)
OCTOAI_TOKEN
val service = OpenAIChatCompletionServiceFactory ( ChatProviderSettings .octoML)
// or with streaming
val service = OpenAIChatCompletionServiceFactory .withStreaming( ChatProviderSettings .octoML)
TOGETHERAI_API_KEY
val service = OpenAIChatCompletionServiceFactory ( ChatProviderSettings .togetherAI)
// or with streaming
val service = OpenAIChatCompletionServiceFactory .withStreaming( ChatProviderSettings .togetherAI)
CEREBRAS_API_KEY
val service = OpenAIChatCompletionServiceFactory ( ChatProviderSettings .cerebras)
// or with streaming
val service = OpenAIChatCompletionServiceFactory .withStreaming( ChatProviderSettings .cerebras)
MISTRAL_API_KEY
val service = OpenAIChatCompletionServiceFactory ( ChatProviderSettings .mistral)
// or with streaming
val service = OpenAIChatCompletionServiceFactory .withStreaming( ChatProviderSettings .mistral)
val service = OpenAIChatCompletionServiceFactory (
coreUrl = " http://localhost:11434/v1/ "
)
oder mit Streaming
val service = OpenAIChatCompletionServiceFactory .withStreaming(
coreUrl = " http://localhost:11434/v1/ "
)
createCompletionStreamed
und createChatCompletionStreamed
von OpenaISTREAMEDServiceExtra (erfordert openai-scala-client-stream
Lib) import io . cequence . openaiscala . service . StreamedServiceTypes . OpenAIStreamedService
import io . cequence . openaiscala . service . OpenAIStreamedServiceImplicits . _
val service : OpenAIStreamedService = OpenAIServiceFactory .withStreaming()
Ähnlich für einen Chat-Completion-Service
import io . cequence . openaiscala . service . OpenAIStreamedServiceImplicits . _
val service = OpenAIChatCompletionServiceFactory .withStreaming(
coreUrl = " https://api.fireworks.ai/inference/v1/ " ,
authHeaders = Seq (( " Authorization " , s " Bearer ${sys.env( " FIREWORKS_API_KEY " )} " ))
)
oder nur, wenn Streaming erforderlich ist
val service : OpenAIChatCompletionStreamedServiceExtra =
OpenAIChatCompletionStreamedServiceFactory (
coreUrl = " https://api.fireworks.ai/inference/v1/ " ,
authHeaders = Seq (( " Authorization " , s " Bearer ${sys.env( " FIREWORKS_API_KEY " )} " ))
)
openai-scala-guice
Lib) class MyClass @ Inject () ( openAIService : OpenAIService ) {...}
Ii. Aufrufen von Funktionen
Die vollständige Dokumentation jedes Anrufs mit seinen jeweiligen Eingaben und Einstellungen finden Sie in Openaiservice. Da alle Anrufe asynchronisiert sind, geben sie Antworten zurück, die in Future
eingepackt sind.
Es gibt ein neues Projekt Openai-Scala-Client-Examples, bei dem Sie viele Beispiele finden können!
service.listModels.map(models =>
models.foreach(println)
)
service.retrieveModel( ModelId .text_davinci_003).map(model =>
println(model.getOrElse( " N/A " ))
)
val text = """ Extract the name and mailing address from this email:
|Dear Kelly,
|It was great to talk to you at the seminar. I thought Jane's talk was quite good.
|Thank you for the book. Here's my address 2111 Ash Lane, Crestview CA 92002
|Best,
|Maya
""" .stripMargin
service.createCompletion(text).map(completion =>
println(completion.choices.head.text)
)
val text = """ Extract the name and mailing address from this email:
|Dear Kelly,
|It was great to talk to you at the seminar. I thought Jane's talk was quite good.
|Thank you for the book. Here's my address 2111 Ash Lane, Crestview CA 92002
|Best,
|Maya
""" .stripMargin
service.createCompletion(
text,
settings = CreateCompletionSettings (
model = ModelId .gpt_4o,
max_tokens = Some ( 1500 ),
temperature = Some ( 0.9 ),
presence_penalty = Some ( 0.2 ),
frequency_penalty = Some ( 0.2 )
)
).map(completion =>
println(completion.choices.head.text)
)
val source = service.createCompletionStreamed(
prompt = " Write me a Shakespeare poem about two cats playing baseball in Russia using at least 2 pages " ,
settings = CreateCompletionSettings (
model = ModelId .text_davinci_003,
max_tokens = Some ( 1500 ),
temperature = Some ( 0.9 ),
presence_penalty = Some ( 0.2 ),
frequency_penalty = Some ( 0.2 )
)
)
source.map(completion =>
println(completion.choices.head.text)
).runWith( Sink .ignore)
Damit dies funktioniert, müssen Sie OpenAIServiceStreamedFactory
von openai-scala-client-stream
Lib verwenden.
val createChatCompletionSettings = CreateChatCompletionSettings (
model = ModelId .gpt_4o
)
val messages = Seq (
SystemMessage ( " You are a helpful assistant. " ),
UserMessage ( " Who won the world series in 2020? " ),
AssistantMessage ( " The Los Angeles Dodgers won the World Series in 2020. " ),
UserMessage ( " Where was it played? " ),
)
service.createChatCompletion(
messages = messages,
settings = createChatCompletionSettings
).map { chatCompletion =>
println(chatCompletion.choices.head.message.content)
}
val messages = Seq (
SystemMessage ( " You are a helpful assistant. " ),
UserMessage ( " What's the weather like in San Francisco, Tokyo, and Paris? " )
)
// as a param type we can use "number", "string", "boolean", "object", "array", and "null"
val tools = Seq (
FunctionSpec (
name = " get_current_weather " ,
description = Some ( " Get the current weather in a given location " ),
parameters = Map (
" type " - > " object " ,
" properties " - > Map (
" location " - > Map (
" type " - > " string " ,
" description " - > " The city and state, e.g. San Francisco, CA "
),
" unit " - > Map (
" type " - > " string " ,
" enum " - > Seq ( " celsius " , " fahrenheit " )
)
),
" required " - > Seq ( " location " )
)
)
)
// if we want to force the model to use the above function as a response
// we can do so by passing: responseToolChoice = Some("get_current_weather")`
service.createChatToolCompletion(
messages = messages,
tools = tools,
responseToolChoice = None , // means "auto"
settings = CreateChatCompletionSettings ( ModelId .gpt_3_5_turbo_1106)
).map { response =>
val chatFunCompletionMessage = response.choices.head.message
val toolCalls = chatFunCompletionMessage.tool_calls.collect {
case (id, x : FunctionCallSpec ) => (id, x)
}
println(
" tool call ids : " + toolCalls.map(_._1).mkString( " , " )
)
println(
" function/tool call names : " + toolCalls.map(_._2.name).mkString( " , " )
)
println(
" function/tool call arguments : " + toolCalls.map(_._2.arguments).mkString( " , " )
)
}
val messages = Seq (
SystemMessage ( " Give me the most populous capital cities in JSON format. " ),
UserMessage ( " List only african countries " )
)
val capitalsSchema = JsonSchema . Object (
properties = Map (
" countries " - > JsonSchema . Array (
items = JsonSchema . Object (
properties = Map (
" country " - > JsonSchema . String (
description = Some ( " The name of the country " )
),
" capital " - > JsonSchema . String (
description = Some ( " The capital city of the country " )
)
),
required = Seq ( " country " , " capital " )
)
)
),
required = Seq ( " countries " )
)
val jsonSchemaDef = JsonSchemaDef (
name = " capitals_response " ,
strict = true ,
structure = schema
)
service
.createChatCompletion(
messages = messages,
settings = DefaultSettings .createJsonChatCompletion(jsonSchemaDef)
)
.map { response =>
val json = Json .parse(messageContent(response))
println( Json .prettyPrint(json))
}
createChatCompletions
oder createChatFunCompletions
aufrufen, können Sie das richtige Modell auswählen und die Kosten senken. Dies ist ein experimentelles Merkmal und funktioniert möglicherweise nicht für alle Modelle. Benötigt openai-scala-count-tokens
lib.Ein Beispiel, wie man Nachrichten -Token zählt:
import io . cequence . openaiscala . service . OpenAICountTokensHelper
import io . cequence . openaiscala . domain .{ AssistantMessage , BaseMessage , FunctionSpec , ModelId , SystemMessage , UserMessage }
class MyCompletionService extends OpenAICountTokensHelper {
def exec = {
val model = ModelId .gpt_4_turbo_2024_04_09
// messages to be sent to OpenAI
val messages : Seq [ BaseMessage ] = Seq (
SystemMessage ( " You are a helpful assistant. " ),
UserMessage ( " Who won the world series in 2020? " ),
AssistantMessage ( " The Los Angeles Dodgers won the World Series in 2020. " ),
UserMessage ( " Where was it played? " ),
)
val tokenCount = countMessageTokens(model, messages)
}
}
Ein Beispiel, wie man Nachrichten -Token zählt, wenn eine Funktion beteiligt ist:
import io . cequence . openaiscala . service . OpenAICountTokensHelper
import io . cequence . openaiscala . domain .{ BaseMessage , FunctionSpec , ModelId , SystemMessage , UserMessage }
class MyCompletionService extends OpenAICountTokensHelper {
def exec = {
val model = ModelId .gpt_4_turbo_2024_04_09
// messages to be sent to OpenAI
val messages : Seq [ BaseMessage ] =
Seq (
SystemMessage ( " You are a helpful assistant. " ),
UserMessage ( " What's the weather like in San Francisco, Tokyo, and Paris? " )
)
// function to be called
val function : FunctionSpec = FunctionSpec (
name = " getWeather " ,
parameters = Map (
" type " - > " object " ,
" properties " - > Map (
" location " - > Map (
" type " - > " string " ,
" description " - > " The city to get the weather for "
),
" unit " - > Map ( " type " - > " string " , " enum " - > List ( " celsius " , " fahrenheit " ))
)
)
)
val tokenCount = countFunMessageTokens(model, messages, Seq (function), Some (function.name))
}
}
✔️ WICHTIG : Nachdem Sie mit dem Service fertig sind, sollten Sie ihn durch den Rufen von service.close
schließen. Andernfalls werden die zugrunde liegenden Ressourcen/Threads nicht veröffentlicht.
III. Verwenden von Adaptern
Adapter für OpenAI -Dienste (CHAT -Abschluss, Kern oder voll) werden von OpenAIServiceAdapters bereitgestellt. Die Adapter werden verwendet, um die Last zwischen mehreren Diensten zu verteilen, transiente Fehler, die Route oder zusätzliche Funktionalität zu liefern. Weitere Informationen finden Sie in Beispielen.
Beachten Sie, dass die Adapter willkürlich kombiniert/gestapelt werden können.
val adapters = OpenAIServiceAdapters .forFullService
val service1 = OpenAIServiceFactory ( " your-api-key1 " )
val service2 = OpenAIServiceFactory ( " your-api-key2 " )
val service = adapters.roundRobin(service1, service2)
val adapters = OpenAIServiceAdapters .forFullService
val service1 = OpenAIServiceFactory ( " your-api-key1 " )
val service2 = OpenAIServiceFactory ( " your-api-key2 " )
val service = adapters.randomOrder(service1, service2)
val adapters = OpenAIServiceAdapters .forFullService
val rawService = OpenAIServiceFactory ()
val service = adapters.log(
rawService,
" openAIService " ,
logger.log
)
val adapters = OpenAIServiceAdapters .forFullService
implicit val retrySettings : RetrySettings = RetrySettings (maxRetries = 10 ).constantInterval( 10 .seconds)
val service = adapters.retry(
OpenAIServiceFactory (),
Some (println(_)) // simple logging
)
class MyCompletionService @ Inject () (
val actorSystem : ActorSystem ,
implicit val ec : ExecutionContext ,
implicit val scheduler : Scheduler
)( val apiKey : String )
extends RetryHelpers {
val service : OpenAIService = OpenAIServiceFactory (apiKey)
implicit val retrySettings : RetrySettings =
RetrySettings (interval = 10 .seconds)
def ask ( prompt : String ) : Future [ String ] =
for {
completion < - service
.createChatCompletion(
List ( MessageSpec ( ChatRole . User , prompt))
)
.retryOnFailure
} yield completion.choices.head.message.content
}
val adapters = OpenAIServiceAdapters .forFullService
// OctoAI
val octoMLService = OpenAIChatCompletionServiceFactory (
coreUrl = " https://text.octoai.run/v1/ " ,
authHeaders = Seq (( " Authorization " , s " Bearer ${sys.env( " OCTOAI_TOKEN " )} " ))
)
// Anthropic
val anthropicService = AnthropicServiceFactory .asOpenAI()
// OpenAI
val openAIService = OpenAIServiceFactory ()
val service : OpenAIService =
adapters.chatCompletionRouter(
// OpenAI service is default so no need to specify its models here
serviceModels = Map (
octoMLService - > Seq ( NonOpenAIModelId .mixtral_8x22b_instruct),
anthropicService - > Seq (
NonOpenAIModelId .claude_2_1,
NonOpenAIModelId .claude_3_opus_20240229,
NonOpenAIModelId .claude_3_haiku_20240307
)
),
openAIService
)
val adapters = OpenAIServiceAdapters .forCoreService
val service = adapters.chatToCompletion(
OpenAICoreServiceFactory (
coreUrl = " https://api.fireworks.ai/inference/v1/ " ,
authHeaders = Seq (( " Authorization " , s " Bearer ${sys.env( " FIREWORKS_API_KEY " )} " ))
)
)
Wen Scala 3?
Februar 2023. Sie haben Recht; Wir haben den kürzesten Monat dafür ausgewählt :) Erledigt!
Ich habe eine Ausnahme in der Zeitüberschreitung. Wie kann ich die Timeout -Einstellung ändern?
Sie können dies entweder tun, indem Sie den Param an timeouts
an OpenAIServiceFactory
übergeben oder wenn Sie Ihre eigene Konfigurationsdatei verwenden, können Sie sie einfach als:
openai-scala-client {
timeouts {
requestTimeoutSec = 200
readTimeoutSec = 200
connectTimeoutSec = 5
pooledConnectionIdleTimeoutSec = 60
}
}
Ich habe eine Ausnahme wie com.typesafe.config.ConfigException$UnresolvedSubstitution: openai-scala-client.conf @ jar:file:.../io/cequence/openai-scala-client_2.13/0.0.1/openai-scala-client_2.13-0.0.1.jar!/openai-scala-client.conf: 4: Could not resolve substitution to a value: ${OPENAI_SCALA_CLIENT_API_KEY}
. Was soll ich tun?
Setzen Sie die env. Variable OPENAI_SCALA_CLIENT_API_KEY
. Wenn Sie hier kein Register haben.
Es sieht alles cool aus. Ich möchte mit Ihnen über Ihre Forschung und Entwicklung chatten?
Schicken Sie uns einfach eine E-Mail unter [email protected].
Diese Bibliothek ist unter den Bedingungen der MIT -Lizenz als Open Source veröffentlicht und veröffentlicht.
Dieses Projekt ist Open-Source und begrüßt jeden Beitrag oder Feedback (hier).
Die Entwicklung dieser Bibliothek wurde von - cequence.io - The future of contracting
unterstützt
Von Peter Banda geschaffen und gepflegt.