├── .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 | [](https://www.nuget.org/packages/ERNIE-Bot.SDK/)
4 | [](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 | [](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 | [](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