├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── dependabot.yml ├── labeler.yml └── workflows │ ├── dotnet.yml │ ├── label.yml │ └── nuget-build.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── Directory.Packages.props ├── LICENSE ├── NuGet.config ├── README.md ├── SK-ERNIE-Bot.sln ├── samples ├── ERNIE-Bot-Kernel-Memory.Sample │ ├── ERNIE-Bot-Kernel-Memory.Sample.csproj │ ├── Program.cs │ └── sample-SK-Readme.pdf ├── ERNIE-Bot.Sample │ ├── Controllers │ │ ├── ApiController.cs │ │ └── Models │ │ │ └── UserInput.cs │ ├── ERNIE-Bot.Sample.csproj │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── appsettings.Development.json │ └── appsettings.json └── SK-ERNIE-Bot.Sample │ ├── Controllers │ ├── ApiController.cs │ └── Models │ │ └── UserInput.cs │ ├── ERNIE-Bot-Semantic-Kernel.Sample.csproj │ ├── Plugins │ └── Demo │ │ └── Translate │ │ ├── config.json │ │ └── skprompt.txt │ ├── Program.cs │ ├── Properties │ └── launchSettings.json │ ├── appsettings.Development.json │ └── appsettings.json ├── src ├── .editorconfig ├── Directory.Build.props ├── ERNIE-Bot.KernelMemory │ ├── ERNIE-Bot.KernelMemory.csproj │ ├── ERNIEBotTextEmbeddingGenerator.cs │ ├── ERNIEBotTextGenerator.cs │ ├── KernelMemoryBuilderExtensions.cs │ └── readme.md ├── ERNIE-Bot.SDK │ ├── Defaults.cs │ ├── DistributedTokenStore.cs │ ├── ERNIE-Bot.SDK.csproj │ ├── ERNIEBotClient.cs │ ├── HttpClientProvider.cs │ ├── ModelEndpoint.cs │ ├── ModelEndpoints.cs │ ├── Models │ │ ├── AccessTokenResponse.cs │ │ ├── ChatRequest.cs │ │ ├── ChatResponse.cs │ │ ├── ERNIEBotError.cs │ │ ├── EmbeddingRequest.cs │ │ ├── EmbeddingsResponse.cs │ │ └── UsageData.cs │ ├── TokenStore │ │ ├── DefaultTokenStore.cs │ │ ├── ITokenStore.cs │ │ └── MemoryTokenStore.cs │ ├── Tokenizer.cs │ └── readme.md └── ERNIE-Bot.SemanticKernel │ ├── ERNIE-Bot.SemanticKernel.csproj │ ├── ERNIEBotAIRequestSettings.cs │ ├── ERNIEBotChatCompletion.cs │ ├── ERNIEBotChatResult.cs │ ├── ERNIEBotEmbeddingGeneration.cs │ ├── ERNIEBotKernelBuilderExtensions.cs │ └── readme.md └── tests ├── ERNIE-Bot.SDK.Tests ├── ERNIE-Bot.SDK.Tests.csproj ├── ERNIEBotClientTests.cs ├── TestDatas │ ├── chat_response.txt │ ├── chat_stream_response.txt │ ├── embedding_response.txt │ ├── error.txt │ └── token_response.txt ├── TestHelper.cs ├── TokenStoreHelper.cs ├── TokenizerTests.cs └── Usings.cs ├── ERNIE-Bot.SemanticKernel.Tests ├── ERNIE-Bot.SemanticKernel.Tests.csproj └── Usings.cs └── IntegrationTests ├── IntegrationTests.csproj ├── SDK ├── ChatCompletionStreamTest.cs ├── ChatCompletionTest.cs ├── ChatCompletionTestEndpoints.cs └── EmbeddingTest.cs └── Usings.cs /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "nuget" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | -------------------------------------------------------------------------------- /.github/labeler.yml: -------------------------------------------------------------------------------- 1 | sdk: 2 | - src/ERNIE-Bot.SDK/** 3 | - tests/ERNIE-Bot.SDK.Tests/** 4 | 5 | sk: 6 | - src/ERNIE-Bot.SemanticKernel/** 7 | - tests/ERNIE-Bot.SemanticKernel.Tests/** 8 | 9 | documentation: 10 | - docs/** 11 | - '**/*.md' 12 | 13 | test: 14 | - tests/** 15 | 16 | sample: 17 | - samples/** 18 | -------------------------------------------------------------------------------- /.github/workflows/dotnet.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a .NET project 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net 3 | 4 | name: .NET-PR 5 | 6 | on: 7 | workflow_dispatch: 8 | pull_request: 9 | branches: [ "main" ] 10 | paths: 11 | - '**.cs' 12 | - '**.csproj' 13 | 14 | jobs: 15 | build: 16 | 17 | runs-on: ubuntu-latest 18 | 19 | env: 20 | NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages 21 | 22 | steps: 23 | - uses: actions/checkout@v3 24 | - name: Setup .NET 25 | uses: actions/setup-dotnet@v3 26 | with: 27 | dotnet-version: 6.0.x 28 | - name: Restore dependencies 29 | run: dotnet restore 30 | - name: Build 31 | run: dotnet build --no-restore 32 | - name: Test 33 | run: | 34 | export UT_PROJECTS=$(find ./tests -type f -name "*.Tests.csproj" | tr '\n' ' ') 35 | for project in $UT_PROJECTS; do 36 | dotnet test $project --no-build -v Normal --logger trx 37 | done 38 | 39 | -------------------------------------------------------------------------------- /.github/workflows/label.yml: -------------------------------------------------------------------------------- 1 | # This workflow will triage pull requests and apply a label based on the 2 | # paths that are modified in the pull request. 3 | # 4 | # To use this workflow, you will need to set up a .github/labeler.yml 5 | # file with configuration. For more information, see: 6 | # https://github.com/actions/labeler 7 | 8 | name: Labeler 9 | on: 10 | pull_request: 11 | 12 | jobs: 13 | label: 14 | runs-on: ubuntu-latest 15 | permissions: 16 | contents: read 17 | pull-requests: write 18 | 19 | steps: 20 | - uses: actions/labeler@v4 21 | with: 22 | repo-token: "${{ secrets.GITHUB_TOKEN }}" 23 | -------------------------------------------------------------------------------- /.github/workflows/nuget-build.yml: -------------------------------------------------------------------------------- 1 | name: NuGet-Build 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | tags: 7 | - '*' 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | env: 13 | NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages 14 | 15 | steps: 16 | - uses: actions/checkout@v3 17 | - name: Setup .NET 18 | uses: actions/setup-dotnet@v3 19 | with: 20 | dotnet-version: 6.0.x 21 | - name: Restore dependencies 22 | run: dotnet restore 23 | - name: Build & Pack 24 | run: | 25 | dotnet build -c Release --no-restore 26 | dotnet pack -c Release -o nupkgs 27 | - name: Upload Artifact 28 | uses: actions/upload-artifact@v3.1.3 29 | with: 30 | name: nuget-packages 31 | path: ${{ github.workspace }}/nupkgs/*.nupkg 32 | - name: Push NuGet 33 | run: dotnet nuget push **/*.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_API_KEY }} --skip-duplicate 34 | 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Ll]og/ 33 | [Ll]ogs/ 34 | 35 | # Visual Studio 2015/2017 cache/options directory 36 | .vs/ 37 | # Uncomment if you have tasks that create the project's static files in wwwroot 38 | #wwwroot/ 39 | 40 | # Visual Studio 2017 auto generated files 41 | Generated\ Files/ 42 | 43 | # MSTest test Results 44 | [Tt]est[Rr]esult*/ 45 | [Bb]uild[Ll]og.* 46 | 47 | # NUnit 48 | *.VisualState.xml 49 | TestResult.xml 50 | nunit-*.xml 51 | 52 | # Build Results of an ATL Project 53 | [Dd]ebugPS/ 54 | [Rr]eleasePS/ 55 | dlldata.c 56 | 57 | # Benchmark Results 58 | BenchmarkDotNet.Artifacts/ 59 | 60 | # .NET Core 61 | project.lock.json 62 | project.fragment.lock.json 63 | artifacts/ 64 | 65 | # ASP.NET Scaffolding 66 | ScaffoldingReadMe.txt 67 | 68 | # StyleCop 69 | StyleCopReport.xml 70 | 71 | # Files built by Visual Studio 72 | *_i.c 73 | *_p.c 74 | *_h.h 75 | *.ilk 76 | *.meta 77 | *.obj 78 | *.iobj 79 | *.pch 80 | *.pdb 81 | *.ipdb 82 | *.pgc 83 | *.pgd 84 | *.rsp 85 | *.sbr 86 | *.tlb 87 | *.tli 88 | *.tlh 89 | *.tmp 90 | *.tmp_proj 91 | *_wpftmp.csproj 92 | *.log 93 | *.tlog 94 | *.vspscc 95 | *.vssscc 96 | .builds 97 | *.pidb 98 | *.svclog 99 | *.scc 100 | 101 | # Chutzpah Test files 102 | _Chutzpah* 103 | 104 | # Visual C++ cache files 105 | ipch/ 106 | *.aps 107 | *.ncb 108 | *.opendb 109 | *.opensdf 110 | *.sdf 111 | *.cachefile 112 | *.VC.db 113 | *.VC.VC.opendb 114 | 115 | # Visual Studio profiler 116 | *.psess 117 | *.vsp 118 | *.vspx 119 | *.sap 120 | 121 | # Visual Studio Trace Files 122 | *.e2e 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Coverlet is a free, cross platform Code Coverage Tool 146 | coverage*.json 147 | coverage*.xml 148 | coverage*.info 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 | .sass-cache/ 165 | 166 | # Installshield output folder 167 | [Ee]xpress/ 168 | 169 | # DocProject is a documentation generator add-in 170 | DocProject/buildhelp/ 171 | DocProject/Help/*.HxT 172 | DocProject/Help/*.HxC 173 | DocProject/Help/*.hhc 174 | DocProject/Help/*.hhk 175 | DocProject/Help/*.hhp 176 | DocProject/Help/Html2 177 | DocProject/Help/html 178 | 179 | # Click-Once directory 180 | publish/ 181 | 182 | # Publish Web Output 183 | *.[Pp]ublish.xml 184 | *.azurePubxml 185 | # Note: Comment the next line if you want to checkin your web deploy settings, 186 | # but database connection strings (with potential passwords) will be unencrypted 187 | *.pubxml 188 | *.publishproj 189 | 190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 191 | # checkin your Azure Web App publish settings, but sensitive information contained 192 | # in these scripts will be unencrypted 193 | PublishScripts/ 194 | 195 | # NuGet Packages 196 | *.nupkg 197 | # NuGet Symbol Packages 198 | *.snupkg 199 | # The packages folder can be ignored because of Package Restore 200 | **/[Pp]ackages/* 201 | # except build/, which is used as an MSBuild target. 202 | !**/[Pp]ackages/build/ 203 | # Uncomment if necessary however generally it will be regenerated when needed 204 | #!**/[Pp]ackages/repositories.config 205 | # NuGet v3's project.json files produces more ignorable files 206 | *.nuget.props 207 | *.nuget.targets 208 | 209 | # Microsoft Azure Build Output 210 | csx/ 211 | *.build.csdef 212 | 213 | # Microsoft Azure Emulator 214 | ecf/ 215 | rcf/ 216 | 217 | # Windows Store app package directories and files 218 | AppPackages/ 219 | BundleArtifacts/ 220 | Package.StoreAssociation.xml 221 | _pkginfo.txt 222 | *.appx 223 | *.appxbundle 224 | *.appxupload 225 | 226 | # Visual Studio cache files 227 | # files ending in .cache can be ignored 228 | *.[Cc]ache 229 | # but keep track of directories ending in .cache 230 | !?*.[Cc]ache/ 231 | 232 | # Others 233 | ClientBin/ 234 | ~$* 235 | *~ 236 | *.dbmdl 237 | *.dbproj.schemaview 238 | *.jfm 239 | *.pfx 240 | *.publishsettings 241 | orleans.codegen.cs 242 | 243 | # Including strong name files can present a security risk 244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 245 | #*.snk 246 | 247 | # Since there are multiple workflows, uncomment next line to ignore bower_components 248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 249 | #bower_components/ 250 | 251 | # RIA/Silverlight projects 252 | Generated_Code/ 253 | 254 | # Backup & report files from converting an old project file 255 | # to a newer Visual Studio version. Backup files are not needed, 256 | # because we have git ;-) 257 | _UpgradeReport_Files/ 258 | Backup*/ 259 | UpgradeLog*.XML 260 | UpgradeLog*.htm 261 | ServiceFabricBackup/ 262 | *.rptproj.bak 263 | 264 | # SQL Server files 265 | *.mdf 266 | *.ldf 267 | *.ndf 268 | 269 | # Business Intelligence projects 270 | *.rdl.data 271 | *.bim.layout 272 | *.bim_*.settings 273 | *.rptproj.rsuser 274 | *- [Bb]ackup.rdl 275 | *- [Bb]ackup ([0-9]).rdl 276 | *- [Bb]ackup ([0-9][0-9]).rdl 277 | 278 | # Microsoft Fakes 279 | FakesAssemblies/ 280 | 281 | # GhostDoc plugin setting file 282 | *.GhostDoc.xml 283 | 284 | # Node.js Tools for Visual Studio 285 | .ntvs_analysis.dat 286 | node_modules/ 287 | 288 | # Visual Studio 6 build log 289 | *.plg 290 | 291 | # Visual Studio 6 workspace options file 292 | *.opt 293 | 294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 295 | *.vbw 296 | 297 | # Visual Studio 6 auto-generated project file (contains which files were open etc.) 298 | *.vbp 299 | 300 | # Visual Studio 6 workspace and project file (working project files containing files to include in project) 301 | *.dsw 302 | *.dsp 303 | 304 | # Visual Studio 6 technical files 305 | *.ncb 306 | *.aps 307 | 308 | # Visual Studio LightSwitch build output 309 | **/*.HTMLClient/GeneratedArtifacts 310 | **/*.DesktopClient/GeneratedArtifacts 311 | **/*.DesktopClient/ModelManifest.xml 312 | **/*.Server/GeneratedArtifacts 313 | **/*.Server/ModelManifest.xml 314 | _Pvt_Extensions 315 | 316 | # Paket dependency manager 317 | .paket/paket.exe 318 | paket-files/ 319 | 320 | # FAKE - F# Make 321 | .fake/ 322 | 323 | # CodeRush personal settings 324 | .cr/personal 325 | 326 | # Python Tools for Visual Studio (PTVS) 327 | __pycache__/ 328 | *.pyc 329 | 330 | # Cake - Uncomment if you are using it 331 | # tools/** 332 | # !tools/packages.config 333 | 334 | # Tabs Studio 335 | *.tss 336 | 337 | # Telerik's JustMock configuration file 338 | *.jmconfig 339 | 340 | # BizTalk build output 341 | *.btp.cs 342 | *.btm.cs 343 | *.odx.cs 344 | *.xsd.cs 345 | 346 | # OpenCover UI analysis results 347 | OpenCover/ 348 | 349 | # Azure Stream Analytics local run output 350 | ASALocalRun/ 351 | 352 | # MSBuild Binary and Structured Log 353 | *.binlog 354 | 355 | # NVidia Nsight GPU debugger configuration file 356 | *.nvuser 357 | 358 | # MFractors (Xamarin productivity tool) working folder 359 | .mfractor/ 360 | 361 | # Local History for Visual Studio 362 | .localhistory/ 363 | 364 | # Visual Studio History (VSHistory) files 365 | .vshistory/ 366 | 367 | # BeatPulse healthcheck temp database 368 | healthchecksdb 369 | 370 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 371 | MigrationBackup/ 372 | 373 | # Ionide (cross platform F# VS Code tools) working folder 374 | .ionide/ 375 | 376 | # Fody - auto-generated XML schema 377 | FodyWeavers.xsd 378 | 379 | # VS Code files for those working on multiple tools 380 | .vscode/* 381 | !.vscode/settings.json 382 | !.vscode/tasks.json 383 | !.vscode/launch.json 384 | !.vscode/extensions.json 385 | *.code-workspace 386 | 387 | # Local History for Visual Studio Code 388 | .history/ 389 | 390 | # Windows Installer files from build outputs 391 | *.cab 392 | *.msi 393 | *.msix 394 | *.msm 395 | *.msp 396 | 397 | # JetBrains Rider 398 | *.sln.iml 399 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | developer@custouch.com. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /Directory.Packages.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | all 20 | runtime; build; native; contentfiles; analyzers; buildtransitive 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Custouch 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 | -------------------------------------------------------------------------------- /NuGet.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # semantic-kernel-ERNIE-Bot 2 | 3 | [![NuGet](https://img.shields.io/nuget/v/ERNIE-Bot.SDK?label=sdk)](https://www.nuget.org/packages/ERNIE-Bot.SDK/) 4 | [![NuGet](https://img.shields.io/nuget/v/ERNIE-Bot.SemanticKernel?label=sk)](https://www.nuget.org/packages/ERNIE-Bot.SemanticKernel/) 5 | 6 | Semantic Kernel 集成文心千帆 7 | 8 | - [如何使用 ERNIE-Bot SDK](./src/ERNIE-Bot.SDK/readme.md) 9 | - [如何使用 ERNIE-Bot Semantic Kernel 集成](./src/ERNIE-Bot.SemanticKernel/readme.md) 10 | 11 | -------------------------------------------------------------------------------- /SK-ERNIE-Bot.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.31903.59 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{BB18CA42-C76C-44A3-9758-E77FCFE94353}" 7 | ProjectSection(SolutionItems) = preProject 8 | src\Directory.Build.props = src\Directory.Build.props 9 | EndProjectSection 10 | EndProject 11 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ERNIE-Bot.SemanticKernel", "src\ERNIE-Bot.SemanticKernel\ERNIE-Bot.SemanticKernel.csproj", "{A2822608-D4A3-4AE6-856C-484DC27CF18F}" 12 | EndProject 13 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ERNIE-Bot.SDK", "src\ERNIE-Bot.SDK\ERNIE-Bot.SDK.csproj", "{876A5DBE-75C2-4BE0-A5D3-45451AB180D8}" 14 | EndProject 15 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{4EE43261-6566-4D2D-BCC2-9D89A4BBEE84}" 16 | EndProject 17 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ERNIE-Bot.SDK.Tests", "tests\ERNIE-Bot.SDK.Tests\ERNIE-Bot.SDK.Tests.csproj", "{78C62497-E3B9-41A0-BF4F-129FDB50D053}" 18 | EndProject 19 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{8545A6B2-D942-4658-9413-278F1B33612D}" 20 | EndProject 21 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ERNIE-Bot.Sample", "samples\ERNIE-Bot.Sample\ERNIE-Bot.Sample.csproj", "{5CEE2488-705C-4AD9-A7F2-F37A886E4C62}" 22 | EndProject 23 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ERNIE-Bot.SemanticKernel.Tests", "tests\ERNIE-Bot.SemanticKernel.Tests\ERNIE-Bot.SemanticKernel.Tests.csproj", "{42992CFE-0E45-42DF-A2C7-07BAF0FC0001}" 24 | EndProject 25 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ERNIE-Bot-Semantic-Kernel.Sample", "samples\SK-ERNIE-Bot.Sample\ERNIE-Bot-Semantic-Kernel.Sample.csproj", "{4575E288-2ABA-49A8-BBBC-F146B2ED7E09}" 26 | EndProject 27 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{1750E273-D16C-4C82-B473-48A8D7EFFEAA}" 28 | ProjectSection(SolutionItems) = preProject 29 | .editorconfig = .editorconfig 30 | Directory.Packages.props = Directory.Packages.props 31 | README.md = README.md 32 | EndProjectSection 33 | EndProject 34 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IntegrationTests", "tests\IntegrationTests\IntegrationTests.csproj", "{1E14C259-AEAE-42D2-9533-ACC26DA1287F}" 35 | EndProject 36 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ERNIE-Bot.KernelMemory", "src\ERNIE-Bot.KernelMemory\ERNIE-Bot.KernelMemory.csproj", "{07CF237D-43D8-449B-AB1F-C843FD2D3136}" 37 | EndProject 38 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ERNIE-Bot-Kernel-Memory.Sample", "samples\ERNIE-Bot-Kernel-Memory.Sample\ERNIE-Bot-Kernel-Memory.Sample.csproj", "{5C058EEF-A6A6-4C0F-AC71-6B7EA92498B0}" 39 | EndProject 40 | Global 41 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 42 | Debug|Any CPU = Debug|Any CPU 43 | Release|Any CPU = Release|Any CPU 44 | EndGlobalSection 45 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 46 | {A2822608-D4A3-4AE6-856C-484DC27CF18F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 47 | {A2822608-D4A3-4AE6-856C-484DC27CF18F}.Debug|Any CPU.Build.0 = Debug|Any CPU 48 | {A2822608-D4A3-4AE6-856C-484DC27CF18F}.Release|Any CPU.ActiveCfg = Release|Any CPU 49 | {A2822608-D4A3-4AE6-856C-484DC27CF18F}.Release|Any CPU.Build.0 = Release|Any CPU 50 | {876A5DBE-75C2-4BE0-A5D3-45451AB180D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 51 | {876A5DBE-75C2-4BE0-A5D3-45451AB180D8}.Debug|Any CPU.Build.0 = Debug|Any CPU 52 | {876A5DBE-75C2-4BE0-A5D3-45451AB180D8}.Release|Any CPU.ActiveCfg = Release|Any CPU 53 | {876A5DBE-75C2-4BE0-A5D3-45451AB180D8}.Release|Any CPU.Build.0 = Release|Any CPU 54 | {78C62497-E3B9-41A0-BF4F-129FDB50D053}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 55 | {78C62497-E3B9-41A0-BF4F-129FDB50D053}.Debug|Any CPU.Build.0 = Debug|Any CPU 56 | {78C62497-E3B9-41A0-BF4F-129FDB50D053}.Release|Any CPU.ActiveCfg = Release|Any CPU 57 | {78C62497-E3B9-41A0-BF4F-129FDB50D053}.Release|Any CPU.Build.0 = Release|Any CPU 58 | {5CEE2488-705C-4AD9-A7F2-F37A886E4C62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 59 | {5CEE2488-705C-4AD9-A7F2-F37A886E4C62}.Debug|Any CPU.Build.0 = Debug|Any CPU 60 | {5CEE2488-705C-4AD9-A7F2-F37A886E4C62}.Release|Any CPU.ActiveCfg = Release|Any CPU 61 | {5CEE2488-705C-4AD9-A7F2-F37A886E4C62}.Release|Any CPU.Build.0 = Release|Any CPU 62 | {42992CFE-0E45-42DF-A2C7-07BAF0FC0001}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 63 | {42992CFE-0E45-42DF-A2C7-07BAF0FC0001}.Debug|Any CPU.Build.0 = Debug|Any CPU 64 | {42992CFE-0E45-42DF-A2C7-07BAF0FC0001}.Release|Any CPU.ActiveCfg = Release|Any CPU 65 | {42992CFE-0E45-42DF-A2C7-07BAF0FC0001}.Release|Any CPU.Build.0 = Release|Any CPU 66 | {4575E288-2ABA-49A8-BBBC-F146B2ED7E09}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 67 | {4575E288-2ABA-49A8-BBBC-F146B2ED7E09}.Debug|Any CPU.Build.0 = Debug|Any CPU 68 | {4575E288-2ABA-49A8-BBBC-F146B2ED7E09}.Release|Any CPU.ActiveCfg = Release|Any CPU 69 | {4575E288-2ABA-49A8-BBBC-F146B2ED7E09}.Release|Any CPU.Build.0 = Release|Any CPU 70 | {1E14C259-AEAE-42D2-9533-ACC26DA1287F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 71 | {1E14C259-AEAE-42D2-9533-ACC26DA1287F}.Debug|Any CPU.Build.0 = Debug|Any CPU 72 | {1E14C259-AEAE-42D2-9533-ACC26DA1287F}.Release|Any CPU.ActiveCfg = Release|Any CPU 73 | {1E14C259-AEAE-42D2-9533-ACC26DA1287F}.Release|Any CPU.Build.0 = Release|Any CPU 74 | {07CF237D-43D8-449B-AB1F-C843FD2D3136}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 75 | {07CF237D-43D8-449B-AB1F-C843FD2D3136}.Debug|Any CPU.Build.0 = Debug|Any CPU 76 | {07CF237D-43D8-449B-AB1F-C843FD2D3136}.Release|Any CPU.ActiveCfg = Release|Any CPU 77 | {07CF237D-43D8-449B-AB1F-C843FD2D3136}.Release|Any CPU.Build.0 = Release|Any CPU 78 | {5C058EEF-A6A6-4C0F-AC71-6B7EA92498B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 79 | {5C058EEF-A6A6-4C0F-AC71-6B7EA92498B0}.Debug|Any CPU.Build.0 = Debug|Any CPU 80 | {5C058EEF-A6A6-4C0F-AC71-6B7EA92498B0}.Release|Any CPU.ActiveCfg = Release|Any CPU 81 | {5C058EEF-A6A6-4C0F-AC71-6B7EA92498B0}.Release|Any CPU.Build.0 = Release|Any CPU 82 | EndGlobalSection 83 | GlobalSection(SolutionProperties) = preSolution 84 | HideSolutionNode = FALSE 85 | EndGlobalSection 86 | GlobalSection(NestedProjects) = preSolution 87 | {A2822608-D4A3-4AE6-856C-484DC27CF18F} = {BB18CA42-C76C-44A3-9758-E77FCFE94353} 88 | {876A5DBE-75C2-4BE0-A5D3-45451AB180D8} = {BB18CA42-C76C-44A3-9758-E77FCFE94353} 89 | {78C62497-E3B9-41A0-BF4F-129FDB50D053} = {4EE43261-6566-4D2D-BCC2-9D89A4BBEE84} 90 | {5CEE2488-705C-4AD9-A7F2-F37A886E4C62} = {8545A6B2-D942-4658-9413-278F1B33612D} 91 | {42992CFE-0E45-42DF-A2C7-07BAF0FC0001} = {4EE43261-6566-4D2D-BCC2-9D89A4BBEE84} 92 | {4575E288-2ABA-49A8-BBBC-F146B2ED7E09} = {8545A6B2-D942-4658-9413-278F1B33612D} 93 | {1E14C259-AEAE-42D2-9533-ACC26DA1287F} = {4EE43261-6566-4D2D-BCC2-9D89A4BBEE84} 94 | {07CF237D-43D8-449B-AB1F-C843FD2D3136} = {BB18CA42-C76C-44A3-9758-E77FCFE94353} 95 | {5C058EEF-A6A6-4C0F-AC71-6B7EA92498B0} = {8545A6B2-D942-4658-9413-278F1B33612D} 96 | EndGlobalSection 97 | GlobalSection(ExtensibilityGlobals) = postSolution 98 | SolutionGuid = {9277BACD-5820-497C-B2F1-F71532226D39} 99 | EndGlobalSection 100 | EndGlobal 101 | -------------------------------------------------------------------------------- /samples/ERNIE-Bot-Kernel-Memory.Sample/ERNIE-Bot-Kernel-Memory.Sample.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net6.0 6 | ERNIE_Bot_Kernel_Memory.Sample 7 | enable 8 | 84a2cf80-3689-4f7e-b25f-661eea20cf5d 9 | enable 10 | false 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | PreserveNewest 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /samples/ERNIE-Bot-Kernel-Memory.Sample/Program.cs: -------------------------------------------------------------------------------- 1 | using ERNIE_Bot.KernelMemory; 2 | using ERNIE_Bot.SDK; 3 | using Microsoft.Extensions.Configuration; 4 | using Microsoft.KernelMemory; 5 | using Microsoft.KernelMemory.Configuration; 6 | using System.Threading.RateLimiting; 7 | 8 | var config = new ConfigurationBuilder() 9 | .AddUserSecrets() 10 | .Build(); 11 | 12 | var client = new ERNIEBotClient(config["ClientId"]!, config["ClientSecret"]!, 13 | HttpClientProvider.CreateFixedWindowRateLimitedClient(new FixedWindowRateLimiterOptions() 14 | { 15 | Window = TimeSpan.FromSeconds(1), 16 | PermitLimit = 5, 17 | QueueLimit = 100 18 | })); 19 | 20 | var memory = new KernelMemoryBuilder() 21 | .WithERNIEBotTextGenerator(client) 22 | .WithERNIEBotEmbeddingGenerator(client, ModelEndpoints.bge_large_en) 23 | .With(new TextPartitioningOptions 24 | { 25 | MaxTokensPerParagraph = 300, 26 | MaxTokensPerLine = 100, 27 | OverlappingTokens = 50 28 | }) 29 | .Build(); 30 | 31 | await memory.ImportDocumentAsync("sample-SK-Readme.pdf"); 32 | 33 | var question = "什么是 Semantic Kernel?"; 34 | 35 | Console.WriteLine($"\n\nQuestion: {question}"); 36 | 37 | var answer = await memory.AskAsync(question); 38 | 39 | Console.WriteLine($"\nAnswer: {answer.Result}"); 40 | 41 | Console.WriteLine("\n\n Sources:\n"); 42 | 43 | foreach (var x in answer.RelevantSources) 44 | { 45 | Console.WriteLine($" - {x.SourceName} - {x.Link} [{x.Partitions.First().LastUpdate:D}]"); 46 | } 47 | -------------------------------------------------------------------------------- /samples/ERNIE-Bot-Kernel-Memory.Sample/sample-SK-Readme.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/custouch/semantic-kernel-ERNIE-Bot/315ea37403780049d832504bb35f7882f65d4004/samples/ERNIE-Bot-Kernel-Memory.Sample/sample-SK-Readme.pdf -------------------------------------------------------------------------------- /samples/ERNIE-Bot.Sample/Controllers/ApiController.cs: -------------------------------------------------------------------------------- 1 | using ERNIE_Bot.Sample.Controllers.Models; 2 | using ERNIE_Bot.SDK; 3 | using ERNIE_Bot.SDK.Models; 4 | using Microsoft.AspNetCore.Mvc; 5 | using System.Text; 6 | 7 | namespace ERNIE_Bot.Sample.Controllers 8 | { 9 | [Route("api")] 10 | [ApiController] 11 | public class ApiController : ControllerBase 12 | { 13 | private readonly ERNIEBotClient _client; 14 | 15 | public ApiController(ERNIEBotClient client) 16 | { 17 | this._client = client; 18 | } 19 | 20 | [HttpPost("Chat")] 21 | public async Task ChatAsync([FromBody] UserInput input) 22 | { 23 | if (string.IsNullOrWhiteSpace(input.Text)) 24 | { 25 | return NoContent(); 26 | } 27 | 28 | var result = await _client.ChatAsync(new ChatCompletionsRequest() 29 | { 30 | Messages = new List 31 | { 32 | new Message() 33 | { 34 | Content = input.Text, 35 | Role = MessageRole.User 36 | } 37 | } 38 | }, ModelEndpoints.ERNIE_Bot); 39 | 40 | return Ok(result.Result); 41 | } 42 | 43 | [HttpPost("ChatTurbo")] 44 | public async Task ChatTurboAsync([FromBody] UserInput input) 45 | { 46 | if (string.IsNullOrWhiteSpace(input.Text)) 47 | { 48 | return NoContent(); 49 | } 50 | 51 | var result = await _client.ChatAsync(new ChatCompletionsRequest() 52 | { 53 | Messages = new List 54 | { 55 | new Message() 56 | { 57 | Content = input.Text, 58 | Role = MessageRole.User 59 | } 60 | } 61 | }, ModelEndpoints.ERNIE_Bot_Turbo); 62 | 63 | return Ok(result.Result); 64 | } 65 | 66 | [HttpPost("ChatPro")] 67 | public async Task ChatProAsync([FromBody] UserInput input) 68 | { 69 | if (string.IsNullOrWhiteSpace(input.Text)) 70 | { 71 | return NoContent(); 72 | } 73 | 74 | var result = await _client.ChatAsync(new ChatCompletionsRequest() 75 | { 76 | Messages = new List 77 | { 78 | new Message() 79 | { 80 | Content = input.Text, 81 | Role = MessageRole.User 82 | } 83 | } 84 | }, ModelEndpoints.ERNIE_Bot_4); 85 | 86 | return Ok(result.Result); 87 | } 88 | 89 | [HttpPost("ChatBLOOMZ")] 90 | public async Task ChatBLOOMZAsync([FromBody] UserInput input) 91 | { 92 | if (string.IsNullOrWhiteSpace(input.Text)) 93 | { 94 | return NoContent(); 95 | } 96 | 97 | var result = await _client.ChatAsync(new ChatCompletionsRequest() 98 | { 99 | Messages = new List 100 | { 101 | new Message() 102 | { 103 | Content = input.Text, 104 | Role = MessageRole.User 105 | } 106 | } 107 | }, ModelEndpoints.BLOOMZ_7B); 108 | 109 | return Ok(result.Result); 110 | } 111 | 112 | [HttpPost("ChatStream")] 113 | public async Task ChatStreamAsync([FromBody] UserInput input) 114 | { 115 | if (string.IsNullOrWhiteSpace(input.Text)) 116 | { 117 | await Response.CompleteAsync(); 118 | } 119 | 120 | var results = _client.ChatStreamAsync(new ChatCompletionsRequest() 121 | { 122 | Messages = new List 123 | { 124 | new Message() 125 | { 126 | Content = input.Text, 127 | Role = MessageRole.User 128 | } 129 | } 130 | }, ModelEndpoints.ERNIE_Bot); 131 | 132 | await foreach (var result in results) 133 | { 134 | await Response.WriteAsync("data: " + result.Result + "\n\n", Encoding.UTF8); 135 | await Response.Body.FlushAsync(); 136 | } 137 | 138 | await Response.CompleteAsync(); 139 | } 140 | 141 | [HttpPost("Embedding")] 142 | public async Task EmbeddingAsync([FromBody] UserInput input) 143 | { 144 | if (string.IsNullOrWhiteSpace(input.Text)) 145 | { 146 | return NoContent(); 147 | } 148 | 149 | var result = await _client.EmbeddingsAsync(new EmbeddingsRequest() 150 | { 151 | Input = new List() 152 | { 153 | input.Text 154 | } 155 | }, ModelEndpoints.bge_large_en); 156 | 157 | return Ok(result.Data.FirstOrDefault()?.Embedding); 158 | } 159 | 160 | [HttpPost("History")] 161 | public async Task HistoryAsync([FromBody] UserHistoryInput input) 162 | { 163 | if (!input.Messages.Any()) 164 | { 165 | return NoContent(); 166 | } 167 | 168 | var messages = input.Messages.Select(_ => new Message() 169 | { 170 | Role = _.Role, 171 | Content = _.Text 172 | }); 173 | 174 | var result = await _client.ChatAsync(new ChatCompletionsRequest() 175 | { 176 | Messages = messages.ToList() 177 | }, ModelEndpoints.ERNIE_Bot); 178 | 179 | return Ok(result.Result); 180 | } 181 | 182 | [HttpPost("JsonFormat")] 183 | public async Task JsonFormatAsync([FromBody] UserInput input) 184 | { 185 | if (string.IsNullOrWhiteSpace(input.Text)) 186 | { 187 | return NoContent(); 188 | } 189 | 190 | var result = await _client.ChatAsync(new ChatCompletionsRequest() 191 | { 192 | Messages = new List 193 | { 194 | new Message() 195 | { 196 | Content = input.Text, 197 | Role = MessageRole.User 198 | } 199 | }, 200 | ResponseFormat = "json_object" 201 | }, ModelEndpoints.ERNIE_Bot_4); 202 | 203 | return Ok(result.Result); 204 | } 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /samples/ERNIE-Bot.Sample/Controllers/Models/UserInput.cs: -------------------------------------------------------------------------------- 1 | using ERNIE_Bot.SDK.Models; 2 | 3 | namespace ERNIE_Bot.Sample.Controllers.Models 4 | { 5 | public class UserInput 6 | { 7 | public string Role { get; set; } = MessageRole.User; 8 | public string Text { get; set; } = string.Empty; 9 | } 10 | 11 | public class UserHistoryInput 12 | { 13 | public List Messages { get; set; } = new List { }; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /samples/ERNIE-Bot.Sample/ERNIE-Bot.Sample.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0 5 | enable 6 | enable 7 | ERNIE_Bot.Sample 8 | 84a2cf80-3689-4f7e-b25f-661eea20cf5d 9 | false 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /samples/ERNIE-Bot.Sample/Program.cs: -------------------------------------------------------------------------------- 1 | using ERNIE_Bot.SDK; 2 | 3 | var builder = WebApplication.CreateBuilder(args); 4 | 5 | // Add services to the container. 6 | 7 | builder.Services.AddControllers(); 8 | // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle 9 | builder.Services.AddEndpointsApiExplorer(); 10 | builder.Services.AddSwaggerGen(); 11 | 12 | builder.Services.AddScoped(svc => 13 | { 14 | var logger = svc.GetRequiredService>(); 15 | 16 | var clientId = builder.Configuration["ClientId"]; 17 | var secret = builder.Configuration["ClientSecret"]; 18 | 19 | return new ERNIEBotClient(clientId, secret, logger: logger); 20 | }); 21 | 22 | var app = builder.Build(); 23 | 24 | // Configure the HTTP request pipeline. 25 | if (app.Environment.IsDevelopment()) 26 | { 27 | app.UseSwagger(); 28 | app.UseSwaggerUI(); 29 | } 30 | 31 | app.UseAuthorization(); 32 | 33 | app.MapControllers(); 34 | 35 | app.Run(); 36 | -------------------------------------------------------------------------------- /samples/ERNIE-Bot.Sample/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:36502", 8 | "sslPort": 0 9 | } 10 | }, 11 | "profiles": { 12 | "ERNIE_Bot.Sample": { 13 | "commandName": "Project", 14 | "dotnetRunMessages": true, 15 | "launchBrowser": true, 16 | "launchUrl": "swagger", 17 | "applicationUrl": "http://localhost:5017", 18 | "environmentVariables": { 19 | "ASPNETCORE_ENVIRONMENT": "Development" 20 | } 21 | }, 22 | "IIS Express": { 23 | "commandName": "IISExpress", 24 | "launchBrowser": true, 25 | "launchUrl": "swagger", 26 | "environmentVariables": { 27 | "ASPNETCORE_ENVIRONMENT": "Development" 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /samples/ERNIE-Bot.Sample/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /samples/ERNIE-Bot.Sample/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /samples/SK-ERNIE-Bot.Sample/Controllers/ApiController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using Microsoft.SemanticKernel; 3 | using Microsoft.SemanticKernel.ChatCompletion; 4 | using Microsoft.SemanticKernel.Embeddings; 5 | using Microsoft.SemanticKernel.TextGeneration; 6 | using Microsoft.SemanticKernel.Memory; 7 | using SK_ERNIE_Bot.Sample.Controllers.Models; 8 | using System.Text; 9 | using System.Threading; 10 | 11 | namespace SK_ERNIE_Bot.Sample.Controllers 12 | { 13 | [Route("api/")] 14 | [ApiController] 15 | public class ApiController : ControllerBase 16 | { 17 | private readonly Kernel _kernel; 18 | 19 | public ApiController(Kernel kernel) 20 | { 21 | this._kernel = kernel; 22 | } 23 | 24 | [HttpPost] 25 | public async Task ChatAsync([FromBody] UserInput input, CancellationToken cancellationToken) 26 | { 27 | if (string.IsNullOrWhiteSpace(input.Text)) 28 | { 29 | return NoContent(); 30 | } 31 | 32 | var chat = _kernel.GetRequiredService(); 33 | var history = new ChatHistory(); 34 | history.AddUserMessage(input.Text); 35 | 36 | var result = await chat.GetChatMessageContentAsync(history, cancellationToken: cancellationToken); 37 | 38 | return Ok(result); 39 | } 40 | 41 | [HttpPost("text")] 42 | public async Task TextAsync([FromBody] UserInput input, CancellationToken cancellationToken) 43 | { 44 | if (string.IsNullOrWhiteSpace(input.Text)) 45 | { 46 | return NoContent(); 47 | } 48 | 49 | var completion = _kernel.GetRequiredService(); 50 | 51 | var result = await completion.GetTextContentAsync(input.Text, null, cancellationToken: cancellationToken); 52 | 53 | var text = result.Text; 54 | return Ok(text); 55 | } 56 | 57 | [HttpPost("stream")] 58 | public async Task ChatStreamAsync([FromBody] UserInput input, CancellationToken cancellationToken) 59 | { 60 | if (string.IsNullOrWhiteSpace(input.Text)) 61 | { 62 | await Response.CompleteAsync(); 63 | } 64 | 65 | var chat = _kernel.GetRequiredService(); 66 | var history = new ChatHistory(); 67 | history.AddUserMessage(input.Text); 68 | var results = chat.GetStreamingChatMessageContentsAsync(history, cancellationToken: cancellationToken); 69 | 70 | await foreach (var result in results) 71 | { 72 | await Response.WriteAsync("data: " + result + "\n\n", Encoding.UTF8); 73 | await Response.Body.FlushAsync(); 74 | } 75 | 76 | await Response.CompleteAsync(); 77 | } 78 | 79 | [HttpPost("embedding")] 80 | public async Task EmbeddingAsync([FromBody] UserInput input, [FromServices] ISemanticTextMemory memory, CancellationToken cancellationToken) 81 | { 82 | const string collection = "demo"; 83 | if (string.IsNullOrWhiteSpace(input.Text)) 84 | { 85 | return NoContent(); 86 | } 87 | 88 | var id = await memory.SaveInformationAsync(collection, input.Text, "1", cancellationToken: cancellationToken); 89 | var embedding = await memory.GetAsync(collection, id, true, cancellationToken: cancellationToken); 90 | 91 | var result = embedding!.Embedding; 92 | 93 | return Ok(result!.Value.ToArray()); 94 | } 95 | 96 | [HttpPost("function")] 97 | public async Task FuncAsync([FromBody] UserInput input, CancellationToken cancellationToken) 98 | { 99 | const string prompt = """ 100 | 翻译以下内容为英文: 101 | 102 | {{$input}} 103 | 104 | """; 105 | var func = _kernel.CreateFunctionFromPrompt(prompt); 106 | var result = await _kernel.InvokeAsync(func, new() { ["input"] = input.Text }, cancellationToken: cancellationToken); 107 | return Ok(result.GetValue()); 108 | } 109 | 110 | [HttpPost("semanticPlugin")] 111 | public async Task SemanticPlugin([FromBody] UserInput input, CancellationToken cancellationToken) 112 | { 113 | var plugin = _kernel.ImportPluginFromPromptDirectory("Plugins/Demo", "Demo"); 114 | 115 | var translateFunc = plugin["Translate"]; 116 | 117 | var result = await _kernel.InvokeAsync(translateFunc, new() { ["input"] = input.Text }, cancellationToken: cancellationToken); 118 | return Ok(result.GetValue()); 119 | } 120 | 121 | [HttpPost("chat_with_system")] 122 | public async Task ChatWithSystemAsync([FromBody] UserInput input, CancellationToken cancellationToken) 123 | { 124 | if (string.IsNullOrWhiteSpace(input.Text)) 125 | { 126 | return NoContent(); 127 | } 128 | 129 | var chat = _kernel.GetRequiredService(); 130 | 131 | var history = new ChatHistory($"你是一个友善的AI助手。你的名字叫做Alice,今天是{DateTime.Today}."); 132 | 133 | history.AddUserMessage(input.Text); 134 | 135 | var result = await chat.GetChatMessageContentsAsync(history, null, cancellationToken: cancellationToken); 136 | 137 | var text = result[0].Content; 138 | return Ok(text); 139 | } 140 | 141 | [HttpPost("get_usage")] 142 | public async Task GetUsageAsync([FromBody] UserInput input, CancellationToken cancellationToken) 143 | { 144 | var plugin = _kernel.ImportPluginFromPromptDirectory("Plugins/Demo", "Demo"); 145 | 146 | var translateFunc = plugin["Translate"]; 147 | 148 | var result = await _kernel.InvokeAsync(translateFunc, new() { ["input"] = input.Text }, cancellationToken: cancellationToken); 149 | 150 | var value = result.GetValue(); 151 | 152 | var usage = result.Metadata?["Usage"]; 153 | 154 | return Ok(new 155 | { 156 | value, 157 | usage 158 | }); 159 | } 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /samples/SK-ERNIE-Bot.Sample/Controllers/Models/UserInput.cs: -------------------------------------------------------------------------------- 1 | namespace SK_ERNIE_Bot.Sample.Controllers.Models 2 | { 3 | public class UserInput 4 | { 5 | public string Text { get; set; } = string.Empty; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /samples/SK-ERNIE-Bot.Sample/ERNIE-Bot-Semantic-Kernel.Sample.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0 5 | enable 6 | enable 7 | SK_ERNIE_Bot.Sample 8 | 84a2cf80-3689-4f7e-b25f-661eea20cf5d 9 | 11 10 | false 11 | SKEXP0001;SKEXP0003;SKEXP0050;SKEXP0052 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | Always 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /samples/SK-ERNIE-Bot.Sample/Plugins/Demo/Translate/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "schema": 1, 3 | "type": "completion", 4 | "description": "", 5 | "completion": { 6 | }, 7 | "default_services": [], 8 | "input": { 9 | "parameters": [] 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /samples/SK-ERNIE-Bot.Sample/Plugins/Demo/Translate/skprompt.txt: -------------------------------------------------------------------------------- 1 | 翻译以下内容为英文: 2 | 3 | {{$input}} 4 | -------------------------------------------------------------------------------- /samples/SK-ERNIE-Bot.Sample/Program.cs: -------------------------------------------------------------------------------- 1 | using ERNIE_Bot.SDK; 2 | using Microsoft.SemanticKernel; 3 | using Microsoft.SemanticKernel.Memory; 4 | 5 | var builder = WebApplication.CreateBuilder(args); 6 | 7 | // Add services to the container. 8 | 9 | builder.Services.AddControllers(); 10 | // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle 11 | builder.Services.AddEndpointsApiExplorer(); 12 | builder.Services.AddSwaggerGen(); 13 | 14 | builder.Services.AddScoped(svc => 15 | { 16 | var kernel = Kernel.CreateBuilder() 17 | .WithERNIEBotChatCompletionService(svc, builder.Configuration, "ernie_bot", ModelEndpoints.ERNIE_Bot) 18 | .Build(); 19 | return kernel; 20 | }); 21 | 22 | builder.Services.AddScoped(svc => 23 | { 24 | var memory = new MemoryBuilder() 25 | .WithERNIEBotEmbeddingGenerationService(svc, builder.Configuration) 26 | .WithMemoryStore(new VolatileMemoryStore()) 27 | .Build(); 28 | return memory; 29 | }); 30 | 31 | var app = builder.Build(); 32 | 33 | // Configure the HTTP request pipeline. 34 | if (app.Environment.IsDevelopment()) 35 | { 36 | app.UseSwagger(); 37 | app.UseSwaggerUI(); 38 | } 39 | 40 | app.UseAuthorization(); 41 | 42 | app.MapControllers(); 43 | 44 | app.Run(); 45 | -------------------------------------------------------------------------------- /samples/SK-ERNIE-Bot.Sample/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:62718", 8 | "sslPort": 0 9 | } 10 | }, 11 | "profiles": { 12 | "SK_ERNIE_Bot.Sample": { 13 | "commandName": "Project", 14 | "dotnetRunMessages": true, 15 | "launchBrowser": true, 16 | "launchUrl": "swagger", 17 | "applicationUrl": "http://localhost:5177", 18 | "environmentVariables": { 19 | "ASPNETCORE_ENVIRONMENT": "Development" 20 | } 21 | }, 22 | "IIS Express": { 23 | "commandName": "IISExpress", 24 | "launchBrowser": true, 25 | "launchUrl": "swagger", 26 | "environmentVariables": { 27 | "ASPNETCORE_ENVIRONMENT": "Development" 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /samples/SK-ERNIE-Bot.Sample/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /samples/SK-ERNIE-Bot.Sample/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*", 9 | "ClientId": "**************", 10 | "ClientSecret": "****************" 11 | } 12 | -------------------------------------------------------------------------------- /src/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | # All files 4 | [*] 5 | indent_style = space 6 | 7 | # Xml files 8 | [*.xml] 9 | indent_size = 2 10 | 11 | [*.cs] 12 | #### Naming styles #### 13 | 14 | # Naming rules 15 | 16 | dotnet_naming_rule.private_readonly_field_should_be_begin_with__.severity = suggestion 17 | dotnet_naming_rule.private_readonly_field_should_be_begin_with__.symbols = private_readonly_field 18 | dotnet_naming_rule.private_readonly_field_should_be_begin_with__.style = begin_with__ 19 | 20 | # Symbol specifications 21 | 22 | dotnet_naming_symbols.private_readonly_field.applicable_kinds = field 23 | dotnet_naming_symbols.private_readonly_field.applicable_accessibilities = private 24 | dotnet_naming_symbols.private_readonly_field.required_modifiers = readonly 25 | 26 | # Naming styles 27 | 28 | dotnet_naming_style.begin_with__.required_prefix = _ 29 | dotnet_naming_style.begin_with__.required_suffix = 30 | dotnet_naming_style.begin_with__.word_separator = 31 | dotnet_naming_style.begin_with__.capitalization = camel_case 32 | csharp_indent_labels = one_less_than_current 33 | csharp_using_directive_placement = outside_namespace:silent 34 | csharp_prefer_simple_using_statement = true:suggestion 35 | csharp_prefer_braces = true:silent 36 | csharp_style_namespace_declarations = block_scoped:silent 37 | csharp_style_prefer_method_group_conversion = true:silent 38 | csharp_style_prefer_top_level_statements = true:silent 39 | csharp_style_prefer_primary_constructors = true:suggestion 40 | csharp_style_expression_bodied_methods = false:silent 41 | csharp_style_expression_bodied_constructors = false:silent 42 | csharp_style_expression_bodied_operators = false:silent 43 | csharp_style_expression_bodied_properties = true:silent 44 | csharp_style_expression_bodied_indexers = true:silent 45 | csharp_style_expression_bodied_accessors = true:silent 46 | csharp_style_expression_bodied_lambdas = true:silent 47 | csharp_style_expression_bodied_local_functions = false:silent 48 | 49 | [*.{cs,vb}] 50 | #### Naming styles #### 51 | 52 | # Naming rules 53 | 54 | dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion 55 | dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface 56 | dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i 57 | 58 | dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion 59 | dotnet_naming_rule.types_should_be_pascal_case.symbols = types 60 | dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case 61 | 62 | dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion 63 | dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members 64 | dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case 65 | 66 | # Symbol specifications 67 | 68 | dotnet_naming_symbols.interface.applicable_kinds = interface 69 | dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 70 | dotnet_naming_symbols.interface.required_modifiers = 71 | 72 | dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum 73 | dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 74 | dotnet_naming_symbols.types.required_modifiers = 75 | 76 | dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method 77 | dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 78 | dotnet_naming_symbols.non_field_members.required_modifiers = 79 | 80 | # Naming styles 81 | 82 | dotnet_naming_style.begins_with_i.required_prefix = I 83 | dotnet_naming_style.begins_with_i.required_suffix = 84 | dotnet_naming_style.begins_with_i.word_separator = 85 | dotnet_naming_style.begins_with_i.capitalization = pascal_case 86 | 87 | dotnet_naming_style.pascal_case.required_prefix = 88 | dotnet_naming_style.pascal_case.required_suffix = 89 | dotnet_naming_style.pascal_case.word_separator = 90 | dotnet_naming_style.pascal_case.capitalization = pascal_case 91 | 92 | dotnet_naming_style.pascal_case.required_prefix = 93 | dotnet_naming_style.pascal_case.required_suffix = 94 | dotnet_naming_style.pascal_case.word_separator = 95 | dotnet_naming_style.pascal_case.capitalization = pascal_case 96 | dotnet_style_operator_placement_when_wrapping = beginning_of_line 97 | tab_width = 4 98 | indent_size = 4 99 | end_of_line = crlf 100 | dotnet_style_coalesce_expression = true:suggestion 101 | dotnet_style_null_propagation = true:suggestion 102 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion 103 | dotnet_style_prefer_auto_properties = true:silent 104 | dotnet_style_object_initializer = true:suggestion 105 | dotnet_style_collection_initializer = true:suggestion 106 | dotnet_style_prefer_simplified_boolean_expressions = true:suggestion 107 | dotnet_style_predefined_type_for_locals_parameters_members = true:silent 108 | dotnet_style_predefined_type_for_member_access = true:silent 109 | dotnet_diagnostic.VSTHRD111.severity = error 110 | -------------------------------------------------------------------------------- /src/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.1 5 | $(AssemblyName) 6 | enable 7 | enable 8 | 12 9 | Custouch 10 | LICENSE 11 | 12 | https://github.com/custouch/semantic-kernel-ERNIE-Bot 13 | https://github.com/custouch/semantic-kernel-ERNIE-Bot 14 | git 15 | 0.14.4 16 | ..\..\nupkgs 17 | readme.md 18 | SKEXP0001;SKEXP0002;SKEXP0052;SKEXP0003 19 | 20 | 21 | 22 | 23 | 24 | True 25 | \ 26 | 27 | 28 | 29 | 30 | 31 | True 32 | \ 33 | 34 | 35 | 36 | 37 | true 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/ERNIE-Bot.KernelMemory/ERNIE-Bot.KernelMemory.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0 5 | ERNIE_Bot.KernelMemory 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/ERNIE-Bot.KernelMemory/ERNIEBotTextEmbeddingGenerator.cs: -------------------------------------------------------------------------------- 1 | using ERNIE_Bot.SDK; 2 | using Microsoft.KernelMemory; 3 | using Microsoft.KernelMemory.AI; 4 | using Microsoft.SemanticKernel.AI.Embeddings; 5 | 6 | namespace ERNIE_Bot.KernelMemory 7 | { 8 | /// 9 | /// Generating text embeddings using ERNIEBotClient. 10 | /// 11 | public class ERNIEBotTextEmbeddingGenerator : ITextEmbeddingGenerator 12 | { 13 | private readonly ERNIEBotClient _client; 14 | private readonly EmbeddingModelEndpoint _endpoint; 15 | 16 | /// 17 | /// Initializes a new instance of the class. 18 | /// 19 | /// The ERNIEBotClient instance to use for generating embeddings. 20 | /// The endpoint to use for the embedding model. Defaults to ModelEndpoints.Embedding_v1. 21 | public ERNIEBotTextEmbeddingGenerator(ERNIEBotClient client, EmbeddingModelEndpoint? endpoint = null) 22 | { 23 | this._client = client; 24 | _endpoint = endpoint ?? ModelEndpoints.Embedding_v1; 25 | } 26 | 27 | public int MaxTokens => _endpoint.MaxTokens; 28 | 29 | /// 30 | public async Task GenerateEmbeddingAsync(string text, CancellationToken cancellationToken = default) 31 | { 32 | var embeddings = await _client.EmbeddingsAsync(new SDK.Models.EmbeddingsRequest() 33 | { 34 | Input = [text] 35 | }, _endpoint, cancellationToken).ConfigureAwait(false); 36 | 37 | return new Embedding(embeddings.Data[0].Embedding.Select(e => (float)e).ToArray()); 38 | } 39 | 40 | public int CountTokens(string text) 41 | { 42 | return Tokenizer.ApproxNumTokens(text); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/ERNIE-Bot.KernelMemory/ERNIEBotTextGenerator.cs: -------------------------------------------------------------------------------- 1 | using ERNIE_Bot.SDK; 2 | using Microsoft.KernelMemory.AI; 3 | using System.Runtime.CompilerServices; 4 | 5 | namespace ERNIE_Bot.KernelMemory 6 | { 7 | /// 8 | /// Generating text using ERNIEBotClient. 9 | /// 10 | public class ERNIEBotTextGenerator : ITextGenerator 11 | { 12 | private readonly ERNIEBotClient _client; 13 | private readonly ModelEndpoint _endpoint; 14 | 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | /// The ERNIEBotClient instance to use for generating text. 19 | /// The endpoint to use for the model. Defaults to ModelEndpoints.ERNIE_Bot_Turbo. 20 | public ERNIEBotTextGenerator(ERNIEBotClient client, ModelEndpoint? endpoint = null) 21 | { 22 | this._client = client; 23 | _endpoint = endpoint ?? ModelEndpoints.ERNIE_Bot_Turbo; 24 | } 25 | 26 | public int MaxTokenTotal => _endpoint.MaxTokens; 27 | 28 | public int CountTokens(string text) => Tokenizer.ApproxNumTokens(text); 29 | 30 | /// 31 | public async IAsyncEnumerable GenerateTextAsync(string prompt, TextGenerationOptions options, [EnumeratorCancellation] CancellationToken cancellationToken = default) 32 | { 33 | var result = _client.ChatStreamAsync(new SDK.Models.ChatRequest() 34 | { 35 | Messages = new List() 36 | { 37 | new SDK.Models.Message() 38 | { 39 | Role = SDK.Models.MessageRole.User, 40 | Content = prompt 41 | } 42 | }, 43 | }, _endpoint, cancellationToken); 44 | 45 | await foreach (var response in result) 46 | { 47 | yield return response.Result; 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/ERNIE-Bot.KernelMemory/KernelMemoryBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using ERNIE_Bot.SDK; 2 | using Microsoft.KernelMemory; 3 | 4 | namespace ERNIE_Bot.KernelMemory 5 | { 6 | /// 7 | /// Provides extension methods for configuring the KernelMemoryBuilder with ERNIEBot defaults. 8 | /// 9 | public static class KernelMemoryBuilderExtensions 10 | { 11 | /// 12 | /// Configures the KernelMemoryBuilder with ERNIEBot text generation. 13 | /// 14 | /// The KernelMemoryBuilder instance to configure. 15 | /// The ERNIEBotClient instance to use for text generation. 16 | /// The endpoint to use for the text generation model. Defaults to ModelEndpoints.ERNIE_Bot_Turbo. 17 | /// The configured KernelMemoryBuilder instance. 18 | public static KernelMemoryBuilder WithERNIEBotTextGenerator(this KernelMemoryBuilder builder, ERNIEBotClient client, ModelEndpoint? endpoint = null) 19 | { 20 | builder.WithCustomTextGenerator(new ERNIEBotTextGenerator(client, endpoint)); 21 | return builder; 22 | } 23 | 24 | /// 25 | /// Configures the KernelMemoryBuilder with ERNIEBot embedding generation. 26 | /// 27 | /// The KernelMemoryBuilder instance to configure. 28 | /// The ERNIEBotClient instance to use for embedding generation. 29 | /// The endpoint to use for the embedding generation model. Defaults to ModelEndpoints.Embedding_v1. 30 | /// The configured KernelMemoryBuilder instance. 31 | public static KernelMemoryBuilder WithERNIEBotEmbeddingGenerator(this KernelMemoryBuilder builder, ERNIEBotClient client, EmbeddingModelEndpoint? endpoint = null) 32 | { 33 | builder.WithCustomEmbeddingGenerator(new ERNIEBotTextEmbeddingGenerator(client, endpoint)); 34 | return builder; 35 | } 36 | 37 | /// 38 | /// Configures the KernelMemoryBuilder with ERNIEBot defaults. 39 | /// 40 | /// The KernelMemoryBuilder instance to configure. 41 | /// The client ID to use for the ERNIEBotClient instance. 42 | /// The client secret to use for the ERNIEBotClient instance. 43 | /// The configured KernelMemoryBuilder instance. 44 | public static KernelMemoryBuilder WithERNIEBotDefaults(this KernelMemoryBuilder builder, string clientId, string clientSecret) 45 | { 46 | var client = new ERNIEBotClient(clientId, clientSecret); 47 | return builder.WithERNIEBotDefaults(client); 48 | } 49 | 50 | /// 51 | /// Configures the KernelMemoryBuilder with ERNIEBot defaults. 52 | /// 53 | /// The KernelMemoryBuilder instance to configure. 54 | /// The ERNIEBotClient instance to use for text and embedding generation. 55 | /// The configured KernelMemoryBuilder instance. 56 | public static KernelMemoryBuilder WithERNIEBotDefaults(this KernelMemoryBuilder builder, ERNIEBotClient client) 57 | { 58 | builder.WithERNIEBotTextGenerator(client); 59 | builder.WithERNIEBotEmbeddingGenerator(client); 60 | return builder; 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/ERNIE-Bot.KernelMemory/readme.md: -------------------------------------------------------------------------------- 1 | # ERNIE-Bot Kernel Memory 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/ERNIE-Bot.SDK/Defaults.cs: -------------------------------------------------------------------------------- 1 | namespace ERNIE_Bot.SDK 2 | { 3 | public static class Defaults 4 | { 5 | public static string AccessTokenEndpoint = "https://aip.baidubce.com/oauth/2.0/token"; 6 | 7 | public static string EmbeddingV1Endpoint = "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/embeddings/embedding-v1"; 8 | 9 | public static string TokenCacheName = "ERNIE_BOT:AK"; 10 | 11 | /// 12 | /// Use ModelEndpoints to get the model name 13 | /// 14 | /// 15 | /// 16 | public static string Endpoint(string model) => $"https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/{model}"; 17 | 18 | /// 19 | /// Use ModelEndpoints to get the Model Endpoint 20 | /// 21 | public static string Endpoint(Endpoint endpoint) => $"https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/{endpoint.Task}/{endpoint.Model}"; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/ERNIE-Bot.SDK/DistributedTokenStore.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Caching.Distributed; 2 | 3 | namespace ERNIE_Bot.SDK 4 | { 5 | public class DistributedTokenStore : ITokenStore 6 | { 7 | private readonly IDistributedCache _cache; 8 | 9 | public DistributedTokenStore(IDistributedCache cache) 10 | { 11 | this._cache = cache; 12 | } 13 | 14 | public async Task GetTokenAsync(CancellationToken cancellationToken) 15 | { 16 | cancellationToken.ThrowIfCancellationRequested(); 17 | 18 | return await _cache.GetStringAsync(Defaults.TokenCacheName).ConfigureAwait(false); 19 | } 20 | 21 | public async Task SaveTokenAsync(string accessToken, TimeSpan expiration, CancellationToken cancellationToken) 22 | { 23 | cancellationToken.ThrowIfCancellationRequested(); 24 | 25 | await _cache.SetStringAsync(Defaults.TokenCacheName, accessToken, new DistributedCacheEntryOptions() 26 | { 27 | AbsoluteExpirationRelativeToNow = expiration 28 | }, cancellationToken).ConfigureAwait(false); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/ERNIE-Bot.SDK/ERNIE-Bot.SDK.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | ERNIE_Bot.SDK 4 | ERNIE-Bot.SDK 5 | LLM,ERNIE-Bot,文心千帆 6 | ERNIE-Bot(文心千帆) .NET SDK 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/ERNIE-Bot.SDK/ERNIEBotClient.cs: -------------------------------------------------------------------------------- 1 | using ERNIE_Bot.SDK.Models; 2 | using Microsoft; 3 | using Microsoft.Extensions.Logging; 4 | using Microsoft.Extensions.Logging.Abstractions; 5 | using System.Runtime.CompilerServices; 6 | using System.Text; 7 | using System.Text.Json; 8 | using System.Threading.RateLimiting; 9 | 10 | namespace ERNIE_Bot.SDK 11 | { 12 | public class ERNIEBotClient 13 | { 14 | private readonly string _clientId; 15 | private readonly string _clientSecret; 16 | private readonly HttpClient _client; 17 | private readonly ITokenStore _tokenStore; 18 | private readonly ILogger _logger; 19 | 20 | public ERNIEBotClient(string clientId, string clientSecret, HttpClient? client = null, ITokenStore? tokenStore = null, ILogger? logger = null) 21 | { 22 | Requires.NotNullOrWhiteSpace(clientId, nameof(clientId)); 23 | Requires.NotNullOrWhiteSpace(clientSecret, nameof(clientSecret)); 24 | 25 | this._logger = logger ?? NullLoggerFactory.Instance.CreateLogger(nameof(ERNIEBotClient)); 26 | 27 | this._clientId = clientId; 28 | this._clientSecret = clientSecret; 29 | this._client = client ?? HttpClientProvider.CreateClient(); 30 | this._tokenStore = tokenStore ?? new DefaultTokenStore(); 31 | } 32 | 33 | public ERNIEBotClient(string clientId, string clientSecret, int rateLimit, ITokenStore? tokenStore = null, ILogger? logger = null) 34 | : this(clientId, clientSecret, HttpClientProvider.CreateFixedWindowRateLimitedClient(new FixedWindowRateLimiterOptions() 35 | { 36 | PermitLimit = rateLimit, 37 | QueueProcessingOrder = QueueProcessingOrder.OldestFirst, 38 | Window = TimeSpan.FromSeconds(1), 39 | }), tokenStore, logger) 40 | { 41 | } 42 | 43 | /// 44 | /// API for Chat Completion 45 | /// 46 | /// 47 | /// 48 | /// 49 | /// 50 | public Task ChatAsync(ChatRequest request, string endpoint, CancellationToken cancellationToken = default) 51 | => this.ChatAsync(request, new ModelEndpoint(endpoint), cancellationToken); 52 | 53 | /// 54 | /// API for Chat Completion 55 | /// 56 | /// 57 | /// 58 | /// 59 | /// 60 | public async Task ChatAsync(ChatRequest request, ModelEndpoint modelEndpoint, CancellationToken cancellationToken = default) 61 | { 62 | if (request.Stream.HasValue && request.Stream.Value) 63 | { 64 | request.Stream = false; 65 | } 66 | 67 | OrganizeChatMessages(request.Messages); 68 | 69 | var webRequest = await CreateRequestAsync(HttpMethod.Post, Defaults.Endpoint(modelEndpoint), request).ConfigureAwait(false); 70 | 71 | var response = await _client.SendAsync(webRequest, cancellationToken).ConfigureAwait(false); 72 | 73 | return await ParseResponseAsync(response).ConfigureAwait(false); 74 | } 75 | 76 | /// 77 | /// Stream API for Chat Completion 78 | /// 79 | /// 80 | /// 81 | /// 82 | /// 83 | public IAsyncEnumerable ChatStreamAsync(ChatRequest request, string modelEndpoint, CancellationToken cancellationToken = default) 84 | => this.ChatStreamAsync(request, new ModelEndpoint(modelEndpoint), cancellationToken); 85 | 86 | /// 87 | /// Stream API for Chat Completion 88 | /// 89 | /// 90 | /// 91 | /// 92 | /// 93 | public async IAsyncEnumerable ChatStreamAsync(ChatRequest request, ModelEndpoint modelEndpoint, [EnumeratorCancellation] CancellationToken cancellationToken = default) 94 | { 95 | request.Stream = true; 96 | 97 | OrganizeChatMessages(request.Messages); 98 | 99 | var webRequest = await CreateRequestAsync(HttpMethod.Post, Defaults.Endpoint(modelEndpoint), request, cancellationToken).ConfigureAwait(false); 100 | 101 | var response = await _client.SendAsync(webRequest, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); 102 | 103 | await foreach (var item in ParseResponseStreamAsync(response, cancellationToken).ConfigureAwait(false)) 104 | { 105 | yield return item; 106 | } 107 | } 108 | 109 | /// 110 | /// Embedding Api For ERNIE-Bot 111 | /// 112 | /// 113 | public async Task EmbeddingsAsync(EmbeddingsRequest request, CancellationToken cancellationToken = default) 114 | { 115 | var webRequest = await CreateRequestAsync(HttpMethod.Post, Defaults.Endpoint(ModelEndpoints.Embedding_v1), request).ConfigureAwait(false); 116 | 117 | var response = await _client.SendAsync(webRequest, cancellationToken).ConfigureAwait(false); 118 | 119 | return await ParseResponseAsync(response).ConfigureAwait(false); 120 | } 121 | 122 | /// 123 | /// Embedding Api for custom Embedding Model 124 | /// 125 | /// 126 | /// 127 | /// 128 | /// 129 | public async Task EmbeddingsAsync(EmbeddingsRequest request, EmbeddingModelEndpoint modelEndpoint, CancellationToken cancellationToken = default) 130 | { 131 | var webRequest = await CreateRequestAsync(HttpMethod.Post, Defaults.Endpoint(modelEndpoint), request).ConfigureAwait(false); 132 | 133 | var response = await _client.SendAsync(webRequest, cancellationToken).ConfigureAwait(false); 134 | 135 | return await ParseResponseAsync(response).ConfigureAwait(false); 136 | } 137 | 138 | /// 139 | /// Get Access Token 140 | /// 141 | /// 142 | /// 143 | /// 144 | public async Task GetAccessTokenAsync(CancellationToken cancellationToken = default) 145 | { 146 | var token = await _tokenStore.GetTokenAsync(cancellationToken).ConfigureAwait(false); 147 | 148 | if (!string.IsNullOrWhiteSpace(token)) 149 | { 150 | return token; 151 | } 152 | 153 | var url = $"{Defaults.AccessTokenEndpoint}?client_id={_clientId}&client_secret={_clientSecret}&grant_type=client_credentials"; 154 | 155 | var webRequest = new HttpRequestMessage(HttpMethod.Post, url); 156 | var response = await _client.SendAsync(webRequest, cancellationToken).ConfigureAwait(false); 157 | var accessToken = await ParseResponseAsync(response).ConfigureAwait(false); 158 | 159 | if (string.IsNullOrWhiteSpace(accessToken.AccessToken)) 160 | { 161 | throw new HttpRequestException($"Failed to get access token"); 162 | } 163 | 164 | await _tokenStore.SaveTokenAsync(accessToken.AccessToken, TimeSpan.FromSeconds(accessToken.Expiration), cancellationToken).ConfigureAwait(false); 165 | 166 | return accessToken.AccessToken; 167 | } 168 | 169 | #region ===== private methods ===== 170 | 171 | private async Task CreateRequestAsync(HttpMethod method, string path, TRequest? body = null, CancellationToken cancellationToken = default) where TRequest : class 172 | { 173 | var accessToken = await GetAccessTokenAsync(cancellationToken).ConfigureAwait(false); 174 | 175 | var uri = path + "?access_token=" + accessToken; 176 | 177 | var request = new HttpRequestMessage(method, uri); 178 | 179 | if (body != null) 180 | { 181 | request.Content = new StringContent(JsonSerializer.Serialize(body), Encoding.UTF8, "application/json"); 182 | } 183 | 184 | return request; 185 | } 186 | 187 | private async Task ParseResponseAsync(HttpResponseMessage response) 188 | { 189 | var responseJson = await response.Content.ReadAsStringAsync().ConfigureAwait(false); 190 | var error = JsonSerializer.Deserialize(responseJson); 191 | 192 | if (error?.Code != -1) 193 | { 194 | throw new ERNIEBotException(error); 195 | } 196 | 197 | var result = JsonSerializer.Deserialize(responseJson); 198 | if (result != null) 199 | { 200 | return result; 201 | } 202 | else 203 | { 204 | throw new ERNIEBotException(-1, "Invalid response content"); 205 | } 206 | } 207 | 208 | private async IAsyncEnumerable ParseResponseStreamAsync(HttpResponseMessage response, [EnumeratorCancellation] CancellationToken cancellationToken = default) 209 | { 210 | if (!response.IsSuccessStatusCode) 211 | { 212 | var responseJson = await response.Content.ReadAsStringAsync().ConfigureAwait(false); 213 | 214 | var error = JsonSerializer.Deserialize(responseJson); 215 | 216 | throw new ERNIEBotException(error); 217 | } 218 | 219 | await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); 220 | using var reader = new StreamReader(stream); 221 | 222 | while (!reader.EndOfStream) 223 | { 224 | cancellationToken.ThrowIfCancellationRequested(); 225 | 226 | var line = await reader.ReadLineAsync().ConfigureAwait(false); 227 | 228 | if (string.IsNullOrEmpty(line)) 229 | { 230 | continue; 231 | } 232 | 233 | line = RemovePrefix(line, "data: "); 234 | 235 | ChatResponse? block; 236 | try 237 | { 238 | block = JsonSerializer.Deserialize(line); 239 | } 240 | catch (Exception) 241 | { 242 | throw new ERNIEBotException(-1, "Invalid response content"); 243 | } 244 | 245 | if (block != null) 246 | { 247 | yield return block; 248 | 249 | if (block.IsEnd.HasValue && block.IsEnd.Value) 250 | { 251 | break; 252 | }; 253 | } 254 | } 255 | } 256 | 257 | private string RemovePrefix(string text, string prefix) 258 | { 259 | if (text.StartsWith(prefix)) 260 | { 261 | return text.Substring(prefix.Length); 262 | } 263 | else 264 | { 265 | return text; 266 | } 267 | } 268 | 269 | private void OrganizeChatMessages(List messages) 270 | { 271 | if (!messages.Any()) 272 | { 273 | throw new ERNIEBotException(-1, "no messages"); 274 | } 275 | 276 | if (messages.Count % 2 == 0) 277 | { 278 | if (messages.First().Role != MessageRole.User) 279 | { 280 | messages.RemoveAt(0); 281 | _logger.LogWarning("Messages count must be odd, Remove the first message to ensure the API call is working properly."); 282 | } 283 | } 284 | } 285 | 286 | #endregion ===== private methods ===== 287 | } 288 | } 289 | -------------------------------------------------------------------------------- /src/ERNIE-Bot.SDK/HttpClientProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | using System.Net; 3 | using System.Threading.RateLimiting; 4 | 5 | namespace ERNIE_Bot.SDK 6 | { 7 | public class HttpClientProvider 8 | { 9 | public static HttpClient CreateClient() 10 | { 11 | return new HttpClient(); 12 | } 13 | 14 | public static HttpClient CreateRateLimitedClient(RateLimiter limiter) 15 | { 16 | return new HttpClient(new ClientSideRateLimitedHandler(limiter)); 17 | } 18 | 19 | public static HttpClient CreateFixedWindowRateLimitedClient(FixedWindowRateLimiterOptions fixedWindowRateLimiterOptions) 20 | { 21 | return CreateRateLimitedClient(new FixedWindowRateLimiter(fixedWindowRateLimiterOptions)); 22 | } 23 | } 24 | 25 | /// 26 | /// ref: https://learn.microsoft.com/dotnet/core/extensions/http-ratelimiter 27 | /// 28 | internal sealed class ClientSideRateLimitedHandler 29 | : DelegatingHandler, IAsyncDisposable 30 | { 31 | private readonly RateLimiter _rateLimiter; 32 | 33 | public ClientSideRateLimitedHandler(RateLimiter limiter) 34 | : base(new HttpClientHandler()) => _rateLimiter = limiter; 35 | 36 | protected override async Task SendAsync( 37 | HttpRequestMessage request, CancellationToken cancellationToken) 38 | { 39 | using RateLimitLease lease = await _rateLimiter.AcquireAsync( 40 | permitCount: 1, cancellationToken).ConfigureAwait(false); 41 | 42 | if (lease.IsAcquired) 43 | { 44 | return await base.SendAsync(request, cancellationToken).ConfigureAwait(false); 45 | } 46 | 47 | var response = new HttpResponseMessage(HttpStatusCode.TooManyRequests); 48 | if (lease.TryGetMetadata( 49 | MetadataName.RetryAfter, out TimeSpan retryAfter)) 50 | { 51 | response.Headers.Add( 52 | "Retry-After", 53 | ((int)retryAfter.TotalSeconds).ToString( 54 | NumberFormatInfo.InvariantInfo)); 55 | } 56 | 57 | return response; 58 | } 59 | 60 | async ValueTask IAsyncDisposable.DisposeAsync() 61 | { 62 | await _rateLimiter.DisposeAsync().ConfigureAwait(false); 63 | 64 | Dispose(disposing: false); 65 | GC.SuppressFinalize(this); 66 | } 67 | 68 | protected override void Dispose(bool disposing) 69 | { 70 | base.Dispose(disposing); 71 | 72 | if (disposing) 73 | { 74 | _rateLimiter.Dispose(); 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/ERNIE-Bot.SDK/ModelEndpoint.cs: -------------------------------------------------------------------------------- 1 | namespace ERNIE_Bot.SDK 2 | { 3 | /// 4 | /// Use ModelEndpoints to get the model name 5 | /// 6 | public abstract class Endpoint 7 | { 8 | public string Model { get; set; } 9 | public string Task { get; set; } 10 | public int MaxTokens { get; set; } 11 | 12 | internal Endpoint(string model, string task, int maxTokens) 13 | { 14 | Model = model; 15 | Task = task; 16 | MaxTokens = maxTokens; 17 | } 18 | 19 | public static implicit operator string(Endpoint endpoint) 20 | { 21 | return endpoint.Model; 22 | } 23 | } 24 | 25 | /// 26 | public class ModelEndpoint : Endpoint 27 | { 28 | public ModelEndpoint(string model, int maxTokens = 2000) : base(model, "chat", maxTokens) 29 | { 30 | } 31 | } 32 | 33 | /// 34 | public class EmbeddingModelEndpoint : Endpoint 35 | { 36 | public EmbeddingModelEndpoint(string endpoint, int maxTokens = 384) : base(endpoint, "embeddings", maxTokens) 37 | { 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/ERNIE-Bot.SDK/ModelEndpoints.cs: -------------------------------------------------------------------------------- 1 | namespace ERNIE_Bot.SDK 2 | { 3 | public static class ModelEndpoints 4 | { 5 | /// 6 | /// ERNIE Bot 8k Chat Model 7 | /// 8 | public static readonly ModelEndpoint ERNIE_Bot_8K = new("ernie_bot_8k", 6000); 9 | 10 | /// 11 | /// ERNIE Bot 4 Chat Model 12 | /// 13 | public static readonly ModelEndpoint ERNIE_Bot_4 = new("completions_pro", 5000); 14 | 15 | /// 16 | /// ERNIE Bot Chat Model 17 | /// 18 | public static readonly ModelEndpoint ERNIE_Bot = new("completions"); 19 | 20 | /// 21 | /// 22 | /// 23 | public static readonly ModelEndpoint ERNIE_Bot_35_4K_0205 = new("ernie-3.5-4k-0205"); 24 | 25 | /// 26 | /// 27 | /// 28 | public static readonly ModelEndpoint ERNIE_Bot_35_8K_0205 = new("ernie-3.5-8k-0205"); 29 | 30 | /// 31 | /// ERNIE Bot Turbo Chat Model 32 | /// 33 | public static readonly ModelEndpoint ERNIE_Bot_Turbo = new("eb-instant", 7000); 34 | 35 | /// 36 | /// ERNIE Bot Speed Chat Model 37 | /// 38 | public static readonly ModelEndpoint ERNIE_Bot_Speed = new("ernie_speed", 7000); 39 | 40 | /// 41 | /// BLOOMZ 7B Chat Model 42 | /// 43 | public static readonly ModelEndpoint BLOOMZ_7B = new("bloomz_7b1"); 44 | 45 | /// 46 | /// Llama2 7b Chat Model 47 | /// 48 | public static readonly ModelEndpoint Llama_2_7b_chat = new("llama_2_7b"); 49 | 50 | /// 51 | /// Llama2 13b Chat Model 52 | /// 53 | public static readonly ModelEndpoint Llama_2_13b_chat = new("llama_2_13b"); 54 | 55 | /// 56 | /// Llama2 70b Chat Model 57 | /// 58 | public static readonly ModelEndpoint Llama_2_70b_chat = new("llama_2_70b"); 59 | 60 | /// 61 | /// Qianfan BLOOMZ 7B Chat Model 62 | /// 63 | public static readonly ModelEndpoint Qianfan_BLOOMZ_7B_compressed = new("qianfan_bloomz_7b_compressed"); 64 | 65 | /// 66 | /// Qianfan Chinese Llama2 7B Chat Model 67 | /// 68 | public static readonly ModelEndpoint Qianfan_Chinese_Llama_2_7b = new("qianfan_chinese_llama_2_7b"); 69 | 70 | /// 71 | /// Qianfan Chinese Llama2 13B Chat Model 72 | /// 73 | public static readonly ModelEndpoint Qianfan_Chinese_Llama_2_13b = new("qianfan_chinese_llama_2_13b"); 74 | 75 | /// 76 | /// ChatGLM2 6b 32k Chat Model 77 | /// 78 | public static readonly ModelEndpoint ChatGLM2_6b_32k = new("chatglm2_6b_32k"); 79 | 80 | /// 81 | /// XuanYuan 70B Chat 4bit 82 | /// 83 | public static readonly ModelEndpoint XuanYuan_70B_Chat_4bit = new("xuanyuan_70b_chat"); 84 | 85 | /// 86 | /// ChatLaw 87 | /// 88 | public static readonly ModelEndpoint ChatLaw = new("chatlaw"); 89 | 90 | /// 91 | /// AquilaChat-7B Chat Model 92 | /// 93 | public static readonly ModelEndpoint AquilaChat_7b = new("aquilachat_7b"); 94 | 95 | /// 96 | /// Embedding-V1 Embedding Model 97 | /// 98 | public static readonly EmbeddingModelEndpoint Embedding_v1 = new("embedding-v1"); 99 | 100 | /// 101 | /// bge-large-zh Embedding Model 102 | /// 103 | public static readonly EmbeddingModelEndpoint bge_large_zh = new("bge_large_zh", 512); 104 | 105 | /// 106 | /// bge-large-en Embedding Model 107 | /// 108 | public static readonly EmbeddingModelEndpoint bge_large_en = new("bge_large_en", 512); 109 | 110 | /// 111 | /// 112 | /// 113 | public static readonly EmbeddingModelEndpoint Tao_8k = new("tao_8k", 8192); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/ERNIE-Bot.SDK/Models/AccessTokenResponse.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace ERNIE_Bot.SDK.Models 4 | { 5 | /// 6 | /// Access Token Response 7 | /// 8 | public class AccessTokenResponse 9 | { 10 | [JsonPropertyName("access_token")] 11 | public string AccessToken { get; set; } = string.Empty; 12 | 13 | [JsonPropertyName("refresh_token")] 14 | public string RefreshToken { get; set; } = string.Empty; 15 | 16 | [JsonPropertyName("expires_in")] 17 | public long Expiration { get; set; } 18 | 19 | [JsonPropertyName("session_key")] 20 | public string SessionKey { get; set; } = string.Empty; 21 | 22 | [JsonPropertyName("session_secret")] 23 | public string SessionSecret { get; set; } = string.Empty; 24 | 25 | [JsonPropertyName("scope")] 26 | public string Scope { get; set; } = string.Empty; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/ERNIE-Bot.SDK/Models/ChatRequest.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace ERNIE_Bot.SDK.Models 4 | { 5 | public class ChatRequest 6 | { 7 | [JsonPropertyName("system")] 8 | public string? System { get; set; } 9 | 10 | [JsonPropertyName("messages")] 11 | public List Messages { get; set; } = new List(); 12 | 13 | public bool? Stream { get; set; } 14 | 15 | [JsonPropertyName("user_id")] 16 | public string? UserId { get; set; } 17 | } 18 | 19 | public class ChatCompletionsRequest : ChatRequest 20 | { 21 | [JsonPropertyName("temperature")] 22 | public float? Temperature { get; set; } 23 | 24 | [JsonPropertyName("top_p")] 25 | public float? TopP { get; set; } 26 | 27 | [JsonPropertyName("penalty_score")] 28 | public float? PenaltyScore { get; set; } 29 | 30 | /// 31 | /// 指定响应内容的格式,说明:
32 | ///(1)可选值:
33 | ///· json_object:以json格式返回,可能出现不满足效果情况
34 | ///· text:以文本格式返回
35 | ///(2)如果不填写参数response_format值,默认为text
36 | ///
37 | [JsonPropertyName("response_format")] 38 | public string? ResponseFormat { get; set; } 39 | 40 | /// 41 | /// 指定模型最大输出token数,范围[2, 2048] 42 | /// 43 | [JsonPropertyName("max_output_tokens")] 44 | public int? MaxTokens { get; set; } 45 | 46 | /// 47 | /// 生成停止标识,当模型生成结果以stop中某个元素结尾时,停止文本生成。 48 | ///
说明: 49 | ///
(1)每个元素长度不超过20字符 50 | ///
(2)最多4个元素 51 | ///
52 | [JsonPropertyName("stop")] 53 | public string[]? Stops { get; set; } 54 | 55 | /// 56 | /// 是否强制关闭实时搜索功能,默认false,表示不关闭 57 | /// 58 | [JsonPropertyName("disable_search")] 59 | public bool? DisableSearch { get; set; } 60 | 61 | /// 62 | /// 是否开启引用返回,说明: 63 | ///(1)开启后,有概率触发搜索溯源信息search_info,search_info内容见响应参数介绍 64 | ///(2)默认false,不开启 65 | [JsonPropertyName("enable_citation")] 66 | public bool? EnableCitation { get; set; } 67 | } 68 | 69 | public class FunctionInfo 70 | { 71 | 72 | } 73 | 74 | public class Message 75 | { 76 | [JsonPropertyName("role")] 77 | public string Role { get; set; } = string.Empty; 78 | 79 | [JsonPropertyName("content")] 80 | public string Content { get; set; } = string.Empty; 81 | 82 | [JsonPropertyName("name")] 83 | public string? Name { get; set; } 84 | } 85 | public static class MessageRole 86 | { 87 | public const string User = "user"; 88 | public const string Assistant = "assistant"; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/ERNIE-Bot.SDK/Models/ChatResponse.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace ERNIE_Bot.SDK.Models 4 | { 5 | public class ChatResponse 6 | { 7 | [JsonPropertyName("id")] 8 | public string Id { get; set; } = string.Empty; 9 | 10 | [JsonPropertyName("object")] 11 | public string Object { get; set; } = "chat.completion"; 12 | 13 | [JsonPropertyName("created")] 14 | public int Created { get; set; } 15 | 16 | [JsonPropertyName("sentence_id")] 17 | public int? SentenceId { get; set; } 18 | 19 | [JsonPropertyName("is_truncated")] 20 | public bool? IsTruncated { get; set; } 21 | 22 | [JsonPropertyName("is_end")] 23 | public bool? IsEnd { get; set; } 24 | 25 | [JsonPropertyName("result")] 26 | public string Result { get; set; } = string.Empty; 27 | 28 | [JsonPropertyName("need_clear_history")] 29 | public bool NeedClearHistory { get; set; } 30 | 31 | [JsonPropertyName("usage")] 32 | public UsageData Usage { get; set; } = new UsageData(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/ERNIE-Bot.SDK/Models/ERNIEBotError.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace ERNIE_Bot.SDK.Models 4 | { 5 | public class ERNIEBotError 6 | { 7 | [JsonPropertyName("error_code")] 8 | public int Code { get; set; } = -1; 9 | 10 | [JsonPropertyName("error_msg")] 11 | public string Message { get; set; } = "unknown"; 12 | } 13 | 14 | public class ERNIEBotException : Exception 15 | { 16 | public ERNIEBotError Error { get; } 17 | 18 | public ERNIEBotException(ERNIEBotError? error) : base(error?.Message) 19 | { 20 | Error = error ?? new ERNIEBotError(); 21 | } 22 | 23 | public ERNIEBotException(int code, string message) 24 | : this(new ERNIEBotError() 25 | { 26 | Code = code, 27 | Message = message 28 | }) 29 | { } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/ERNIE-Bot.SDK/Models/EmbeddingRequest.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace ERNIE_Bot.SDK.Models 4 | { 5 | public class EmbeddingsRequest 6 | { 7 | [JsonPropertyName("input")] 8 | public List Input { get; set; } = new List(); 9 | 10 | [JsonPropertyName("user_id")] 11 | public string? UserId { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/ERNIE-Bot.SDK/Models/EmbeddingsResponse.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace ERNIE_Bot.SDK.Models 4 | { 5 | public class EmbeddingsResponse 6 | { 7 | [JsonPropertyName("id")] 8 | public string Id { get; set; } = string.Empty; 9 | 10 | [JsonPropertyName("object")] 11 | public string ObjectType { get; set; } = "embedding_list"; 12 | 13 | [JsonPropertyName("created")] 14 | public int Created { get; set; } 15 | 16 | [JsonPropertyName("data")] 17 | public List Data { get; set; } = new List(); 18 | 19 | [JsonPropertyName("usage")] 20 | public UsageData Usage { get; set; } = new UsageData(); 21 | } 22 | 23 | public class EmbeddingData 24 | { 25 | [JsonPropertyName("object")] 26 | public string ObjectType { get; set; } = "embedding"; 27 | 28 | [JsonPropertyName("embedding")] 29 | public List Embedding { get; set; } = new List(); 30 | 31 | [JsonPropertyName("index")] 32 | public int Index { get; set; } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/ERNIE-Bot.SDK/Models/UsageData.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace ERNIE_Bot.SDK.Models 4 | { 5 | public class UsageData 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 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/ERNIE-Bot.SDK/TokenStore/DefaultTokenStore.cs: -------------------------------------------------------------------------------- 1 | namespace ERNIE_Bot.SDK 2 | { 3 | public class DefaultTokenStore : ITokenStore 4 | { 5 | private static string? _access_token = null; 6 | private static DateTime? _expires_at = null; 7 | 8 | public Task GetTokenAsync(CancellationToken cancellationToken) 9 | { 10 | cancellationToken.ThrowIfCancellationRequested(); 11 | 12 | if (_expires_at.HasValue && _expires_at.Value > DateTime.UtcNow) 13 | { 14 | return Task.FromResult(_access_token); 15 | } 16 | return Task.FromResult((string?)null); 17 | } 18 | 19 | public Task SaveTokenAsync(string accessToken, TimeSpan expiration, CancellationToken cancellationToken) 20 | { 21 | cancellationToken.ThrowIfCancellationRequested(); 22 | 23 | _access_token = accessToken; 24 | _expires_at = DateTime.UtcNow.Add(expiration); 25 | return Task.CompletedTask; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/ERNIE-Bot.SDK/TokenStore/ITokenStore.cs: -------------------------------------------------------------------------------- 1 | namespace ERNIE_Bot.SDK 2 | { 3 | public interface ITokenStore 4 | { 5 | Task SaveTokenAsync(string accessToken, TimeSpan expiration, CancellationToken cancellationToken); 6 | 7 | Task GetTokenAsync(CancellationToken cancellationToken); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/ERNIE-Bot.SDK/TokenStore/MemoryTokenStore.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Caching.Distributed; 2 | using Microsoft.Extensions.Caching.Memory; 3 | 4 | namespace ERNIE_Bot.SDK 5 | { 6 | public class MemoryTokenStore : ITokenStore 7 | { 8 | private readonly IMemoryCache _cache; 9 | 10 | public MemoryTokenStore(IMemoryCache cache) 11 | { 12 | this._cache = cache; 13 | } 14 | 15 | public Task GetTokenAsync(CancellationToken cancellationToken) 16 | { 17 | cancellationToken.ThrowIfCancellationRequested(); 18 | 19 | _cache.TryGetValue(Defaults.TokenCacheName, out string? accessToken); 20 | return Task.FromResult(accessToken); 21 | } 22 | 23 | public Task SaveTokenAsync(string accessToken, TimeSpan expiration, CancellationToken cancellationToken) 24 | { 25 | cancellationToken.ThrowIfCancellationRequested(); 26 | 27 | _cache.Set(Defaults.TokenCacheName, accessToken, expiration); 28 | return Task.CompletedTask; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/ERNIE-Bot.SDK/Tokenizer.cs: -------------------------------------------------------------------------------- 1 | using System.Text.RegularExpressions; 2 | 3 | namespace ERNIE_Bot.SDK 4 | { 5 | /// 6 | /// This class provides methods for tokenizing text. 7 | /// 8 | public static class Tokenizer 9 | { 10 | public static int ApproxNumTokens(string text) 11 | { 12 | int chinese = Regex.Matches(text, @"\p{IsCJKUnifiedIdeographs}").Count; 13 | int english = Regex.Replace(text, @"[^\p{IsBasicLatin}-]", " ") 14 | .Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries) 15 | .Count(w => !string.IsNullOrWhiteSpace(w) && w != "-" && w != "_"); 16 | 17 | return chinese + (int)Math.Floor(english * 1.3); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/ERNIE-Bot.SDK/readme.md: -------------------------------------------------------------------------------- 1 | # ERNIE-Bot SDK 2 | 3 | [![NuGet](https://img.shields.io/nuget/v/ERNIE-Bot.SDK?label=sdk)](https://www.nuget.org/packages/ERNIE-Bot.SDK/) 4 | 5 | ERNIE-Bot(文心千帆) .NET SDK 6 | 7 | ## 安装 8 | 9 | ``` 10 | dotnet add package ERNIE-Bot.SDK --prerelease 11 | ``` 12 | 13 | ## 使用 14 | 15 | 引入该 Package 之后,实例化`ERNIEBotClient` 即可使用。 16 | 17 | ```csharp 18 | var clientId = builder.Configuration["ClientId"]; 19 | var secret = builder.Configuration["ClientSecret"]; 20 | 21 | var client = new ERNIEBotClient(clientId, secret); 22 | ``` 23 | 24 | ### ChatCompletion 25 | 26 | 直接使用ChatAsync方法可以完成对话。 27 | 28 | 其中 ModelEndpoint 是预置的模型地址,可以使用 ModelEndpoints 类来获取所有支持的模型地址。 29 | 30 | ```csharp 31 | await client.ChatAsync(new ChatCompletionsRequest() 32 | { 33 | Messages = new List 34 | { 35 | new Message() 36 | { 37 | Content = input.Text, 38 | Role = MessageRole.User 39 | } 40 | } 41 | }, ModelEndpoints.ERNIE_Bot); 42 | ``` 43 | 44 | ### ChatCompletionStream 45 | 46 | 使用 ChatStreamAsync 方法可以获取一个流,该流会不断的返回对话结果。 47 | 48 | ```csharp 49 | var results = client.ChatStreamAsync(new ChatCompletionsRequest() 50 | { 51 | Messages = new List 52 | { 53 | new Message() 54 | { 55 | Content = input.Text, 56 | Role = MessageRole.User 57 | } 58 | } 59 | }, ModelEndpoints.ERNIE_Bot); 60 | 61 | ``` 62 | 63 | 可以使用一下方法获取流中的数据。 64 | 65 | ```csharp 66 | await foreach (var result in results) 67 | { 68 | // do something with result 69 | } 70 | ``` 71 | 72 | ### Embedding 73 | 74 | 使用 EmbeddingAsync 方法可以获取文本的 Embedding。 75 | 同样可以使用 ModelEndpoints 类来获取所支持的Embedding模型的地址。 76 | 77 | ```csharp 78 | var result = await _client.EmbeddingsAsync(new EmbeddingsRequest() 79 | { 80 | Input = new List() 81 | { 82 | input.Text 83 | } 84 | },ModelEndpoints.Embedding_v1); 85 | ``` 86 | 87 | ### 自定义模型 88 | 89 | 如果您使用了自定义的模型服务,可以通过以下方法声明自定义模型的地址。 90 | 91 | ```csharp 92 | var endpoint = new ModelEndpoint("{申请发布时填写的API地址}"); 93 | ``` 94 | 95 | 96 | #### API 鉴权令牌的存储和管理 97 | 98 | 由于百度的接口采用了AccessToken的鉴权方式,所以需要在使用之前先获取AccessToken,然后在请求的时候带上AccessToken。为了方便管理,SDK提供了`ITokenStore`接口,用于存储和管理AccessToken。 99 | 100 | 用户可自行实现该接口,自行管理AccessToken的存储和更新。SDK提供了`MemoryTokenStore`,在内存中存储AccessToken,该实现依赖于`MemoryCache`。 101 | 102 | 103 | ## 接口支持 104 | 105 | - [x] API 鉴权 106 | - [x] ERNIE-Bot 107 | - [x] ERNIE-Bot-turbo 108 | - [x] Embedding-V1 109 | - [x] BLOOMZ-7B 110 | - [x] Llama_2_7b_chat 111 | - [x] Llama_2_13b_chat 112 | - [x] Llama_2_70b_chat 113 | - [x] Qianfan_BLOOMZ_7B_compressed 114 | - [x] Qianfan_Chinese_Llama_2_7b 115 | - [x] ChatGLM2_6b_32k 116 | - [x] AquilaChat_7b 117 | - [x] bge_large_zh 118 | - [x] bge_large_en 119 | - [x] 自定义chat模型 120 | - [ ] Prompt模版 121 | 122 | 123 | -------------------------------------------------------------------------------- /src/ERNIE-Bot.SemanticKernel/ERNIE-Bot.SemanticKernel.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | ERNIE_Bot.SemanticKernel 5 | ERNIE-Bot.SemanticKernel 6 | LLM,ERNIE-Bot,Semantic Kernel,AI 7 | ERNIE-Bot(文心千帆) 集成 Semantic Kernel 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/ERNIE-Bot.SemanticKernel/ERNIEBotAIRequestSettings.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.SemanticKernel; 2 | using System.Text.Json; 3 | using System.Text.Json.Serialization; 4 | 5 | public class ERNIEBotAIRequestSettings : PromptExecutionSettings 6 | { 7 | [JsonPropertyName("temperature")] 8 | public float? Temperature { get; set; } 9 | 10 | [JsonPropertyName("top_p")] 11 | public float? TopP { get; set; } 12 | 13 | [JsonPropertyName("penalty_score")] 14 | public float? PenaltyScore { get; set; } 15 | 16 | [JsonPropertyName("response_format")] 17 | public string? ResponseFormat { get; set; } 18 | 19 | [JsonPropertyName("max_output_tokens")] 20 | public int? MaxTokens { get; set; } 21 | 22 | public static ERNIEBotAIRequestSettings FromRequestSettings(PromptExecutionSettings? requestSettings, int? defaultMaxTokens = null) 23 | { 24 | if (requestSettings is null) 25 | { 26 | return new ERNIEBotAIRequestSettings(); 27 | } 28 | 29 | if (requestSettings is ERNIEBotAIRequestSettings requestSettingERNIEBotAIRequestSettings) 30 | { 31 | return requestSettingERNIEBotAIRequestSettings; 32 | } 33 | 34 | var json = JsonSerializer.Serialize(requestSettings); 35 | var ernieBotAIRequestSettings = JsonSerializer.Deserialize(json, s_options); 36 | 37 | if (ernieBotAIRequestSettings is not null) 38 | { 39 | return ernieBotAIRequestSettings; 40 | } 41 | 42 | throw new ArgumentException($"Invalid request settings, cannot convert to {nameof(ERNIEBotAIRequestSettings)}", nameof(requestSettings)); 43 | } 44 | 45 | private static readonly JsonSerializerOptions s_options = CreateOptions(); 46 | 47 | private static JsonSerializerOptions CreateOptions() 48 | { 49 | JsonSerializerOptions options = new() 50 | { 51 | WriteIndented = true, 52 | MaxDepth = 20, 53 | AllowTrailingCommas = true, 54 | PropertyNameCaseInsensitive = true, 55 | ReadCommentHandling = JsonCommentHandling.Skip 56 | }; 57 | 58 | return options; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/ERNIE-Bot.SemanticKernel/ERNIEBotChatCompletion.cs: -------------------------------------------------------------------------------- 1 | using Connectors.AI.ERNIEBot; 2 | using ERNIE_Bot.SDK; 3 | using ERNIE_Bot.SDK.Models; 4 | using Microsoft.SemanticKernel; 5 | using Microsoft.SemanticKernel.ChatCompletion; 6 | using Microsoft.SemanticKernel.TextGeneration; 7 | using Microsoft.SemanticKernel.Services; 8 | using System; 9 | using System.Runtime.CompilerServices; 10 | 11 | public class ERNIEBotChatCompletion : IChatCompletionService, ITextGenerationService 12 | { 13 | protected readonly ERNIEBotClient _client; 14 | private readonly ModelEndpoint _modelEndpoint; 15 | private readonly Dictionary _attributes = new(); 16 | 17 | public IReadOnlyDictionary Attributes => this._attributes; 18 | 19 | public ERNIEBotChatCompletion(ERNIEBotClient client, ModelEndpoint? modelEndpoint = null) 20 | { 21 | this._client = client; 22 | 23 | this._modelEndpoint = modelEndpoint ?? ModelEndpoints.ERNIE_Bot; 24 | } 25 | 26 | public async Task> GetChatMessageContentsAsync(ChatHistory chat, PromptExecutionSettings? executionSettings = null, Kernel? kernel = null, CancellationToken cancellationToken = default) 27 | { 28 | var messages = ChatHistoryToMessages(chat, out var system); 29 | executionSettings ??= new PromptExecutionSettings(); 30 | 31 | var settings = ERNIEBotAIRequestSettings.FromRequestSettings(executionSettings); 32 | 33 | ChatResponse result = await InternalCompletionsAsync(messages, 34 | settings.Temperature, 35 | settings.TopP, 36 | settings.PenaltyScore, 37 | system, 38 | cancellationToken 39 | ).ConfigureAwait(false); 40 | var metadata = GetResponseMetadata(result); 41 | return new List() { new ERNIEBotChatMessage(result, metadata) }; 42 | } 43 | 44 | public async IAsyncEnumerable GetStreamingChatMessageContentsAsync(ChatHistory chatHistory, PromptExecutionSettings? executionSettings = null, Kernel? kernel = null, [EnumeratorCancellation] CancellationToken cancellationToken = default) 45 | { 46 | var messages = ChatHistoryToMessages(chatHistory, out var system); 47 | 48 | executionSettings ??= new PromptExecutionSettings(); 49 | 50 | var settings = ERNIEBotAIRequestSettings.FromRequestSettings(executionSettings); 51 | 52 | var results = InternalCompletionsStreamAsync(messages, 53 | settings.Temperature, 54 | settings.TopP, 55 | settings.PenaltyScore, 56 | system, 57 | cancellationToken 58 | ).ConfigureAwait(false); 59 | await foreach (var result in results) 60 | { 61 | var metadata = GetResponseMetadata(result); 62 | yield return new ERNIEBotStreamingChatMessage(result, metadata); 63 | } 64 | } 65 | 66 | public async Task> GetTextContentsAsync(string prompt, PromptExecutionSettings? executionSettings = null, Kernel? kernel = null, CancellationToken cancellationToken = default) 67 | { 68 | executionSettings ??= new PromptExecutionSettings(); 69 | var messages = StringToMessages(prompt); 70 | 71 | var settings = ERNIEBotAIRequestSettings.FromRequestSettings(executionSettings); 72 | 73 | var result = await InternalCompletionsAsync(messages, 74 | settings.Temperature, 75 | settings.TopP, 76 | settings.PenaltyScore, 77 | null, 78 | cancellationToken 79 | ).ConfigureAwait(false); 80 | 81 | return new List() { new(result.Result, metadata: GetResponseMetadata(result)) }.AsReadOnly(); 82 | } 83 | 84 | public async IAsyncEnumerable GetStreamingTextContentsAsync(string prompt, PromptExecutionSettings? executionSettings = null, Kernel? kernel = null, [EnumeratorCancellation] CancellationToken cancellationToken = default) 85 | { 86 | var messages = StringToMessages(prompt); 87 | executionSettings ??= new PromptExecutionSettings(); 88 | 89 | var settings = ERNIEBotAIRequestSettings.FromRequestSettings(executionSettings); 90 | 91 | var results = InternalCompletionsStreamAsync(messages, 92 | settings.Temperature, 93 | settings.TopP, 94 | settings.PenaltyScore, 95 | null, 96 | cancellationToken 97 | ); 98 | await foreach (var result in results) 99 | { 100 | yield return new StreamingTextContent(result.Result, metadata: GetResponseMetadata(result)); 101 | } 102 | } 103 | 104 | 105 | public ChatHistory CreateNewChat(string? instructions = null) 106 | { 107 | var history = new ChatHistory(); 108 | 109 | if (instructions != null) 110 | { 111 | history.AddSystemMessage(instructions); 112 | } 113 | 114 | return history; 115 | } 116 | 117 | private static Dictionary GetResponseMetadata(ChatResponse result) 118 | { 119 | return new Dictionary() 120 | { 121 | {nameof(result.Id), result.Id}, 122 | {nameof(result.Created), result.Created}, 123 | {nameof(result.NeedClearHistory), result.NeedClearHistory}, 124 | {nameof(result.Usage), result.Usage } 125 | }; 126 | } 127 | 128 | private List StringToMessages(string text) 129 | { 130 | return 131 | [ 132 | new Message() 133 | { 134 | Role = MessageRole.User, 135 | Content = text 136 | } 137 | ]; 138 | } 139 | 140 | private List ChatHistoryToMessages(ChatHistory chatHistory, out string? system) 141 | { 142 | system = null; 143 | 144 | if (chatHistory.Count == 1) 145 | { 146 | return StringToMessages(chatHistory.First().Content!); 147 | } 148 | 149 | if (chatHistory.First().Role == AuthorRole.System) 150 | { 151 | system = chatHistory.First().Content; 152 | } 153 | 154 | return chatHistory 155 | .Where(_ => _.Role != AuthorRole.System) 156 | .Select(m => new Message() 157 | { 158 | Role = AuthorRoleToMessageRole(m.Role), 159 | Content = m.Content! 160 | }).ToList(); 161 | } 162 | 163 | private string AuthorRoleToMessageRole(AuthorRole role) 164 | { 165 | if (role == AuthorRole.User) return MessageRole.User; 166 | if (role == AuthorRole.Assistant) return MessageRole.Assistant; 167 | return MessageRole.User; 168 | } 169 | 170 | protected virtual async Task InternalCompletionsAsync(List messages, float? temperature, float? topP, float? penaltyScore, string? system, CancellationToken cancellationToken) 171 | { 172 | try 173 | { 174 | return await _client.ChatAsync(new ChatCompletionsRequest() 175 | { 176 | Messages = messages, 177 | Temperature = temperature, 178 | TopP = topP, 179 | PenaltyScore = penaltyScore, 180 | System = system, 181 | }, _modelEndpoint, cancellationToken).ConfigureAwait(false); 182 | } 183 | catch (ERNIEBotException ex) 184 | { 185 | throw new KernelException(ex.Error.Message, ex); 186 | } 187 | } 188 | 189 | protected virtual IAsyncEnumerable InternalCompletionsStreamAsync(List messages, float? temperature, float? topP, float? penaltyScore, string? system, CancellationToken cancellationToken) 190 | { 191 | try 192 | { 193 | return _client.ChatStreamAsync(new ChatCompletionsRequest() 194 | { 195 | Messages = messages, 196 | Temperature = temperature, 197 | TopP = topP, 198 | PenaltyScore = penaltyScore, 199 | System = system, 200 | }, _modelEndpoint, cancellationToken); 201 | } 202 | catch (ERNIEBotException ex) 203 | { 204 | throw new KernelException(ex.Error.Message, ex); 205 | } 206 | } 207 | 208 | } 209 | -------------------------------------------------------------------------------- /src/ERNIE-Bot.SemanticKernel/ERNIEBotChatResult.cs: -------------------------------------------------------------------------------- 1 | using ERNIE_Bot.SDK.Models; 2 | using Microsoft.SemanticKernel; 3 | using Microsoft.SemanticKernel.ChatCompletion; 4 | 5 | namespace Connectors.AI.ERNIEBot 6 | { 7 | internal class ERNIEBotChatMessage : ChatMessageContent 8 | { 9 | public ERNIEBotChatMessage(ChatResponse response, IReadOnlyDictionary? metadata = null) 10 | : base(AuthorRole.Assistant, response.Result, metadata: metadata) 11 | { 12 | 13 | } 14 | } 15 | 16 | internal class ERNIEBotStreamingChatMessage : StreamingChatMessageContent 17 | { 18 | public ERNIEBotStreamingChatMessage(ChatResponse response, IReadOnlyDictionary? metadata = null) 19 | : base(AuthorRole.Assistant, response.Result, response, metadata: metadata) 20 | { 21 | 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/ERNIE-Bot.SemanticKernel/ERNIEBotEmbeddingGeneration.cs: -------------------------------------------------------------------------------- 1 | using ERNIE_Bot.SDK; 2 | using ERNIE_Bot.SDK.Models; 3 | using Microsoft.SemanticKernel; 4 | using Microsoft.SemanticKernel.Embeddings; 5 | 6 | public class ERNIEBotEmbeddingGeneration : ITextEmbeddingGenerationService 7 | { 8 | private readonly ERNIEBotClient _client; 9 | private readonly Dictionary _attributes = new(); 10 | public IReadOnlyDictionary Attributes => this._attributes; 11 | 12 | public ERNIEBotEmbeddingGeneration(ERNIEBotClient client) 13 | { 14 | this._client = client; 15 | } 16 | 17 | public async Task>> GenerateEmbeddingsAsync(IList data, Kernel? kernel = null, CancellationToken cancellationToken = default) 18 | { 19 | try 20 | { 21 | var embeddings = await _client.EmbeddingsAsync(new EmbeddingsRequest() 22 | { 23 | Input = data.ToList() 24 | }, cancellationToken).ConfigureAwait(false); 25 | 26 | // TODO: ITextEmbeddingGeneration not support ReadOnlyMemory 27 | return embeddings.Data.Select(d => new ReadOnlyMemory(d.Embedding.Select(e => (float)e).ToArray())).ToList(); 28 | } 29 | catch (ERNIEBotException ex) 30 | { 31 | throw new KernelException(ex.Error.Message, ex); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/ERNIE-Bot.SemanticKernel/ERNIEBotKernelBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using ERNIE_Bot.SDK; 2 | using Microsoft.Extensions.Configuration; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Microsoft.Extensions.Logging; 5 | using Microsoft.SemanticKernel.ChatCompletion; 6 | using Microsoft.SemanticKernel.TextGeneration; 7 | using Microsoft.SemanticKernel.Memory; 8 | 9 | namespace Microsoft.SemanticKernel 10 | { 11 | public static class ERNIEBotKernelBuilderExtensions 12 | { 13 | /// 14 | /// Adds the ERNIE Bot chat completion service to the builder with the specified service and configuration, 15 | /// along with optional parameters. 16 | /// 17 | /// The kernel builder. 18 | /// The service provider. 19 | /// The configuration provider. 20 | /// The service identifier. 21 | /// The model endpoint. 22 | /// The updated kernel builder. 23 | public static IKernelBuilder WithERNIEBotChatCompletionService(this IKernelBuilder builder, 24 | IServiceProvider service, IConfiguration configuration, 25 | string? serviceId = null, 26 | ModelEndpoint? modelEndpoint = null) 27 | { 28 | var client = CreateERNIEBotClient(service, configuration); 29 | var generation = new ERNIEBotChatCompletion(client, modelEndpoint); 30 | builder.Services.AddKeyedSingleton(serviceId, generation); 31 | builder.Services.AddKeyedSingleton(serviceId, generation); 32 | 33 | return builder; 34 | } 35 | 36 | /// 37 | /// 38 | /// 39 | /// 40 | /// 41 | /// 42 | /// 43 | /// 44 | /// 45 | /// 46 | /// 47 | public static IKernelBuilder WithERNIEBotChatCompletionService(this IKernelBuilder builder, 48 | string clientId, string secret, 49 | string? serviceId = null, 50 | ModelEndpoint? modelEndpoint = null) 51 | { 52 | 53 | var client = CreateERNIEBotClient(clientId, secret); 54 | var generation = new ERNIEBotChatCompletion(client, modelEndpoint); 55 | builder.Services.AddKeyedSingleton(serviceId, generation); 56 | builder.Services.AddKeyedSingleton(serviceId, generation); 57 | 58 | return builder; 59 | } 60 | 61 | /// 62 | /// 63 | /// 64 | /// 65 | /// 66 | /// 67 | /// 68 | 69 | public static MemoryBuilder WithERNIEBotEmbeddingGenerationService(this MemoryBuilder builder, 70 | IServiceProvider service, IConfiguration configuration) 71 | { 72 | var client = CreateERNIEBotClient(service, configuration); 73 | var generation = new ERNIEBotEmbeddingGeneration(client); 74 | builder.WithTextEmbeddingGeneration(generation); 75 | return builder; 76 | } 77 | /// 78 | /// 79 | /// 80 | /// 81 | /// 82 | /// 83 | /// 84 | public static MemoryBuilder WithERNIEBotEmbeddingGenerationService(this MemoryBuilder builder, 85 | string clientId, string secret) 86 | { 87 | var client = CreateERNIEBotClient(clientId, secret); 88 | var generation = new ERNIEBotEmbeddingGeneration(client); 89 | builder.WithTextEmbeddingGeneration(generation); 90 | return builder; 91 | } 92 | 93 | private static ERNIEBotClient CreateERNIEBotClient(string clientId, string secret) 94 | { 95 | Requires.NotNullOrWhiteSpace(clientId, "ClientId"); 96 | Requires.NotNullOrWhiteSpace(secret, "ClientSecret"); 97 | 98 | return new ERNIEBotClient(clientId, secret, null, null, null); 99 | } 100 | 101 | private static ERNIEBotClient CreateERNIEBotClient(IServiceProvider service, IConfiguration configuration) 102 | { 103 | var client = service.GetService()?.CreateClient(); 104 | 105 | var tokenStore = service.GetService(); 106 | var logger = service.GetService>(); 107 | 108 | var clientId = configuration["ClientId"]!; 109 | var secret = configuration["ClientSecret"]!; 110 | 111 | Requires.NotNullOrWhiteSpace(clientId, "ClientId"); 112 | Requires.NotNullOrWhiteSpace(secret, "ClientSecret"); 113 | 114 | return new ERNIEBotClient(clientId, secret, client, tokenStore, logger); 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/ERNIE-Bot.SemanticKernel/readme.md: -------------------------------------------------------------------------------- 1 | # ERNIE-Bot Semantic Kernel 2 | 3 | [![NuGet](https://img.shields.io/nuget/v/ERNIE-Bot.SemanticKernel?label=sk)](https://www.nuget.org/packages/ERNIE-Bot.SemanticKernel/) 4 | 5 | 6 | ERNIE-Bot(文心千帆) Semantic Kernel 集成 7 | 8 | ## 安装 9 | 10 | ``` 11 | dotnet add package ERNIE-Bot.SemanticKernel --prerelease 12 | ``` 13 | 14 | ## 使用 15 | 16 | ``` 17 | 18 | builder.Services.AddScoped(svc => 19 | { 20 | var kernel = Kernel.Builder 21 | // 使用 ERNIE Bot 22 | .WithERNIEBotChatCompletionService(svc, builder.Configuration, "ernie_bot", ModelEndpoints.ERNIE_Bot) 23 | .Build(); 24 | return kernel; 25 | }); 26 | 27 | builder.Services.AddScoped(svc => 28 | { 29 | var memory = new MemoryBuilder() 30 | .WithERNIEBotEmbeddingGenerationService(svc, builder.Configuration) 31 | .WithMemoryStore(new VolatileMemoryStore()) 32 | .Build(); 33 | return memory; 34 | }); 35 | ``` 36 | 37 | 38 | ## 功能 39 | 40 | - [x] IChatCompletion 41 | - [x] ITextCompletion 42 | - [x] ITextEmbeddingGeneration 43 | -------------------------------------------------------------------------------- /tests/ERNIE-Bot.SDK.Tests/ERNIE-Bot.SDK.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0 5 | ERNIE_BOT.SDK.Tests 6 | enable 7 | enable 8 | 9 | false 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | PreserveNewest 23 | 24 | 25 | PreserveNewest 26 | 27 | 28 | PreserveNewest 29 | 30 | 31 | PreserveNewest 32 | 33 | 34 | PreserveNewest 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | runtime; build; native; contentfiles; analyzers; buildtransitive 44 | all 45 | 46 | 47 | runtime; build; native; contentfiles; analyzers; buildtransitive 48 | all 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /tests/ERNIE-Bot.SDK.Tests/ERNIEBotClientTests.cs: -------------------------------------------------------------------------------- 1 | using ERNIE_Bot.SDK.Models; 2 | using ERNIE_BOT.SDK.Tests; 3 | 4 | namespace ERNIE_Bot.SDK.Tests 5 | { 6 | public class ERNIEBotClientTests 7 | { 8 | [Fact] 9 | public void ClientCreateTest() 10 | { 11 | var clientId = "test"; 12 | var clientSecret = "test"; 13 | 14 | var client = new ERNIEBotClient(clientId, clientSecret); 15 | 16 | Assert.NotNull(client); 17 | } 18 | 19 | [Fact()] 20 | public async Task ChatCompletionsAsyncTest() 21 | { 22 | var httpClient = await TestHelper.FakeHttpClient("chat_response.txt"); 23 | var fakeTokenStore = new TokenStoreHelper("test_token"); 24 | var client = new ERNIEBotClient("test", "test", httpClient, fakeTokenStore); 25 | 26 | var result = await client.ChatAsync(new ChatCompletionsRequest() 27 | { 28 | Messages = 29 | { 30 | new Message() 31 | { 32 | Role = MessageRole.User, 33 | Content = "Hello?" 34 | } 35 | } 36 | }, ModelEndpoints.ERNIE_Bot); 37 | 38 | Assert.NotEmpty(result.Result); 39 | } 40 | 41 | [Fact()] 42 | public async Task ChatCompletionsStreamAsyncTest() 43 | { 44 | var httpClient = await TestHelper.FakeHttpClient("chat_stream_response.txt"); 45 | var fakeTokenStore = new TokenStoreHelper("test_token"); 46 | var client = new ERNIEBotClient("test", "test", httpClient, fakeTokenStore); 47 | 48 | var results = client.ChatStreamAsync(new ChatCompletionsRequest() 49 | { 50 | Messages = 51 | { 52 | new Message() 53 | { 54 | Role = MessageRole.User, 55 | Content = "Hello?" 56 | } 57 | } 58 | }, ModelEndpoints.ERNIE_Bot); 59 | 60 | await foreach (var result in results) 61 | { 62 | Assert.NotEmpty(result.Result); 63 | } 64 | } 65 | 66 | [Fact()] 67 | public async Task ChatEBInstantAsyncTest() 68 | { 69 | var httpClient = await TestHelper.FakeHttpClient("chat_response.txt"); 70 | var fakeTokenStore = new TokenStoreHelper("test_token"); 71 | var client = new ERNIEBotClient("test", "test", httpClient, fakeTokenStore); 72 | 73 | var result = await client.ChatAsync(new ChatRequest() 74 | { 75 | Messages = 76 | { 77 | new Message() 78 | { 79 | Role = MessageRole.User, 80 | Content = "Hello?" 81 | } 82 | } 83 | }, ModelEndpoints.ERNIE_Bot_Turbo); 84 | 85 | Assert.NotEmpty(result.Result); 86 | } 87 | 88 | [Fact()] 89 | public async Task ChatEBInstantStreamAsyncTest() 90 | { 91 | var httpClient = await TestHelper.FakeHttpClient("chat_stream_response.txt"); 92 | var fakeTokenStore = new TokenStoreHelper("test_token"); 93 | var client = new ERNIEBotClient("test", "test", httpClient, fakeTokenStore); 94 | 95 | var results = client.ChatStreamAsync(new ChatRequest() 96 | { 97 | Messages = 98 | { 99 | new Message() 100 | { 101 | Role = MessageRole.User, 102 | Content = "Hello?" 103 | } 104 | } 105 | }, ModelEndpoints.ERNIE_Bot_Turbo); 106 | 107 | await foreach (var result in results) 108 | { 109 | Assert.NotEmpty(result.Result); 110 | } 111 | } 112 | 113 | [Fact()] 114 | public async Task EmbeddingsAsyncTest() 115 | { 116 | var httpClient = await TestHelper.FakeHttpClient("embedding_response.txt"); 117 | var fakeTokenStore = new TokenStoreHelper("test_token"); 118 | var client = new ERNIEBotClient("test", "test", httpClient, fakeTokenStore); 119 | 120 | var result = await client.EmbeddingsAsync(new Models.EmbeddingsRequest() 121 | { 122 | Input = { "test" } 123 | }); 124 | 125 | Assert.NotEmpty(result.Data); 126 | } 127 | 128 | [Fact()] 129 | public async Task GetAccessTokenAsyncTest() 130 | { 131 | var httpClient = await TestHelper.FakeHttpClient("token_response.txt"); 132 | var fakeTokenStore = new TokenStoreHelper(null); 133 | var client = new ERNIEBotClient("test", "test", httpClient, fakeTokenStore); 134 | 135 | var ak = await client.GetAccessTokenAsync(); 136 | 137 | Assert.NotNull(ak); 138 | } 139 | 140 | [Fact] 141 | public async Task ThrowErrorTest() 142 | { 143 | var httpClient = await TestHelper.FakeHttpClient("error.txt"); 144 | var fakeTokenStore = new TokenStoreHelper("test"); 145 | var client = new ERNIEBotClient("test", "test", httpClient, fakeTokenStore); 146 | 147 | await Assert.ThrowsAsync(async () => 148 | { 149 | await client.EmbeddingsAsync(new EmbeddingsRequest()); 150 | }); 151 | } 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /tests/ERNIE-Bot.SDK.Tests/TestDatas/chat_response.txt: -------------------------------------------------------------------------------- 1 | { 2 | "id": "as-bcmt5ct4iy", 3 | "object": "chat.completion", 4 | "created": 1680167072, 5 | "result": "您好,我是百度研发的知识增强大语言模型,中文名是文心一言,英文名是ERNIE-Bot。我能够与人对话互动,回答问题,协助创作,高效便捷地帮助人们获取信息、知识和灵感。", 6 | "need_clear_history": false, 7 | "usage": { 8 | "prompt_tokens": 7, 9 | "completion_tokens": 67, 10 | "total_tokens": 74 11 | } 12 | } -------------------------------------------------------------------------------- /tests/ERNIE-Bot.SDK.Tests/TestDatas/chat_stream_response.txt: -------------------------------------------------------------------------------- 1 | data: {"id":"as-ywwpgx4dt7","object":"chat.completion","created":1680166793,"sentence_id":0,"is_end":false,"result":"以下是一些适合自驾游的路线推荐:\n\n1.","need_clear_history":false,"usage":{"prompt_tokens":11,"completion_tokens":16,"total_tokens":27}} 2 | 3 | data: {"id":"as-ywwpgx4dt7","object":"chat.completion","created":1680166794,"sentence_id":1,"is_end":false,"result":" 中国大陆最美的景观大道:川藏线,从成都出发,沿着川藏公路一路向西,经过稻城亚丁、理塘、巴塘、芒康等美景,最终到达拉萨。","need_clear_history":false,"usage":{"prompt_tokens":11,"completion_tokens":50,"total_tokens":77}} 4 | 5 | data: {"id":"as-ywwpgx4dt7","object":"chat.completion","created":1680166795,"sentence_id":2,"is_end":false,"result":"\n2. 丝绸之路:这是一条贯穿中国东西部的公路,从上海出发,经过西安、兰州、乌鲁木齐等城市,最终到达喀什。","need_clear_history":false,"usage":{"prompt_tokens":11,"completion_tokens":43,"total_tokens":120}} 6 | 7 | data: {"id":"as-ywwpgx4dt7","object":"chat.completion","created":1680166796,"sentence_id":3,"is_end":false,"result":"沿途可以欣赏到中国北方和南方的不同景色。\n3. 西北大环线:从成都出发,经过都江堰、青城山、丹巴、塔公草原、新都桥等景点,最终到达西宁。","need_clear_history":false,"usage":{"prompt_tokens":11,"completion_tokens":56,"total_tokens":176}} 8 | 9 | data: {"id":"as-ywwpgx4dt7","object":"chat.completion","created":1680166799,"sentence_id":4,"is_end":false,"result":"这条路线可以领略到中国西北地区的壮美风光。\n4. 东北环线:从沈阳出发,经过长春、吉林、延吉等城市,最终到达哈尔滨。","need_clear_history":false,"usage":{"prompt_tokens":11,"completion_tokens":48,"total_tokens":224}} 10 | 11 | data: {"id":"as-ywwpgx4dt7","object":"chat.completion","created":1680166800,"sentence_id":5,"is_end":false,"result":"沿途可以欣赏到中国东北地区的广阔草原和森林。\n5. 西南环线:从成都出发,经过雅安、康定、理塘、稻城亚丁等景点,最终到达香格里拉。","need_clear_history":false,"usage":{"prompt_tokens":11,"completion_tokens":54,"total_tokens":278}} 12 | 13 | data: {"id":"as-ywwpgx4dt7","object":"chat.completion","created":1680166802,"sentence_id":6,"is_end":false,"result":"这条路线可以领略到中国西南地区的高山峡谷和民族文化。\n6. 海南环线:从三亚出发,经过海口、文昌、万宁等城市,最终到达三亚。","need_clear_history":false,"usage":{"prompt_tokens":11,"completion_tokens":52,"total_tokens":330}} 14 | 15 | data: {"id":"as-ywwpgx4dt7","object":"chat.completion","created":1680166803,"sentence_id":7,"is_end":false,"result":"这条路线可以欣赏到中国南方的海岸线和热带雨林。\n7. 滇藏线:从昆明出发,经过大理、丽江、香格里拉等景点,最终到达西藏拉萨。","need_clear_history":false,"usage":{"prompt_tokens":11,"completion_tokens":52,"total_tokens":382}} 16 | 17 | data: {"id":"as-ywwpgx4dt7","object":"chat.completion","created":1680166804,"sentence_id":8,"is_end":true,"result":"这条路线可以领略到中国西南地区和西藏地区的自然风光和人文景观。","need_clear_history":false,"usage":{"prompt_tokens":11,"completion_tokens":30,"total_tokens":412}} -------------------------------------------------------------------------------- /tests/ERNIE-Bot.SDK.Tests/TestDatas/embedding_response.txt: -------------------------------------------------------------------------------- 1 | { 2 | "id": "as-gjs275mj6s", 3 | "object": "embedding_list", 4 | "created": 1687155816, 5 | "data": [ 6 | { 7 | "object": "embedding", 8 | "embedding": [ 9 | 0.018314670771360397, 10 | 0.00942440889775753, 11 | -0.36294862627983093 12 | ], 13 | "index": 0 14 | }, 15 | { 16 | "object": "embedding", 17 | "embedding": [ 18 | 0.12250778824090958, 19 | 0.07934671640396118, 20 | 0 21 | ], 22 | "index": 1 23 | } 24 | ], 25 | "usage": { 26 | "prompt_tokens": 12, 27 | "total_tokens": 12 28 | } 29 | } -------------------------------------------------------------------------------- /tests/ERNIE-Bot.SDK.Tests/TestDatas/error.txt: -------------------------------------------------------------------------------- 1 | { 2 | "error_code": 110, 3 | "error_msg": "Access token invalid or no longer valid" 4 | } -------------------------------------------------------------------------------- /tests/ERNIE-Bot.SDK.Tests/TestDatas/token_response.txt: -------------------------------------------------------------------------------- 1 | { 2 | "refresh_token": "test_refresh_token", 3 | "expires_in": 2592000, 4 | "session_key": "test_session_key", 5 | "access_token": "test_access_token", 6 | "scope": "public brain_all_scope easydl_mgr easydl_retail_mgr ai_custom_retail_image_stitch ai_custom_test_oversea easydl_pro_job easydl_pro_mgr ai_custom_yiyan_com ai_custom_yiyan_com_eb_instant ai_custom_yiyan_com_bloomz7b1 ai_custom_yiyan_com_emb_text wise_adapt lebo_resource_base lightservice_public hetu_basic lightcms_map_poi kaidian_kaidian ApsMisTest_Test权限 vis-classify_flower lpq_开放 cop_helloScope ApsMis_fangdi_permission smartapp_snsapi_base smartapp_mapp_dev_manage iop_autocar oauth_tp_app smartapp_smart_game_openapi oauth_sessionkey smartapp_swanid_verify smartapp_opensource_openapi smartapp_opensource_recapi fake_face_detect_开放Scope vis-ocr_虚拟人物助理 idl-video_虚拟人物助理 smartapp_component smartapp_search_plugin avatar_video_test b2b_tp_openapi b2b_tp_openapi_online smartapp_gov_aladin_to_xcx", 7 | "session_secret": "test_session_secret" 8 | } -------------------------------------------------------------------------------- /tests/ERNIE-Bot.SDK.Tests/TestHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | 3 | namespace ERNIE_BOT.SDK.Tests 4 | { 5 | internal static class TestHelper 6 | { 7 | internal static async Task GetHttpResponseFormFileAsync(string fileName, bool isStream = false) 8 | { 9 | var filePath = Path.Combine("./TestDatas", fileName); 10 | 11 | if (!File.Exists(filePath)) 12 | { 13 | throw new FileNotFoundException(fileName); 14 | } 15 | 16 | if (!isStream) 17 | { 18 | var content = File.ReadAllText(filePath); 19 | return new HttpResponseMessage 20 | { 21 | StatusCode = HttpStatusCode.OK, 22 | Content = new StringContent(content) 23 | }; 24 | } 25 | else 26 | { 27 | var content = File.ReadAllLines(filePath); 28 | var stream = new MemoryStream(); 29 | var writer = new StreamWriter(stream); 30 | var streamContent = new StreamContent(stream); 31 | foreach (var line in content) 32 | { 33 | await writer.WriteAsync(line); 34 | await writer.FlushAsync(); 35 | } 36 | return new HttpResponseMessage 37 | { 38 | StatusCode = HttpStatusCode.OK, 39 | Content = streamContent 40 | }; 41 | } 42 | } 43 | 44 | internal static async Task FakeHttpClient(string fileName, bool isStream = false) 45 | { 46 | var response = await GetHttpResponseFormFileAsync(fileName, isStream); 47 | var client = new HttpClient(new MockHttpMessageHandler(response)); 48 | 49 | return client; 50 | } 51 | } 52 | 53 | public class MockHttpMessageHandler : HttpMessageHandler 54 | { 55 | private readonly HttpResponseMessage _response; 56 | 57 | public MockHttpMessageHandler(HttpResponseMessage response) 58 | { 59 | this._response = response; 60 | } 61 | 62 | protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 63 | { 64 | return Task.FromResult(_response); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /tests/ERNIE-Bot.SDK.Tests/TokenStoreHelper.cs: -------------------------------------------------------------------------------- 1 | using ERNIE_Bot.SDK; 2 | 3 | namespace ERNIE_BOT.SDK.Tests 4 | { 5 | internal class TokenStoreHelper : ITokenStore 6 | { 7 | private string? _token; 8 | 9 | public TokenStoreHelper(string? token) 10 | { 11 | _token = token; 12 | } 13 | 14 | public Task GetTokenAsync(CancellationToken cancellationToken) 15 | { 16 | return Task.FromResult(_token); 17 | } 18 | 19 | public Task SaveTokenAsync(string accessToken, TimeSpan expiration, CancellationToken cancellationToken) 20 | { 21 | return Task.CompletedTask; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/ERNIE-Bot.SDK.Tests/TokenizerTests.cs: -------------------------------------------------------------------------------- 1 | namespace ERNIE_Bot.SDK.Tests 2 | { 3 | public class TokenizerTests 4 | { 5 | [Fact] 6 | public void TestApproxNumTokens() 7 | { 8 | string text = "这是一段测试文字This is a test string."; 9 | int expected = 14; 10 | int actual = Tokenizer.ApproxNumTokens(text); 11 | Assert.Equal(expected, actual); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tests/ERNIE-Bot.SDK.Tests/Usings.cs: -------------------------------------------------------------------------------- 1 | global using Xunit; 2 | -------------------------------------------------------------------------------- /tests/ERNIE-Bot.SemanticKernel.Tests/ERNIE-Bot.SemanticKernel.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0 5 | ERNIE_Bot.SemanticKernel.Tests 6 | enable 7 | enable 8 | 9 | false 10 | 11 | 12 | 13 | 14 | 15 | 16 | runtime; build; native; contentfiles; analyzers; buildtransitive 17 | all 18 | 19 | 20 | runtime; build; native; contentfiles; analyzers; buildtransitive 21 | all 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /tests/ERNIE-Bot.SemanticKernel.Tests/Usings.cs: -------------------------------------------------------------------------------- 1 | global using Xunit; -------------------------------------------------------------------------------- /tests/IntegrationTests/IntegrationTests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0 5 | enable 6 | enable 7 | 8 | false 9 | 10 | 84a2cf80-3689-4f7e-b25f-661eea20cf5d 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | all 20 | 21 | 22 | runtime; build; native; contentfiles; analyzers; buildtransitive 23 | all 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /tests/IntegrationTests/SDK/ChatCompletionStreamTest.cs: -------------------------------------------------------------------------------- 1 | using ERNIE_Bot.SDK; 2 | using Microsoft; 3 | using Microsoft.Extensions.Configuration; 4 | 5 | namespace IntegrationTests.SDK 6 | { 7 | public class ChatCompletionStreamTest 8 | { 9 | private ERNIEBotClient _client; 10 | 11 | public ChatCompletionStreamTest() 12 | { 13 | var config = new ConfigurationBuilder() 14 | .AddUserSecrets(GetType().Assembly) 15 | .Build(); 16 | 17 | var clientId = config["ClientId"]; 18 | var clientSecret = config["ClientSecret"]; 19 | 20 | Requires.NotNullOrEmpty(clientId!); 21 | Requires.NotNullOrEmpty(clientSecret!); 22 | 23 | _client = new ERNIEBotClient(clientId, clientSecret); 24 | } 25 | 26 | #region StreamChatCompletion 27 | 28 | private async IAsyncEnumerable InternalStreamChatAsync(ModelEndpoint endpoint) 29 | { 30 | var response = _client.ChatStreamAsync(new ERNIE_Bot.SDK.Models.ChatRequest() 31 | { 32 | Messages = new List() 33 | { 34 | new ERNIE_Bot.SDK.Models.Message() 35 | { 36 | Role = ERNIE_Bot.SDK.Models.MessageRole.User, 37 | Content = "Hello" 38 | } 39 | } 40 | }, endpoint); 41 | 42 | await foreach (var r in response) 43 | { 44 | yield return r.Result; 45 | } 46 | } 47 | 48 | [Theory] 49 | [ClassData(typeof(ChatCompletionTestEndpoints))] 50 | public async Task StreamChatAsync(ModelEndpoint endpoint) 51 | { 52 | await foreach (var r in InternalStreamChatAsync(endpoint)) 53 | { 54 | Assert.NotNull(r); 55 | break; 56 | } 57 | } 58 | #endregion StreamChatCompletion 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /tests/IntegrationTests/SDK/ChatCompletionTest.cs: -------------------------------------------------------------------------------- 1 | using ERNIE_Bot.SDK; 2 | using Microsoft; 3 | using Microsoft.Extensions.Configuration; 4 | 5 | namespace IntegrationTests.SDK 6 | { 7 | public class ChatCompletionTest 8 | { 9 | private ERNIEBotClient _client; 10 | 11 | public ChatCompletionTest() 12 | { 13 | var config = new ConfigurationBuilder() 14 | .AddUserSecrets(GetType().Assembly) 15 | .Build(); 16 | 17 | var clientId = config["ClientId"]; 18 | var clientSecret = config["ClientSecret"]; 19 | 20 | Requires.NotNullOrEmpty(clientId!); 21 | Requires.NotNullOrEmpty(clientSecret!); 22 | 23 | _client = new ERNIEBotClient(clientId, clientSecret); 24 | } 25 | 26 | #region ChatCompletion 27 | 28 | private async Task InternalChatAsync(ModelEndpoint endpoint) 29 | { 30 | var response = await _client.ChatAsync(new ERNIE_Bot.SDK.Models.ChatRequest() 31 | { 32 | Messages = new List() 33 | { 34 | new ERNIE_Bot.SDK.Models.Message() 35 | { 36 | Role = ERNIE_Bot.SDK.Models.MessageRole.User, 37 | Content = "Hello" 38 | } 39 | } 40 | }, endpoint); 41 | return response.Result; 42 | } 43 | 44 | [Theory] 45 | [ClassData(typeof(ChatCompletionTestEndpoints))] 46 | public async Task ChatAsync(ModelEndpoint endpoint) 47 | { 48 | var result = await InternalChatAsync(endpoint); 49 | 50 | Assert.NotNull(result); 51 | } 52 | 53 | #endregion ChatCompletion 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /tests/IntegrationTests/SDK/ChatCompletionTestEndpoints.cs: -------------------------------------------------------------------------------- 1 | using ERNIE_Bot.SDK; 2 | using System.Collections; 3 | 4 | namespace IntegrationTests.SDK 5 | { 6 | public class ChatCompletionTestEndpoints : IEnumerable 7 | { 8 | public ChatCompletionTestEndpoints() 9 | { 10 | _endpoints = typeof(ModelEndpoints).GetFields(System.Reflection.BindingFlags.Public | 11 | System.Reflection.BindingFlags.Static) 12 | .Where(f => f.FieldType == typeof(ModelEndpoint)) 13 | .Select(f => (ModelEndpoint)f.GetValue(null)!) 14 | .ToList(); 15 | } 16 | public readonly List _endpoints; 17 | 18 | public IEnumerator GetEnumerator() 19 | => this._endpoints.Select(e => new[] { e }).GetEnumerator(); 20 | 21 | IEnumerator IEnumerable.GetEnumerator() 22 | => this._endpoints.GetEnumerator(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/IntegrationTests/SDK/EmbeddingTest.cs: -------------------------------------------------------------------------------- 1 | using ERNIE_Bot.SDK; 2 | using Microsoft; 3 | using Microsoft.Extensions.Configuration; 4 | 5 | namespace IntegrationTests.SDK 6 | { 7 | public class EmbeddingTest 8 | { 9 | private ERNIEBotClient _client; 10 | 11 | public EmbeddingTest() 12 | { 13 | var config = new ConfigurationBuilder() 14 | .AddUserSecrets(GetType().Assembly) 15 | .Build(); 16 | 17 | var clientId = config["ClientId"]; 18 | var clientSecret = config["ClientSecret"]; 19 | 20 | Requires.NotNullOrEmpty(clientId!); 21 | Requires.NotNullOrEmpty(clientSecret!); 22 | 23 | _client = new ERNIEBotClient(clientId, clientSecret); 24 | } 25 | 26 | #region Embedding 27 | 28 | private async Task> InternalEmbeddingAsync(EmbeddingModelEndpoint endpoint) 29 | { 30 | var response = await _client.EmbeddingsAsync(new ERNIE_Bot.SDK.Models.EmbeddingsRequest() 31 | { 32 | Input = new List { "Hello" } 33 | }, endpoint); 34 | return response.Data.First().Embedding; 35 | } 36 | 37 | [Fact] 38 | public async Task EmbeddingV1Async() 39 | { 40 | var result = await InternalEmbeddingAsync(ModelEndpoints.Embedding_v1); 41 | 42 | Assert.NotEmpty(result); 43 | } 44 | 45 | [Fact] 46 | public async Task bge_large_zhAsync() 47 | { 48 | var result = await InternalEmbeddingAsync(ModelEndpoints.bge_large_zh); 49 | 50 | Assert.NotEmpty(result); 51 | } 52 | 53 | [Fact] 54 | public async Task bge_large_enAsync() 55 | { 56 | var result = await InternalEmbeddingAsync(ModelEndpoints.bge_large_en); 57 | 58 | Assert.NotEmpty(result); 59 | } 60 | 61 | #endregion Embedding 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /tests/IntegrationTests/Usings.cs: -------------------------------------------------------------------------------- 1 | global using Xunit; 2 | --------------------------------------------------------------------------------