├── .github └── workflows │ ├── codeql-analysis.yml │ ├── dotnet.yml │ └── nuget.yml ├── .gitignore ├── Directory.Build.props ├── LICENSE ├── ManagedCode.OpenAI.Tests ├── Architecture │ ├── Constants.cs │ └── IntegrationTestsRuntime.cs ├── Attributes │ └── ManualTestAttribute.cs ├── Base │ └── BaseTestClass.cs ├── ChatTests.cs ├── CommonTests.cs ├── CompletionTests.cs ├── EditTests.cs ├── Extensions │ ├── ConfigurationExtensions.cs │ ├── GenericTypeExtensions.cs │ └── MockExtensions.cs ├── ImageTests.cs ├── ManagedCode.OpenAI.Tests.csproj ├── ModelsTests.cs ├── ModerationTests.cs ├── Properties │ ├── Resources.Designer.cs │ └── Resources.resx ├── Resources │ └── dog.png ├── Services │ └── TestGptClientBuilder.cs ├── Startup.cs └── testsettings.json ├── ManagedCode.OpenAI.sln ├── ManagedCode.OpenAI.sln.DotSettings ├── ManagedCode.OpenAI ├── API │ ├── Abstractions │ │ └── IOpenAiWebClient.cs │ ├── Base │ │ └── BaseCompletionsResponseDto.cs │ ├── Chat │ │ ├── ChatChoiceDto.cs │ │ ├── ChatRequestDto.cs │ │ ├── ChatResponseDto.cs │ │ ├── MessageDto.cs │ │ └── UsageDto.cs │ ├── Completions │ │ ├── CompletionChoiceDto.cs │ │ ├── CompletionRequestDto.cs │ │ └── CompletionResponseDto.cs │ ├── Edit │ │ ├── EditChoiceDto.cs │ │ ├── EditRequestDto.cs │ │ └── EditResponseDto.cs │ ├── Errors │ │ ├── OpenAIError.cs │ │ ├── OpenAIErrorCode.cs │ │ └── OpenAIException.cs │ ├── File │ │ ├── FileDeleteResponseDto.cs │ │ ├── FileInfoDto.cs │ │ └── FilesInfoResponseDto.cs │ ├── Image │ │ ├── BaseImageRequestDto.cs │ │ ├── EditImageRequestDto.cs │ │ ├── GenerateImageRequestDto.cs │ │ ├── ImageResponseDataDto.cs │ │ ├── ImageResponseDto.cs │ │ └── VariationImageRequestDto.cs │ ├── Models │ │ ├── ModelDto.cs │ │ ├── ModelsResponseDto.cs │ │ └── PermissionDto.cs │ ├── Moderation │ │ ├── CategoryDto.cs │ │ ├── CategoryResultDto.cs │ │ ├── ModerationRequestDto.cs │ │ └── ModerationResponseDto.cs │ └── OpenAIWebClient.cs ├── Chat │ ├── Abstractions │ │ ├── IChatMessage.cs │ │ ├── IChatMessageParameters.cs │ │ ├── IChatMessageParametersBuilder.cs │ │ ├── IChatSession.cs │ │ ├── IChatSessionLoader.cs │ │ ├── IChatSessionRecord.cs │ │ ├── IGptChat.cs │ │ └── IUsage.cs │ ├── Extensions │ │ ├── ChatExtensions.cs │ │ ├── ClientChatExtensions.cs │ │ └── MapperChatExtensions.cs │ ├── GptChat.cs │ ├── Message │ │ ├── ChatMessage.cs │ │ ├── ChatMessageParameters.cs │ │ ├── ChatMessageParametersBuilder.cs │ │ └── Usage.cs │ └── Session │ │ ├── ChatSession.cs │ │ ├── ChatSessionLoader.cs │ │ └── ChatSessionRecord.cs ├── Client │ ├── Abstractions │ │ ├── IAnswer.cs │ │ ├── IGptClient.cs │ │ ├── IGptClientBuilder.cs │ │ ├── IGptClientConfiguration.cs │ │ ├── IGptClientConfigurationBuilder.cs │ │ ├── IModel.cs │ │ └── IPermission.cs │ ├── Configuration │ │ ├── DefaultGptClientConfiguration.cs │ │ └── GptClientConfigurationBuilder.cs │ ├── Extensions │ │ ├── GptClientExtensions.cs │ │ └── MapperClientExtensions.cs │ ├── GptClient.cs │ ├── GptClientBuilder.cs │ ├── Models │ │ ├── Answer.cs │ │ ├── GptModel.cs │ │ ├── Model.cs │ │ ├── Permission.cs │ │ └── RoleType.cs │ └── ServiceCollectionExtensions.cs ├── Completions │ ├── Abstractions │ │ ├── ICompletionBuilder.cs │ │ └── ICompletionsMessage.cs │ ├── CompletionsBuilder.cs │ ├── CompletionsMessage.cs │ ├── Extensions │ │ └── MapperCompletionsExtensions.cs │ └── ManagedCode.OpenAI.Client.Completions.csproj ├── Edit │ ├── Abstractions │ │ ├── IEditBuilder.cs │ │ └── IEditMessage.cs │ ├── EditBuilder.cs │ ├── EditMessage.cs │ └── Extensions │ │ └── MapperEditExtensions.cs ├── Extensions │ ├── EnumExtensions.cs │ ├── ServiceCollectionExtensions.cs │ └── ValidationExtensions.cs ├── Image │ ├── Abstractions │ │ ├── IBaseImageBuilder.cs │ │ ├── IEditImageBuilder.cs │ │ ├── IGenerateImageBuilder.cs │ │ ├── IGptImage.cs │ │ ├── IImageClient.cs │ │ ├── IImageLoader.cs │ │ └── IVariationImageBuilder.cs │ ├── Builders │ │ ├── BaseImageBuilder.cs │ │ ├── DefaultImageLoader.cs │ │ ├── EditImageBuilder.cs │ │ ├── GenerateImageBuilder.cs │ │ └── VariationImageBuilder.cs │ ├── Extensions │ │ ├── ImageClientExtensions.cs │ │ └── MapperImageExtensions.cs │ ├── ImageClient.cs │ └── Models │ │ ├── GptImage.cs │ │ ├── ImageFormat.cs │ │ └── ImageResolution.cs ├── ManagedCode.OpenAI.csproj ├── ManagedCode.OpenAI.csproj.DotSettings └── Moderation │ ├── Abstractions │ ├── ICategory.cs │ ├── IModeration.cs │ └── IModerationBuilder.cs │ ├── Exceptions │ └── MapperModerationExtensions.cs │ ├── Model │ ├── Category.cs │ └── Moderation.cs │ └── ModerationBuilder.cs ├── README.md └── logo.png /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ main ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ main ] 20 | schedule: 21 | - cron: '35 11 * * 4' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | 28 | strategy: 29 | fail-fast: false 30 | matrix: 31 | language: [ 'csharp' ] 32 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] 33 | # Learn more: 34 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed 35 | 36 | steps: 37 | - name: Checkout repository 38 | uses: actions/checkout@v3 39 | 40 | # Initializes the CodeQL tools for scanning. 41 | - name: Initialize CodeQL 42 | uses: github/codeql-action/init@v2 43 | with: 44 | languages: ${{ matrix.language }} 45 | # If you wish to specify custom queries, you can do so here or in a config file. 46 | # By default, queries listed here will override any specified in a config file. 47 | # Prefix the list here with "+" to use these queries and those in the config file. 48 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 49 | 50 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 51 | # If this step fails, then you should remove it and run the build manually (see below) 52 | - name: Autobuild 53 | uses: github/codeql-action/autobuild@v2 54 | 55 | # ℹ️ Command-line programs to run using the OS shell. 56 | # 📚 https://git.io/JvXDl 57 | 58 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 59 | # and modify them (or add more) to build your code if your project 60 | # uses a compiled language 61 | 62 | #- run: | 63 | # make bootstrap 64 | # make release 65 | 66 | - name: Perform CodeQL Analysis 67 | uses: github/codeql-action/analyze@v2 68 | -------------------------------------------------------------------------------- /.github/workflows/dotnet.yml: -------------------------------------------------------------------------------- 1 | name: .NET 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | 10 | # Allows you to run this workflow manually from the Actions tab 11 | workflow_dispatch: 12 | 13 | jobs: 14 | 15 | build-and-test: 16 | runs-on: ubuntu-latest 17 | 18 | steps: 19 | 20 | - uses: actions/checkout@v3 21 | - name: Setup .NET 22 | uses: actions/setup-dotnet@v3 23 | with: 24 | dotnet-version: 7.0.x 25 | 26 | # run build and test 27 | - name: Restore dependencies 28 | run: dotnet restore 29 | - name: Build 30 | run: dotnet build --no-restore 31 | - name: Test and Collect Code Coverage 32 | run: dotnet test -p:CollectCoverage=true --collect:"XPlat Code Coverage" --results-directory ./coverage 33 | 34 | 35 | # - name: coveralls 36 | # uses: coverallsapp/github-action@master 37 | # with: 38 | # github-token: ${{secrets.GITHUB_TOKEN }} 39 | # path-to-lcov: coverage/coverage.info 40 | -------------------------------------------------------------------------------- /.github/workflows/nuget.yml: -------------------------------------------------------------------------------- 1 | name: nuget 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | 7 | # Allows you to run this workflow manually from the Actions tab 8 | workflow_dispatch: 9 | 10 | jobs: 11 | nuget-pack: 12 | 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v3 17 | - name: Setup .NET 18 | uses: actions/setup-dotnet@v3 19 | with: 20 | dotnet-version: 7.0.x 21 | 22 | - name: Restore dependencies 23 | run: dotnet restore 24 | - name: Build 25 | run: dotnet build --configuration Release 26 | - name: Test 27 | run: dotnet test --configuration Release 28 | - name: Pack 29 | run: dotnet pack -p:IncludeSymbols=false -p:SymbolPackageFormat=snupkg --configuration Release 30 | 31 | - name: publish nuget packages 32 | run: | 33 | shopt -s globstar 34 | for file in **/*.nupkg 35 | do 36 | dotnet nuget push "$file" --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate 37 | done -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.toptal.com/developers/gitignore/api/windows,linux,macos,visualstudio,visualstudiocode,intellij,intellij+all,rider,angular,dotnetcore,aspnetcore,xamarinstudio 3 | # Edit at https://www.toptal.com/developers/gitignore?templates=windows,linux,macos,visualstudio,visualstudiocode,intellij,intellij+all,rider,angular,dotnetcore,aspnetcore,xamarinstudio 4 | 5 | ### Angular ### 6 | ## Angular ## 7 | # compiled output 8 | dist/ 9 | tmp/ 10 | app/**/*.js 11 | app/**/*.js.map 12 | 13 | # dependencies 14 | node_modules/ 15 | bower_components/ 16 | 17 | # IDEs and editors 18 | .idea/ 19 | 20 | # misc 21 | .sass-cache/ 22 | connect.lock/ 23 | coverage/ 24 | libpeerconnection.log/ 25 | npm-debug.log 26 | testem.log 27 | typings/ 28 | .angular/ 29 | 30 | # e2e 31 | e2e/*.js 32 | e2e/*.map 33 | 34 | # System Files 35 | .DS_Store/ 36 | 37 | ### ASPNETCore ### 38 | ## Ignore Visual Studio temporary files, build results, and 39 | ## files generated by popular Visual Studio add-ons. 40 | 41 | # User-specific files 42 | *.suo 43 | *.user 44 | *.userosscache 45 | *.sln.docstates 46 | 47 | # User-specific files (MonoDevelop/Xamarin Studio) 48 | *.userprefs 49 | 50 | # Build results 51 | [Dd]ebug/ 52 | [Dd]ebugPublic/ 53 | [Rr]elease/ 54 | [Rr]eleases/ 55 | x64/ 56 | x86/ 57 | bld/ 58 | [Bb]in/ 59 | [Oo]bj/ 60 | [Ll]og/ 61 | 62 | # Visual Studio 2015 cache/options directory 63 | .vs/ 64 | # Uncomment if you have tasks that create the project's static files in wwwroot 65 | #wwwroot/ 66 | 67 | # MSTest test Results 68 | [Tt]est[Rr]esult*/ 69 | [Bb]uild[Ll]og.* 70 | 71 | # NUNIT 72 | *.VisualState.xml 73 | TestResult.xml 74 | 75 | # Build Results of an ATL Project 76 | [Dd]ebugPS/ 77 | [Rr]eleasePS/ 78 | dlldata.c 79 | 80 | # DNX 81 | project.lock.json 82 | project.fragment.lock.json 83 | artifacts/ 84 | 85 | *_i.c 86 | *_p.c 87 | *_i.h 88 | *.ilk 89 | *.meta 90 | *.obj 91 | *.pch 92 | *.pdb 93 | *.pgc 94 | *.pgd 95 | *.rsp 96 | *.sbr 97 | *.tlb 98 | *.tli 99 | *.tlh 100 | *.tmp 101 | *.tmp_proj 102 | *.log 103 | *.vspscc 104 | *.vssscc 105 | .builds 106 | *.pidb 107 | *.svclog 108 | *.scc 109 | 110 | # Chutzpah Test files 111 | _Chutzpah* 112 | 113 | # Visual C++ cache files 114 | ipch/ 115 | *.aps 116 | *.ncb 117 | *.opendb 118 | *.opensdf 119 | *.sdf 120 | *.cachefile 121 | *.VC.db 122 | *.VC.VC.opendb 123 | 124 | # Visual Studio profiler 125 | *.psess 126 | *.vsp 127 | *.vspx 128 | *.sap 129 | 130 | # TFS 2012 Local Workspace 131 | $tf/ 132 | 133 | # Guidance Automation Toolkit 134 | *.gpState 135 | 136 | # ReSharper is a .NET coding add-in 137 | _ReSharper*/ 138 | *.[Rr]e[Ss]harper 139 | *.DotSettings.user 140 | 141 | # JustCode is a .NET coding add-in 142 | .JustCode 143 | 144 | # TeamCity is a build add-in 145 | _TeamCity* 146 | 147 | # DotCover is a Code Coverage Tool 148 | *.dotCover 149 | 150 | # Visual Studio code coverage results 151 | *.coverage 152 | *.coveragexml 153 | 154 | # NCrunch 155 | _NCrunch_* 156 | .*crunch*.local.xml 157 | nCrunchTemp_* 158 | 159 | # MightyMoose 160 | *.mm.* 161 | AutoTest.Net/ 162 | 163 | # Web workbench (sass) 164 | 165 | # Installshield output folder 166 | [Ee]xpress/ 167 | 168 | # DocProject is a documentation generator add-in 169 | DocProject/buildhelp/ 170 | DocProject/Help/*.HxT 171 | DocProject/Help/*.HxC 172 | DocProject/Help/*.hhc 173 | DocProject/Help/*.hhk 174 | DocProject/Help/*.hhp 175 | DocProject/Help/Html2 176 | DocProject/Help/html 177 | 178 | # Click-Once directory 179 | publish/ 180 | 181 | # Publish Web Output 182 | *.[Pp]ublish.xml 183 | *.azurePubxml 184 | # TODO: Comment the next line if you want to checkin your web deploy settings 185 | # but database connection strings (with potential passwords) will be unencrypted 186 | *.pubxml 187 | *.publishproj 188 | 189 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 190 | # checkin your Azure Web App publish settings, but sensitive information contained 191 | # in these scripts will be unencrypted 192 | PublishScripts/ 193 | 194 | # NuGet Packages 195 | *.nupkg 196 | # The packages folder can be ignored because of Package Restore 197 | **/packages/* 198 | # except build/, which is used as an MSBuild target. 199 | !**/packages/build/ 200 | # Uncomment if necessary however generally it will be regenerated when needed 201 | #!**/packages/repositories.config 202 | # NuGet v3's project.json files produces more ignoreable files 203 | *.nuget.props 204 | *.nuget.targets 205 | 206 | # Microsoft Azure Build Output 207 | csx/ 208 | *.build.csdef 209 | 210 | # Microsoft Azure Emulator 211 | ecf/ 212 | rcf/ 213 | 214 | # Windows Store app package directories and files 215 | AppPackages/ 216 | BundleArtifacts/ 217 | Package.StoreAssociation.xml 218 | _pkginfo.txt 219 | 220 | # Visual Studio cache files 221 | # files ending in .cache can be ignored 222 | *.[Cc]ache 223 | # but keep track of directories ending in .cache 224 | !*.[Cc]ache/ 225 | 226 | # Others 227 | ClientBin/ 228 | ~$* 229 | *~ 230 | *.dbmdl 231 | *.dbproj.schemaview 232 | *.jfm 233 | *.pfx 234 | *.publishsettings 235 | orleans.codegen.cs 236 | 237 | # Since there are multiple workflows, uncomment next line to ignore bower_components 238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 239 | #bower_components/ 240 | 241 | # RIA/Silverlight projects 242 | Generated_Code/ 243 | 244 | # Backup & report files from converting an old project file 245 | # to a newer Visual Studio version. Backup files are not needed, 246 | # because we have git ;-) 247 | _UpgradeReport_Files/ 248 | Backup*/ 249 | UpgradeLog*.XML 250 | UpgradeLog*.htm 251 | 252 | # SQL Server files 253 | *.mdf 254 | *.ldf 255 | 256 | # Business Intelligence projects 257 | *.rdl.data 258 | *.bim.layout 259 | *.bim_*.settings 260 | 261 | # Microsoft Fakes 262 | FakesAssemblies/ 263 | 264 | # GhostDoc plugin setting file 265 | *.GhostDoc.xml 266 | 267 | # Node.js Tools for Visual Studio 268 | .ntvs_analysis.dat 269 | 270 | # Visual Studio 6 build log 271 | *.plg 272 | 273 | # Visual Studio 6 workspace options file 274 | *.opt 275 | 276 | # Visual Studio LightSwitch build output 277 | **/*.HTMLClient/GeneratedArtifacts 278 | **/*.DesktopClient/GeneratedArtifacts 279 | **/*.DesktopClient/ModelManifest.xml 280 | **/*.Server/GeneratedArtifacts 281 | **/*.Server/ModelManifest.xml 282 | _Pvt_Extensions 283 | 284 | # Paket dependency manager 285 | .paket/paket.exe 286 | paket-files/ 287 | 288 | # FAKE - F# Make 289 | .fake/ 290 | 291 | # JetBrains Rider 292 | *.sln.iml 293 | 294 | # CodeRush 295 | .cr/ 296 | 297 | # Python Tools for Visual Studio (PTVS) 298 | __pycache__/ 299 | *.pyc 300 | 301 | # Cake - Uncomment if you are using it 302 | # tools/ 303 | 304 | ### DotnetCore ### 305 | # .NET Core build folders 306 | bin/ 307 | obj/ 308 | 309 | # Common node modules locations 310 | /node_modules 311 | /wwwroot/node_modules 312 | 313 | ### Intellij ### 314 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 315 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 316 | 317 | # User-specific stuff 318 | .idea/**/workspace.xml 319 | .idea/**/tasks.xml 320 | .idea/**/usage.statistics.xml 321 | .idea/**/dictionaries 322 | .idea/**/shelf 323 | 324 | # AWS User-specific 325 | .idea/**/aws.xml 326 | 327 | # Generated files 328 | .idea/**/contentModel.xml 329 | 330 | # Sensitive or high-churn files 331 | .idea/**/dataSources/ 332 | .idea/**/dataSources.ids 333 | .idea/**/dataSources.local.xml 334 | .idea/**/sqlDataSources.xml 335 | .idea/**/dynamic.xml 336 | .idea/**/uiDesigner.xml 337 | .idea/**/dbnavigator.xml 338 | 339 | # Gradle 340 | .idea/**/gradle.xml 341 | .idea/**/libraries 342 | 343 | # Gradle and Maven with auto-import 344 | # When using Gradle or Maven with auto-import, you should exclude module files, 345 | # since they will be recreated, and may cause churn. Uncomment if using 346 | # auto-import. 347 | # .idea/artifacts 348 | # .idea/compiler.xml 349 | # .idea/jarRepositories.xml 350 | # .idea/modules.xml 351 | # .idea/*.iml 352 | # .idea/modules 353 | # *.iml 354 | # *.ipr 355 | 356 | # CMake 357 | cmake-build-*/ 358 | 359 | # Mongo Explorer plugin 360 | .idea/**/mongoSettings.xml 361 | 362 | # File-based project format 363 | *.iws 364 | 365 | # IntelliJ 366 | out/ 367 | 368 | # mpeltonen/sbt-idea plugin 369 | .idea_modules/ 370 | 371 | # JIRA plugin 372 | atlassian-ide-plugin.xml 373 | 374 | # Cursive Clojure plugin 375 | .idea/replstate.xml 376 | 377 | # SonarLint plugin 378 | .idea/sonarlint/ 379 | 380 | # Crashlytics plugin (for Android Studio and IntelliJ) 381 | com_crashlytics_export_strings.xml 382 | crashlytics.properties 383 | crashlytics-build.properties 384 | fabric.properties 385 | 386 | # Editor-based Rest Client 387 | .idea/httpRequests 388 | 389 | # Android studio 3.1+ serialized cache file 390 | .idea/caches/build_file_checksums.ser 391 | 392 | ### Intellij Patch ### 393 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 394 | 395 | # *.iml 396 | # modules.xml 397 | # .idea/misc.xml 398 | # *.ipr 399 | 400 | # Sonarlint plugin 401 | # https://plugins.jetbrains.com/plugin/7973-sonarlint 402 | .idea/**/sonarlint/ 403 | 404 | # SonarQube Plugin 405 | # https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin 406 | .idea/**/sonarIssues.xml 407 | 408 | # Markdown Navigator plugin 409 | # https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced 410 | .idea/**/markdown-navigator.xml 411 | .idea/**/markdown-navigator-enh.xml 412 | .idea/**/markdown-navigator/ 413 | 414 | # Cache file creation bug 415 | # See https://youtrack.jetbrains.com/issue/JBR-2257 416 | .idea/$CACHE_FILE$ 417 | 418 | # CodeStream plugin 419 | # https://plugins.jetbrains.com/plugin/12206-codestream 420 | .idea/codestream.xml 421 | 422 | ### Intellij+all ### 423 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 424 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 425 | 426 | # User-specific stuff 427 | 428 | # AWS User-specific 429 | 430 | # Generated files 431 | 432 | # Sensitive or high-churn files 433 | 434 | # Gradle 435 | 436 | # Gradle and Maven with auto-import 437 | # When using Gradle or Maven with auto-import, you should exclude module files, 438 | # since they will be recreated, and may cause churn. Uncomment if using 439 | # auto-import. 440 | # .idea/artifacts 441 | # .idea/compiler.xml 442 | # .idea/jarRepositories.xml 443 | # .idea/modules.xml 444 | # .idea/*.iml 445 | # .idea/modules 446 | # *.iml 447 | # *.ipr 448 | 449 | # CMake 450 | 451 | # Mongo Explorer plugin 452 | 453 | # File-based project format 454 | 455 | # IntelliJ 456 | 457 | # mpeltonen/sbt-idea plugin 458 | 459 | # JIRA plugin 460 | 461 | # Cursive Clojure plugin 462 | 463 | # SonarLint plugin 464 | 465 | # Crashlytics plugin (for Android Studio and IntelliJ) 466 | 467 | # Editor-based Rest Client 468 | 469 | # Android studio 3.1+ serialized cache file 470 | 471 | ### Intellij+all Patch ### 472 | # Ignore everything but code style settings and run configurations 473 | # that are supposed to be shared within teams. 474 | 475 | .idea/* 476 | 477 | !.idea/codeStyles 478 | !.idea/runConfigurations 479 | 480 | ### Linux ### 481 | 482 | # temporary files which can be created if a process still has a handle open of a deleted file 483 | .fuse_hidden* 484 | 485 | # KDE directory preferences 486 | .directory 487 | 488 | # Linux trash folder which might appear on any partition or disk 489 | .Trash-* 490 | 491 | # .nfs files are created when an open file is removed but is still being accessed 492 | .nfs* 493 | 494 | ### macOS ### 495 | # General 496 | .DS_Store 497 | .AppleDouble 498 | .LSOverride 499 | 500 | # Icon must end with two \r 501 | Icon 502 | 503 | 504 | # Thumbnails 505 | ._* 506 | 507 | # Files that might appear in the root of a volume 508 | .DocumentRevisions-V100 509 | .fseventsd 510 | .Spotlight-V100 511 | .TemporaryItems 512 | .Trashes 513 | .VolumeIcon.icns 514 | .com.apple.timemachine.donotpresent 515 | 516 | # Directories potentially created on remote AFP share 517 | .AppleDB 518 | .AppleDesktop 519 | Network Trash Folder 520 | Temporary Items 521 | .apdisk 522 | 523 | ### Rider ### 524 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 525 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 526 | 527 | # User-specific stuff 528 | 529 | # AWS User-specific 530 | 531 | # Generated files 532 | 533 | # Sensitive or high-churn files 534 | 535 | # Gradle 536 | 537 | # Gradle and Maven with auto-import 538 | # When using Gradle or Maven with auto-import, you should exclude module files, 539 | # since they will be recreated, and may cause churn. Uncomment if using 540 | # auto-import. 541 | # .idea/artifacts 542 | # .idea/compiler.xml 543 | # .idea/jarRepositories.xml 544 | # .idea/modules.xml 545 | # .idea/*.iml 546 | # .idea/modules 547 | # *.iml 548 | # *.ipr 549 | 550 | # CMake 551 | 552 | # Mongo Explorer plugin 553 | 554 | # File-based project format 555 | 556 | # IntelliJ 557 | 558 | # mpeltonen/sbt-idea plugin 559 | 560 | # JIRA plugin 561 | 562 | # Cursive Clojure plugin 563 | 564 | # SonarLint plugin 565 | 566 | # Crashlytics plugin (for Android Studio and IntelliJ) 567 | 568 | # Editor-based Rest Client 569 | 570 | # Android studio 3.1+ serialized cache file 571 | 572 | ### VisualStudioCode ### 573 | .vscode/* 574 | !.vscode/settings.json 575 | !.vscode/tasks.json 576 | !.vscode/launch.json 577 | !.vscode/extensions.json 578 | !.vscode/*.code-snippets 579 | 580 | # Local History for Visual Studio Code 581 | .history/ 582 | 583 | # Built Visual Studio Code Extensions 584 | *.vsix 585 | 586 | ### VisualStudioCode Patch ### 587 | # Ignore all local history of files 588 | .history 589 | .ionide 590 | 591 | # Support for Project snippet scope 592 | 593 | ### Windows ### 594 | # Windows thumbnail cache files 595 | Thumbs.db 596 | Thumbs.db:encryptable 597 | ehthumbs.db 598 | ehthumbs_vista.db 599 | 600 | # Dump file 601 | *.stackdump 602 | 603 | # Folder config file 604 | [Dd]esktop.ini 605 | 606 | # Recycle Bin used on file shares 607 | $RECYCLE.BIN/ 608 | 609 | # Windows Installer files 610 | *.cab 611 | *.msi 612 | *.msix 613 | *.msm 614 | *.msp 615 | 616 | # Windows shortcuts 617 | *.lnk 618 | 619 | ### XamarinStudio ### 620 | .packages 621 | 622 | ### VisualStudio ### 623 | ## 624 | ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore 625 | 626 | # User-specific files 627 | *.rsuser 628 | 629 | # User-specific files (MonoDevelop/Xamarin Studio) 630 | 631 | # Mono auto generated files 632 | mono_crash.* 633 | 634 | # Build results 635 | [Ww][Ii][Nn]32/ 636 | [Aa][Rr][Mm]/ 637 | [Aa][Rr][Mm]64/ 638 | [Ll]ogs/ 639 | 640 | # Visual Studio 2015/2017 cache/options directory 641 | # Uncomment if you have tasks that create the project's static files in wwwroot 642 | 643 | # Visual Studio 2017 auto generated files 644 | Generated\ Files/ 645 | 646 | # MSTest test Results 647 | 648 | # NUnit 649 | nunit-*.xml 650 | 651 | # Build Results of an ATL Project 652 | 653 | # Benchmark Results 654 | BenchmarkDotNet.Artifacts/ 655 | 656 | # .NET Core 657 | 658 | # ASP.NET Scaffolding 659 | ScaffoldingReadMe.txt 660 | 661 | # StyleCop 662 | StyleCopReport.xml 663 | 664 | # Files built by Visual Studio 665 | *_h.h 666 | *.iobj 667 | *.ipdb 668 | *_wpftmp.csproj 669 | *.tlog 670 | 671 | # Chutzpah Test files 672 | 673 | # Visual C++ cache files 674 | 675 | # Visual Studio profiler 676 | 677 | # Visual Studio Trace Files 678 | *.e2e 679 | 680 | # TFS 2012 Local Workspace 681 | 682 | # Guidance Automation Toolkit 683 | 684 | # ReSharper is a .NET coding add-in 685 | 686 | # TeamCity is a build add-in 687 | 688 | # DotCover is a Code Coverage Tool 689 | 690 | # AxoCover is a Code Coverage Tool 691 | .axoCover/* 692 | !.axoCover/settings.json 693 | 694 | # Coverlet is a free, cross platform Code Coverage Tool 695 | coverage*.json 696 | coverage*.xml 697 | coverage*.info 698 | 699 | # Visual Studio code coverage results 700 | 701 | # NCrunch 702 | 703 | # MightyMoose 704 | 705 | # Web workbench (sass) 706 | 707 | # Installshield output folder 708 | 709 | # DocProject is a documentation generator add-in 710 | 711 | # Click-Once directory 712 | 713 | # Publish Web Output 714 | # Note: Comment the next line if you want to checkin your web deploy settings, 715 | # but database connection strings (with potential passwords) will be unencrypted 716 | 717 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 718 | # checkin your Azure Web App publish settings, but sensitive information contained 719 | # in these scripts will be unencrypted 720 | 721 | # NuGet Packages 722 | # NuGet Symbol Packages 723 | *.snupkg 724 | # The packages folder can be ignored because of Package Restore 725 | **/[Pp]ackages/* 726 | # except build/, which is used as an MSBuild target. 727 | !**/[Pp]ackages/build/ 728 | # Uncomment if necessary however generally it will be regenerated when needed 729 | #!**/[Pp]ackages/repositories.config 730 | # NuGet v3's project.json files produces more ignorable files 731 | 732 | # Microsoft Azure Build Output 733 | 734 | # Microsoft Azure Emulator 735 | 736 | # Windows Store app package directories and files 737 | *.appx 738 | *.appxbundle 739 | *.appxupload 740 | 741 | # Visual Studio cache files 742 | # files ending in .cache can be ignored 743 | # but keep track of directories ending in .cache 744 | !?*.[Cc]ache/ 745 | 746 | # Others 747 | 748 | # Including strong name files can present a security risk 749 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 750 | #*.snk 751 | 752 | # Since there are multiple workflows, uncomment next line to ignore bower_components 753 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 754 | 755 | # RIA/Silverlight projects 756 | 757 | # Backup & report files from converting an old project file 758 | # to a newer Visual Studio version. Backup files are not needed, 759 | # because we have git ;-) 760 | ServiceFabricBackup/ 761 | *.rptproj.bak 762 | 763 | # SQL Server files 764 | *.ndf 765 | 766 | # Business Intelligence projects 767 | *.rptproj.rsuser 768 | *- [Bb]ackup.rdl 769 | *- [Bb]ackup ([0-9]).rdl 770 | *- [Bb]ackup ([0-9][0-9]).rdl 771 | 772 | # Microsoft Fakes 773 | 774 | # GhostDoc plugin setting file 775 | 776 | # Node.js Tools for Visual Studio 777 | 778 | # Visual Studio 6 build log 779 | 780 | # Visual Studio 6 workspace options file 781 | 782 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 783 | *.vbw 784 | 785 | # Visual Studio 6 auto-generated project file (contains which files were open etc.) 786 | *.vbp 787 | 788 | # Visual Studio 6 workspace and project file (working project files containing files to include in project) 789 | *.dsw 790 | *.dsp 791 | 792 | # Visual Studio 6 technical files 793 | 794 | # Visual Studio LightSwitch build output 795 | 796 | # Paket dependency manager 797 | 798 | # FAKE - F# Make 799 | 800 | # CodeRush personal settings 801 | .cr/personal 802 | 803 | # Python Tools for Visual Studio (PTVS) 804 | 805 | # Cake - Uncomment if you are using it 806 | # tools/** 807 | # !tools/packages.config 808 | 809 | # Tabs Studio 810 | *.tss 811 | 812 | # Telerik's JustMock configuration file 813 | *.jmconfig 814 | 815 | # BizTalk build output 816 | *.btp.cs 817 | *.btm.cs 818 | *.odx.cs 819 | *.xsd.cs 820 | 821 | # OpenCover UI analysis results 822 | OpenCover/ 823 | 824 | # Azure Stream Analytics local run output 825 | ASALocalRun/ 826 | 827 | # MSBuild Binary and Structured Log 828 | *.binlog 829 | 830 | # NVidia Nsight GPU debugger configuration file 831 | *.nvuser 832 | 833 | # MFractors (Xamarin productivity tool) working folder 834 | .mfractor/ 835 | 836 | # Local History for Visual Studio 837 | .localhistory/ 838 | 839 | # Visual Studio History (VSHistory) files 840 | .vshistory/ 841 | 842 | # BeatPulse healthcheck temp database 843 | healthchecksdb 844 | 845 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 846 | MigrationBackup/ 847 | 848 | # Ionide (cross platform F# VS Code tools) working folder 849 | .ionide/ 850 | 851 | # Fody - auto-generated XML schema 852 | FodyWeavers.xsd 853 | 854 | # VS Code files for those working on multiple tools 855 | *.code-workspace 856 | 857 | # Local History for Visual Studio Code 858 | 859 | # Windows Installer files from build outputs 860 | 861 | # JetBrains Rider 862 | 863 | ### VisualStudio Patch ### 864 | # Additional files built by Visual Studio 865 | 866 | # End of https://www.toptal.com/developers/gitignore/api/windows,linux,macos,visualstudio,visualstudiocode,intellij,intellij+all,rider,angular,dotnetcore,aspnetcore,xamarinstudio 867 | 868 | 869 | 870 | # Ignore fields 871 | ManagedCode.OpenAI.Client.Experiments/ -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ManagedCode 5 | Copyright © 2021-$([System.DateTime]::Now.ToString(`yyyy`)) ManagedCode SAS 6 | true 7 | true 8 | true 9 | snupkg 10 | Github 11 | $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb 12 | logo.png 13 | MIT 14 | true 15 | README.md 16 | 17 | https://github.com/managedcode/OpenAI 18 | https://github.com/managedcode/OpenAI 19 | Managed Code - OpenAI 20 | 0.0.5 21 | 0.0.5 22 | 23 | 24 | 25 | true 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | all 34 | runtime; build; native; contentfiles; analyzers; buildtransitive 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Managed-Code 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ManagedCode.OpenAI.Tests/Architecture/Constants.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.Tests.Architecture 2 | { 3 | internal static class Constants 4 | { 5 | public const string TestSettingsFilePath = "testsettings.json"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /ManagedCode.OpenAI.Tests/Architecture/IntegrationTestsRuntime.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.Tests.Extensions; 2 | using Microsoft.Extensions.Configuration; 3 | 4 | namespace ManagedCode.OpenAI.Tests.Architecture 5 | { 6 | internal class IntegrationTestsRuntime 7 | { 8 | private static IntegrationTestsRuntime? _default; 9 | 10 | private IntegrationTestsRuntime() 11 | { 12 | var builder = new ConfigurationBuilder(); 13 | builder.AddJsonFile(Constants.TestSettingsFilePath); 14 | var configuration = builder.Build(); 15 | IsManualTestsEnabled = !string.IsNullOrWhiteSpace(configuration.OpenAIApiKey()); 16 | } 17 | 18 | public static IntegrationTestsRuntime Default => _default 19 | ??= new IntegrationTestsRuntime(); 20 | 21 | public bool IsManualTestsEnabled { get; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ManagedCode.OpenAI.Tests/Attributes/ManualTestAttribute.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.Tests.Architecture; 2 | using Xunit; 3 | 4 | namespace ManagedCode.OpenAI.Tests.Attributes 5 | { 6 | public class ManualTestAttribute : FactAttribute 7 | { 8 | public ManualTestAttribute() 9 | { 10 | if (!IntegrationTestsRuntime.Default.IsManualTestsEnabled) 11 | { 12 | Skip = "Test Disabled"; 13 | } 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ManagedCode.OpenAI.Tests/Base/BaseTestClass.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.Tests.Extensions; 2 | using ManagedCode.OpenAI.Tests.Services; 3 | using Microsoft.Extensions.Configuration; 4 | using Xunit.Abstractions; 5 | 6 | namespace ManagedCode.OpenAI.Tests.Base 7 | { 8 | public class BaseTestClass 9 | { 10 | public BaseTestClass(ITestOutputHelper output, IConfiguration configuration) 11 | { 12 | Output = output; 13 | ClientBuilder = new TestGptClientBuilder(configuration.OpenAIApiKey(), 14 | configuration.IsUseOpenAIWebClientMock()); 15 | } 16 | 17 | public ITestOutputHelper Output { get; } 18 | internal ITestGptClientBuilder ClientBuilder { get; } 19 | 20 | protected void Log(string message) 21 | { 22 | Output.WriteLine(message); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ManagedCode.OpenAI.Tests/ChatTests.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using ManagedCode.OpenAI.Chat; 3 | using ManagedCode.OpenAI.Client; 4 | using ManagedCode.OpenAI.Tests.Attributes; 5 | using ManagedCode.OpenAI.Tests.Base; 6 | using Microsoft.Extensions.Configuration; 7 | using Xunit.Abstractions; 8 | 9 | namespace ManagedCode.OpenAI.Tests; 10 | 11 | public class ChatTests: BaseTestClass 12 | { 13 | public ChatTests(ITestOutputHelper output, IConfiguration configuration) 14 | : base(output, configuration) 15 | { 16 | } 17 | 18 | 19 | [ManualTest] 20 | public async Task AskSingle_Success() 21 | { 22 | var client = ClientBuilder.Build(); 23 | 24 | var chat = client.OpenChat(); 25 | var question1 = "Distance to the sun?"; 26 | var question2 = "Why so far?"; 27 | 28 | Log($"Question: '{question1}'"); 29 | var answer1 = await chat.AskAsync(question1); 30 | Log($"Answer: '{answer1.Data.Content}'"); 31 | 32 | Log($"Question: '{question2}'"); 33 | var answer2 = await chat.AskAsync(question2); 34 | Log($"Answer: '{answer2.Data.Content}'"); 35 | 36 | answer1.Data.Content.Should().NotBeNullOrWhiteSpace(); 37 | answer2.Data.Content.Should().NotBeNullOrWhiteSpace(); 38 | } 39 | 40 | [ManualTest] 41 | public async Task AskMultiple_Success() 42 | { 43 | var client = ClientBuilder.Build(); 44 | var chat = client.OpenChat(); 45 | var question = "Distance to the sun?"; 46 | 47 | Log($"Question: '{question}'"); 48 | var answer = await chat.AskMultipleAsync(question, 3); 49 | 50 | foreach (var chatMessage in answer.Data) 51 | { 52 | Log($"Answer: '{chatMessage.Content}'"); 53 | chatMessage.Content.Should().NotBeNullOrWhiteSpace(); 54 | } 55 | } 56 | 57 | 58 | [ManualTest] 59 | public async Task ChatSessionSaveLoad_Success() 60 | { 61 | var client = ClientBuilder.Build(); 62 | var chat = client.OpenChat(); 63 | var question = "Distance to the sun?"; 64 | 65 | await chat.AskAsync(question); 66 | var sessionJson = chat.Session.ToJson(); 67 | Log($"Session json: '{sessionJson}'"); 68 | 69 | var newChat = client.OpenChat(x => x.FromJson(sessionJson)); 70 | var loadedSessionJson = newChat.Session.ToJson(); 71 | Log($"Loaded session json: '{loadedSessionJson}'"); 72 | 73 | sessionJson.Should().BeEquivalentTo(loadedSessionJson); 74 | } 75 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI.Tests/CommonTests.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using ManagedCode.OpenAI.Client; 3 | using ManagedCode.OpenAI.Extensions; 4 | using Xunit; 5 | using Xunit.Abstractions; 6 | 7 | namespace ManagedCode.OpenAI.Tests; 8 | 9 | public class CommonTests 10 | { 11 | private readonly ITestOutputHelper _output; 12 | 13 | 14 | public CommonTests(ITestOutputHelper output) 15 | { 16 | _output = output; 17 | } 18 | 19 | [Fact] 20 | public async Task UploadFile_Success() 21 | { 22 | var enumValue = GptModel.Gpt40613; 23 | var enumName = enumValue.Name(); // Enum.GetName(enumValue); 24 | enumName.Should().Be("gpt-4-0613"); 25 | } 26 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI.Tests/CompletionTests.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using ManagedCode.OpenAI.Tests.Attributes; 3 | using ManagedCode.OpenAI.Tests.Base; 4 | using Microsoft.Extensions.Configuration; 5 | using Xunit.Abstractions; 6 | 7 | namespace ManagedCode.OpenAI.Tests 8 | { 9 | public class CompletionTests : BaseTestClass 10 | { 11 | public CompletionTests(ITestOutputHelper output, IConfiguration configuration) 12 | : base(output, configuration) 13 | { 14 | } 15 | 16 | [ManualTest] 17 | public async Task CreateCompletion_Success() 18 | { 19 | var client = ClientBuilder.Build(); 20 | var result = await client 21 | .Completion("Say this is a test") 22 | .ExecuteAsync(); 23 | 24 | result.Data.Content.Should().NotBeNullOrWhiteSpace(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ManagedCode.OpenAI.Tests/EditTests.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using ManagedCode.OpenAI.Tests.Attributes; 3 | using ManagedCode.OpenAI.Tests.Base; 4 | using Microsoft.Extensions.Configuration; 5 | using Xunit.Abstractions; 6 | 7 | namespace ManagedCode.OpenAI.Tests 8 | { 9 | public class EditTests: BaseTestClass 10 | { 11 | public EditTests(ITestOutputHelper output, IConfiguration configuration) 12 | : base(output, configuration) 13 | { 14 | } 15 | 16 | [ManualTest] 17 | public async Task EditMessage_Success() 18 | { 19 | var client = ClientBuilder.Build(); 20 | var result = await client.Edit($"AABBAADD", 21 | "Remove all 'A' symbols from string") 22 | .ExecuteAsync(); 23 | 24 | result.Data.Content.Trim().Should().BeEquivalentTo("BBDD"); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ManagedCode.OpenAI.Tests/Extensions/ConfigurationExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Configuration; 2 | 3 | namespace ManagedCode.OpenAI.Tests.Extensions 4 | { 5 | public static class ConfigurationExtensions 6 | { 7 | public static bool IsUseOpenAIWebClientMock(this IConfiguration configuration) 8 | { 9 | return configuration.GetValue("IsUseOpenAIWebClientMock"); 10 | } 11 | 12 | public static string OpenAIApiKey(this IConfiguration configuration) 13 | { 14 | return configuration.GetValue("OpenAIKey"); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ManagedCode.OpenAI.Tests/Extensions/GenericTypeExtensions.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace ManagedCode.OpenAI.Tests.Extensions 4 | { 5 | public static class GenericTypeExtensions 6 | { 7 | public static bool Is(this T val1, T val2) 8 | where T: IEquatable 9 | { 10 | return EqualityComparer.Default.Equals(val1, val2); 11 | } 12 | 13 | public static string ToJson(this TModel model) 14 | where TModel:class 15 | { 16 | return JsonConvert.SerializeObject(model, Formatting.Indented); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ManagedCode.OpenAI.Tests/Extensions/MockExtensions.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.API; 2 | using ManagedCode.OpenAI.Client; 3 | using Moq; 4 | 5 | namespace ManagedCode.OpenAI.Tests.Extensions 6 | { 7 | internal static class MockExtensions 8 | { 9 | public static IGptClient Client(this Mock webClient) 10 | { 11 | throw new NullReferenceException(); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ManagedCode.OpenAI.Tests/ImageTests.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using ManagedCode.OpenAI.Image; 3 | using ManagedCode.OpenAI.Tests.Attributes; 4 | using ManagedCode.OpenAI.Tests.Base; 5 | using ManagedCode.OpenAI.Tests.Properties; 6 | using Microsoft.Extensions.Configuration; 7 | using Xunit.Abstractions; 8 | 9 | namespace ManagedCode.OpenAI.Tests; 10 | 11 | public class ImageTests: BaseTestClass 12 | { 13 | public ImageTests(ITestOutputHelper output, IConfiguration configuration) 14 | : base(output, configuration) 15 | { 16 | } 17 | 18 | 19 | [ManualTest] 20 | public async Task GenerateImage_Success() 21 | { 22 | var client = ClientBuilder.Build(); 23 | var image = await client.ImageClient.GenerateImage("Red dragon") 24 | .SetImageResolution(ImageResolution._512x512).ExecuteAsync(); 25 | 26 | Log($"Image url: {image.Content}"); 27 | image.Content.Should().NotBeNullOrWhiteSpace(); 28 | } 29 | 30 | [ManualTest] 31 | public async Task GenerateImageMultiple_Success() 32 | { 33 | var client = ClientBuilder.Build(); 34 | var result = await client.ImageClient 35 | .GenerateImage("Red dragon") 36 | .SetImageResolution(ImageResolution._512x512) 37 | .ExecuteMultipleAsync(2); 38 | 39 | result.Content.Should().HaveCount(2); 40 | foreach (var image in result.Content) 41 | { 42 | Log($"Image url: {image}"); 43 | image.Should().NotBeNullOrWhiteSpace(); 44 | } 45 | } 46 | 47 | 48 | [ManualTest] 49 | public async Task EditImage_Success() 50 | { 51 | var client = ClientBuilder.Build(); 52 | var edited = await client 53 | .ImageClient.EditImage("change color to blue", 54 | x => x.FromBytes(Resources.Dog)) 55 | .AsUrl() 56 | .ExecuteAsync(); 57 | 58 | Log($"Edited image url: {edited.Content}"); 59 | edited.Content.Should().NotBeNullOrWhiteSpace(); 60 | } 61 | 62 | [ManualTest] 63 | public async Task EditImageMultiple_Success() 64 | { 65 | var client = ClientBuilder.Build(); 66 | var edited = await client 67 | .ImageClient.EditImage("change color to blue", 68 | x => x.FromBytes(Resources.Dog)) 69 | .AsUrl() 70 | .ExecuteMultipleAsync(2); 71 | 72 | edited.Content.Should().HaveCount(2); 73 | foreach (var image in edited.Content) 74 | { 75 | Log($"Edited image url: {image}"); 76 | image.Should().NotBeNullOrWhiteSpace(); 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI.Tests/ManagedCode.OpenAI.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0 5 | enable 6 | enable 7 | false 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | PreserveNewest 17 | 18 | 19 | 20 | 21 | 22 | all 23 | runtime; build; native; contentfiles; analyzers; buildtransitive 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | all 34 | runtime; build; native; contentfiles; analyzers; buildtransitive 35 | 36 | 37 | all 38 | runtime; build; native; contentfiles; analyzers; buildtransitive 39 | 40 | 41 | all 42 | runtime; build; native; contentfiles; analyzers; buildtransitive 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | True 53 | True 54 | Resources.resx 55 | 56 | 57 | 58 | 59 | 60 | ResXFileCodeGenerator 61 | Resources.Designer.cs 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /ManagedCode.OpenAI.Tests/ModelsTests.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using ManagedCode.OpenAI.API.Errors; 3 | using ManagedCode.OpenAI.Extensions; 4 | using ManagedCode.OpenAI.Tests.Attributes; 5 | using ManagedCode.OpenAI.Tests.Base; 6 | using ManagedCode.OpenAI.Tests.Extensions; 7 | using Microsoft.Extensions.Configuration; 8 | using Xunit.Abstractions; 9 | 10 | namespace ManagedCode.OpenAI.Tests 11 | { 12 | public class ModelsTests : BaseTestClass 13 | { 14 | public ModelsTests(ITestOutputHelper output, IConfiguration configuration) 15 | : base(output, configuration) 16 | { 17 | 18 | } 19 | 20 | [ManualTest] 21 | public async Task GetModel_ModelNotFoundException() 22 | { 23 | var modelName = "WRONG_MODEL_NAME"; 24 | var client = ClientBuilder.Build(); 25 | 26 | await client.Invoking(async x => await x.GetModelAsync(modelName)) 27 | .Should().ThrowAsync() 28 | .Where(x => x.ErrorCode 29 | .Is(OpenAIErrorCode.ModelNotFound.Name())); 30 | } 31 | 32 | [ManualTest] 33 | public async Task GetModel_Success() 34 | { 35 | var modelName = "babbage"; 36 | var client = ClientBuilder.Build(); 37 | var model = await client.GetModelAsync(modelName); 38 | model.Id.Should().Be(modelName); 39 | } 40 | 41 | [ManualTest] 42 | public async Task GetModels_Success() 43 | { 44 | var expectedModels = new[] { "babbage", "davinci", "text-davinci-edit-001" }; 45 | var client = ClientBuilder.Build(); 46 | 47 | var models = await client.GetModelsAsync(); 48 | models.Select(x => x.Id).ToList().Should() 49 | .Contain(expectedModels); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /ManagedCode.OpenAI.Tests/ModerationTests.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using ManagedCode.OpenAI.Tests.Attributes; 3 | using ManagedCode.OpenAI.Tests.Base; 4 | using ManagedCode.OpenAI.Tests.Extensions; 5 | using Microsoft.Extensions.Configuration; 6 | using Xunit.Abstractions; 7 | 8 | namespace ManagedCode.OpenAI.Tests; 9 | 10 | public class ModerationTests : BaseTestClass 11 | { 12 | 13 | public ModerationTests(ITestOutputHelper output, IConfiguration configuration) 14 | : base(output, configuration) 15 | { 16 | } 17 | 18 | [ManualTest] 19 | public async Task CreateModeration_Success() 20 | { 21 | var client = ClientBuilder.Build(); 22 | 23 | var moderation = await client.Moderation().ExecuteAsync("I kill you"); 24 | 25 | //assert 26 | moderation.Categories.Violence.Should().BeTrue(); 27 | moderation.Should().NotBeNull(); 28 | moderation.Categories.Should().NotBeNull(); 29 | moderation.CategoryScores.Should().NotBeNull(); 30 | 31 | Log($"Moderation content: {Environment.NewLine}{moderation.ToJson()}"); 32 | } 33 | 34 | [ManualTest] 35 | public async Task CreateMultipleModeration_Success() 36 | { 37 | var client = ClientBuilder.Build(); 38 | 39 | var moderationItems = await client.Moderation() 40 | .ExecuteMultipleAsync("I kill you", "You must die"); 41 | 42 | 43 | //assert 44 | moderationItems.Should().NotBeNull().And.HaveCount(2); 45 | foreach (var moderation in moderationItems) 46 | moderation.Categories.Violence.Should().BeTrue(); 47 | 48 | Log($"Moderation content: {Environment.NewLine}{moderationItems.ToJson()}"); 49 | } 50 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI.Tests/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // 5 | // Changes to this file may cause incorrect behavior and will be lost if 6 | // the code is regenerated. 7 | // 8 | //------------------------------------------------------------------------------ 9 | 10 | namespace ManagedCode.OpenAI.Tests.Properties { 11 | using System; 12 | 13 | 14 | [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] 15 | [System.Diagnostics.DebuggerNonUserCodeAttribute()] 16 | [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 17 | internal class Resources { 18 | 19 | private static System.Resources.ResourceManager resourceMan; 20 | 21 | private static System.Globalization.CultureInfo resourceCulture; 22 | 23 | [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 24 | internal Resources() { 25 | } 26 | 27 | [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] 28 | internal static System.Resources.ResourceManager ResourceManager { 29 | get { 30 | if (object.Equals(null, resourceMan)) { 31 | System.Resources.ResourceManager temp = new System.Resources.ResourceManager("ManagedCode.OpenAI.Tests.Properties.Resources", typeof(Resources).Assembly); 32 | resourceMan = temp; 33 | } 34 | return resourceMan; 35 | } 36 | } 37 | 38 | [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static System.Globalization.CultureInfo Culture { 40 | get { 41 | return resourceCulture; 42 | } 43 | set { 44 | resourceCulture = value; 45 | } 46 | } 47 | 48 | internal static byte[] Dog { 49 | get { 50 | object obj = ResourceManager.GetObject("Dog", resourceCulture); 51 | return ((byte[])(obj)); 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /ManagedCode.OpenAI.Tests/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 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 | text/microsoft-resx 112 | 113 | 114 | 2.0 115 | 116 | 117 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, 118 | PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 122 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, 123 | PublicKeyToken=b77a5c561934e089 124 | 125 | 126 | 128 | 129 | ..\Resources\dog.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, 130 | PublicKeyToken=b77a5c561934e089 131 | 132 | 133 | -------------------------------------------------------------------------------- /ManagedCode.OpenAI.Tests/Resources/dog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/managedcode/OpenAI/1418997288050139d499bc1f36b24575227b8f24/ManagedCode.OpenAI.Tests/Resources/dog.png -------------------------------------------------------------------------------- /ManagedCode.OpenAI.Tests/Services/TestGptClientBuilder.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.API; 2 | using ManagedCode.OpenAI.Client; 3 | using Moq; 4 | 5 | namespace ManagedCode.OpenAI.Tests.Services 6 | { 7 | internal interface ITestGptClientBuilder : IGptClientBuilder 8 | { 9 | public ITestGptClientBuilder ConfigureMockWebClient(Action> mock); 10 | } 11 | 12 | internal class TestGptClientBuilder : GptClientBuilder, ITestGptClientBuilder 13 | { 14 | private Action>? _mockConfiguration; 15 | 16 | public TestGptClientBuilder(string apiKey, bool useWebMockClient) : base(apiKey) 17 | { 18 | IsUseWebMockClient = useWebMockClient; 19 | } 20 | 21 | protected bool IsUseWebMockClient { get; } 22 | 23 | public ITestGptClientBuilder ConfigureMockWebClient(Action> mock) 24 | { 25 | _mockConfiguration = mock; 26 | return this; 27 | } 28 | 29 | public override GptClient Build() 30 | { 31 | if (IsUseWebMockClient && _mockConfiguration != null) 32 | { 33 | var mock = new Mock(); 34 | _mockConfiguration.Invoke(mock); 35 | return new GptClient(Configuration, mock.Object); 36 | } 37 | 38 | return base.Build(); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /ManagedCode.OpenAI.Tests/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Microsoft.Extensions.Configuration; 3 | using ManagedCode.OpenAI.Tests.Architecture; 4 | using ManagedCode.OpenAI.Tests.Services; 5 | 6 | namespace ManagedCode.OpenAI.Tests 7 | { 8 | public class Startup 9 | { 10 | public void ConfigureServices(IServiceCollection services) 11 | { 12 | AddConfiguration(services); 13 | services.AddScoped(); 14 | } 15 | 16 | private void AddConfiguration(IServiceCollection services) 17 | { 18 | var builder = new ConfigurationBuilder(); 19 | builder.AddJsonFile(Constants.TestSettingsFilePath); 20 | var configuration = builder.Build(); 21 | 22 | services.AddSingleton(x => configuration); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ManagedCode.OpenAI.Tests/testsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "OpenAIKey": "", 3 | "IsUseOpenAIWebClientMock": "false" 4 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ManagedCode.OpenAI", "ManagedCode.OpenAI\ManagedCode.OpenAI.csproj", "{8A870C9E-7641-4546-B7B2-9FEE0445A76C}" 4 | EndProject 5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ManagedCode.OpenAI.Tests", "ManagedCode.OpenAI.Tests\ManagedCode.OpenAI.Tests.csproj", "{A9F57AEF-9EBA-405A-8B74-1B1BD2BEC70B}" 6 | EndProject 7 | Global 8 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 9 | Debug|Any CPU = Debug|Any CPU 10 | Release|Any CPU = Release|Any CPU 11 | EndGlobalSection 12 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 13 | {8A870C9E-7641-4546-B7B2-9FEE0445A76C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 14 | {8A870C9E-7641-4546-B7B2-9FEE0445A76C}.Debug|Any CPU.Build.0 = Debug|Any CPU 15 | {8A870C9E-7641-4546-B7B2-9FEE0445A76C}.Release|Any CPU.ActiveCfg = Release|Any CPU 16 | {8A870C9E-7641-4546-B7B2-9FEE0445A76C}.Release|Any CPU.Build.0 = Release|Any CPU 17 | {A9F57AEF-9EBA-405A-8B74-1B1BD2BEC70B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 18 | {A9F57AEF-9EBA-405A-8B74-1B1BD2BEC70B}.Debug|Any CPU.Build.0 = Debug|Any CPU 19 | {A9F57AEF-9EBA-405A-8B74-1B1BD2BEC70B}.Release|Any CPU.ActiveCfg = Release|Any CPU 20 | {A9F57AEF-9EBA-405A-8B74-1B1BD2BEC70B}.Release|Any CPU.Build.0 = Release|Any CPU 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /ManagedCode.OpenAI.sln.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | AI 3 | True 4 | True -------------------------------------------------------------------------------- /ManagedCode.OpenAI/API/Abstractions/IOpenAiWebClient.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.API.Edit; 2 | using ManagedCode.OpenAI.API.File; 3 | using ManagedCode.OpenAI.API.Image; 4 | using ManagedCode.OpenAI.API.Moderation; 5 | 6 | namespace ManagedCode.OpenAI.API; 7 | 8 | internal interface IOpenAiWebClient : IDisposable 9 | { 10 | public Task ModelsAsync(); 11 | 12 | public Task ModelAsync(string modelId); 13 | 14 | Task ChatAsync(ChatRequestDto request); 15 | 16 | Task CompletionsAsync(CompletionRequestDto request); 17 | 18 | Task EditAsync(EditRequestDto request); 19 | 20 | Task GenerateImageAsync(GenerateImageRequestDto request); 21 | Task EditImageAsync(EditImageRequestDto request); 22 | Task VariationImageAsync(VariationImageRequestDto request); 23 | 24 | #region Moderations 25 | 26 | Task ModerationAsync(ModerationRequestDto request); 27 | 28 | #endregion 29 | 30 | #region Files 31 | 32 | Task FilesInfoAsync(); 33 | Task CreateFileAsync(string content, string fileName, string purpose = "fine-tune"); 34 | Task CreateFileAsync(Stream content, string fileName, string purpose = "fine-tune"); 35 | Task CreateFileAsync(byte[] content, string fileName, string purpose = "fine-tune"); 36 | Task CreateFileAsync(ReadOnlyMemory content, string fileName, string purpose = "fine-tune"); 37 | Task DeleteFileAsync(string fileId); 38 | Task FileInfoAsync(string fileId); 39 | 40 | // TODO: This may be a stream 41 | // I don't know what response type is returned here 42 | Task GetContentFromFileAsync(string fileId); 43 | 44 | #endregion 45 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/API/Base/BaseCompletionsResponseDto.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace ManagedCode.OpenAI.API; 4 | 5 | internal abstract class BaseCompletionsResponseDto 6 | { 7 | [JsonPropertyName("id")] 8 | public string Id { get; set; } 9 | 10 | [JsonPropertyName("object")] 11 | public string Object { get; set; } 12 | 13 | [JsonPropertyName("created")] 14 | public int Created { get; set; } 15 | 16 | [JsonPropertyName("model")] 17 | public string Model { get; set; } 18 | 19 | [JsonPropertyName("choices")] 20 | public List Choices { get; set; } 21 | 22 | [JsonPropertyName("usage")] 23 | public UsageDto Usage { get; set; } 24 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/API/Chat/ChatChoiceDto.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace ManagedCode.OpenAI.API; 4 | 5 | internal class ChatChoiceDto 6 | { 7 | [JsonPropertyName("index")] 8 | public int Index { get; set; } 9 | 10 | [JsonPropertyName("message")] 11 | public MessageDto Message { get; set; } 12 | 13 | [JsonPropertyName("finish_reason")] 14 | public string FinishReason { get; set; } 15 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/API/Chat/ChatRequestDto.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace ManagedCode.OpenAI.API; 4 | 5 | internal class ChatRequestDto 6 | { 7 | [JsonPropertyName("model")] 8 | public required string Model { get; set; } 9 | 10 | [JsonPropertyName("messages")] 11 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] 12 | public required List Messages { get; set; } = new(); 13 | 14 | [JsonPropertyName("temperature")] 15 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] 16 | public required float? Temperature { get; set; } 17 | 18 | [JsonPropertyName("top_p")] 19 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] 20 | public required float? TopP { get; set; } 21 | 22 | [JsonPropertyName("n")] 23 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] 24 | public required int? N { get; set; } 25 | 26 | [JsonPropertyName("stream")] 27 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] 28 | public required bool? Stream { get; set; } 29 | 30 | [JsonPropertyName("max_tokens")] 31 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] 32 | public required int? MaxTokens { get; set; } 33 | 34 | [JsonPropertyName("presence_penalty")] 35 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] 36 | public required float? PresencePenalty { get; set; } 37 | 38 | [JsonPropertyName("frequency_penalty")] 39 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] 40 | public required float? FrequencyPenalty { get; set; } 41 | 42 | [JsonPropertyName("logit_biat")] 43 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] 44 | public Dictionary? LogitBias { get; set; } 45 | 46 | [JsonPropertyName("user")] 47 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] 48 | public required string? User { get; set; } 49 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/API/Chat/ChatResponseDto.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.API; 2 | 3 | internal class ChatResponseDto : BaseCompletionsResponseDto 4 | { 5 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/API/Chat/MessageDto.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace ManagedCode.OpenAI.API; 4 | 5 | internal class MessageDto 6 | { 7 | [JsonPropertyName("role")] 8 | public string Role { get; set; } 9 | 10 | [JsonPropertyName("content")] 11 | public string Content { get; set; } 12 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/API/Chat/UsageDto.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace ManagedCode.OpenAI.API; 4 | 5 | internal class UsageDto 6 | { 7 | [JsonPropertyName("prompt_tokens")] 8 | public int PromptTokens { get; set; } 9 | 10 | [JsonPropertyName("completion_tokens")] 11 | public int CompletionTokens { get; set; } 12 | 13 | [JsonPropertyName("total_tokens")] 14 | public int TotalTokens { get; set; } 15 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/API/Completions/CompletionChoiceDto.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace ManagedCode.OpenAI.API; 4 | 5 | internal class CompletionChoiceDto 6 | { 7 | [JsonPropertyName("text")] 8 | public string Text { get; set; } 9 | 10 | [JsonPropertyName("index")] 11 | public int Index { get; set; } 12 | 13 | [JsonPropertyName("logprobs")] 14 | public int? Logprobs { get; set; } 15 | 16 | [JsonPropertyName("finish_reason")] 17 | public string FinishReason { get; set; } 18 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/API/Completions/CompletionRequestDto.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using System.Text.Json.Serialization; 3 | 4 | namespace ManagedCode.OpenAI.API; 5 | 6 | internal class CompletionRequestDto 7 | { 8 | [JsonPropertyName("model")] 9 | public string Model { get; set; } 10 | 11 | [JsonPropertyName("prompt")] 12 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] 13 | public List Prompt { get; set; } = new(); 14 | 15 | 16 | [JsonPropertyName("suffix")] 17 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] 18 | public string? Suffix { get; set; } 19 | 20 | [Range(0, 2024)] 21 | [JsonPropertyName("max_tokens")] 22 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] 23 | public int? MaxTokens { get; set; } 24 | 25 | [Range(0, 2f)] 26 | [JsonPropertyName("temperature")] 27 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] 28 | public float? Temperature { get; set; } 29 | 30 | [JsonPropertyName("top_p")] 31 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] 32 | public int? TopP { get; set; } 33 | 34 | [Range(0, 10)] 35 | [JsonPropertyName("n")] 36 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] 37 | public int? N { get; set; } 38 | 39 | [JsonPropertyName("stream")] 40 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] 41 | public bool? Stream { get; set; } 42 | 43 | [Range(1, int.MaxValue)] 44 | [JsonPropertyName("logprobs")] 45 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] 46 | public int? Logprobs { get; set; } 47 | 48 | [JsonPropertyName("echo")] 49 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] 50 | public bool? Echo { get; set; } 51 | 52 | [MaxLength(4)] 53 | [JsonPropertyName("stop")] 54 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] 55 | public string[]? Stop { get; set; } 56 | 57 | [Range(0, 2f)] 58 | [JsonPropertyName("presence_penalty")] 59 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] 60 | public float? PresencePenalty { get; set; } 61 | 62 | [Range(-2f, 2f)] 63 | [JsonPropertyName("frequency_penalty")] 64 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] 65 | public float? FrequencyPenalty { get; set; } 66 | 67 | [Range(1, int.MaxValue)] 68 | [JsonPropertyName("best_of")] 69 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] 70 | public int? BestOf { get; set; } 71 | 72 | [JsonPropertyName("logit_biat")] 73 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] 74 | public Dictionary? LogitBias { get; set; } 75 | 76 | [JsonPropertyName("user")] 77 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] 78 | public string? User { get; set; } 79 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/API/Completions/CompletionResponseDto.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.API; 2 | 3 | internal class CompletionResponseDto : BaseCompletionsResponseDto 4 | { 5 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/API/Edit/EditChoiceDto.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace ManagedCode.OpenAI.API.Edit; 4 | 5 | internal class EditChoiceDto 6 | { 7 | [JsonPropertyName("text")] 8 | public string Text { get; set; } 9 | 10 | [JsonPropertyName("index")] 11 | public int Index { get; set; } 12 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/API/Edit/EditRequestDto.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using System.Text.Json.Serialization; 3 | 4 | namespace ManagedCode.OpenAI.API.Edit; 5 | 6 | internal class EditRequestDto 7 | { 8 | [JsonPropertyName("model")] 9 | public string Model { get; set; } 10 | 11 | [JsonPropertyName("input")] 12 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] 13 | public string Input { get; set; } 14 | 15 | [JsonPropertyName("instruction")] 16 | public string Instruction { get; set; } 17 | 18 | [JsonPropertyName("n")] 19 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] 20 | public int? Count { get; set; } 21 | 22 | [Range(0, 2f)] 23 | [JsonPropertyName("temperature")] 24 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] 25 | public float? Temperature { get; set; } 26 | 27 | [JsonPropertyName("top_p")] 28 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] 29 | public float? TopP { get; set; } 30 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/API/Edit/EditResponseDto.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.API.Edit; 2 | 3 | internal class EditResponseDto : BaseCompletionsResponseDto 4 | { 5 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/API/Errors/OpenAIError.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace ManagedCode.OpenAI.API.Errors; 4 | 5 | internal class OpenAIErrorResponse 6 | { 7 | [JsonPropertyName("error")] 8 | public OpenAIError Error { get; set; } 9 | 10 | } 11 | 12 | internal class OpenAIError 13 | { 14 | [JsonPropertyName("message")] 15 | public string Message { get; set; } 16 | 17 | [JsonPropertyName("type")] 18 | public string Type { get; set; } 19 | 20 | [JsonPropertyName("model")] 21 | public string Model { get; set; } 22 | 23 | [JsonPropertyName("code")] 24 | public string Code { get; set; } 25 | } 26 | -------------------------------------------------------------------------------- /ManagedCode.OpenAI/API/Errors/OpenAIErrorCode.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.Serialization; 2 | 3 | namespace ManagedCode.OpenAI.API.Errors; 4 | 5 | public enum OpenAIErrorCode 6 | { 7 | [EnumMember(Value = "model_not_found")] 8 | ModelNotFound, 9 | } 10 | -------------------------------------------------------------------------------- /ManagedCode.OpenAI/API/Errors/OpenAIException.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using ManagedCode.OpenAI.Extensions; 3 | 4 | namespace ManagedCode.OpenAI.API.Errors; 5 | 6 | public class OpenAIException : HttpRequestException 7 | { 8 | public OpenAIException(string message, string code, HttpStatusCode statusCode 9 | ) : 10 | base(message, null, statusCode) 11 | { 12 | ErrorCode = code; 13 | } 14 | 15 | public OpenAIException(OpenAIErrorCode errorCode) 16 | { 17 | ErrorCode = errorCode.Name(); 18 | } 19 | 20 | public string ErrorCode { get; } 21 | } 22 | -------------------------------------------------------------------------------- /ManagedCode.OpenAI/API/File/FileDeleteResponseDto.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace ManagedCode.OpenAI.API.File; 4 | 5 | internal class FileDeleteResponseDto 6 | { 7 | [JsonPropertyName("id")] 8 | public string Id { get; set; } 9 | 10 | [JsonPropertyName("object")] 11 | public string Object { get; set; } 12 | 13 | [JsonPropertyName("deleted")] 14 | public bool Deleted { get; set; } 15 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/API/File/FileInfoDto.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace ManagedCode.OpenAI.API.File; 4 | 5 | internal class FileInfoDto 6 | { 7 | [JsonPropertyName("id")] 8 | public string Id { get; set; } 9 | 10 | [JsonPropertyName("object")] 11 | public string Object { get; set; } 12 | 13 | [JsonPropertyName("bytes")] 14 | public int Bytes { get; set; } 15 | 16 | [JsonPropertyName("created_at")] 17 | public int CreatedAt { get; set; } 18 | 19 | [JsonPropertyName("filename")] 20 | public string Filename { get; set; } 21 | 22 | [JsonPropertyName("purpose")] 23 | public string Purpose { get; set; } 24 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/API/File/FilesInfoResponseDto.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace ManagedCode.OpenAI.API.File; 4 | 5 | internal class FilesInfoResponseDto 6 | { 7 | [JsonPropertyName("data")] 8 | public FileInfoDto[] Data { get; set; } 9 | 10 | [JsonPropertyName("object")] 11 | public string Object { get; set; } 12 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/API/Image/BaseImageRequestDto.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using System.Text.Json.Serialization; 3 | 4 | namespace ManagedCode.OpenAI.API.Image; 5 | 6 | internal class BaseImageRequestDto 7 | { 8 | [Range(0, 10)] 9 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] 10 | [JsonPropertyName("n")] 11 | public int? N { get; set; } 12 | 13 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] 14 | [JsonPropertyName("size")] 15 | public string? Size { get; set; } 16 | 17 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] 18 | [JsonPropertyName("response_format")] 19 | public string? ResponseFormat { get; set; } 20 | 21 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] 22 | [JsonPropertyName("user")] 23 | public string? User { get; set; } 24 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/API/Image/EditImageRequestDto.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace ManagedCode.OpenAI.API.Image; 4 | 5 | internal class EditImageRequestDto : BaseImageRequestDto 6 | { 7 | [JsonPropertyName("prompt")] 8 | public string Description { get; set; } 9 | 10 | [JsonPropertyName("image")] 11 | public string ImageBase64 { get; set; } 12 | 13 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] 14 | [JsonPropertyName("mask")] 15 | public string? MaskBase64 { get; set; } 16 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/API/Image/GenerateImageRequestDto.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace ManagedCode.OpenAI.API.Image; 4 | 5 | internal class GenerateImageRequestDto : BaseImageRequestDto 6 | { 7 | [JsonPropertyName("prompt")] 8 | public string Description { get; set; } 9 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/API/Image/ImageResponseDataDto.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace ManagedCode.OpenAI.API.Image; 4 | 5 | internal class ImageResponseDataDto 6 | { 7 | [JsonPropertyName("url")] 8 | public string Url { get; set; } 9 | 10 | [JsonPropertyName("b64_json")] 11 | public string B64Json { get; set; } 12 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/API/Image/ImageResponseDto.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace ManagedCode.OpenAI.API.Image; 4 | 5 | internal class ImageResponseDto 6 | { 7 | [JsonPropertyName("created")] 8 | public int Created { get; set; } 9 | 10 | [JsonPropertyName("data")] 11 | public List Data { get; set; } 12 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/API/Image/VariationImageRequestDto.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace ManagedCode.OpenAI.API.Image; 4 | 5 | internal class VariationImageRequestDto : BaseImageRequestDto 6 | { 7 | [JsonPropertyName("image")] 8 | public string ImageBase64 { get; set; } 9 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/API/Models/ModelDto.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace ManagedCode.OpenAI.API; 4 | 5 | internal class ModelDto 6 | { 7 | [JsonPropertyName("id")] 8 | public string Id { get; set; } 9 | 10 | [JsonPropertyName("object")] 11 | public string Object { get; set; } 12 | 13 | [JsonPropertyName("owned_by")] 14 | public string OwnedBy { get; set; } 15 | 16 | [JsonPropertyName("permission")] 17 | public PermissionDto[] Permission { get; set; } 18 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/API/Models/ModelsResponseDto.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace ManagedCode.OpenAI.API; 4 | 5 | internal class ModelsResponseDto 6 | { 7 | [JsonPropertyName("data")] 8 | public ModelDto[] Models { get; set; } 9 | 10 | [JsonPropertyName("object")] 11 | public string Object { get; set; } 12 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/API/Models/PermissionDto.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace ManagedCode.OpenAI.API; 4 | 5 | internal class PermissionDto 6 | { 7 | [JsonPropertyName("id")] 8 | public string Id { get; set; } 9 | 10 | [JsonPropertyName("object")] 11 | public string Object { get; set; } 12 | 13 | [JsonPropertyName("created")] 14 | public int Created { get; set; } 15 | 16 | [JsonPropertyName("allow_create_engine")] 17 | public bool AllowCreateEngine { get; set; } 18 | 19 | [JsonPropertyName("allow_sampling")] 20 | public bool AllowSampling { get; set; } 21 | 22 | [JsonPropertyName("allow_logprobs")] 23 | public bool AllowLogprobs { get; set; } 24 | 25 | [JsonPropertyName("allow_search_indices")] 26 | public bool AllowSearchIndices { get; set; } 27 | 28 | [JsonPropertyName("allow_view")] 29 | public bool AllowView { get; set; } 30 | 31 | [JsonPropertyName("allow_fine_tuning")] 32 | public bool AllowFineTuning { get; set; } 33 | 34 | [JsonPropertyName("organization")] 35 | public string Organization { get; set; } 36 | 37 | [JsonPropertyName("group")] 38 | public object Group { get; set; } 39 | 40 | [JsonPropertyName("is_blocking")] 41 | public bool IsBlocking { get; set; } 42 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/API/Moderation/CategoryDto.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace ManagedCode.OpenAI.API.Moderation; 4 | 5 | internal class CategoryDto where TResult : struct 6 | { 7 | [JsonPropertyName("hate")] 8 | public TResult Hate { get; set; } 9 | 10 | [JsonPropertyName("hate/threatening")] 11 | public TResult HateThreatening { get; set; } 12 | 13 | [JsonPropertyName("self-harm")] 14 | public TResult SelfHarm { get; set; } 15 | 16 | [JsonPropertyName("sexual")] 17 | public TResult Sexual { get; set; } 18 | 19 | [JsonPropertyName("sexual/minors")] 20 | public TResult SexualMinors { get; set; } 21 | 22 | [JsonPropertyName("violence")] 23 | public TResult Violence { get; set; } 24 | 25 | [JsonPropertyName("violence/graphic")] 26 | public TResult ViolenceGraphic { get; set; } 27 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/API/Moderation/CategoryResultDto.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace ManagedCode.OpenAI.API.Moderation; 4 | 5 | internal class CategoryResultDto 6 | { 7 | [JsonPropertyName("categories")] 8 | public CategoryDto Categories { get; set; } 9 | 10 | [JsonPropertyName("category_scores")] 11 | public CategoryDto CategoryScores { get; set; } 12 | 13 | [JsonPropertyName("flagged")] 14 | public bool Flagged { get; set; } 15 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/API/Moderation/ModerationRequestDto.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace ManagedCode.OpenAI.API.Moderation; 4 | 5 | internal class ModerationRequestDto 6 | { 7 | [JsonPropertyName("input")] 8 | public List Input { get; set; } = new(); 9 | 10 | [JsonPropertyName("model")] 11 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] 12 | public string Model { get; set; } 13 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/API/Moderation/ModerationResponseDto.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace ManagedCode.OpenAI.API.Moderation; 4 | 5 | internal class ModerationResponseDto 6 | { 7 | [JsonPropertyName("id")] 8 | public string Id { get; set; } 9 | 10 | [JsonPropertyName("model")] 11 | public string Model { get; set; } 12 | 13 | [JsonPropertyName("results")] 14 | public CategoryResultDto[] Results { get; set; } 15 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/API/OpenAIWebClient.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Http.Json; 2 | using System.Text.Json; 3 | using ManagedCode.OpenAI.API.Edit; 4 | using ManagedCode.OpenAI.API.Errors; 5 | using ManagedCode.OpenAI.API.File; 6 | using ManagedCode.OpenAI.API.Image; 7 | using ManagedCode.OpenAI.API.Moderation; 8 | 9 | namespace ManagedCode.OpenAI.API; 10 | 11 | internal class OpenAiWebClient : IOpenAiWebClient 12 | { 13 | private const string AUTHORIZATION = "Authorization"; 14 | private const string AUTHORIZATION_FORMAT = "Bearer {0}"; 15 | private const string ORGANIZATION = "OpenAI-Organization"; 16 | private const string URL_BASE = "https://api.openai.com/v1/"; 17 | private const string URL_LIST_MODELS = "models"; 18 | private const string URL_MODEL = "models/{0}"; 19 | private const string URL_CHAT_COMPLETIONS = "chat/completions"; 20 | private const string URL_COMPLETIONS = "completions"; 21 | private const string URL_EDITS = "edits"; 22 | private const string URL_IMAGE_GENERATION = "images/generations"; 23 | private const string URL_IMAGE_EDIT = "images/edits"; 24 | private const string URL_IMAGE_VARIATION = "images/variations"; 25 | private const string URL_FILES = "files"; 26 | private const string URL_FILE = "files/{0}"; 27 | private const string URL_FILE_CONTEXT = "files/{0}/content"; 28 | 29 | private const string URL_MODERATION = "moderations"; 30 | 31 | 32 | private readonly HttpClient _httpClient; 33 | 34 | public OpenAiWebClient(string apiKey) 35 | { 36 | _httpClient = new HttpClient(); 37 | _httpClient.DefaultRequestHeaders.Add(AUTHORIZATION, 38 | string.Format(AUTHORIZATION_FORMAT, apiKey)); 39 | 40 | _httpClient.BaseAddress = new Uri(URL_BASE); 41 | } 42 | 43 | public OpenAiWebClient(string apiKey, string organization) 44 | { 45 | _httpClient = new HttpClient(); 46 | _httpClient.DefaultRequestHeaders.Add(AUTHORIZATION, 47 | string.Format(AUTHORIZATION_FORMAT, apiKey)); 48 | 49 | _httpClient.DefaultRequestHeaders.Add(ORGANIZATION, organization); 50 | _httpClient.BaseAddress = new Uri(URL_BASE); 51 | } 52 | 53 | 54 | public async Task ModelsAsync() 55 | { 56 | var httpResponseMessage = await _httpClient.GetAsync(URL_LIST_MODELS); 57 | return await ReadAsync(httpResponseMessage); 58 | } 59 | 60 | public async Task ModelAsync(string modelId) 61 | { 62 | var httpResponseMessage = await _httpClient.GetAsync( 63 | string.Format(URL_MODEL, modelId.Trim())); 64 | return await ReadAsync(httpResponseMessage); 65 | } 66 | 67 | public async Task ChatAsync(ChatRequestDto request) 68 | { 69 | var response = await _httpClient.PostAsJsonAsync(URL_CHAT_COMPLETIONS, request); 70 | return await ReadAsync(response); 71 | } 72 | 73 | public async Task CompletionsAsync(CompletionRequestDto request) 74 | { 75 | var response = await _httpClient.PostAsJsonAsync(URL_COMPLETIONS, request); 76 | return await ReadAsync(response); 77 | } 78 | 79 | public async Task EditAsync(EditRequestDto request) 80 | { 81 | var response = await _httpClient.PostAsJsonAsync(URL_EDITS, request); 82 | return await ReadAsync(response); 83 | } 84 | 85 | public async Task GenerateImageAsync(GenerateImageRequestDto request) 86 | { 87 | var response = await _httpClient.PostAsJsonAsync(URL_IMAGE_GENERATION, request); 88 | return await ReadAsync(response); 89 | } 90 | 91 | public async Task EditImageAsync(EditImageRequestDto request) 92 | { 93 | var imageBytes = Convert.FromBase64String(request.ImageBase64); 94 | var parameters = ToImageRequestParameters(request); 95 | using var form = new MultipartFormDataContent(); 96 | 97 | foreach (var parameter in parameters) 98 | form.Add(parameter.Key, parameter.Value); 99 | 100 | form.Add(new StreamContent(new MemoryStream(imageBytes)), "image", "image.png"); 101 | 102 | if (!string.IsNullOrWhiteSpace(request.MaskBase64)) 103 | { 104 | var maskBytes = Convert.FromBase64String(request.MaskBase64); 105 | form.Add(new StreamContent(new MemoryStream(maskBytes)), "mask", "mask.png"); 106 | } 107 | 108 | form.Add(new StringContent(request.Description), "prompt"); 109 | 110 | var response = await _httpClient.PostAsync(URL_IMAGE_EDIT, form); 111 | return await ReadAsync(response); 112 | } 113 | 114 | public async Task VariationImageAsync(VariationImageRequestDto request) 115 | { 116 | var imageBytes = Convert.FromBase64String(request.ImageBase64); 117 | 118 | var parameters = ToImageRequestParameters(request); 119 | using var form = new MultipartFormDataContent(); 120 | 121 | foreach (var parameter in parameters) 122 | form.Add(parameter.Key, parameter.Value); 123 | 124 | form.Add(new ByteArrayContent(imageBytes), "image", "image.png"); 125 | 126 | var response = await _httpClient.PostAsync(URL_IMAGE_VARIATION, form); 127 | return await ReadAsync(response); 128 | } 129 | 130 | public void Dispose() 131 | { 132 | _httpClient.Dispose(); 133 | } 134 | 135 | #region Moderations 136 | 137 | public async Task ModerationAsync(ModerationRequestDto request) 138 | { 139 | var httpResponseMessage = await _httpClient.PostAsJsonAsync(URL_MODERATION, request); 140 | 141 | return await ReadAsync(httpResponseMessage); 142 | } 143 | 144 | #endregion 145 | 146 | private async Task ReadAsync(HttpResponseMessage response) 147 | { 148 | if (!response.IsSuccessStatusCode) 149 | { 150 | var responseContent = await response.Content.ReadAsStringAsync(); 151 | var error = JsonDeserialize(responseContent).Error; 152 | throw new OpenAIException(error.Message, error.Code, response.StatusCode); 153 | } 154 | 155 | var responseBody = await response.Content.ReadAsStringAsync(); 156 | return JsonDeserialize(responseBody); 157 | } 158 | 159 | private async Task ReadAsStringAsync(HttpResponseMessage response) 160 | { 161 | if (!response.IsSuccessStatusCode) 162 | { 163 | var responseContent = await response.Content.ReadAsStringAsync(); 164 | var error = JsonDeserialize(responseContent).Error; 165 | throw new OpenAIException(error.Message, error.Code, response.StatusCode); 166 | } 167 | 168 | return await response.Content.ReadAsStringAsync(); 169 | } 170 | 171 | private TModel JsonDeserialize(string jsonStr) 172 | { 173 | return JsonSerializer.Deserialize(jsonStr) 174 | ?? throw new NullReferenceException(); 175 | } 176 | 177 | private Dictionary ToImageRequestParameters(BaseImageRequestDto request) 178 | { 179 | var result = new Dictionary(); 180 | 181 | if (!string.IsNullOrWhiteSpace(request.Size)) 182 | result.Add(new StringContent(request.Size), "size"); 183 | 184 | if (!string.IsNullOrWhiteSpace(request.ResponseFormat)) 185 | result.Add(new StringContent(request.ResponseFormat), "response_format"); 186 | 187 | if (!string.IsNullOrWhiteSpace(request.User)) 188 | result.Add(new StringContent(request.User), "user"); 189 | 190 | if (request.N.HasValue) 191 | result.Add(new StringContent(request.N.Value.ToString()), "n"); 192 | return result; 193 | } 194 | 195 | #region Files 196 | 197 | public async Task FilesInfoAsync() 198 | { 199 | var httpResponseMessage = await _httpClient.GetAsync(URL_FILES); 200 | return await ReadAsync(httpResponseMessage); 201 | } 202 | 203 | private async Task CreateFileAsync(HttpContent content, string fileName, string purpose = "fine-tune") 204 | { 205 | MultipartFormDataContent multipartFormDataContent = new(); 206 | multipartFormDataContent.Add(new StringContent(purpose), "purpose"); 207 | multipartFormDataContent.Add(content, "file", fileName); 208 | 209 | var httpResponseMessage = await _httpClient.PostAsync(URL_FILES, multipartFormDataContent); 210 | 211 | return await ReadAsync(httpResponseMessage); 212 | } 213 | 214 | public async Task CreateFileAsync(Stream content, string fileName, string purpose = "fine-tune") 215 | { 216 | StreamContent streamContent = new(content); 217 | return await CreateFileAsync(streamContent, fileName, purpose); 218 | } 219 | 220 | public async Task CreateFileAsync(string content, string fileName, string purpose = "fine-tune") 221 | { 222 | StringContent stringContent = new(content); 223 | return await CreateFileAsync(stringContent, fileName, purpose); 224 | } 225 | 226 | public async Task CreateFileAsync(byte[] content, string fileName, string purpose = "fine-tune") 227 | { 228 | ByteArrayContent byteArrayContent = new(content); 229 | return await CreateFileAsync(byteArrayContent, fileName, purpose); 230 | } 231 | 232 | public async Task CreateFileAsync(ReadOnlyMemory content, string fileName, string purpose = 233 | "fine-tune") 234 | { 235 | ReadOnlyMemoryContent readOnlyMemoryContent = new(content); 236 | return await CreateFileAsync(readOnlyMemoryContent, fileName, purpose); 237 | } 238 | 239 | 240 | public async Task DeleteFileAsync(string fileId) 241 | { 242 | var resultUrl = string.Format(URL_FILE, fileId); 243 | var httpResponseMessage = await _httpClient.DeleteAsync(resultUrl); 244 | 245 | return await ReadAsync(httpResponseMessage); 246 | } 247 | 248 | public async Task FileInfoAsync(string fileId) 249 | { 250 | var resultUrl = string.Format(URL_FILE, fileId); 251 | 252 | var httpResponseMessage = await _httpClient.GetAsync(resultUrl); 253 | 254 | return await ReadAsync(httpResponseMessage); 255 | } 256 | 257 | // TODO: It is not known what the result of the query returns 258 | public async Task GetContentFromFileAsync(string fileId) 259 | { 260 | var resultUrl = string.Format(URL_FILE_CONTEXT, fileId); 261 | var httpResponseMessage = await _httpClient.GetAsync(resultUrl); 262 | 263 | return await ReadAsStringAsync(httpResponseMessage); 264 | } 265 | 266 | #endregion 267 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Chat/Abstractions/IChatMessage.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.Chat; 2 | 3 | public interface IChatMessage 4 | { 5 | public string Content { get; } 6 | public string Role { get; } 7 | public string FinishReason { get; set; } 8 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Chat/Abstractions/IChatMessageParameters.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.Chat; 2 | 3 | public interface IChatMessageParameters 4 | { 5 | public string? Role { get; } 6 | 7 | public string? ModelId { get; } 8 | 9 | public float? Temperature { get; } 10 | 11 | public float? TopP { get; } 12 | 13 | public bool? Stream { get; } 14 | 15 | public int? MaxTokens { get; } 16 | 17 | public float? PresencePenalty { get; } 18 | 19 | public float? FrequencyPenalty { get; } 20 | 21 | public Dictionary? LogitBias { get; } 22 | 23 | public string? User { get; } 24 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Chat/Abstractions/IChatMessageParametersBuilder.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.Client; 2 | 3 | namespace ManagedCode.OpenAI.Chat; 4 | 5 | public interface IChatMessageParametersBuilder 6 | { 7 | public IChatMessageParametersBuilder SetModel(string modelId); 8 | public IChatMessageParametersBuilder SetModel(GptModel model); 9 | public IChatMessageParametersBuilder SetRole(string role); 10 | public IChatMessageParametersBuilder SetRole(RoleType role); 11 | public IChatMessageParametersBuilder SetMaxTokens(int maxTokens); 12 | public IChatMessageParametersBuilder SetTemperature(float temperature); 13 | public IChatMessageParametersBuilder SetNucleus(float value); 14 | public IChatMessageParametersBuilder SetStream(); 15 | public IChatMessageParametersBuilder SetPresencePenalty(float number); 16 | public IChatMessageParametersBuilder SetFrequencyPenalty(float number); 17 | public IChatMessageParametersBuilder SetLogitBias(Dictionary dictionary); 18 | public IChatMessageParametersBuilder SetLogitBias(string key, int value); 19 | public IChatMessageParametersBuilder SetUser(string user); 20 | 21 | public IChatMessageParameters Build(); 22 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Chat/Abstractions/IChatSession.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.Chat; 2 | 3 | public interface IChatSession 4 | { 5 | public string ToJson(); 6 | 7 | public IChatSessionRecord[] Records(); 8 | 9 | public void AddRecord(IChatSessionRecord record); 10 | 11 | public void AddRecords(IChatSessionRecord[] records); 12 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Chat/Abstractions/IChatSessionLoader.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.Chat; 2 | 3 | public interface IChatSessionLoader 4 | { 5 | IChatSession FromJson(string json); 6 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Chat/Abstractions/IChatSessionRecord.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.Chat; 2 | 3 | public interface IChatSessionRecord 4 | { 5 | string Role { get; } 6 | string Content { get; } 7 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Chat/Abstractions/IGptChat.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.Client; 2 | 3 | namespace ManagedCode.OpenAI.Chat; 4 | 5 | public interface IGptChat 6 | { 7 | public IChatSession Session { get; } 8 | 9 | public Task> AskAsync(string message); 10 | 11 | public Task> AskAsync(string message, IChatMessageParameters parameters); 12 | 13 | public Task> AskMultipleAsync(string message, int countOfAnswers); 14 | 15 | public Task> AskMultipleAsync(string message, int countOfAnswers, 16 | IChatMessageParameters parameters); 17 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Chat/Abstractions/IUsage.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.Chat; 2 | 3 | public interface IUsage 4 | { 5 | public int PromptTokens { get; } 6 | 7 | public int CompletionTokens { get; } 8 | 9 | public int TotalTokens { get; } 10 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Chat/Extensions/ChatExtensions.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.Client; 2 | 3 | namespace ManagedCode.OpenAI.Chat; 4 | 5 | public static class ChatExtensions 6 | { 7 | public static Task> AskAsync(this IGptChat chat, string message, 8 | Func parameters) 9 | { 10 | var builder = new ChatMessageParametersBuilder(); 11 | return chat.AskAsync(message, parameters.Invoke(builder)); 12 | } 13 | 14 | public static Task> AskMultipleAsync(this IGptChat chat, 15 | string message, int countOfAnswers, 16 | Func parameters) 17 | { 18 | var builder = new ChatMessageParametersBuilder(); 19 | return chat.AskMultipleAsync(message, countOfAnswers, parameters.Invoke(builder)); 20 | } 21 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Chat/Extensions/ClientChatExtensions.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.Client; 2 | 3 | namespace ManagedCode.OpenAI.Chat; 4 | 5 | public static class ClientChatExtensions 6 | { 7 | public static IGptChat OpenChat(this IGptClient client) 8 | { 9 | return client.OpenChat(new ChatSession()); 10 | } 11 | 12 | public static IGptChat OpenChat(this IGptClient client, IChatSession session) 13 | { 14 | var builder = new ChatMessageParametersBuilder(); 15 | builder.SetModel(client.Configuration.ModelId); 16 | return client.OpenChat(builder.Build(), session); 17 | } 18 | 19 | public static IGptChat OpenChat(this IGptClient client, IChatMessageParameters defaultMessageParameters) 20 | { 21 | return client.OpenChat(defaultMessageParameters, new ChatSession()); 22 | } 23 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Chat/Extensions/MapperChatExtensions.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.API; 2 | using ManagedCode.OpenAI.Client; 3 | 4 | namespace ManagedCode.OpenAI.Chat; 5 | 6 | internal static class MapperChatExtensions 7 | { 8 | public static IPermission ToPermission(this PermissionDto dto) 9 | { 10 | return new Permission 11 | { 12 | AllowCreateEngine = dto.AllowCreateEngine, 13 | AllowFineTuning = dto.AllowFineTuning, 14 | AllowLogProbs = dto.AllowLogprobs, 15 | AllowSampling = dto.AllowSampling, 16 | AllowSearchIndices = dto.AllowSearchIndices, 17 | AllowView = dto.AllowView, 18 | Created = dto.Created, 19 | Id = dto.Id, 20 | IsBlocking = dto.IsBlocking, 21 | Organization = dto.Organization 22 | }; 23 | } 24 | 25 | public static IAnswer ToChatAnswer(this ChatResponseDto dto) 26 | { 27 | return new Answer 28 | { 29 | Id = dto.Id, 30 | ModelId = dto.Model, 31 | Usage = dto.Usage.ToUsage(), 32 | Data = dto.Choices.First().ToChatMessage(), 33 | Created = dto.Created 34 | }; 35 | } 36 | 37 | public static IAnswer ToChatAnswerCollection(this ChatResponseDto dto) 38 | { 39 | return new Answer 40 | { 41 | Id = dto.Id, 42 | ModelId = dto.Model, 43 | Usage = dto.Usage.ToUsage(), 44 | Data = dto.Choices.Select(x => x.ToChatMessage()).ToArray(), 45 | Created = dto.Created 46 | }; 47 | } 48 | 49 | public static IChatMessage ToChatMessage(this ChatChoiceDto dto) 50 | { 51 | return new ChatMessage 52 | { 53 | Content = dto.Message.Content, 54 | Role = dto.Message.Role, 55 | FinishReason = dto.FinishReason 56 | }; 57 | } 58 | 59 | public static IUsage ToUsage(this UsageDto dto) 60 | { 61 | return new Usage 62 | { 63 | CompletionTokens = dto.CompletionTokens, 64 | PromptTokens = dto.PromptTokens, 65 | TotalTokens = dto.TotalTokens 66 | }; 67 | } 68 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Chat/GptChat.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.API; 2 | using ManagedCode.OpenAI.Client; 3 | using ManagedCode.OpenAI.Extensions; 4 | 5 | namespace ManagedCode.OpenAI.Chat; 6 | 7 | internal class GptChat : IGptChat 8 | { 9 | private const RoleType DEFAULT_ROLE = RoleType.User; 10 | private const GptModel DEFAULT_MODEL = GptModel.Gpt35Turbo; 11 | private readonly IChatMessageParameters _defaultMessageParameters; 12 | 13 | private readonly IOpenAiWebClient _webClient; 14 | 15 | public GptChat(IOpenAiWebClient webClient, IChatSession session, 16 | IChatMessageParameters defaultMessageParameters) 17 | { 18 | _webClient = webClient; 19 | _defaultMessageParameters = defaultMessageParameters; 20 | Session = session; 21 | } 22 | 23 | public IChatSession Session { get; } 24 | 25 | public async Task> AskAsync(string message) 26 | { 27 | return await AskAsync(message, _defaultMessageParameters); 28 | } 29 | 30 | public async Task> AskAsync(string message, IChatMessageParameters parameters) 31 | { 32 | var askMessage = CreateAskMessage(message, parameters); 33 | var request = ToChatRequest(askMessage, 1, parameters); 34 | 35 | var response = await _webClient.ChatAsync(request); 36 | UpdateSession(response, askMessage); 37 | return response.ToChatAnswer(); 38 | } 39 | 40 | public async Task> AskMultipleAsync(string message, int countOfAnswers) 41 | { 42 | return await AskMultipleAsync(message, countOfAnswers, _defaultMessageParameters); 43 | } 44 | 45 | public async Task> AskMultipleAsync(string message, int countOfAnswers, 46 | IChatMessageParameters parameters) 47 | { 48 | var askMessage = CreateAskMessage(message, parameters); 49 | var request = ToChatRequest(askMessage, countOfAnswers, parameters); 50 | var response = await _webClient.ChatAsync(request); 51 | 52 | UpdateSession(response, askMessage); 53 | return response.ToChatAnswerCollection(); 54 | } 55 | 56 | private void UpdateSession(ChatResponseDto response, MessageDto askMessage) 57 | { 58 | Session.AddRecord(new ChatSessionRecord 59 | { 60 | Content = askMessage.Content, 61 | Role = askMessage.Role 62 | }); 63 | 64 | var responseRecords = 65 | response.Choices.Select(x => (IChatSessionRecord)new ChatSessionRecord 66 | { 67 | Content = x.Message.Content, 68 | Role = x.Message.Role 69 | }).ToArray(); 70 | 71 | 72 | Session.AddRecords(responseRecords); 73 | } 74 | 75 | private MessageDto CreateAskMessage(string message, IChatMessageParameters parameters) 76 | { 77 | return new MessageDto 78 | { 79 | Content = message, 80 | Role = (parameters.Role ?? _defaultMessageParameters.Role) ?? DEFAULT_ROLE.Name() 81 | }; 82 | } 83 | 84 | private ChatRequestDto ToChatRequest(MessageDto askMessage, 85 | int countOfAnswers, IChatMessageParameters parameters) 86 | { 87 | var messages = Session.Records().Select(x => new MessageDto 88 | { 89 | Content = x.Content, 90 | Role = x.Role 91 | }).ToList(); 92 | 93 | messages.Add(askMessage); 94 | 95 | return new ChatRequestDto 96 | { 97 | FrequencyPenalty = parameters.FrequencyPenalty ?? _defaultMessageParameters.FrequencyPenalty, 98 | LogitBias = parameters.LogitBias ?? _defaultMessageParameters.LogitBias, 99 | MaxTokens = parameters.MaxTokens ?? _defaultMessageParameters.MaxTokens, 100 | Model = (parameters.ModelId ?? _defaultMessageParameters.ModelId) ?? DEFAULT_MODEL.Name(), 101 | N = countOfAnswers, 102 | PresencePenalty = parameters.PresencePenalty ?? _defaultMessageParameters.PresencePenalty, 103 | Stream = parameters.Stream ?? _defaultMessageParameters.Stream, 104 | Temperature = parameters.Temperature ?? _defaultMessageParameters.Temperature, 105 | TopP = parameters.TopP ?? _defaultMessageParameters.TopP, 106 | User = parameters.User ?? _defaultMessageParameters.User, 107 | Messages = messages 108 | }; 109 | } 110 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Chat/Message/ChatMessage.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.Chat; 2 | 3 | internal class ChatMessage : IChatMessage 4 | { 5 | public required string Content { get; set; } 6 | public required string Role { get; set; } 7 | 8 | public required string FinishReason { get; set; } 9 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Chat/Message/ChatMessageParameters.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace ManagedCode.OpenAI.Chat; 4 | 5 | public class ChatMessageParameters : IChatMessageParameters 6 | { 7 | public string? Role { get; set; } 8 | public string? ModelId { get; set; } 9 | 10 | [Range(0, 2f)] 11 | public float? Temperature { get; set; } 12 | 13 | public float? TopP { get; set; } 14 | public bool? Stream { get; set; } 15 | 16 | [Range(0, 2048)] 17 | public int? MaxTokens { get; set; } 18 | 19 | [Range(-2f, 2f)] 20 | public float? PresencePenalty { get; set; } 21 | 22 | [Range(-2f, 2f)] 23 | public float? FrequencyPenalty { get; set; } 24 | 25 | public Dictionary? LogitBias { get; set; } 26 | public string? User { get; set; } 27 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Chat/Message/ChatMessageParametersBuilder.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.Client; 2 | using ManagedCode.OpenAI.Extensions; 3 | 4 | namespace ManagedCode.OpenAI.Chat; 5 | 6 | public class ChatMessageParametersBuilder : IChatMessageParametersBuilder 7 | { 8 | private readonly ChatMessageParameters _parameters; 9 | 10 | public ChatMessageParametersBuilder() 11 | { 12 | _parameters = new ChatMessageParameters(); 13 | } 14 | 15 | public IChatMessageParametersBuilder SetModel(string modelId) 16 | { 17 | _parameters.ModelId = modelId; 18 | return this; 19 | } 20 | 21 | public IChatMessageParametersBuilder SetModel(GptModel model) 22 | { 23 | _parameters.ModelId = model.Name(); 24 | return this; 25 | } 26 | 27 | public IChatMessageParametersBuilder SetRole(string role) 28 | { 29 | _parameters.Role = role; 30 | return this; 31 | } 32 | 33 | public IChatMessageParametersBuilder SetRole(RoleType role) 34 | { 35 | _parameters.Role = role.Name(); 36 | return this; 37 | } 38 | 39 | public IChatMessageParametersBuilder SetMaxTokens(int maxTokens) 40 | { 41 | _parameters.MaxTokens = maxTokens; 42 | return this; 43 | } 44 | 45 | public IChatMessageParametersBuilder SetTemperature(float temperature) 46 | { 47 | _parameters.Temperature = temperature; 48 | return this; 49 | } 50 | 51 | public IChatMessageParametersBuilder SetNucleus(float value) 52 | { 53 | _parameters.TopP = value; 54 | return this; 55 | } 56 | 57 | public IChatMessageParametersBuilder SetStream() 58 | { 59 | _parameters.Stream = true; 60 | return this; 61 | } 62 | 63 | public IChatMessageParametersBuilder SetPresencePenalty(float number) 64 | { 65 | _parameters.PresencePenalty = number; 66 | return this; 67 | } 68 | 69 | public IChatMessageParametersBuilder SetFrequencyPenalty(float number) 70 | { 71 | _parameters.FrequencyPenalty = number; 72 | return this; 73 | } 74 | 75 | public IChatMessageParametersBuilder SetLogitBias(Dictionary dictionary) 76 | { 77 | _parameters.LogitBias = dictionary; 78 | return this; 79 | } 80 | 81 | public IChatMessageParametersBuilder SetLogitBias(string key, int value) 82 | { 83 | var dict = _parameters.LogitBias ??= new Dictionary(); 84 | dict.Add(key, value); 85 | return this; 86 | } 87 | 88 | public IChatMessageParametersBuilder SetUser(string user) 89 | { 90 | _parameters.User = user; 91 | return this; 92 | } 93 | 94 | public IChatMessageParameters Build() 95 | { 96 | _parameters.Validate(); 97 | return _parameters; 98 | } 99 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Chat/Message/Usage.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.Chat; 2 | 3 | internal class Usage : IUsage 4 | { 5 | public required int PromptTokens { get; set; } 6 | public required int CompletionTokens { get; set; } 7 | public required int TotalTokens { get; set; } 8 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Chat/Session/ChatSession.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json; 2 | 3 | namespace ManagedCode.OpenAI.Chat; 4 | 5 | internal class ChatSession : IChatSession 6 | { 7 | public List ListRecords { get; } = new(); 8 | 9 | public string ToJson() 10 | { 11 | return JsonSerializer.Serialize(ListRecords); 12 | } 13 | 14 | IChatSessionRecord[] IChatSession.Records() 15 | { 16 | return ListRecords.ToArray(); 17 | } 18 | 19 | public void AddRecord(IChatSessionRecord record) 20 | { 21 | ListRecords.Add(record); 22 | } 23 | 24 | public void AddRecords(IChatSessionRecord[] records) 25 | { 26 | ListRecords.AddRange(records); 27 | } 28 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Chat/Session/ChatSessionLoader.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json; 2 | 3 | namespace ManagedCode.OpenAI.Chat; 4 | 5 | public class ChatSessionLoader : IChatSessionLoader 6 | { 7 | public IChatSession FromJson(string json) 8 | { 9 | var records = JsonSerializer.Deserialize(json) 10 | ?? throw new ArgumentException($"Wrong session format: {json}"); 11 | 12 | var session = new ChatSession(); 13 | session.AddRecords(records.Cast().ToArray()); 14 | return session; 15 | } 16 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Chat/Session/ChatSessionRecord.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.Chat; 2 | 3 | internal class ChatSessionRecord : IChatSessionRecord 4 | { 5 | public required string Role { get; set; } 6 | public required string Content { get; set; } 7 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Client/Abstractions/IAnswer.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.Chat; 2 | 3 | namespace ManagedCode.OpenAI.Client; 4 | 5 | public interface IAnswer 6 | { 7 | public TModel Data { get; } 8 | 9 | public IUsage Usage { get; } 10 | 11 | public int Created { get; } 12 | 13 | public string ModelId { get; } 14 | 15 | public string Id { get; } 16 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Client/Abstractions/IGptClient.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.Chat; 2 | using ManagedCode.OpenAI.Completions; 3 | using ManagedCode.OpenAI.Edit; 4 | using ManagedCode.OpenAI.Image; 5 | using ManagedCode.OpenAI.Moderation; 6 | 7 | namespace ManagedCode.OpenAI.Client; 8 | 9 | public interface IGptClient 10 | { 11 | public IGptClientConfiguration Configuration { get; } 12 | 13 | public IImageClient ImageClient { get; } 14 | 15 | void Configure(IGptClientConfiguration configuration); 16 | void Configure(Func configuration); 17 | 18 | public Task GetModelsAsync(); 19 | public Task GetModelAsync(string modelId); 20 | 21 | IGptChat OpenChat(IChatMessageParameters defaultMessageParameters, IChatSession session); 22 | ICompletionBuilder Completion(string prompt); 23 | IEditBuilder Edit(string input, string instruction); 24 | IModerationBuilder Moderation(); 25 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Client/Abstractions/IGptClientBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.Client; 2 | 3 | public interface IGptClientBuilder 4 | { 5 | public IGptClientBuilder WithOrganization(string organization); 6 | 7 | public IGptClientBuilder Configure(Action configuration); 8 | 9 | public GptClient Build(); 10 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Client/Abstractions/IGptClientConfiguration.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.Client; 2 | 3 | public interface IGptClientConfiguration 4 | { 5 | public string ModelId { get; } 6 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Client/Abstractions/IGptClientConfigurationBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.Client; 2 | 3 | public interface IGptClientConfigurationBuilder 4 | { 5 | IGptClientConfigurationBuilder SetDefaultModel(string modelId); 6 | IGptClientConfigurationBuilder SetDefaultModel(GptModel model); 7 | 8 | IGptClientConfiguration Build(); 9 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Client/Abstractions/IModel.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.Client; 2 | 3 | public interface IModel 4 | { 5 | public string Id { get; } 6 | 7 | public string OwnedBy { get; } 8 | 9 | public IPermission[] Permission { get; } 10 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Client/Abstractions/IPermission.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.Client; 2 | 3 | public interface IPermission 4 | { 5 | public string Id { get; } 6 | 7 | public int Created { get; } 8 | 9 | public bool AllowCreateEngine { get; } 10 | 11 | public bool AllowSampling { get; } 12 | 13 | public bool AllowLogProbs { get; } 14 | 15 | public bool AllowSearchIndices { get; } 16 | 17 | public bool AllowView { get; } 18 | 19 | public bool AllowFineTuning { get; } 20 | 21 | public string Organization { get; } 22 | 23 | public bool IsBlocking { get; } 24 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Client/Configuration/DefaultGptClientConfiguration.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.Extensions; 2 | 3 | namespace ManagedCode.OpenAI.Client; 4 | 5 | public class DefaultGptClientConfiguration : IGptClientConfiguration 6 | { 7 | private const GptModel DEFAULT_MODEL = GptModel.Gpt35Turbo; 8 | 9 | public DefaultGptClientConfiguration() 10 | { 11 | ModelId = DEFAULT_MODEL.Name(); 12 | } 13 | 14 | public string ModelId { get; set; } 15 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Client/Configuration/GptClientConfigurationBuilder.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.Extensions; 2 | 3 | namespace ManagedCode.OpenAI.Client; 4 | 5 | public class GptClientConfigurationBuilder : IGptClientConfigurationBuilder 6 | { 7 | private readonly DefaultGptClientConfiguration _configuration; 8 | 9 | public GptClientConfigurationBuilder() 10 | { 11 | _configuration = new DefaultGptClientConfiguration(); 12 | } 13 | 14 | public IGptClientConfigurationBuilder SetDefaultModel(string modelId) 15 | { 16 | _configuration.ModelId = modelId; 17 | return this; 18 | } 19 | 20 | public IGptClientConfigurationBuilder SetDefaultModel(GptModel model) 21 | { 22 | _configuration.ModelId = model.Name(); 23 | return this; 24 | } 25 | 26 | public IGptClientConfiguration Build() 27 | { 28 | return _configuration; 29 | } 30 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Client/Extensions/GptClientExtensions.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.Chat; 2 | 3 | namespace ManagedCode.OpenAI.Client; 4 | 5 | public static class GptClientExtensions 6 | { 7 | public static IGptChat OpenChat(this IGptClient client, 8 | IChatMessageParameters defaultMessageParameters, string json) 9 | { 10 | return client.OpenChat(defaultMessageParameters, x => x.FromJson(json)); 11 | } 12 | 13 | public static IGptChat OpenChat(this IGptClient client, Func session) 14 | { 15 | var sessionLoader = DefaultSessionLoader(); 16 | return client.OpenChat(session.Invoke(sessionLoader)); 17 | } 18 | 19 | public static IGptChat OpenChat(this IGptClient client, IChatMessageParameters defaultMessageParameters, 20 | Func session) 21 | { 22 | var sessionLoader = DefaultSessionLoader(); 23 | return client.OpenChat(defaultMessageParameters, session.Invoke(sessionLoader)); 24 | } 25 | 26 | private static IChatSessionLoader DefaultSessionLoader() 27 | { 28 | return new ChatSessionLoader(); 29 | } 30 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Client/Extensions/MapperClientExtensions.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.API; 2 | using ManagedCode.OpenAI.Chat; 3 | 4 | namespace ManagedCode.OpenAI.Client; 5 | 6 | internal static class MapperClientExtensions 7 | { 8 | public static IModel ToModel(this ModelDto dto) 9 | { 10 | return new Model 11 | { 12 | Id = dto.Id, 13 | OwnedBy = dto.OwnedBy, 14 | Permission = dto.Permission.Select(x => x.ToPermission()).ToArray() 15 | }; 16 | } 17 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Client/GptClient.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.API; 2 | using ManagedCode.OpenAI.Chat; 3 | using ManagedCode.OpenAI.Completions; 4 | using ManagedCode.OpenAI.Edit; 5 | using ManagedCode.OpenAI.Image; 6 | using ManagedCode.OpenAI.Moderation; 7 | 8 | namespace ManagedCode.OpenAI.Client; 9 | 10 | public class GptClient : IGptClient 11 | { 12 | private IOpenAiWebClient _webClient = null!; 13 | 14 | public GptClient(string apiKey) 15 | { 16 | Init(apiKey, default, new DefaultGptClientConfiguration()); 17 | } 18 | 19 | public GptClient(string apiKey, IGptClientConfiguration configuration) 20 | { 21 | Init(apiKey, default, configuration); 22 | } 23 | 24 | public GptClient(string apiKey, string organization) 25 | { 26 | Init(apiKey, organization, new DefaultGptClientConfiguration()); 27 | } 28 | 29 | public GptClient(string apiKey, string organization, IGptClientConfiguration configuration) 30 | { 31 | Init(apiKey, organization, configuration); 32 | } 33 | 34 | 35 | internal GptClient(string apiKey, IGptClientConfiguration configuration, string? organization) 36 | { 37 | Init(apiKey, organization, configuration); 38 | } 39 | 40 | internal GptClient(IGptClientConfiguration configuration, IOpenAiWebClient webClient) 41 | { 42 | _webClient = webClient; 43 | Configuration = new DefaultGptClientConfiguration(); 44 | ImageClient = new ImageClient(_webClient); 45 | Configuration = configuration; 46 | } 47 | 48 | private GptClient() 49 | { 50 | } 51 | 52 | 53 | public IGptClientConfiguration Configuration { get; private set; } = null!; 54 | public IImageClient ImageClient { get; private set; } = null!; 55 | 56 | public void Configure(IGptClientConfiguration configuration) 57 | { 58 | Configuration = configuration; 59 | } 60 | 61 | public void Configure(Func configuration) 62 | { 63 | var builder = new GptClientConfigurationBuilder(); 64 | Configure(configuration.Invoke(builder)); 65 | } 66 | 67 | public async Task GetModelsAsync() 68 | { 69 | var models = await _webClient.ModelsAsync(); 70 | return models.Models.Select(x => x.ToModel()).ToArray(); 71 | } 72 | 73 | public async Task GetModelAsync(string modelId) 74 | { 75 | var model = await _webClient.ModelAsync(modelId); 76 | return model.ToModel(); 77 | } 78 | 79 | public IGptChat OpenChat(IChatMessageParameters defaultMessageParameters, IChatSession session) 80 | { 81 | return new GptChat(_webClient, session, defaultMessageParameters); 82 | } 83 | 84 | public ICompletionBuilder Completion(string prompt) 85 | { 86 | return new CompletionsBuilder(_webClient, prompt); 87 | } 88 | 89 | public IEditBuilder Edit(string input, string instruction) 90 | { 91 | return new EditBuilder(_webClient, input, instruction); 92 | } 93 | 94 | public IModerationBuilder Moderation() 95 | { 96 | return new ModerationBuilder(_webClient); 97 | } 98 | 99 | public static IGptClientBuilder Builder(string apiKey) 100 | { 101 | return new GptClientBuilder(apiKey); 102 | } 103 | 104 | private void Init(string apiKey, string? organization, IGptClientConfiguration configuration) 105 | { 106 | var webClient = string.IsNullOrWhiteSpace(organization) 107 | ? new OpenAiWebClient(apiKey) 108 | : new OpenAiWebClient(apiKey, organization); 109 | 110 | _webClient = webClient; 111 | Configuration = configuration; 112 | ImageClient = new ImageClient(_webClient); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Client/GptClientBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.Client; 2 | 3 | public class GptClientBuilder : IGptClientBuilder 4 | { 5 | 6 | public GptClientBuilder(string apiKey) 7 | { 8 | ApiKey = apiKey; 9 | Configuration = new DefaultGptClientConfiguration(); 10 | } 11 | 12 | protected string ApiKey { get; set; } 13 | protected IGptClientConfiguration Configuration { get; set; } 14 | protected string? Organization { get; set; } 15 | 16 | public IGptClientBuilder WithOrganization(string organization) 17 | { 18 | Organization = organization; 19 | return this; 20 | } 21 | 22 | public IGptClientBuilder Configure(Action configuration) 23 | { 24 | var builder = new GptClientConfigurationBuilder(); 25 | configuration.Invoke(builder); 26 | Configuration = builder.Build(); 27 | return this; 28 | } 29 | 30 | public virtual GptClient Build() 31 | { 32 | var client = new GptClient(ApiKey, Configuration, Organization); 33 | return client; 34 | } 35 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Client/Models/Answer.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.Chat; 2 | 3 | namespace ManagedCode.OpenAI.Client; 4 | 5 | internal class Answer : IAnswer 6 | { 7 | public required TModel Data { get; set; } 8 | public required IUsage Usage { get; set; } 9 | public required int Created { get; set; } 10 | public required string ModelId { get; set; } 11 | public required string Id { get; set; } 12 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Client/Models/GptModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Runtime.Serialization; 3 | 4 | namespace ManagedCode.OpenAI.Client; 5 | 6 | public enum GptModel 7 | { 8 | 9 | [EnumMember(Value = "gpt-4")] 10 | [Description("gpt-4")] 11 | Gpt4, 12 | 13 | [EnumMember(Value = "gpt-4-0613")] 14 | [Description("gpt-4-0613")] 15 | Gpt40613, 16 | 17 | [EnumMember(Value = "gpt-4-32k")] 18 | [Description("gpt-4-32k")] 19 | Gpt432k, 20 | 21 | [EnumMember(Value = "gpt-4-32k-0613")] 22 | [Description("gpt-4-32k-0613")] 23 | Gpt432k0613, 24 | 25 | [EnumMember(Value = "gpt-3.5-turbo")] 26 | [Description("gpt-3.5-turbo")] 27 | Gpt35Turbo, 28 | 29 | [EnumMember(Value = "gpt-3.5-turbo-16k")] 30 | [Description("gpt-3.5-turbo-16k")] 31 | Gpt35Turbo16k, 32 | 33 | [EnumMember(Value = "gpt-3.5-turbo-0613")] 34 | [Description("gpt-3.5-turbo-0613")] 35 | Gpt35Turbo0613, 36 | 37 | [EnumMember(Value = "gpt-3.5-turbo-16k-0613")] 38 | [Description("gpt-3.5-turbo-16k-0613")] 39 | Gpt35Turbo16k0613, 40 | 41 | [EnumMember(Value = "text-davinci-003")] 42 | [Description("text-davinci-003")] 43 | TextDavinci003, 44 | 45 | [EnumMember(Value = "text-curie-001")] 46 | [Description("text-curie-001")] 47 | TextCurie001, 48 | 49 | [EnumMember(Value = "text-babbage-001")] 50 | [Description("text-babbage-001")] 51 | TextBabbage001, 52 | 53 | [EnumMember(Value = "text-ada-001")] 54 | [Description("text-ada-001")] 55 | TextAda001, 56 | 57 | [EnumMember(Value = "text-davinci-002")] 58 | [Description("text-davinci-002")] 59 | TextDavinci002, 60 | 61 | [EnumMember(Value = "text-davinci-001")] 62 | [Description("text-davinci-001")] 63 | TextDavinci001, 64 | 65 | [EnumMember(Value = "davinci-instruct-beta")] 66 | [Description("davinci-instruct-beta")] 67 | DavinciInstructBeta, 68 | 69 | [EnumMember(Value = "davinci")] 70 | [Description("davinci")] 71 | Davinci, 72 | 73 | [EnumMember(Value = "curie-instruct-beta")] 74 | [Description("curie-instruct-beta")] 75 | CurieInstructBeta, 76 | 77 | [EnumMember(Value = "curie")] 78 | [Description("curie")] 79 | Curie, 80 | 81 | [EnumMember(Value = "babbage")] 82 | [Description("babbage")] 83 | Babbage, 84 | 85 | [EnumMember(Value = "ada")] 86 | [Description("ada")] 87 | Ada, 88 | 89 | [EnumMember(Value = "code-davinci-002")] 90 | [Description("code-davinci-002")] 91 | CodeDavinci002, 92 | 93 | [EnumMember(Value = "code-cushman-001")] 94 | [Description("code-cushman-001")] 95 | CodeCushman001, 96 | 97 | 98 | [EnumMember(Value = "text-moderation-stable")] 99 | [Description("text-moderation-stable")] 100 | TextModerationStable, 101 | 102 | [EnumMember(Value = "text-moderation-latest")] 103 | [Description("text-moderation-latest")] 104 | TextModerationLatest, 105 | 106 | [EnumMember(Value = "text-davinci-edit-001")] 107 | [Description("text-davinci-edit-001")] 108 | TextDavinciEdit001, 109 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Client/Models/Model.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.Client; 2 | 3 | internal class Model : IModel 4 | { 5 | public required string Id { get; set; } 6 | public required string OwnedBy { get; set; } 7 | public required IPermission[] Permission { get; set; } 8 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Client/Models/Permission.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.Client; 2 | 3 | internal class Permission : IPermission 4 | { 5 | public required string Id { get; set; } 6 | public required int Created { get; set; } 7 | public required bool AllowCreateEngine { get; set; } 8 | public required bool AllowSampling { get; set; } 9 | public required bool AllowLogProbs { get; set; } 10 | public required bool AllowSearchIndices { get; set; } 11 | public required bool AllowView { get; set; } 12 | public required bool AllowFineTuning { get; set; } 13 | public required string Organization { get; set; } 14 | public required bool IsBlocking { get; set; } 15 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Client/Models/RoleType.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.Serialization; 2 | 3 | namespace ManagedCode.OpenAI.Client; 4 | 5 | public enum RoleType 6 | { 7 | [EnumMember(Value = "user")] User, 8 | 9 | [EnumMember(Value = "Assistant")] Assistant 10 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Client/ServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using Microsoft.Extensions.DependencyInjection; 3 | 4 | [assembly: InternalsVisibleTo("ManagedCode.OpenAI.Tests", AllInternalsVisible = true)] 5 | [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] 6 | 7 | namespace ManagedCode.OpenAI.Client; 8 | 9 | public static class ServiceCollectionExtensions 10 | { 11 | public static void AddOpenAI(this IServiceCollection collection, string apiKey) 12 | { 13 | collection.AddSingleton(s => new GptClient(apiKey)); 14 | } 15 | 16 | public static void AddOpenAI(this IServiceCollection collection, string apiKey, 17 | Action build) 18 | { 19 | var builder = new GptClientBuilder(apiKey); 20 | build.Invoke(builder); 21 | collection.AddSingleton(s => builder.Build()); 22 | } 23 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Completions/Abstractions/ICompletionBuilder.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.Client; 2 | 3 | namespace ManagedCode.OpenAI.Completions; 4 | 5 | public interface ICompletionBuilder 6 | { 7 | public ICompletionBuilder AddPrompt(string prompt); 8 | public ICompletionBuilder AddPrompt(params string[] prompts); 9 | public ICompletionBuilder SetSuffix(string suffix); 10 | public ICompletionBuilder SetMaxTokens(int maxTokens); 11 | public ICompletionBuilder SetTemperature(float temperature); 12 | public ICompletionBuilder SetStream(); 13 | public ICompletionBuilder SetLogProbs(int count); 14 | public ICompletionBuilder SetEcho(); 15 | public ICompletionBuilder SetStop(string stop); 16 | public ICompletionBuilder SetStop(string[] stop); 17 | public ICompletionBuilder SetPresencePenalty(float number); 18 | public ICompletionBuilder SetFrequencyPenalty(float number); 19 | public ICompletionBuilder SetBestOf(int integer); 20 | public ICompletionBuilder SetLogitBias(Dictionary dictionary); 21 | public ICompletionBuilder AddLogitBias(string key, int value); 22 | public ICompletionBuilder SetUsername(string user); 23 | public ICompletionBuilder SetModel(string modelId); 24 | public ICompletionBuilder SetModel(GptModel model); 25 | 26 | 27 | public Task> ExecuteAsync(); 28 | 29 | public Task> ExecuteMultipleAsync(int count); 30 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Completions/Abstractions/ICompletionsMessage.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.Completions; 2 | 3 | public interface ICompletionsMessage 4 | { 5 | public string Content { get; } 6 | public string FinishReason { get; } 7 | public int? LogProbs { get; set; } 8 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Completions/CompletionsBuilder.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.API; 2 | using ManagedCode.OpenAI.Client; 3 | using ManagedCode.OpenAI.Extensions; 4 | 5 | namespace ManagedCode.OpenAI.Completions; 6 | 7 | internal class CompletionsBuilder : ICompletionBuilder 8 | { 9 | private const GptModel DEFAULT_MODEL = GptModel.TextDavinci003; 10 | private readonly CompletionRequestDto _request; 11 | private readonly IOpenAiWebClient _webClient; 12 | 13 | public CompletionsBuilder(IOpenAiWebClient webClient, string prompt) 14 | { 15 | _request = new CompletionRequestDto(); 16 | _webClient = webClient; 17 | 18 | AddPrompt(prompt); 19 | SetModel(DEFAULT_MODEL); 20 | } 21 | 22 | public ICompletionBuilder AddPrompt(string prompt) 23 | { 24 | if (prompt.Length > 1024) 25 | throw new ArgumentException(); 26 | 27 | _request.Prompt.Add(prompt); 28 | return this; 29 | } 30 | 31 | public ICompletionBuilder AddPrompt(params string[] prompts) 32 | { 33 | _request.Prompt.AddRange(prompts); 34 | return this; 35 | } 36 | 37 | public ICompletionBuilder SetSuffix(string suffix) 38 | { 39 | _request.Suffix = suffix; 40 | return this; 41 | } 42 | 43 | public ICompletionBuilder SetMaxTokens(int maxTokens) 44 | { 45 | _request.MaxTokens = maxTokens; 46 | return this; 47 | } 48 | 49 | public ICompletionBuilder SetTemperature(float temperature) 50 | { 51 | _request.Temperature = temperature; 52 | return this; 53 | } 54 | 55 | // TODO: How to work, when stream is true? 56 | public ICompletionBuilder SetStream() 57 | { 58 | _request.Stream = true; 59 | return this; 60 | } 61 | 62 | public ICompletionBuilder SetLogProbs(int count) 63 | { 64 | _request.Logprobs = count; 65 | return this; 66 | } 67 | 68 | public ICompletionBuilder SetEcho() 69 | { 70 | _request.Echo = true; 71 | return this; 72 | } 73 | 74 | public ICompletionBuilder SetStop(string stop) 75 | { 76 | _request.Stop = new[] { stop }; 77 | return this; 78 | } 79 | 80 | public ICompletionBuilder SetStop(string[] stop) 81 | { 82 | _request.Stop = stop; 83 | return this; 84 | } 85 | 86 | public ICompletionBuilder SetPresencePenalty(float number) 87 | { 88 | _request.PresencePenalty = number; 89 | return this; 90 | } 91 | 92 | public ICompletionBuilder SetFrequencyPenalty(float number) 93 | { 94 | _request.FrequencyPenalty = number; 95 | return this; 96 | } 97 | 98 | public ICompletionBuilder SetBestOf(int integer) 99 | { 100 | if (_request.Stream == true) throw new NotSupportedException("Results cannot be streamed."); 101 | 102 | _request.BestOf = integer; 103 | return this; 104 | } 105 | 106 | public ICompletionBuilder SetLogitBias(Dictionary dictionary) 107 | { 108 | _request.LogitBias = dictionary; 109 | return this; 110 | } 111 | 112 | public ICompletionBuilder AddLogitBias(string key, int value) 113 | { 114 | var dict = _request.LogitBias ??= new Dictionary(); 115 | dict.Add(key, value); 116 | return this; 117 | } 118 | 119 | public ICompletionBuilder SetUsername(string user) 120 | { 121 | _request.User = user; 122 | return this; 123 | } 124 | 125 | public ICompletionBuilder SetModel(string modelId) 126 | { 127 | _request.Model = modelId; 128 | return this; 129 | } 130 | 131 | public ICompletionBuilder SetModel(GptModel model) 132 | { 133 | _request.Model = model.Name(); 134 | return this; 135 | } 136 | 137 | public async Task> ExecuteAsync() 138 | { 139 | _request.Validate(); 140 | var response = await _webClient.CompletionsAsync(_request); 141 | return response.ToCompletionsAnswer(); 142 | } 143 | 144 | public async Task> ExecuteMultipleAsync(int count) 145 | { 146 | _request.N = count; 147 | _request.Validate(); 148 | var response = await _webClient.CompletionsAsync(_request); 149 | return response.ToCompletionsAnswerCollection(); 150 | } 151 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Completions/CompletionsMessage.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.Completions; 2 | 3 | internal class CompletionsMessage : ICompletionsMessage 4 | { 5 | public required string Content { get; set; } 6 | public required string FinishReason { get; set; } 7 | public required int? LogProbs { get; set; } 8 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Completions/Extensions/MapperCompletionsExtensions.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.API; 2 | using ManagedCode.OpenAI.Chat; 3 | using ManagedCode.OpenAI.Client; 4 | 5 | namespace ManagedCode.OpenAI.Completions; 6 | 7 | internal static class MapperCompletionsExtensions 8 | { 9 | public static ICompletionsMessage ToCompletionsMessage(this CompletionChoiceDto dto) 10 | { 11 | return new CompletionsMessage 12 | { 13 | Content = dto.Text, 14 | LogProbs = dto.Logprobs, 15 | FinishReason = dto.FinishReason 16 | }; 17 | } 18 | 19 | public static IAnswer ToCompletionsAnswer(this CompletionResponseDto dto) 20 | { 21 | return new Answer 22 | { 23 | Id = dto.Id, 24 | ModelId = dto.Model, 25 | Usage = dto.Usage.ToUsage(), 26 | Data = dto.Choices.First().ToCompletionsMessage(), 27 | Created = dto.Created 28 | }; 29 | } 30 | 31 | public static IAnswer ToCompletionsAnswerCollection(this CompletionResponseDto dto) 32 | { 33 | return new Answer 34 | { 35 | Id = dto.Id, 36 | ModelId = dto.Model, 37 | Usage = dto.Usage.ToUsage(), 38 | Data = dto.Choices.Select(x => x.ToCompletionsMessage()).ToArray(), 39 | Created = dto.Created 40 | }; 41 | } 42 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Completions/ManagedCode.OpenAI.Client.Completions.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | ..\..\..\.nuget\packages\newtonsoft.json\13.0.3\lib\net6.0\Newtonsoft.Json.dll 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Edit/Abstractions/IEditBuilder.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.Client; 2 | 3 | namespace ManagedCode.OpenAI.Edit; 4 | 5 | public interface IEditBuilder 6 | { 7 | public IEditBuilder SetModel(string modelId); 8 | 9 | public IEditBuilder SetModel(GptModel model); 10 | 11 | public IEditBuilder SetTemperature(float temperature); 12 | 13 | public IEditBuilder SetTopP(float topP); 14 | 15 | 16 | public Task> ExecuteAsync(); 17 | 18 | public Task> ExecuteMultipleAsync(int count); 19 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Edit/Abstractions/IEditMessage.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.Edit; 2 | 3 | public interface IEditMessage 4 | { 5 | public string Content { get; } 6 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Edit/EditBuilder.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.API; 2 | using ManagedCode.OpenAI.API.Edit; 3 | using ManagedCode.OpenAI.Client; 4 | using ManagedCode.OpenAI.Extensions; 5 | 6 | namespace ManagedCode.OpenAI.Edit; 7 | 8 | internal class EditBuilder : IEditBuilder 9 | { 10 | private const GptModel DEFAULT_MODEL = GptModel.TextDavinciEdit001; 11 | private readonly IOpenAiWebClient _client; 12 | private readonly EditRequestDto _request; 13 | 14 | public EditBuilder(IOpenAiWebClient client,string input, string instruction) 15 | { 16 | _client = client; 17 | _request = new EditRequestDto 18 | { 19 | Model = DEFAULT_MODEL.Name(), 20 | Input = input, 21 | Instruction = instruction 22 | }; 23 | } 24 | 25 | public IEditBuilder SetModel(string modelId) 26 | { 27 | _request.Model = modelId; 28 | return this; 29 | } 30 | 31 | public IEditBuilder SetModel(GptModel model) 32 | { 33 | _request.Model = model.Name(); 34 | return this; 35 | } 36 | 37 | public IEditBuilder SetTemperature(float temperature) 38 | { 39 | _request.Temperature = temperature; 40 | return this; 41 | } 42 | 43 | public IEditBuilder SetTopP(float topP) 44 | { 45 | _request.TopP = topP; 46 | return this; 47 | } 48 | 49 | 50 | public async Task> ExecuteAsync() 51 | { 52 | _request.Validate(); 53 | var response = await _client.EditAsync(_request); 54 | return response.ToEditAnswer(); 55 | } 56 | 57 | public async Task> ExecuteMultipleAsync(int count) 58 | { 59 | _request.Validate(); 60 | var response = await _client.EditAsync(_request); 61 | return response.ToEditAnswerCollection(); 62 | } 63 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Edit/EditMessage.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.Edit; 2 | 3 | internal class EditMessage : IEditMessage 4 | { 5 | public required string Content { get; set; } 6 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Edit/Extensions/MapperEditExtensions.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.API.Edit; 2 | using ManagedCode.OpenAI.Chat; 3 | using ManagedCode.OpenAI.Client; 4 | 5 | namespace ManagedCode.OpenAI.Edit; 6 | 7 | internal static class MapperEditExtensions 8 | { 9 | public static IAnswer ToEditAnswer(this EditResponseDto dto) 10 | { 11 | return new Answer 12 | { 13 | Id = dto.Id, 14 | ModelId = dto.Model, 15 | Usage = dto.Usage.ToUsage(), 16 | Data = dto.Choices.First().ToEditMessage(), 17 | Created = dto.Created 18 | }; 19 | } 20 | 21 | public static IAnswer ToEditAnswerCollection(this EditResponseDto dto) 22 | { 23 | return new Answer 24 | { 25 | Id = dto.Id, 26 | ModelId = dto.Model, 27 | Usage = dto.Usage.ToUsage(), 28 | Data = dto.Choices.Select(x => x.ToEditMessage()).ToArray(), 29 | Created = dto.Created 30 | }; 31 | } 32 | 33 | public static IEditMessage ToEditMessage(this EditChoiceDto dto) 34 | { 35 | return new EditMessage 36 | { 37 | Content = dto.Text 38 | }; 39 | } 40 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Extensions/EnumExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.Serialization; 2 | 3 | namespace ManagedCode.OpenAI.Extensions; 4 | 5 | internal static class EnumExtensions 6 | { 7 | public static string Name(this Enum value) 8 | { 9 | var field = value.GetType().GetField(value.ToString()); 10 | 11 | var attributes = (EnumMemberAttribute[])field!.GetCustomAttributes( 12 | typeof(EnumMemberAttribute), false); 13 | 14 | if (attributes.Length == 0) 15 | return value.ToString(); 16 | 17 | return attributes.First().Value 18 | ?? throw new Exception($"{value} value property not specified in attribute"); 19 | } 20 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Extensions/ServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.Client; 2 | using Microsoft.Extensions.DependencyInjection; 3 | 4 | namespace ManagedCode.OpenAI.Extensions; 5 | 6 | public static class ServiceCollectionExtensions 7 | { 8 | public static void AddOpenAI(this IServiceCollection collection, string apiKey) 9 | { 10 | collection.AddSingleton(s => new GptClient(apiKey)); 11 | } 12 | 13 | public static void AddOpenAI(this IServiceCollection collection, string apiKey, string organization) 14 | { 15 | collection.AddSingleton(s => new GptClient(apiKey, organization)); 16 | } 17 | 18 | public static void AddOpenAI(this IServiceCollection collection, string apiKey, 19 | IGptClientConfiguration configuration) 20 | { 21 | collection.AddSingleton(s => new GptClient(apiKey, configuration)); 22 | } 23 | 24 | public static void AddOpenAI(this IServiceCollection collection, string apiKey, 25 | Action configuration) 26 | { 27 | var config = new DefaultGptClientConfiguration(); 28 | configuration.Invoke(config); 29 | collection.AddSingleton(s => new GptClient(apiKey, config)); 30 | } 31 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Extensions/ValidationExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace ManagedCode.OpenAI.Extensions; 4 | 5 | internal static class ValidationExtensions 6 | { 7 | public static void Validate(this object obj) 8 | { 9 | Validator.ValidateObject(obj, new ValidationContext(obj), true); 10 | } 11 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Image/Abstractions/IBaseImageBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.Image; 2 | 3 | public interface IBaseImageBuilder 4 | { 5 | public TBuilder SetImageResolution(string resolution); 6 | public TBuilder SetImageResolution(ImageResolution resolution); 7 | 8 | public TBuilder AsBase64String(); 9 | 10 | public TBuilder AsUrl(); 11 | 12 | public TBuilder SetUser(string user); 13 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Image/Abstractions/IEditImageBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.Image; 2 | 3 | public interface IEditImageBuilder : IBaseImageBuilder 4 | { 5 | public IEditImageBuilder SetImageMask(string base64); 6 | 7 | public Task> ExecuteAsync(); 8 | 9 | public Task> ExecuteMultipleAsync(int count); 10 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Image/Abstractions/IGenerateImageBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.Image; 2 | 3 | public interface IGenerateImageBuilder : IBaseImageBuilder 4 | { 5 | public Task> ExecuteAsync(); 6 | 7 | public Task> ExecuteMultipleAsync(int count); 8 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Image/Abstractions/IGptImage.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.Image; 2 | 3 | public interface IGptImage 4 | { 5 | TData Content { get; } 6 | 7 | int Created { get; } 8 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Image/Abstractions/IImageClient.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.Image; 2 | 3 | public interface IImageClient 4 | { 5 | public IGenerateImageBuilder GenerateImage(string description); 6 | 7 | public IEditImageBuilder EditImage(string description, string imageBase64); 8 | 9 | public IVariationImageBuilder VariationImage(string imageBase64); 10 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Image/Abstractions/IImageLoader.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.Image; 2 | 3 | public interface IImageLoader 4 | { 5 | public string FromBytes(byte[] bytes); 6 | 7 | public string FromBase64(string base64); 8 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Image/Abstractions/IVariationImageBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.Image; 2 | 3 | public interface IVariationImageBuilder : IBaseImageBuilder 4 | { 5 | public Task> ExecuteAsync(); 6 | 7 | public Task> ExecuteMultipleAsync(int count); 8 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Image/Builders/BaseImageBuilder.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.API.Image; 2 | using ManagedCode.OpenAI.Extensions; 3 | 4 | namespace ManagedCode.OpenAI.Image; 5 | 6 | internal abstract class BaseImageBuilder : IBaseImageBuilder 7 | where TRequest : BaseImageRequestDto, new() 8 | where TBuilder : IBaseImageBuilder 9 | { 10 | protected BaseImageBuilder() 11 | { 12 | Request = new TRequest(); 13 | } 14 | 15 | protected TRequest Request { get; } 16 | 17 | public TBuilder SetImageResolution(string resolution) 18 | { 19 | Request.Size = resolution; 20 | return Builder(); 21 | } 22 | 23 | public TBuilder SetImageResolution(ImageResolution resolution) 24 | { 25 | Request.Size = resolution.Name(); 26 | return Builder(); 27 | } 28 | 29 | public TBuilder AsBase64String() 30 | { 31 | Request.ResponseFormat = ImageFormat.Base64Json.Name(); 32 | return Builder(); 33 | } 34 | 35 | public TBuilder AsUrl() 36 | { 37 | Request.ResponseFormat = ImageFormat.Url.Name(); 38 | return Builder(); 39 | } 40 | 41 | public TBuilder SetUser(string user) 42 | { 43 | Request.User = user; 44 | return Builder(); 45 | } 46 | 47 | protected abstract TBuilder Builder(); 48 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Image/Builders/DefaultImageLoader.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.Image; 2 | 3 | internal class DefaultImageLoader : IImageLoader 4 | { 5 | public string FromBytes(byte[] bytes) 6 | { 7 | return Convert.ToBase64String(bytes); 8 | } 9 | 10 | public string FromBase64(string base64) 11 | { 12 | return base64; 13 | } 14 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Image/Builders/EditImageBuilder.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.API; 2 | using ManagedCode.OpenAI.API.Image; 3 | using ManagedCode.OpenAI.Extensions; 4 | 5 | namespace ManagedCode.OpenAI.Image; 6 | 7 | internal class EditImageBuilder : BaseImageBuilder, 8 | IEditImageBuilder 9 | { 10 | private readonly IOpenAiWebClient _webClient; 11 | 12 | public EditImageBuilder(IOpenAiWebClient webClient, string instruction, string imageB64) 13 | { 14 | _webClient = webClient; 15 | Request.Description = instruction; 16 | Request.ImageBase64 = imageB64; 17 | } 18 | 19 | public IEditImageBuilder SetImageMask(string base64) 20 | { 21 | Request.MaskBase64 = base64; 22 | return this; 23 | } 24 | 25 | public async Task> ExecuteAsync() 26 | { 27 | Request.Validate(); 28 | var response = await _webClient.EditImageAsync(Request); 29 | return response.AsSingle(); 30 | } 31 | 32 | public async Task> ExecuteMultipleAsync(int count) 33 | { 34 | Request.N = count; 35 | Request.Validate(); 36 | var response = await _webClient.EditImageAsync(Request); 37 | return response.AsMultiple(); 38 | } 39 | 40 | protected override IEditImageBuilder Builder() 41 | { 42 | return this; 43 | } 44 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Image/Builders/GenerateImageBuilder.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.API; 2 | using ManagedCode.OpenAI.API.Image; 3 | using ManagedCode.OpenAI.Extensions; 4 | 5 | namespace ManagedCode.OpenAI.Image; 6 | 7 | internal class GenerateImageBuilder : 8 | BaseImageBuilder, 9 | IGenerateImageBuilder 10 | { 11 | private readonly IOpenAiWebClient _webClient; 12 | 13 | public GenerateImageBuilder(IOpenAiWebClient webClient, string description) 14 | { 15 | _webClient = webClient; 16 | Request.Description = description; 17 | } 18 | 19 | public async Task> ExecuteAsync() 20 | { 21 | Request.Validate(); 22 | var response = await _webClient.GenerateImageAsync(Request); 23 | return response.AsSingle(); 24 | } 25 | 26 | public async Task> ExecuteMultipleAsync(int count) 27 | { 28 | Request.N = count; 29 | Request.Validate(); 30 | var response = await _webClient.GenerateImageAsync(Request); 31 | return response.AsMultiple(); 32 | } 33 | 34 | protected override IGenerateImageBuilder Builder() 35 | { 36 | return this; 37 | } 38 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Image/Builders/VariationImageBuilder.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.API; 2 | using ManagedCode.OpenAI.API.Image; 3 | using ManagedCode.OpenAI.Extensions; 4 | 5 | namespace ManagedCode.OpenAI.Image; 6 | 7 | internal class VariationImageBuilder : BaseImageBuilder, 8 | IVariationImageBuilder 9 | { 10 | private readonly IOpenAiWebClient _client; 11 | 12 | public VariationImageBuilder(IOpenAiWebClient client, string imageBase64) 13 | { 14 | _client = client; 15 | Request.ImageBase64 = imageBase64; 16 | } 17 | 18 | 19 | public async Task> ExecuteAsync() 20 | { 21 | Request.Validate(); 22 | var response = await _client.VariationImageAsync(Request); 23 | return response.AsSingle(); 24 | } 25 | 26 | public async Task> ExecuteMultipleAsync(int count) 27 | { 28 | Request.Validate(); 29 | var response = await _client.VariationImageAsync(Request); 30 | return response.AsMultiple(); 31 | } 32 | 33 | protected override IVariationImageBuilder Builder() 34 | { 35 | return this; 36 | } 37 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Image/Extensions/ImageClientExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.Image; 2 | 3 | public static class ImageClientExtensions 4 | { 5 | public static IEditImageBuilder EditImage(this IImageClient client, 6 | string instruction, Func image) 7 | { 8 | var loader = new DefaultImageLoader(); 9 | return client.EditImage(instruction, image.Invoke(loader)); 10 | } 11 | 12 | public static IVariationImageBuilder VariationImage(this IImageClient client, 13 | Func image) 14 | { 15 | var loader = new DefaultImageLoader(); 16 | return client.VariationImage(image.Invoke(loader)); 17 | } 18 | 19 | public static IEditImageBuilder SetImageMask(this IEditImageBuilder builder, 20 | Func image) 21 | { 22 | var loader = new DefaultImageLoader(); 23 | builder.SetImageMask(image.Invoke(loader)); 24 | return builder; 25 | } 26 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Image/Extensions/MapperImageExtensions.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.API.Image; 2 | 3 | namespace ManagedCode.OpenAI.Image; 4 | 5 | internal static class MapperImageExtensions 6 | { 7 | public static IGptImage AsSingle(this ImageResponseDto response) 8 | { 9 | return new GptImage 10 | { 11 | Content = ExtractContents(response).First(), 12 | Created = response.Created 13 | }; 14 | } 15 | 16 | public static IGptImage AsMultiple(this ImageResponseDto response) 17 | { 18 | return new GptImage 19 | { 20 | Content = ExtractContents(response), 21 | Created = response.Created 22 | }; 23 | } 24 | 25 | private static string[] ExtractContents(ImageResponseDto response) 26 | { 27 | if (!string.IsNullOrWhiteSpace(response.Data.First().Url)) 28 | return response.Data.Select(x => x.Url).ToArray(); 29 | 30 | if (!string.IsNullOrWhiteSpace(response.Data.First().B64Json)) 31 | return response.Data.Select(x => x.B64Json).ToArray(); 32 | 33 | throw new ArgumentNullException("Failed to get image content"); 34 | } 35 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Image/ImageClient.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.API; 2 | 3 | namespace ManagedCode.OpenAI.Image; 4 | 5 | internal class ImageClient : IImageClient 6 | { 7 | private readonly IOpenAiWebClient _webClient; 8 | 9 | public ImageClient(IOpenAiWebClient webClient) 10 | { 11 | _webClient = webClient; 12 | } 13 | 14 | public IGenerateImageBuilder GenerateImage(string description) 15 | { 16 | return new GenerateImageBuilder(_webClient, description); 17 | } 18 | 19 | public IEditImageBuilder EditImage(string description, string imageBase64) 20 | { 21 | return new EditImageBuilder(_webClient, description, imageBase64); 22 | } 23 | 24 | public IVariationImageBuilder VariationImage(string imageBase64) 25 | { 26 | return new VariationImageBuilder(_webClient, imageBase64); 27 | } 28 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Image/Models/GptImage.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.Image; 2 | 3 | internal class GptImage : IGptImage 4 | { 5 | public required TData Content { get; set; } 6 | public required int Created { get; set; } 7 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Image/Models/ImageFormat.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Runtime.Serialization; 3 | 4 | namespace ManagedCode.OpenAI.Image; 5 | 6 | public enum ImageFormat 7 | { 8 | [EnumMember(Value = "url")] 9 | [Description("url")] 10 | Url, 11 | 12 | [EnumMember(Value = "b64_json")] 13 | [Description("b64_json")] 14 | Base64Json 15 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Image/Models/ImageResolution.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Runtime.Serialization; 3 | 4 | namespace ManagedCode.OpenAI.Image; 5 | 6 | public enum ImageResolution 7 | { 8 | [EnumMember(Value = "256x256")] 9 | [Description("256x256")] 10 | _256x256, 11 | 12 | [EnumMember(Value = "512x512")] 13 | [Description("512x512")] 14 | _512x512, 15 | 16 | [EnumMember(Value = "1024x1024")] 17 | [Description("1024x1024")] 18 | _1024x1024 19 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/ManagedCode.OpenAI.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0 5 | enable 6 | enable 7 | true 8 | 11 9 | 10 | 11 | 12 | 13 | ManagedCode.OpenAI 14 | ManagedCode.OpenAI 15 | OpenAI 16 | managedcode, OpenAI, ChatGPT, API 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /ManagedCode.OpenAI/ManagedCode.OpenAI.csproj.DotSettings: -------------------------------------------------------------------------------- 1 |  5 | True 7 | True 9 | True 11 | True 13 | True 15 | True 17 | True 19 | True 21 | True 23 | True 25 | True 27 | True 29 | True 31 | True 33 | True 35 | True 37 | True 39 | True 41 | True 43 | True 45 | True 47 | True 49 | True 51 | True 53 | True 55 | True -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Moderation/Abstractions/ICategory.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.Moderation; 2 | 3 | public interface ICategory where TResult : struct 4 | { 5 | public TResult Hate { get; } 6 | public TResult HateThreatening { get; } 7 | public TResult SelfHarm { get; } 8 | public TResult Sexual { get; } 9 | public TResult SexualMinors { get; } 10 | public TResult Violence { get; } 11 | public TResult ViolenceGraphic { get; } 12 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Moderation/Abstractions/IModeration.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.Moderation; 2 | 3 | public interface IModeration 4 | { 5 | ICategory Categories { get; } 6 | ICategory CategoryScores { get; } 7 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Moderation/Abstractions/IModerationBuilder.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.Client; 2 | 3 | namespace ManagedCode.OpenAI.Moderation; 4 | 5 | public interface IModerationBuilder 6 | { 7 | public IModerationBuilder SetModel(string model); 8 | public IModerationBuilder SetModel(GptModel model); 9 | 10 | public Task ExecuteAsync(string input); 11 | public Task ExecuteMultipleAsync(params string[] inputs); 12 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Moderation/Exceptions/MapperModerationExtensions.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.API.Moderation; 2 | 3 | namespace ManagedCode.OpenAI.Moderation; 4 | 5 | internal static class MapperModerationExtensions 6 | { 7 | public static ICategory ToCategory(this CategoryDto dto) where TResult : struct 8 | { 9 | return new Category 10 | { 11 | Hate = dto.Hate, 12 | HateThreatening = dto.HateThreatening, 13 | SelfHarm = dto.SelfHarm, 14 | Sexual = dto.Sexual, 15 | SexualMinors = dto.SexualMinors, 16 | Violence = dto.Violence, 17 | ViolenceGraphic = dto.ViolenceGraphic 18 | }; 19 | } 20 | 21 | private static IModeration ToModeration(this CategoryResultDto dto) 22 | { 23 | return new Moderation 24 | { 25 | Categories = dto.Categories.ToCategory(), 26 | CategoryScores = dto.CategoryScores.ToCategory() 27 | }; 28 | } 29 | 30 | 31 | public static IModeration ToModeration(this ModerationResponseDto dto) 32 | { 33 | return dto.Results.First().ToModeration(); 34 | } 35 | 36 | public static IModeration[] ToModerationCollection(this ModerationResponseDto dto) 37 | { 38 | return dto.Results.Select(e => e.ToModeration()).ToArray(); 39 | } 40 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Moderation/Model/Category.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.Moderation; 2 | 3 | internal class Category : ICategory where TResult : struct 4 | { 5 | public required TResult Hate { get; set; } 6 | public required TResult HateThreatening { get; set; } 7 | public required TResult SelfHarm { get; set; } 8 | public required TResult Sexual { get; set; } 9 | public required TResult SexualMinors { get; set; } 10 | public required TResult Violence { get; set; } 11 | public required TResult ViolenceGraphic { get; set; } 12 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Moderation/Model/Moderation.cs: -------------------------------------------------------------------------------- 1 | namespace ManagedCode.OpenAI.Moderation; 2 | 3 | public class Moderation : IModeration 4 | { 5 | public required ICategory Categories { get; set; } 6 | public required ICategory CategoryScores { get; set; } 7 | } -------------------------------------------------------------------------------- /ManagedCode.OpenAI/Moderation/ModerationBuilder.cs: -------------------------------------------------------------------------------- 1 | using ManagedCode.OpenAI.API; 2 | using ManagedCode.OpenAI.API.Moderation; 3 | using ManagedCode.OpenAI.Client; 4 | using ManagedCode.OpenAI.Extensions; 5 | 6 | namespace ManagedCode.OpenAI.Moderation; 7 | 8 | internal class ModerationBuilder : IModerationBuilder 9 | { 10 | private const GptModel DEFAULT_MODEL = GptModel.TextModerationStable; 11 | private readonly IOpenAiWebClient _client; 12 | private readonly ModerationRequestDto _requestDto; 13 | 14 | public ModerationBuilder(IOpenAiWebClient client) 15 | { 16 | _client = client; 17 | _requestDto = new ModerationRequestDto 18 | { 19 | Model = DEFAULT_MODEL.Name() 20 | }; 21 | } 22 | 23 | public IModerationBuilder SetModel(string model) 24 | { 25 | _requestDto.Model = model; 26 | return this; 27 | } 28 | 29 | public IModerationBuilder SetModel(GptModel model) 30 | { 31 | return SetModel(model.Name()); 32 | } 33 | 34 | public async Task ExecuteAsync(string input) 35 | { 36 | _requestDto.Input = new List { input }; 37 | var moderationResponseDto = await _client.ModerationAsync(_requestDto); 38 | return moderationResponseDto.ToModeration(); 39 | } 40 | 41 | public async Task ExecuteMultipleAsync(params string[] inputs) 42 | { 43 | _requestDto.Input = inputs.ToList(); 44 | var moderationResponseDto = await _client.ModerationAsync(_requestDto); 45 | return moderationResponseDto.ToModerationCollection(); 46 | } 47 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenAI 2 | 3 | This is an unofficial C# library for the OpenAI API. As there are no official libraries available, we have created our 4 | own to help C# developers interact with the API easily. 5 | 6 | [![.NET](https://github.com/managedcode/OpenAI/actions/workflows/dotnet.yml/badge.svg)](https://github.com/managedcode/OpenAI/actions/workflows/dotnet.yml) 7 | [![Coverage Status](https://coveralls.io/repos/github/managedcode/OpenAI/badge.svg?branch=main&service=github)](https://coveralls.io/github/managedcode/OpenAI?branch=main) 8 | [![nuget](https://github.com/managedcode/OpenAI/actions/workflows/nuget.yml/badge.svg?branch=main)](https://github.com/managedcode/Communication/actions/workflows/nuget.yml) 9 | [![CodeQL](https://github.com/managedcode/OpenAI/actions/workflows/codeql-analysis.yml/badge.svg?branch=main)](https://github.com/managedcode/OpenAI/actions/workflows/codeql-analysis.yml) 10 | [![NuGet Package](https://img.shields.io/nuget/v/ManagedCode.OpenAI.svg)](https://www.nuget.org/packages/ManagedCode.OpenAI) 11 | 12 | ## Installation 13 | 14 | To install the ManagedCode.OpenAI library from NuGet, you can use the following methods: 15 | 16 | ### Package Manager 17 | 18 | Open the Package Manager Console in Visual Studio and run the following command: 19 | 20 | ``` 21 | Install-Package ManagedCode.OpenAI 22 | ``` 23 | 24 | ### .NET CLI 25 | 26 | You can also use the .NET CLI to install the package. Open a terminal/command prompt and run the following command: 27 | 28 | ``` 29 | dotnet add package ManagedCode.OpenAI 30 | ``` 31 | 32 | ## Usage 33 | 34 | Initializing the client 35 | You can initialize the client in two ways: 36 | 37 | ``` cs 38 | var client1 = GptClient.Builder("#API_KEY#") 39 | .WithOrganization("#ORGANIZATION#") 40 | .Build(); 41 | ``` 42 | 43 | ```cs 44 | var client2 = GptClient.Builder("#API_KEY#") 45 | .WithOrganization("#ORGANIZATION#") 46 | .Configure(x => x.SetDefaultModel(GptModel.Ada)) 47 | .Build(); 48 | ``` 49 | 50 | or using DI 51 | 52 | ```cs 53 | builder.Services.AddOpenAI("#API_KEY#"); 54 | 55 | public class MyClass 56 | { 57 | public MyClass(IGptClient client) 58 | { 59 | var chat = client.OpenChat(); 60 | } 61 | } 62 | ``` 63 | 64 | ## Ask chat gpt 65 | 66 | ``` cs 67 | var client = GptClient.Builder("#API_KEY#") 68 | .WithOrganization("#ORGANIZATION#") 69 | .Build(); 70 | var chat = client.OpenChat(); 71 | var answer = await chat.AskAsync("2+2?"); 72 | Console.WriteLine($"Answer: {answer.Data.Content}"); 73 | ``` 74 | 75 | ## Generating an image URL 76 | 77 | ```cs 78 | var client = new GptClient("#API_KEY#"); 79 | var img = await client.ImageClient 80 | .GenerateImage("Big man") 81 | .AsUrl().ExecuteAsync(); 82 | 83 | var url = img.Content; 84 | Console.WriteLine(url); 85 | ``` 86 | 87 | ### Generating an image URL with editing 88 | 89 | ```cs 90 | var client = new GptClient("#API_KEY#"); 91 | var imgBytes = new byte[] { }; 92 | var maskBase64 = "#CONTENT#"; 93 | 94 | var img = await client.ImageClient 95 | .EditImage("Change color to red", x => x.FromBytes(imgBytes)) 96 | .SetImageMask(x => x.FromBase64(maskBase64)) 97 | .AsUrl().ExecuteAsync(); 98 | 99 | // Edited img URL 100 | Console.WriteLine(img.Content); 101 | ``` 102 | 103 | ### Editing an image using a mask 104 | 105 | ```cs 106 | var client = new GptClient("#API_KEY#"); 107 | var imgBytes = new byte[] { }; 108 | var imgCollection = await client.ImageClient 109 | .VariationImage(x => x.FromBytes(imgBytes)) 110 | .AsBase64String() 111 | .ExecuteMultipleAsync(5); 112 | 113 | foreach (var imageBase64 in imgCollection.Content) 114 | Console.WriteLine(imageBase64); 115 | ``` 116 | 117 | ## Generating multiple image variations as base64 strings 118 | 119 | Create multiple variations of an image in base64 string format with 5 results: 120 | 121 | ```cs 122 | var client = new GptClient("#API_KEY#"); 123 | var imgBytes = new byte[] { }; 124 | var imgCollection = await client.ImageClient 125 | .VariationImage(x => x.FromBytes(imgBytes)) 126 | .AsBase64String() 127 | .ExecuteMultipleAsync(5); 128 | 129 | foreach (var imageBase64 in imgCollection.Content) 130 | Console.WriteLine(imageBase64); 131 | ``` 132 | 133 | ## Contributing 134 | 135 | We welcome contributions to this project. Please submit a pull request or create an issue if you'd like to help improve 136 | this library. 137 | 138 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/managedcode/OpenAI/1418997288050139d499bc1f36b24575227b8f24/logo.png --------------------------------------------------------------------------------