Microsoft hat mich an mich gewandt, diese Bibliothek in eine neue offizielle C# Openai -Bibliothek zu verwandeln, und jetzt ist es bereit zu gehen! Beginnend mit v2.0.0-beta.3 hat die offizielle Bibliothek jetzt die volle Berichterstattung und bleibt auf dem neuesten Stand. Weitere Details im Blog-Beitrag hier: https://devblogs.microsoft.com/dotnet/openai-dotnet-library
Dieses Github -Repo bleibt hier, um meine Originalversion der Bibliothek über Version 1.11 zu dokumentieren, die auch noch auf Nuget erhältlich ist. ?
Eine einfache C# .NET -Wrapper -Bibliothek für die OpenAI -API. Mehr Kontext in meinem Blog. Dies ist meine ursprüngliche inoffizielle Wrapper -Bibliothek rund um die OpenAI -API.
var api = new OpenAI_API . OpenAIAPI ( " YOUR_API_KEY " ) ;
var result = await api . Chat . CreateChatCompletionAsync ( " Hello! " ) ;
Console . WriteLine ( result ) ;
// should print something like "Hi! How can I help you?" Ab V2.0.0-beta wurde diese Bibliothek von Microsoft übernommen. Die neue offizielle Version der Bibliothek hat die volle Berichterstattung und bleibt voll auf dem neuesten Stand. Weitere Details im Blog-Beitrag hier: https://devblogs.microsoft.com/dotnet/openai-dotnet-library/ Dieser Github-Repo bleibt hier, um meine Originalversion der Bibliothek über Version 1.11 zu dokumentieren, die auch noch auf Nuget verfügbar ist.
Diese Bibliothek basiert auf .NET Standard 2.0 und sollte daher in allen Versionen von .NET von der herkömmlichen .NET -Framework> = 4.7.2 bis .NET (CORE)> = 3.0 funktionieren. Es sollte über Konsolen -Apps, WinForms, WPF, ASP.NET, Unity, Xamarin usw. funktionieren. Es sollte über Windows, Linux und Mac und möglicherweise sogar mobil funktionieren. Es gibt minimale Abhängigkeiten und es ist öffentlich lizenziert.
Installieren Sie das Paket OpenAI v1.11 von Nuget. So wie über Commandline:
Install-Package OpenAI - Version 1.11 . 0Es gibt 3 Möglichkeiten, Ihre API -Schlüssel in der Reihenfolge der Vorrang zu liefern:
APIAuthentication(string key).openai ein und enthalten die Zeile: OPENAI_API_KEY=sk-aaaabbbbbccccddddd Sie verwenden das APIAuthentication , wenn Sie die API wie gezeigt initialisieren:
// for example
OpenAIAPI api = new OpenAIAPI ( " YOUR_API_KEY " ) ; // shorthand
// or
OpenAIAPI api = new OpenAIAPI ( new APIAuthentication ( " YOUR_API_KEY " ) ) ; // create object manually
// or
OpenAIAPI api = new OpenAIAPI ( APIAuthentication LoadFromEnv ( ) ) ; // use env vars
// or
OpenAIAPI api = new OpenAIAPI ( APIAuthentication LoadFromPath ( ) ) ; // use config file (can optionally specify where to look)
// or
OpenAIAPI api = new OpenAIAPI ( ) ; // uses default, env, or config fileSie können optional eine OpenAiorganization (OpenAI_Organization in Env oder Konfigurationsdatei) angeben, in der angegeben wird, welche Organisation für eine API -Anforderung verwendet wird. Die Nutzung dieser API -Anfragen zählt anhand der Abonnementkontingent der angegebenen Organisation. Organisations -IDs finden Sie auf Ihrer Seite "Organisationseinstellungen".
// for example
OpenAIAPI api = new OpenAIAPI ( new APIAuthentication ( " YOUR_API_KEY " , " org-yourOrgHere " ) ) ; Die Chat -API wird über OpenAIAPI.Chat zugegriffen. Es gibt zwei Möglichkeiten, den Chat -Endpunkt zu verwenden, entweder über vereinfachte Konversationen oder mit den vollständigen Anforderungen/Antwortmethoden.
Mit der Konversationsklasse können Sie problemlos mit ChatGPT interagieren, indem Sie Nachrichten zu einem Chat hinzufügen und ChatGPT fragen, um zu antworten.
var chat = api . Chat . CreateConversation ( ) ;
chat . Model = Model . GPT4_Turbo ;
chat . RequestParameters . Temperature = 0 ;
/// give instruction as System
chat . AppendSystemMessage ( " You are a teacher who helps children understand if things are animals or not. If the user tells you an animal, you say " yes " . If the user tells you something that is not an animal, you say " no " . You only ever respond with " yes " or " no " . You do not say anything else. " ) ;
// give a few examples as user and assistant
chat . AppendUserInput ( " Is this an animal? Cat " ) ;
chat . AppendExampleChatbotOutput ( " Yes " ) ;
chat . AppendUserInput ( " Is this an animal? House " ) ;
chat . AppendExampleChatbotOutput ( " No " ) ;
// now let's ask it a question
chat . AppendUserInput ( " Is this an animal? Dog " ) ;
// and get the response
string response = await chat . GetResponseFromChatbotAsync ( ) ;
Console . WriteLine ( response ) ; // "Yes"
// and continue the conversation by asking another
chat . AppendUserInput ( " Is this an animal? Chair " ) ;
// and get another response
response = await chat . GetResponseFromChatbotAsync ( ) ;
Console . WriteLine ( response ) ; // "No"
// the entire chat history is available in chat.Messages
foreach ( ChatMessage msg in chat . Messages )
{
Console . WriteLine ( $" { msg . Role } : { msg . Content } " ) ;
} Mit dem Streaming können Sie Ergebnisse erzielen, die generiert werden, was dazu beitragen kann, dass sich Ihrer Anwendung reaktionsschneller anfühlt.
Verwenden der neuen C# 8.0 Async -Iteratoren:
var chat = api . Chat . CreateConversation ( ) ;
chat . AppendUserInput ( " How to make a hamburger? " ) ;
await foreach ( var res in chat . StreamResponseEnumerableFromChatbotAsync ( ) )
{
Console . Write ( res ) ;
}Oder wenn Sie klassisches .NET Framework oder C# <8.0 verwenden:
var chat = api . Chat . CreateConversation ( ) ;
chat . AppendUserInput ( " How to make a hamburger? " ) ;
await chat . StreamResponseFromChatbotAsync ( res =>
{
Console . Write ( res ) ;
} ) ; Sie können Bilder an den Chat senden, um das neue GPT-4-Vision-Modell zu verwenden. Dies funktioniert nur mit dem Modell Model.GPT4_Vision . Weitere Informationen und Einschränkungen finden Sie unter https://platform.openai.com/docs/guides/vision.
// the simplest form
var result = await api . Chat . CreateChatCompletionAsync ( " What is the primary non-white color in this logo? " , ImageInput . FromFile ( " path/to/logo.png " ) ) ;
// or in a conversation
var chat = api . Chat . CreateConversation ( ) ;
chat . Model = Model . GPT4_Vision ;
chat . AppendSystemMessage ( " You are a graphic design assistant who helps identify colors. " ) ;
chat . AppendUserInput ( " What are the primary non-white colors in this logo? " , ImageInput . FromFile ( " path/to/logo.png " ) ) ;
string response = await chat . GetResponseFromChatbotAsync ( ) ;
Console . WriteLine ( response ) ; // "Blue and purple"
chat . AppendUserInput ( " What are the primary non-white colors in this logo? " , ImageInput . FromImageUrl ( " https://rogerpincombe.com/templates/rp/center-aligned-no-shadow-small.png " ) ) ;
response = await chat . GetResponseFromChatbotAsync ( ) ;
Console . WriteLine ( response ) ; // "Blue, red, and yellow"
// or when manually creating the ChatMessage
messageWithImage = new ChatMessage ( ChatMessageRole . User , " What colors do these logos have in common? " ) ;
messageWithImage . images . Add ( ImageInput . FromFile ( " path/to/logo.png " ) ) ;
messageWithImage . images . Add ( ImageInput . FromImageUrl ( " https://rogerpincombe.com/templates/rp/center-aligned-no-shadow-small.png " ) ) ;
// you can specify multiple images at once
chat . AppendUserInput ( " What colors do these logos have in common? " , ImageInput . FromFile ( " path/to/logo.png " ) , ImageInput . FromImageUrl ( " https://rogerpincombe.com/templates/rp/center-aligned-no-shadow-small.png " ) ) ; Wenn der Chat -Gesprächsverlauf zu lang wird, passt er möglicherweise nicht in die Kontextlänge des Modells. Standardmäßig werden die früheste Nicht-System-Nachricht (en) aus dem Chat-Verlauf entfernt und der API-Aufruf wird erneut mitgeteilt. Sie können dies deaktivieren, indem chat.AutoTruncateOnContextLengthExceeded = false , oder Sie können den Abschneidungsalgorithmus wie folgt überschreiben:
chat . OnTruncationNeeded += ( sender , args ) =>
{
// args is a List<ChatMessage> with the current chat history. Remove or edit as nessisary.
// replace this with more sophisticated logic for your use-case, such as summarizing the chat history
for ( int i = 0 ; i < args . Count ; i ++ )
{
if ( args [ i ] . Role != ChatMessageRole . System )
{
args . RemoveAt ( i ) ;
return ;
}
}
} ; Möglicherweise möchten Sie auch ein neues Modell mit einer größeren Kontextlänge verwenden. Sie können dies tun, indem chat.Model = Model.ChatGPTTurbo_16k chat.Model = Model.GPT4_Turbo einstellen.
Sie können eine Token -Nutzung über chat.MostRecentApiResult.Usage.PromptTokens und verwandte Eigenschaften sehen.
Sie können mithilfe der OpenAIAPI.Chat.CreateChatCompletionAsync() und verwandten Methoden die vollständige Kontrolle über die Chat -API zugreifen.
async Task < ChatResult > CreateChatCompletionAsync ( ChatRequest request ) ;
// for example
var result = await api . Chat . CreateChatCompletionAsync ( new ChatRequest ( )
{
Model = Model . ChatGPTTurbo ,
Temperature = 0.1 ,
MaxTokens = 50 ,
Messages = new ChatMessage [ ] {
new ChatMessage ( ChatMessageRole . User , " Hello! " )
}
} )
// or
var result = api . Chat . CreateChatCompletionAsync ( " Hello! " ) ;
var reply = results . Choices [ 0 ] . Message ;
Console . WriteLine ( $" { reply . Role } : { reply . Content . Trim ( ) } " ) ;
// or
Console . WriteLine ( results ) ; Es gibt ein ChatResult zurück, bei dem es sich hauptsächlich um Metadaten handelt. Verwenden Sie also die .ToString() -Methode, um den Text zu erhalten, wenn Sie nur den Antworttext des Assistenten wünschen.
Es gibt auch eine asynchrische Streaming -API, die ähnlich wie die Ergebnisse des Endpoint -Streaming -Ergebnisses von Completen funktioniert.
ChatRequest.ResponseFormat dem ChatRequest.ResponseFormats.JsonObject Model.GPT4_Turbo gpt-3.5-turbo-1106 Wenn der JSON -Modus aktiviert ist, wird das Modell nur beschränkt, nur Zeichenfolgen zu generieren, die zu gültigem JSON -Objekt analysiert werden. Weitere Informationen finden Sie unter https://platform.openai.com/docs/guides/text-generation/json-mode.
ChatRequest chatRequest = new ChatRequest ( )
{
Model = model ,
Temperature = 0.0 ,
MaxTokens = 500 ,
ResponseFormat = ChatRequest . ResponseFormats . JsonObject ,
Messages = new ChatMessage [ ] {
new ChatMessage ( ChatMessageRole . System , " You are a helpful assistant designed to output JSON. " ) ,
new ChatMessage ( ChatMessageRole . User , " Who won the world series in 2020? Return JSON of a 'wins' dictionary with the year as the numeric key and the winning team as the string value. " )
}
} ;
var results = await api . Chat . CreateChatCompletionAsync ( chatRequest ) ;
Console . WriteLine ( results ) ;
/* prints:
{
"wins": {
2020: "Los Angeles Dodgers"
}
}
*/ Die Fertigstellung gelten von OpenAI. Die Fertigstellungs -API wird über OpenAIAPI.Completions zugegriffen:
async Task < CompletionResult > CreateCompletionAsync ( CompletionRequest request ) ;
// for example
var result = await api . Completions . CreateCompletionAsync ( new CompletionRequest ( " One Two Three One Two " , model : Model . CurieText , temperature : 0.1 ) ) ;
// or
var result = await api . Completions . CreateCompletionAsync ( " One Two Three One Two " , temperature : 0.1 ) ;
// or other convenience overloads Sie können Ihren CompletionRequest im Voraus erstellen oder einen der Helfer -Überladungen für die Bequemlichkeit verwenden. Es gibt .ToString() CompletionResult zurück.
Mit dem Streaming können Sie Ergebnisse erzielen, die generiert werden, was dazu beitragen kann, dass sich Ihrer Anwendung mehr reaktionsschnell anfühlt, insbesondere bei langsamen Modellen wie Davini.
Verwenden der neuen C# 8.0 Async -Iteratoren:
IAsyncEnumerable < CompletionResult > StreamCompletionEnumerableAsync ( CompletionRequest request ) ;
// for example
await foreach ( var token in api . Completions . StreamCompletionEnumerableAsync ( new CompletionRequest ( " My name is Roger and I am a principal software engineer at Salesforce. This is my resume: " , Model . DavinciText , 200 , 0.5 , presencePenalty : 0.1 , frequencyPenalty : 0.1 ) ) )
{
Console . Write ( token ) ;
}Oder wenn Sie klassisches .NET Framework oder C# <8.0 verwenden:
async Task StreamCompletionAsync ( CompletionRequest request , Action < CompletionResult > resultHandler ) ;
// for example
await api . Completions . StreamCompletionAsync (
new CompletionRequest ( " My name is Roger and I am a principal software engineer at Salesforce. This is my resume: " , Model . DavinciText , 200 , 0.5 , presencePenalty : 0.1 , frequencyPenalty : 0.1 ) ,
res => ResumeTextbox . Text += res . ToString ( ) ) ;Die Audio-API sind Text zu Sprache, Transkription (Sprache zu Text) und Übersetzung (nicht englische Sprache zum englischen Text).
Die TTS -API wird über OpenAIAPI.TextToSpeech aufgerufen:
await api . TextToSpeech . SaveSpeechToFileAsync ( " Hello, brave new world! This is a test. " , outputPath ) ;
// You can open it in the defaul audio player like this:
Process . Start ( outputPath ) ; Sie können auch alle Anforderungsparameter mit einem TextToSpeechRequest -Objekt angeben:
var request = new TextToSpeechRequest ( )
{
Input = " Hello, brave new world! This is a test. " ,
ResponseFormat = ResponseFormats . AAC ,
Model = Model . TTS_HD ,
Voice = Voices . Nova ,
Speed = 0.9
} ;
await api . TextToSpeech . SaveSpeechToFileAsync ( request , " test.aac " ) ; Anstatt in einer Datei zu speichern, können Sie mit api.TextToSpeech.GetSpeechAsStreamAsync(request) einen Audio -Byte -Stream erhalten:
using ( Stream result = await api . TextToSpeech . GetSpeechAsStreamAsync ( " Hello, brave new world! " , Voices . Fable ) )
using ( StreamReader reader = new StreamReader ( result ) )
{
// do something with the audio stream here
} Mit der Audio -Transkriptions -API können Sie in einer der unterstützten Sprachen Text aus Audio generieren. Es wird über OpenAIAPI.Transcriptions zugegriffen:
string resultText = await api . Transcriptions . GetTextAsync ( " path/to/file.mp3 " ) ;Sie können um ausführliche Ergebnisse bitten, die Ihnen Segment- und Token-Ebene-Informationen sowie die Standard-OpenAI-Metadaten wie Verarbeitungszeit erhalten:
AudioResultVerbose result = await api . Transcriptions . GetWithDetailsAsync ( " path/to/file.m4a " ) ;
Console . WriteLine ( result . ProcessingTime . TotalMilliseconds ) ; // 496ms
Console . WriteLine ( result . text ) ; // "Hello, this is a test of the transcription function."
Console . WriteLine ( result . language ) ; // "english"
Console . WriteLine ( result . segments [ 0 ] . no_speech_prob ) ; // 0.03712
// etcSie können auch nach Ergebnissen im SRT- oder VTT -Format bitten, was für die Generierung von Untertiteln für Videos nützlich ist:
string result = await api . Transcriptions . GetAsFormatAsync ( " path/to/file.m4a " , AudioRequest . ResponseFormats . SRT ) ;Zusätzliche Parameter wie Temperatur, Eingabeaufforderung, Sprache usw. können entweder pro Equest oder als Standard angegeben werden:
// inline
result = await api . Transcriptions . GetTextAsync ( " conversation.mp3 " , " en " , " This is a transcript of a conversation between a medical doctor and her patient: " , 0.3 ) ;
// set defaults
api . Transcriptions . DefaultTranscriptionRequestArgs . Language = " en " ;Anstatt eine lokale Datei auf der Festplatte bereitzustellen, können Sie einen Strom von Audio -Bytes bereitstellen. Dies kann nützlich sein, um Audio aus dem Mikrofon oder einer anderen Quelle zu streamen, ohne zuerst auf die Festplatte schreiben zu müssen. Bitte nicht Sie müssen einen Dateinamen angeben, der nicht existieren muss, aber eine genaue Erweiterung für die Art des Audios haben muss, den Sie senden. OpenAI verwendet die Dateiname -Erweiterung, um zu bestimmen, in welchem Format Ihr Audio -Stream sich befindet.
using ( var audioStream = File . OpenRead ( " path-here.mp3 " ) )
{
return await api . Transcriptions . GetTextAsync ( audioStream , " file.mp3 " ) ;
} Mit Übersetzungen können Sie Text von einer der unterstützten Sprachen auf Englisch übertragen. OpenAI unterstützt keine Übersetzung in eine andere Sprache, nur Englisch. Es wird über OpenAIAPI.Translations zugegriffen. Es unterstützt die gleiche Funktionalität wie die Transkriptionen.
string result = await api . Translations . GetTextAsync ( " chinese-example.m4a " ) ; Die Einbettungs -API wird über OpenAIAPI.Embeddings zugegriffen:
async Task < EmbeddingResult > CreateEmbeddingAsync ( EmbeddingRequest request ) ;
// for example
var result = await api . Embeddings . CreateEmbeddingAsync ( new EmbeddingRequest ( " A test text for embedding " , model : Model . AdaTextEmbedding ) ) ;
// or
var result = await api . Embeddings . CreateEmbeddingAsync ( " A test text for embedding " ) ;Das Einbettungsergebnis enthält eine Menge Metadaten, der tatsächliche Vektor von Floats ist in Ergebnis.Data []. Einbettung.
Der Einfachheit halber können Sie direkt nach dem Vektor von Floats fragen und die zusätzlichen Metadaten mit api.Embeddings.GetEmbeddingsAsync("test text here")
Die Moderations -API wird über OpenAIAPI.Moderation : zugegriffen:
async Task < ModerationResult > CreateEmbeddingAsync ( ModerationRequest request ) ;
// for example
var result = await api . Moderation . CallModerationAsync ( new ModerationRequest ( " A test text for moderating " , Model . TextModerationLatest ) ) ;
// or
var result = await api . Moderation . CallModerationAsync ( " A test text for moderating " ) ;
Console . WriteLine ( result . results [ 0 ] . MainContentFlag ) ; Die MainContentFlag sind FlaggedCategories .results[0]
Der API -Endpunkt der Dateien wird über OpenAIAPI.Files zugegriffen:
// uploading
async Task < File > UploadFileAsync ( string filePath , string purpose = " fine-tune " ) ;
// for example
var response = await api . Files . UploadFileAsync ( " fine-tuning-data.jsonl " ) ;
Console . Write ( response . Id ) ; //the id of the uploaded file
// listing
async Task < List < File > > GetFilesAsync ( ) ;
// for example
var response = await api . Files . GetFilesAsync ( ) ;
foreach ( var file in response )
{
Console . WriteLine ( file . Name ) ;
}Es gibt auch Methoden, um Dateiinhalte zu erhalten, eine Datei zu löschen, usw.
Der feine Endpunkt selbst wurde noch nicht implementiert, wird aber bald hinzugefügt.
Die Dall-E-Bildgenerierung-API wird über OpenAIAPI.ImageGenerations zugegriffen:
async Task < ImageResult > CreateImageAsync ( ImageGenerationRequest request ) ;
// for example
var result = await api . ImageGenerations . CreateImageAsync ( new ImageGenerationRequest ( " A drawing of a computer writing a test " , 1 , ImageSize . _512 ) ) ;
// or
var result = await api . ImageGenerations . CreateImageAsync ( " A drawing of a computer writing a test " ) ;
Console . WriteLine ( result . Data [ 0 ] . Url ) ;Das Bildergebnis enthält eine URL für ein Online-Bild oder ein Basis64-kodiertes Bild, abhängig von der ImageGenerationRequest.responseformat (URL ist der Standard).
Verwenden Sie Dall-e 3 wie folgt:
async Task < ImageResult > CreateImageAsync ( ImageGenerationRequest request ) ;
// for example
var result = await api . ImageGenerations . CreateImageAsync ( new ImageGenerationRequest ( " A drawing of a computer writing a test " , OpenAI_API . Models . Model . DALLE3 , ImageSize . _1024x1792 , " hd " ) ) ;
// or
var result = await api . ImageGenerations . CreateImageAsync ( " A drawing of a computer writing a test " , OpenAI_API . Models . Model . DALLE3 ) ;
Console . WriteLine ( result . Data [ 0 ] . Url ) ; Für die Verwendung des Azure OpenAI -Dienstes müssen Sie den Namen Ihrer Azure OpenAI -Ressource sowie Ihre Modellbereitstellungs -ID angeben.
Ich habe keinen Zugriff auf den Microsoft Azure OpenAI -Dienst, daher kann ich diese Funktionalität nicht testen. Wenn Sie Zugriff haben und testen können, geben Sie bitte ein Problem ein, das Ihre Ergebnisse beschreibt. Ein PR mit Integrationstests wäre ebenfalls sehr geschätzt. Insbesondere ist mir unklar, dass die Angabe von Modellen mit Azure auf die gleiche Weise funktioniert.
Weitere Informationen finden Sie in der Dokumentation von Azure OpenAI und detaillierten Screenshots in #64.
Die Konfiguration sollte für den Azure -Service ungefähr so aussehen:
OpenAIAPI api = OpenAIAPI . ForAzure ( " YourResourceName " , " deploymentId " , " api-key " ) ;
api . ApiVersion = " 2023-03-15-preview " ; // needed to access chat endpoint on Azure Sie können dann das api -Objekt wie normal verwenden. Sie können auch angeben, dass die APIAuthentication eine der anderen Möglichkeiten ist, die im obigen Authentifizierungsabschnitt aufgeführt sind. Derzeit unterstützt diese Bibliothek nur den API-Key-Fluss, nicht den Ad-Flow.
Ab dem 2. April 2023 müssen Sie die API-Version 2023-03-15-preview manuell wie oben gezeigt auswählen, um auf den Chat-Endpunkt für Azure zuzugreifen. Sobald dies nicht vorschau ist, aktualisiere ich den Standard.
Sie können eine IHttpClientFactory angeben, die für HTTP -Anfragen verwendet werden soll, mit denen HTTP -Anforderungseigenschaften, Verbindungsbeamten und Verspotten angepasst werden können. Details in #103.
OpenAIAPI api = new OpenAIAPI ( ) ;
api . HttpClientFactory = myIHttpClientFactoryObject ; Jede einzelne Klasse, Methode und Immobilie verfügt über umfangreiche XML -Dokumentation, sodass sie automatisch in IntelliSense angezeigt werden sollte. Dies sollte in Kombination mit der offiziellen OpenAI -Dokumentation ausreichen, um loszulegen. Fühlen Sie sich frei, hier ein Problem zu eröffnen, wenn Sie Fragen haben. Eine bessere Dokumentation kann später kommen.
CC-0 Public Domain
Diese Bibliothek ist lizenzierter CC-0 im öffentlichen Raum. Sie können es für alles, was Sie wollen, öffentlich oder privat verwenden, ohne sich um Erlaubnis oder Lizenz oder was auch immer Sorgen zu machen. Es ist nur eine Wrapper um die OpenAI -API, sodass Sie immer noch direkt von ihnen auf OpenAI von ihnen ausgehen müssen. Ich bin nicht mit OpenAI verbunden und diese Bibliothek wird nicht von ihnen unterstützt. Ich habe nur Beta -Zugriff und wollte eine C# -Bibliothek erstellen, um leichter darauf zuzugreifen. Hoffentlich finden andere dies auch nützlich. Fühlen Sie sich frei, eine PR zu öffnen, wenn Sie etwas beitragen möchten.