├── .gitignore
├── AFECS_Video_Preview.png
├── AzureFunctions.Extensions.CognitiveServices.sln
├── LICENSE
├── README.md
├── logo.png
├── samples
└── AzureFunctions.Extensions.CognitiveServics.Samples
│ ├── .gitignore
│ ├── AzureFunctions.Extensions.CognitiveServics.Samples.csproj
│ ├── CognitiveServicesFunctions.cs
│ ├── ThumbnailGenerator.cs
│ ├── VisionResult.cs
│ └── host.json
├── src
├── AzureFunctions.Extensions.CognitiveServices.sln
└── AzureFunctions.Extensions.CognitiveServices
│ ├── AzureFunctions.Extensions.CognitiveServices.csproj
│ ├── Bindings
│ └── Vision
│ │ ├── Analysis
│ │ ├── VisionAnalysisAttribute.cs
│ │ ├── VisionAnalysisBinding.cs
│ │ ├── VisionAnalysisClient.cs
│ │ ├── VisionAnalysisExtension.cs
│ │ ├── VisionAnalysisModel.cs
│ │ ├── VisionAnalysisRequest.cs
│ │ └── VisionAnalysisStartup.cs
│ │ ├── Describe
│ │ ├── VisionDescribeAttribute.cs
│ │ ├── VisionDescribeBinding.cs
│ │ ├── VisionDescribeClient.cs
│ │ ├── VisionDescribeExtension.cs
│ │ ├── VisionDescribeModel.cs
│ │ ├── VisionDescribeRequest.cs
│ │ └── VisionDescribeStartup.cs
│ │ ├── Domain
│ │ ├── VisionDomainAttribute.cs
│ │ ├── VisionDomainBinding.cs
│ │ ├── VisionDomainCelebrityModel.cs
│ │ ├── VisionDomainClient.cs
│ │ ├── VisionDomainExtension.cs
│ │ ├── VisionDomainLandmarkModel.cs
│ │ ├── VisionDomainRequest.cs
│ │ └── VisionDomainStartup.cs
│ │ ├── Handwriting
│ │ ├── VisionHandwritingAttribute.cs
│ │ ├── VisionHandwritingBinding.cs
│ │ ├── VisionHandwritingClient.cs
│ │ ├── VisionHandwritingExtension.cs
│ │ ├── VisionHandwritingModel.cs
│ │ ├── VisionHandwritingRequest.cs
│ │ └── VisionHandwritingStartup.cs
│ │ ├── IVisionBinding.cs
│ │ ├── Ocr
│ │ ├── VisionOCRAttribute.cs
│ │ ├── VisionOCRBinding.cs
│ │ ├── VisionOCRClient.cs
│ │ ├── VisionOCRExtension.cs
│ │ ├── VisionOCRRequest.cs
│ │ ├── VisionOCRStartup.cs
│ │ └── VisionOcrModel.cs
│ │ ├── Thumbnail
│ │ ├── VisionThumbnailAttribute.cs
│ │ ├── VisionThumbnailBinding.cs
│ │ ├── VisionThumbnailClient.cs
│ │ ├── VisionThumbnailExtension.cs
│ │ ├── VisionThumbnailRequest.cs
│ │ └── VisionThumbnailStartup.cs
│ │ ├── VisionAttributeBase.cs
│ │ ├── VisionErrorModel.cs
│ │ ├── VisionRequestBase.cs
│ │ └── VisionUrlRequest.cs
│ ├── Config
│ ├── RetryPolicy.cs
│ └── VisionConfiguration.cs
│ ├── Properties
│ └── AssemblyInfo.cs
│ └── Services
│ ├── CognitiveServicesClient.cs
│ ├── ICognitiveServicesClient.cs
│ ├── ImageResizeService.cs
│ ├── Models
│ └── ServiceResultModel.cs
│ └── StorageServices.cs
└── tests
└── AzureFunctions.Extensions.CognitiveServices.Tests
├── AzureFunctions.Extensions.CognitiveServices.Tests.csproj
├── Common
├── ExplicitTypeLocator.cs
├── FunctionHost.cs
├── LogMessage.cs
├── TestCognitiveServicesClient.cs
├── TestHelper.cs
├── TestLogger.cs
├── TestLoggerProvider.cs
└── TestNameResolver.cs
├── Resources
├── MockResults.Designer.cs
├── MockResults.resx
├── SamplePhoto.jpeg
├── SamplePhotoTooBig.jpg
├── VisionAnalysisResults.json
└── VisionDescribeResults.json
├── TestHelper.cs
├── TestHelpers
└── VerboseDiagnosticsTraceWriter.cs
├── VisionAnalysisTests.cs
├── VisionDescribeTests.cs
├── VisionDomainTests.cs
├── VisionHandwritingTests.cs
├── VisionOcrTests.cs
├── VisionThumbnailTests.cs
└── local.settings.json
/.gitignore:
--------------------------------------------------------------------------------
1 | ################################################################################
2 | ## Ignore Visual Studio temporary files, build results, and
3 | ## files generated by popular Visual Studio add-ons.
4 | ##
5 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
6 |
7 | # User-specific files
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Build results
17 | [Dd]ebug/
18 | [Dd]ebugPublic/
19 | [Rr]elease/
20 | [Rr]eleases/
21 | x64/
22 | x86/
23 | bld/
24 | [Bb]in/
25 | [Oo]bj/
26 | [Ll]og/
27 |
28 | # Visual Studio 2015/2017 cache/options directory
29 | .vs/
30 | # Uncomment if you have tasks that create the project's static files in wwwroot
31 | #wwwroot/
32 |
33 | # Visual Studio 2017 auto generated files
34 | Generated\ Files/
35 |
36 | # MSTest test Results
37 | [Tt]est[Rr]esult*/
38 | [Bb]uild[Ll]og.*
39 |
40 | # NUNIT
41 | *.VisualState.xml
42 | TestResult.xml
43 |
44 | # Build Results of an ATL Project
45 | [Dd]ebugPS/
46 | [Rr]eleasePS/
47 | dlldata.c
48 |
49 | # Benchmark Results
50 | BenchmarkDotNet.Artifacts/
51 |
52 | # .NET Core
53 | project.lock.json
54 | project.fragment.lock.json
55 | artifacts/
56 | **/Properties/launchSettings.json
57 |
58 | # StyleCop
59 | StyleCopReport.xml
60 |
61 | # Files built by Visual Studio
62 | *_i.c
63 | *_p.c
64 | *_i.h
65 | *.ilk
66 | *.meta
67 | *.obj
68 | *.iobj
69 | *.pch
70 | *.pdb
71 | *.ipdb
72 | *.pgc
73 | *.pgd
74 | *.rsp
75 | *.sbr
76 | *.tlb
77 | *.tli
78 | *.tlh
79 | *.tmp
80 | *.tmp_proj
81 | *.log
82 | *.vspscc
83 | *.vssscc
84 | .builds
85 | *.pidb
86 | *.svclog
87 | *.scc
88 |
89 | # Chutzpah Test files
90 | _Chutzpah*
91 |
92 | # Visual C++ cache files
93 | ipch/
94 | *.aps
95 | *.ncb
96 | *.opendb
97 | *.opensdf
98 | *.sdf
99 | *.cachefile
100 | *.VC.db
101 | *.VC.VC.opendb
102 |
103 | # Visual Studio profiler
104 | *.psess
105 | *.vsp
106 | *.vspx
107 | *.sap
108 |
109 | # Visual Studio Trace Files
110 | *.e2e
111 |
112 | # TFS 2012 Local Workspace
113 | $tf/
114 |
115 | # Guidance Automation Toolkit
116 | *.gpState
117 |
118 | # ReSharper is a .NET coding add-in
119 | _ReSharper*/
120 | *.[Rr]e[Ss]harper
121 | *.DotSettings.user
122 |
123 | # JustCode is a .NET coding add-in
124 | .JustCode
125 |
126 | # TeamCity is a build add-in
127 | _TeamCity*
128 |
129 | # DotCover is a Code Coverage Tool
130 | *.dotCover
131 |
132 | # AxoCover is a Code Coverage Tool
133 | .axoCover/*
134 | !.axoCover/settings.json
135 |
136 | # Visual Studio code coverage results
137 | *.coverage
138 | *.coveragexml
139 |
140 | # NCrunch
141 | _NCrunch_*
142 | .*crunch*.local.xml
143 | nCrunchTemp_*
144 |
145 | # MightyMoose
146 | *.mm.*
147 | AutoTest.Net/
148 |
149 | # Web workbench (sass)
150 | .sass-cache/
151 |
152 | # Installshield output folder
153 | [Ee]xpress/
154 |
155 | # DocProject is a documentation generator add-in
156 | DocProject/buildhelp/
157 | DocProject/Help/*.HxT
158 | DocProject/Help/*.HxC
159 | DocProject/Help/*.hhc
160 | DocProject/Help/*.hhk
161 | DocProject/Help/*.hhp
162 | DocProject/Help/Html2
163 | DocProject/Help/html
164 |
165 | # Click-Once directory
166 | publish/
167 |
168 | # Publish Web Output
169 | *.[Pp]ublish.xml
170 | *.azurePubxml
171 | # Note: Comment the next line if you want to checkin your web deploy settings,
172 | # but database connection strings (with potential passwords) will be unencrypted
173 | *.pubxml
174 | *.publishproj
175 |
176 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
177 | # checkin your Azure Web App publish settings, but sensitive information contained
178 | # in these scripts will be unencrypted
179 | PublishScripts/
180 |
181 | # NuGet Packages
182 | *.nupkg
183 | # The packages folder can be ignored because of Package Restore
184 | **/[Pp]ackages/*
185 | # except build/, which is used as an MSBuild target.
186 | !**/[Pp]ackages/build/
187 | # Uncomment if necessary however generally it will be regenerated when needed
188 | #!**/[Pp]ackages/repositories.config
189 | # NuGet v3's project.json files produces more ignorable files
190 | *.nuget.props
191 | *.nuget.targets
192 |
193 | # Microsoft Azure Build Output
194 | csx/
195 | *.build.csdef
196 |
197 | # Microsoft Azure Emulator
198 | ecf/
199 | rcf/
200 |
201 | # Windows Store app package directories and files
202 | AppPackages/
203 | BundleArtifacts/
204 | Package.StoreAssociation.xml
205 | _pkginfo.txt
206 | *.appx
207 |
208 | # Visual Studio cache files
209 | # files ending in .cache can be ignored
210 | *.[Cc]ache
211 | # but keep track of directories ending in .cache
212 | !*.[Cc]ache/
213 |
214 | # Others
215 | ClientBin/
216 | ~$*
217 | *~
218 | *.dbmdl
219 | *.dbproj.schemaview
220 | *.jfm
221 | *.pfx
222 | *.publishsettings
223 | orleans.codegen.cs
224 |
225 | # Including strong name files can present a security risk
226 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
227 | #*.snk
228 |
229 | # Since there are multiple workflows, uncomment next line to ignore bower_components
230 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
231 | #bower_components/
232 |
233 | # RIA/Silverlight projects
234 | Generated_Code/
235 |
236 | # Backup & report files from converting an old project file
237 | # to a newer Visual Studio version. Backup files are not needed,
238 | # because we have git ;-)
239 | _UpgradeReport_Files/
240 | Backup*/
241 | UpgradeLog*.XML
242 | UpgradeLog*.htm
243 | ServiceFabricBackup/
244 | *.rptproj.bak
245 |
246 | # SQL Server files
247 | *.mdf
248 | *.ldf
249 | *.ndf
250 |
251 | # Business Intelligence projects
252 | *.rdl.data
253 | *.bim.layout
254 | *.bim_*.settings
255 | *.rptproj.rsuser
256 |
257 | # Microsoft Fakes
258 | FakesAssemblies/
259 |
260 | # GhostDoc plugin setting file
261 | *.GhostDoc.xml
262 |
263 | # Node.js Tools for Visual Studio
264 | .ntvs_analysis.dat
265 | node_modules/
266 |
267 | # Visual Studio 6 build log
268 | *.plg
269 |
270 | # Visual Studio 6 workspace options file
271 | *.opt
272 |
273 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
274 | *.vbw
275 |
276 | # Visual Studio LightSwitch build output
277 | **/*.HTMLClient/GeneratedArtifacts
278 | **/*.DesktopClient/GeneratedArtifacts
279 | **/*.DesktopClient/ModelManifest.xml
280 | **/*.Server/GeneratedArtifacts
281 | **/*.Server/ModelManifest.xml
282 | _Pvt_Extensions
283 |
284 | # Paket dependency manager
285 | .paket/paket.exe
286 | paket-files/
287 |
288 | # FAKE - F# Make
289 | .fake/
290 |
291 | # JetBrains Rider
292 | .idea/
293 | *.sln.iml
294 |
295 | # CodeRush
296 | .cr/
297 |
298 | # Python Tools for Visual Studio (PTVS)
299 | __pycache__/
300 | *.pyc
301 |
302 | # Cake - Uncomment if you are using it
303 | # tools/**
304 | # !tools/packages.config
305 |
306 | # Tabs Studio
307 | *.tss
308 |
309 | # Telerik's JustMock configuration file
310 | *.jmconfig
311 |
312 | # BizTalk build output
313 | *.btp.cs
314 | *.btm.cs
315 | *.odx.cs
316 | *.xsd.cs
317 |
318 | # OpenCover UI analysis results
319 | OpenCover/
320 |
321 | # Azure Stream Analytics local run output
322 | ASALocalRun/
323 |
324 | # MSBuild Binary and Structured Log
325 | *.binlog
326 |
327 | # NVidia Nsight GPU debugger configuration file
328 | *.nvuser
329 |
330 | # MFractors (Xamarin productivity tool) working folder
331 | .mfractor/
332 |
--------------------------------------------------------------------------------
/AFECS_Video_Preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joshdcar/azure-functions-extensions-cognitive-services/f6dea9eff6c8d5a9cd1bb99fe21aa63efefac895/AFECS_Video_Preview.png
--------------------------------------------------------------------------------
/AzureFunctions.Extensions.CognitiveServices.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27428.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{71539E00-8C5F-4B45-AA0D-B83CAC58FCA4}"
7 | EndProject
8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{862626B4-433B-4FA4-96DC-815850960814}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AzureFunctions.Extensions.CognitiveServics.Samples", "samples\AzureFunctions.Extensions.CognitiveServics.Samples\AzureFunctions.Extensions.CognitiveServics.Samples.csproj", "{78916DA5-CFEC-40B5-84A6-B0190B076700}"
11 | EndProject
12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{9936F693-95E7-48C4-ADC3-3FFCBC654587}"
13 | EndProject
14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AzureFunctions.Extensions.CognitiveServices", "src\AzureFunctions.Extensions.CognitiveServices\AzureFunctions.Extensions.CognitiveServices.csproj", "{90EED71C-45C7-4952-818B-3643A3E906B9}"
15 | EndProject
16 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3F518617-3B7F-44DD-B6C3-51A55FA76D5C}"
17 | ProjectSection(SolutionItems) = preProject
18 | logo.png = logo.png
19 | README.md = README.md
20 | EndProjectSection
21 | EndProject
22 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AzureFunctions.Extensions.CognitiveServices.Tests", "tests\AzureFunctions.Extensions.CognitiveServices.Tests\AzureFunctions.Extensions.CognitiveServices.Tests.csproj", "{50FAB084-7357-4943-9186-0C3F81CC9F3E}"
23 | EndProject
24 | Global
25 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
26 | Debug|Any CPU = Debug|Any CPU
27 | Release|Any CPU = Release|Any CPU
28 | EndGlobalSection
29 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
30 | {78916DA5-CFEC-40B5-84A6-B0190B076700}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
31 | {78916DA5-CFEC-40B5-84A6-B0190B076700}.Debug|Any CPU.Build.0 = Debug|Any CPU
32 | {78916DA5-CFEC-40B5-84A6-B0190B076700}.Release|Any CPU.ActiveCfg = Release|Any CPU
33 | {78916DA5-CFEC-40B5-84A6-B0190B076700}.Release|Any CPU.Build.0 = Release|Any CPU
34 | {90EED71C-45C7-4952-818B-3643A3E906B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
35 | {90EED71C-45C7-4952-818B-3643A3E906B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
36 | {90EED71C-45C7-4952-818B-3643A3E906B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
37 | {90EED71C-45C7-4952-818B-3643A3E906B9}.Release|Any CPU.Build.0 = Release|Any CPU
38 | {50FAB084-7357-4943-9186-0C3F81CC9F3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
39 | {50FAB084-7357-4943-9186-0C3F81CC9F3E}.Debug|Any CPU.Build.0 = Debug|Any CPU
40 | {50FAB084-7357-4943-9186-0C3F81CC9F3E}.Release|Any CPU.ActiveCfg = Release|Any CPU
41 | {50FAB084-7357-4943-9186-0C3F81CC9F3E}.Release|Any CPU.Build.0 = Release|Any CPU
42 | EndGlobalSection
43 | GlobalSection(SolutionProperties) = preSolution
44 | HideSolutionNode = FALSE
45 | EndGlobalSection
46 | GlobalSection(NestedProjects) = preSolution
47 | {78916DA5-CFEC-40B5-84A6-B0190B076700} = {862626B4-433B-4FA4-96DC-815850960814}
48 | {90EED71C-45C7-4952-818B-3643A3E906B9} = {9936F693-95E7-48C4-ADC3-3FFCBC654587}
49 | {50FAB084-7357-4943-9186-0C3F81CC9F3E} = {71539E00-8C5F-4B45-AA0D-B83CAC58FCA4}
50 | EndGlobalSection
51 | GlobalSection(ExtensibilityGlobals) = postSolution
52 | SolutionGuid = {49F1B715-24A3-4580-BA87-34ED114ED2B8}
53 | EndGlobalSection
54 | EndGlobal
55 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Josh Carlisle
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 |
--------------------------------------------------------------------------------
/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joshdcar/azure-functions-extensions-cognitive-services/f6dea9eff6c8d5a9cd1bb99fe21aa63efefac895/logo.png
--------------------------------------------------------------------------------
/samples/AzureFunctions.Extensions.CognitiveServics.Samples/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # Azure Functions localsettings file
5 | local.settings.json
6 |
7 | # User-specific files
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Build results
17 | [Dd]ebug/
18 | [Dd]ebugPublic/
19 | [Rr]elease/
20 | [Rr]eleases/
21 | x64/
22 | x86/
23 | bld/
24 | [Bb]in/
25 | [Oo]bj/
26 | [Ll]og/
27 |
28 | # Visual Studio 2015 cache/options directory
29 | .vs/
30 | # Uncomment if you have tasks that create the project's static files in wwwroot
31 | #wwwroot/
32 |
33 | # MSTest test Results
34 | [Tt]est[Rr]esult*/
35 | [Bb]uild[Ll]og.*
36 |
37 | # NUNIT
38 | *.VisualState.xml
39 | TestResult.xml
40 |
41 | # Build Results of an ATL Project
42 | [Dd]ebugPS/
43 | [Rr]eleasePS/
44 | dlldata.c
45 |
46 | # DNX
47 | project.lock.json
48 | project.fragment.lock.json
49 | artifacts/
50 |
51 | *_i.c
52 | *_p.c
53 | *_i.h
54 | *.ilk
55 | *.meta
56 | *.obj
57 | *.pch
58 | *.pdb
59 | *.pgc
60 | *.pgd
61 | *.rsp
62 | *.sbr
63 | *.tlb
64 | *.tli
65 | *.tlh
66 | *.tmp
67 | *.tmp_proj
68 | *.log
69 | *.vspscc
70 | *.vssscc
71 | .builds
72 | *.pidb
73 | *.svclog
74 | *.scc
75 |
76 | # Chutzpah Test files
77 | _Chutzpah*
78 |
79 | # Visual C++ cache files
80 | ipch/
81 | *.aps
82 | *.ncb
83 | *.opendb
84 | *.opensdf
85 | *.sdf
86 | *.cachefile
87 | *.VC.db
88 | *.VC.VC.opendb
89 |
90 | # Visual Studio profiler
91 | *.psess
92 | *.vsp
93 | *.vspx
94 | *.sap
95 |
96 | # TFS 2012 Local Workspace
97 | $tf/
98 |
99 | # Guidance Automation Toolkit
100 | *.gpState
101 |
102 | # ReSharper is a .NET coding add-in
103 | _ReSharper*/
104 | *.[Rr]e[Ss]harper
105 | *.DotSettings.user
106 |
107 | # JustCode is a .NET coding add-in
108 | .JustCode
109 |
110 | # TeamCity is a build add-in
111 | _TeamCity*
112 |
113 | # DotCover is a Code Coverage Tool
114 | *.dotCover
115 |
116 | # NCrunch
117 | _NCrunch_*
118 | .*crunch*.local.xml
119 | nCrunchTemp_*
120 |
121 | # MightyMoose
122 | *.mm.*
123 | AutoTest.Net/
124 |
125 | # Web workbench (sass)
126 | .sass-cache/
127 |
128 | # Installshield output folder
129 | [Ee]xpress/
130 |
131 | # DocProject is a documentation generator add-in
132 | DocProject/buildhelp/
133 | DocProject/Help/*.HxT
134 | DocProject/Help/*.HxC
135 | DocProject/Help/*.hhc
136 | DocProject/Help/*.hhk
137 | DocProject/Help/*.hhp
138 | DocProject/Help/Html2
139 | DocProject/Help/html
140 |
141 | # Click-Once directory
142 | publish/
143 |
144 | # Publish Web Output
145 | *.[Pp]ublish.xml
146 | *.azurePubxml
147 | # TODO: Comment the next line if you want to checkin your web deploy settings
148 | # but database connection strings (with potential passwords) will be unencrypted
149 | #*.pubxml
150 | *.publishproj
151 |
152 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
153 | # checkin your Azure Web App publish settings, but sensitive information contained
154 | # in these scripts will be unencrypted
155 | PublishScripts/
156 |
157 | # NuGet Packages
158 | *.nupkg
159 | # The packages folder can be ignored because of Package Restore
160 | **/packages/*
161 | # except build/, which is used as an MSBuild target.
162 | !**/packages/build/
163 | # Uncomment if necessary however generally it will be regenerated when needed
164 | #!**/packages/repositories.config
165 | # NuGet v3's project.json files produces more ignoreable files
166 | *.nuget.props
167 | *.nuget.targets
168 |
169 | # Microsoft Azure Build Output
170 | csx/
171 | *.build.csdef
172 |
173 | # Microsoft Azure Emulator
174 | ecf/
175 | rcf/
176 |
177 | # Windows Store app package directories and files
178 | AppPackages/
179 | BundleArtifacts/
180 | Package.StoreAssociation.xml
181 | _pkginfo.txt
182 |
183 | # Visual Studio cache files
184 | # files ending in .cache can be ignored
185 | *.[Cc]ache
186 | # but keep track of directories ending in .cache
187 | !*.[Cc]ache/
188 |
189 | # Others
190 | ClientBin/
191 | ~$*
192 | *~
193 | *.dbmdl
194 | *.dbproj.schemaview
195 | *.jfm
196 | *.pfx
197 | *.publishsettings
198 | node_modules/
199 | orleans.codegen.cs
200 |
201 | # Since there are multiple workflows, uncomment next line to ignore bower_components
202 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
203 | #bower_components/
204 |
205 | # RIA/Silverlight projects
206 | Generated_Code/
207 |
208 | # Backup & report files from converting an old project file
209 | # to a newer Visual Studio version. Backup files are not needed,
210 | # because we have git ;-)
211 | _UpgradeReport_Files/
212 | Backup*/
213 | UpgradeLog*.XML
214 | UpgradeLog*.htm
215 |
216 | # SQL Server files
217 | *.mdf
218 | *.ldf
219 |
220 | # Business Intelligence projects
221 | *.rdl.data
222 | *.bim.layout
223 | *.bim_*.settings
224 |
225 | # Microsoft Fakes
226 | FakesAssemblies/
227 |
228 | # GhostDoc plugin setting file
229 | *.GhostDoc.xml
230 |
231 | # Node.js Tools for Visual Studio
232 | .ntvs_analysis.dat
233 |
234 | # Visual Studio 6 build log
235 | *.plg
236 |
237 | # Visual Studio 6 workspace options file
238 | *.opt
239 |
240 | # Visual Studio LightSwitch build output
241 | **/*.HTMLClient/GeneratedArtifacts
242 | **/*.DesktopClient/GeneratedArtifacts
243 | **/*.DesktopClient/ModelManifest.xml
244 | **/*.Server/GeneratedArtifacts
245 | **/*.Server/ModelManifest.xml
246 | _Pvt_Extensions
247 |
248 | # Paket dependency manager
249 | .paket/paket.exe
250 | paket-files/
251 |
252 | # FAKE - F# Make
253 | .fake/
254 |
255 | # JetBrains Rider
256 | .idea/
257 | *.sln.iml
258 |
259 | # CodeRush
260 | .cr/
261 |
262 | # Python Tools for Visual Studio (PTVS)
263 | __pycache__/
264 | *.pyc
--------------------------------------------------------------------------------
/samples/AzureFunctions.Extensions.CognitiveServics.Samples/AzureFunctions.Extensions.CognitiveServics.Samples.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | netstandard2.0
4 | v2
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | PreserveNewest
16 |
17 |
18 | PreserveNewest
19 | Never
20 |
21 |
22 |
--------------------------------------------------------------------------------
/samples/AzureFunctions.Extensions.CognitiveServics.Samples/CognitiveServicesFunctions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Threading.Tasks;
4 | using AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Analysis;
5 | using AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Describe;
6 | using AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Domain;
7 | using AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Handwriting;
8 | using AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Ocr;
9 | using AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Thumbnail;
10 | using AzureFunctions.Extensions.CognitiveServices.Bindings;
11 | using Microsoft.Azure.WebJobs;
12 | using Microsoft.Azure.WebJobs.Host;
13 |
14 | namespace AzureFunctions.Extensions.CognitiveServics.Samples
15 | {
16 | [StorageAccount("storageaccount")]
17 | public static class CognitiveServicesFunctions
18 | {
19 |
20 | #region Vision Analysis
21 |
22 | ///
23 | /// Sample calling Vision Analysis Triggered from a blob storage
24 | /// Trigger: Blob Storage
25 | /// Vision Binding: Model Binding w/ Blob Data Source
26 | ///
27 | ///
28 | ///
29 | ///
30 | ///
31 | ///
32 | [FunctionName("VisionAnalysisModelBlobFunction")]
33 | public static async Task VisionAnalysisModelBlobFunctionRun(
34 | [BlobTrigger("analysismodel/{name}")]Stream storageBlob,
35 | [VisionAnalysis(BlobStorageAccount = "StorageAccount",
36 | BlobStoragePath = "analysismodel/{name}",
37 | ImageSource = ImageSource.BlobStorage)]VisionAnalysisModel result,
38 | string name,
39 | TraceWriter log)
40 | {
41 |
42 | log.Info($"Analysis Results:{result}");
43 |
44 | }
45 |
46 |
47 | [FunctionName("VisionAnalysisBlobFunction")]
48 | public static async Task VisionAnalysisRun(
49 | [BlobTrigger("analysis/{name}")]Stream storageBlob,
50 | [Table("VisionResults")]IAsyncCollector results,
51 | [VisionAnalysis()]VisionAnalysisClient visionclient,
52 | string name,
53 | TraceWriter log)
54 | {
55 |
56 | var result = await visionclient.AnalyzeAsync(new VisionAnalysisRequest(storageBlob));
57 |
58 | await results.AddAsync(new VisionResult(Guid.NewGuid().ToString(), "VisionAnalysis") { ResultJson = result.ToString() });
59 |
60 | log.Info($"Analysis Results:{result.ToString()}");
61 |
62 | }
63 |
64 | #endregion
65 |
66 |
67 | [FunctionName("VisionDesribeBlobFunction")]
68 | public static async Task VisionDescribeBlobFunction(
69 | [BlobTrigger("describe/{name}")]Stream storageBlob,
70 | [Table("VisionResults")]IAsyncCollector results,
71 | [VisionDescribe()]VisionDescribeClient visionclient,
72 | string name,
73 | TraceWriter log
74 | )
75 | {
76 | var result = await visionclient.DescribeAsync(new VisionDescribeRequest(storageBlob));
77 |
78 | await results.AddAsync(new VisionResult(Guid.NewGuid().ToString(), "VisionDescribe") { ResultJson = result.ToString() });
79 |
80 | log.Info($"Describe Results:{result.ToString()}");
81 |
82 | }
83 |
84 | [FunctionName("VisionDescribeModelBlobFunction")]
85 | public static async Task VisionDescribeModelBlobFunction(
86 | [BlobTrigger("describe/{name}")]Stream storageBlob,
87 | [Table("VisionResults")]IAsyncCollector results,
88 | [VisionDescribe(BlobStorageAccount = "StorageAccount",
89 | BlobStoragePath = "describemodel/{name}",
90 | ImageSource = ImageSource.BlobStorage)]VisionDescribeModel result,
91 | string name,
92 | TraceWriter log
93 | )
94 | {
95 | log.Info($"Describe Results:{result.ToString()}");
96 | }
97 |
98 | [FunctionName("VisionThumbnailBlobFunction")]
99 | public static async Task VisionThumbnailBlobFunction(
100 | [BlobTrigger("thumbnail/{name}")]Stream storageBlob,
101 | [VisionThumbnail(AutoResize = true,
102 | Height ="100",
103 | Width = "100",
104 | SmartCropping =true)]VisionThumbnailClient visionclient,
105 | [Blob("thumbnailresults/{name}", FileAccess.Write)]Stream thumbnailBlob,
106 | string name,
107 | TraceWriter log
108 | )
109 | {
110 |
111 | var result = await visionclient.ThumbnailAsync(new VisionThumbnailRequest(storageBlob));
112 |
113 | using (MemoryStream stream = new MemoryStream(result))
114 | {
115 | await stream.CopyToAsync(thumbnailBlob);
116 | }
117 |
118 | log.Info($"Image thumbnail generated");
119 |
120 | }
121 |
122 | [FunctionName("VisionOcrBlobFunction")]
123 | public static async Task VisionOcrBlobFunction(
124 | [BlobTrigger("ocrrequest/{name}")]Stream storageBlob,
125 | [Table("VisionResults")]IAsyncCollector results,
126 | [VisionOcr()]VisionOcrClient visionclient,
127 | string name,
128 | TraceWriter log
129 | )
130 | {
131 | var result = await visionclient.OCRAsync(new VisionOcrRequest(storageBlob));
132 |
133 | await results.AddAsync(new VisionResult(Guid.NewGuid().ToString(), "VisionOCR") { ResultJson = result.ToString() });
134 |
135 | log.Info($"OCR Results:{result.ToString()}");
136 |
137 | }
138 |
139 | [FunctionName("VisionHandwritingBlobFunction")]
140 | public static async Task VisionHandwritingBlobFunction(
141 | [BlobTrigger("handwriting/{name}")]Stream storageBlob,
142 | [Table("VisionResults")]IAsyncCollector results,
143 | [VisionHandwriting()]VisionHandwritingClient visionclient,
144 | string name,
145 | TraceWriter log
146 | )
147 | {
148 | var result = await visionclient.HandwritingAsync(new VisionHandwritingRequest(storageBlob));
149 |
150 | await results.AddAsync(new VisionResult(Guid.NewGuid().ToString(), "VisionHandwriting") { ResultJson = result.ToString() });
151 |
152 | log.Info($"Handwriting Results:{result.ToString()}");
153 |
154 | }
155 |
156 | [FunctionName("VisionCelebrityBlobFunction")]
157 | public static async Task VisionCelebrityBlobFunction(
158 | [BlobTrigger("celebrity/{name}")]Stream storageBlob,
159 | [Table("VisionResults")]IAsyncCollector results,
160 | [VisionDomain(Domain = VisionDomainRequest.CELEBRITY_DOMAIN)]VisionDomainClient visionclient,
161 | string name,
162 | TraceWriter log
163 | )
164 | {
165 | var request = new VisionDomainRequest(storageBlob) { Domain = VisionDomainOptions.Celebrity };
166 |
167 | var celebrityResult = await visionclient.AnalyzeCelebrityAsync(request);
168 |
169 | await results.AddAsync(new VisionResult(Guid.NewGuid().ToString(), "VisionDomain") { ResultJson = celebrityResult.ToString() });
170 |
171 | log.Info($"Celebrity Domain results:{celebrityResult.ToString()}");
172 |
173 |
174 | }
175 |
176 | [FunctionName("VisionLandmarkBlobFunction")]
177 | public static async Task VisionLandmarkBlobFunction(
178 | [BlobTrigger("landmarks/{name}")]Stream storageBlob,
179 | [Table("VisionResults")]IAsyncCollector results,
180 | [VisionDomain(Domain = VisionDomainRequest.LANDMARK_DOMAIN)]VisionDomainClient visionclient,
181 | string name,
182 | TraceWriter log
183 | )
184 | {
185 | var landmarkResult = await visionclient.AnalyzeLandmarkAsync(new VisionDomainRequest(storageBlob));
186 |
187 | await results.AddAsync(new VisionResult(Guid.NewGuid().ToString(), "VisionDomain") { ResultJson = landmarkResult.ToString() });
188 |
189 | log.Info($"Celebrity Domain results:{landmarkResult.ToString()}");
190 |
191 |
192 | }
193 | }
194 | }
195 |
--------------------------------------------------------------------------------
/samples/AzureFunctions.Extensions.CognitiveServics.Samples/ThumbnailGenerator.cs:
--------------------------------------------------------------------------------
1 |
2 | using System.IO;
3 | using Microsoft.AspNetCore.Mvc;
4 | using Microsoft.Azure.WebJobs;
5 | using Microsoft.Azure.WebJobs.Extensions.Http;
6 | using Microsoft.AspNetCore.Http;
7 | using Microsoft.Azure.WebJobs.Host;
8 | using Newtonsoft.Json;
9 | using System.Threading.Tasks;
10 | using AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Thumbnail;
11 | using AzureFunctions.Extensions.CognitiveServices.Bindings;
12 |
13 | namespace AzureFunctions.Extensions.CognitiveServics.Samples
14 | {
15 | public static class ThumbnailGenerator
16 | {
17 |
18 |
19 | [StorageAccount("StorageAccount")]
20 | [FunctionName("ThumbnailGenApi")]
21 | public static async Task ThumbnailGenApi(
22 | [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "generatethumbnail/{filename}")]HttpRequest req,
23 | [Blob("images/{filename}", FileAccess.Write)]Stream imageStream,
24 | [Blob("thumbnails/{filename}", FileAccess.Write)]Stream thumbnailImageStream,
25 | [VisionThumbnail(SmartCropping = true, Height = "150", Width = "150")]VisionThumbnailClient client,
26 | string fileName,
27 | TraceWriter log)
28 | {
29 |
30 | //Load Http Request Body into Thumbnail Request
31 |
32 | var request = new VisionThumbnailRequest(req.Body);
33 |
34 | //Generate Thumbnail
35 | var thumbnailBytes = await client.ThumbnailAsync(request);
36 |
37 | //Output Original Image to Blob Storage
38 | using (MemoryStream stream = new MemoryStream(request.ImageBytes))
39 | {
40 | await stream.CopyToAsync(imageStream);
41 | }
42 |
43 | //Output Thumbnail To Blob Storage
44 | using (MemoryStream stream = new MemoryStream(thumbnailBytes))
45 | {
46 | await stream.CopyToAsync(thumbnailImageStream);
47 | }
48 |
49 |
50 | return (ActionResult)new OkResult();
51 |
52 | }
53 |
54 | [StorageAccount("StorageAccount")]
55 | [FunctionName("ThumbnailGenBlobTrigger")]
56 | public static void ThumbnailGenBlobTrigger(
57 |
58 | [BlobTrigger("myimages/{filename}")]byte[] image,
59 | [Blob("mythumbnails/{filename}", FileAccess.Write)]out byte[] thumbnailImage,
60 | [VisionThumbnail(ImageSource=ImageSource.BlobStorage,
61 | BlobStorageAccount ="StorageAccount",
62 | BlobStoragePath ="images/{filename}",
63 | SmartCropping = true,
64 | Height = "150",
65 | Width = "150")]byte[] thumbnail,
66 | string fileName,
67 | TraceWriter log)
68 | {
69 | //Output thumbnail
70 | thumbnailImage = thumbnail;
71 |
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/samples/AzureFunctions.Extensions.CognitiveServics.Samples/VisionResult.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.WindowsAzure.Storage.Table;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace AzureFunctions.Extensions.CognitiveServics.Samples
7 | {
8 | public class VisionResult : TableEntity
9 | {
10 |
11 | public VisionResult(string id, string partitionKey)
12 | {
13 | this.RowKey = id;
14 | this.PartitionKey = partitionKey;
15 | }
16 |
17 | public string ResultJson { get; set; }
18 |
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/samples/AzureFunctions.Extensions.CognitiveServics.Samples/host.json:
--------------------------------------------------------------------------------
1 | {
2 | }
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27428.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AzureFunctions.Extensions.CognitiveServices", "AzureFunctions.Extensions.CognitiveServices\AzureFunctions.Extensions.CognitiveServices.csproj", "{CF825051-50F5-45C6-9220-E794DE51F87C}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AzureFunctions.Extensions.CognitiveServices.Tests", "..\tests\AzureFunctions.Extensions.CognitiveServices.Tests\AzureFunctions.Extensions.CognitiveServices.Tests.csproj", "{37767F3C-FDD9-4F2F-842B-CB347CF46072}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AzureFunctions.Extensions.CognitiveServics.Samples", "..\samples\AzureFunctions.Extensions.CognitiveServics.Samples\AzureFunctions.Extensions.CognitiveServics.Samples.csproj", "{553593F1-CBBC-4555-BB82-616C12E0EC82}"
11 | EndProject
12 | Global
13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
14 | Debug|Any CPU = Debug|Any CPU
15 | Release|Any CPU = Release|Any CPU
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {CF825051-50F5-45C6-9220-E794DE51F87C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19 | {CF825051-50F5-45C6-9220-E794DE51F87C}.Debug|Any CPU.Build.0 = Debug|Any CPU
20 | {CF825051-50F5-45C6-9220-E794DE51F87C}.Release|Any CPU.ActiveCfg = Release|Any CPU
21 | {CF825051-50F5-45C6-9220-E794DE51F87C}.Release|Any CPU.Build.0 = Release|Any CPU
22 | {37767F3C-FDD9-4F2F-842B-CB347CF46072}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23 | {37767F3C-FDD9-4F2F-842B-CB347CF46072}.Debug|Any CPU.Build.0 = Debug|Any CPU
24 | {37767F3C-FDD9-4F2F-842B-CB347CF46072}.Release|Any CPU.ActiveCfg = Release|Any CPU
25 | {37767F3C-FDD9-4F2F-842B-CB347CF46072}.Release|Any CPU.Build.0 = Release|Any CPU
26 | {553593F1-CBBC-4555-BB82-616C12E0EC82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {553593F1-CBBC-4555-BB82-616C12E0EC82}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {553593F1-CBBC-4555-BB82-616C12E0EC82}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {553593F1-CBBC-4555-BB82-616C12E0EC82}.Release|Any CPU.Build.0 = Release|Any CPU
30 | EndGlobalSection
31 | GlobalSection(SolutionProperties) = preSolution
32 | HideSolutionNode = FALSE
33 | EndGlobalSection
34 | GlobalSection(ExtensibilityGlobals) = postSolution
35 | SolutionGuid = {49F1B715-24A3-4580-BA87-34ED114ED2B8}
36 | EndGlobalSection
37 | EndGlobal
38 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/AzureFunctions.Extensions.CognitiveServices.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | Full
6 | true
7 | true
8 | 1.0.0-preview4
9 | Cognitive Services Extensions for Azure Functions
10 | https://github.com/joshdcar/azure-functions-extensions-cognitive-services
11 | git
12 | https://github.com/joshdcar/azure-functions-extensions-cognitive-services
13 | https://choosealicense.com/licenses/mit/
14 | MIT License
15 |
16 | - Support for Azure Functions 2.0 GA
17 | - BREAKING CHANGE: Removed custom support for KeyVault as that functionality is now provided within the core Azure Functions framework.
18 |
19 | More details visit https://github.com/joshdcar/azure-functions-extensions-cognitive-services
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Analysis/VisionAnalysisAttribute.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Azure.WebJobs.Description;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Analysis
7 | {
8 | [Binding]
9 | [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.ReturnValue)]
10 | public class VisionAnalysisAttribute : VisionAttributeBase
11 | {
12 |
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Analysis/VisionAnalysisBinding.cs:
--------------------------------------------------------------------------------
1 | using AzureFunctions.Extensions.CognitiveServices.Config;
2 | using AzureFunctions.Extensions.CognitiveServices.Services;
3 | using Microsoft.Azure.WebJobs.Description;
4 | using Microsoft.Azure.WebJobs.Host.Config;
5 | using Microsoft.Extensions.Logging;
6 | using System;
7 |
8 |
9 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Analysis
10 | {
11 | [Extension("VisionAnalysis")]
12 | public class VisionAnalysisBinding : IExtensionConfigProvider, IVisionBinding
13 | {
14 |
15 | public ICognitiveServicesClient Client {get;set;}
16 |
17 | internal ILoggerFactory _loggerFactory;
18 |
19 | public VisionAnalysisBinding(ILoggerFactory loggerFactory, ICognitiveServicesClient client)
20 | {
21 | _loggerFactory = loggerFactory;
22 | this.Client = client;
23 | }
24 |
25 | public void Initialize(ExtensionConfigContext context)
26 | {
27 |
28 | LoadClient();
29 |
30 | var visionAnalysisRule = context.AddBindingRule();
31 |
32 | visionAnalysisRule.When(nameof(VisionAnalysisAttribute.ImageSource), ImageSource.BlobStorage)
33 | .BindToInput(GetVisionAnalysisModel);
34 |
35 | visionAnalysisRule.When(nameof(VisionAnalysisAttribute.ImageSource), ImageSource.Url)
36 | .BindToInput(GetVisionAnalysisModel);
37 |
38 | visionAnalysisRule.When(nameof(VisionAnalysisAttribute.ImageSource), ImageSource.Client)
39 | .BindToInput(attr => new VisionAnalysisClient(this, attr, _loggerFactory));
40 |
41 | }
42 |
43 | private void LoadClient()
44 | {
45 | if (Client == null)
46 | {
47 | Client = new CognitiveServicesClient(new RetryPolicy(), _loggerFactory);
48 | }
49 | }
50 |
51 | private VisionAnalysisModel GetVisionAnalysisModel(VisionAnalysisAttribute attribute)
52 | {
53 |
54 | if (attribute.ImageSource == Bindings.ImageSource.Client)
55 | {
56 | throw new ArgumentException($"ImageSource of Client does not support binding to vision models. Use Url or BlobStorage instead. ");
57 | }
58 |
59 | attribute.Validate();
60 |
61 | var client = new VisionAnalysisClient(this, attribute, _loggerFactory);
62 |
63 | VisionAnalysisRequest request = new VisionAnalysisRequest();
64 |
65 | if (attribute.ImageSource == ImageSource.BlobStorage)
66 | {
67 | var fileTask = StorageServices.GetFileBytes(attribute.BlobStoragePath, attribute.BlobStorageAccount);
68 | fileTask.Wait();
69 |
70 | request.ImageBytes = fileTask.Result;
71 |
72 | } else
73 | {
74 | request.ImageUrl = attribute.ImageUrl;
75 | }
76 |
77 | var result = client.AnalyzeAsync(request);
78 | result.Wait();
79 |
80 | return result.Result;
81 |
82 | }
83 |
84 |
85 |
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Analysis/VisionAnalysisClient.cs:
--------------------------------------------------------------------------------
1 | using AzureFunctions.Extensions.CognitiveServices.Config;
2 | using AzureFunctions.Extensions.CognitiveServices.Services;
3 | using AzureFunctions.Extensions.CognitiveServices.Services.Models;
4 | using Microsoft.Extensions.Logging;
5 | using Newtonsoft.Json;
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Diagnostics;
9 | using System.Net.Http;
10 | using System.Text;
11 | using System.Threading.Tasks;
12 |
13 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Analysis
14 | {
15 | public class VisionAnalysisClient
16 | {
17 | IVisionBinding _config;
18 | VisionAnalysisAttribute _attr;
19 | ILogger _log;
20 |
21 | public VisionAnalysisClient(IVisionBinding config, VisionAnalysisAttribute attr, ILoggerFactory loggerFactory)
22 | {
23 | this._config = config;
24 | this._attr = attr;
25 | this._log = loggerFactory?.CreateLogger("Host.Bindings.VisionAnalysis");
26 | }
27 |
28 | public async Task AnalyzeAsync(VisionAnalysisRequest request)
29 | {
30 | Stopwatch imageResizeSW = null;
31 |
32 | var visionOperation = await MergeProperties(request, this._config, this._attr);
33 |
34 | if (request.IsUrlImageSource == false)
35 | {
36 |
37 | if (visionOperation.ImageBytes == null || visionOperation.ImageBytes.Length == 0)
38 | {
39 | _log.LogWarning(VisionExceptionMessages.FileMissing);
40 | throw new ArgumentException(VisionExceptionMessages.FileMissing);
41 | }
42 |
43 | if (ImageResizeService.IsImage(visionOperation.ImageBytes) == false)
44 | {
45 | _log.LogWarning(VisionExceptionMessages.InvalidFileType);
46 | throw new ArgumentException(VisionExceptionMessages.InvalidFileType);
47 | }
48 |
49 | if (visionOperation.Oversized == true && visionOperation.AutoResize == false)
50 | {
51 | var message = string.Format(VisionExceptionMessages.FileTooLarge,
52 | VisionConfiguration.MaximumFileSize, visionOperation.ImageBytes.Length);
53 | _log.LogWarning(message);
54 | throw new ArgumentException(message);
55 | }
56 | else if (visionOperation.Oversized == true && visionOperation.AutoResize == true)
57 | {
58 | _log.LogTrace("Resizing Image");
59 |
60 | imageResizeSW = new Stopwatch();
61 |
62 | imageResizeSW.Start();
63 |
64 | visionOperation.ImageBytes = ImageResizeService.ResizeImage(visionOperation.ImageBytes);
65 |
66 | imageResizeSW.Stop();
67 |
68 | _log.LogMetric("VisionAnalysisImageResizeDurationMillisecond", imageResizeSW.ElapsedMilliseconds);
69 |
70 | if (visionOperation.Oversized)
71 | {
72 | var message = string.Format(VisionExceptionMessages.FileTooLargeAfterResize,
73 | VisionConfiguration.MaximumFileSize, visionOperation.ImageBytes.Length);
74 | _log.LogWarning(message);
75 | throw new ArgumentException(message);
76 | }
77 |
78 | }
79 | }
80 |
81 | var result = await SubmitRequest(visionOperation);
82 |
83 | return result;
84 | }
85 |
86 | private async Task SubmitRequest(VisionAnalysisRequest request)
87 | {
88 | Stopwatch sw = new Stopwatch();
89 |
90 | string requestParameters = GetVisionOperationParameters(request);
91 |
92 | string uri = $"{request.Url}/analyze?{requestParameters}";
93 |
94 | ServiceResultModel requestResult = null;
95 |
96 | if (request.IsUrlImageSource)
97 | {
98 | _log.LogTrace($"Submitting Vision Analysis Request");
99 |
100 | var urlRequest = new VisionUrlRequest { Url = request.ImageUrl };
101 | var requestContent = JsonConvert.SerializeObject(urlRequest);
102 |
103 | var content = new StringContent(requestContent);
104 |
105 | sw.Start();
106 |
107 | requestResult = await this._config.Client.PostAsync(uri, request.Key, content, ReturnType.String);
108 |
109 | sw.Stop();
110 |
111 | _log.LogMetric("VisionRequestDurationMillisecond", sw.ElapsedMilliseconds);
112 |
113 | }
114 | else
115 | {
116 | using (ByteArrayContent content = new ByteArrayContent(request.ImageBytes))
117 | {
118 | requestResult = await this._config.Client.PostAsync(uri, request.Key, content, ReturnType.String);
119 | }
120 | }
121 |
122 | if (requestResult.HttpStatusCode == (int)System.Net.HttpStatusCode.OK)
123 | {
124 | _log.LogTrace($"Analysis Request Results: {requestResult.Contents}");
125 |
126 | VisionAnalysisModel result = JsonConvert.DeserializeObject(requestResult.Contents);
127 |
128 | return result;
129 | }
130 | else if (requestResult.HttpStatusCode == (int)System.Net.HttpStatusCode.BadRequest)
131 | {
132 |
133 | VisionErrorModel error = JsonConvert.DeserializeObject(requestResult.Contents);
134 | var message = string.Format(VisionExceptionMessages.CognitiveServicesException, error.Code, error.Message);
135 |
136 | _log.LogWarning(message);
137 |
138 | throw new Exception(message);
139 | }
140 | else
141 | {
142 | var message = string.Format(VisionExceptionMessages.CognitiveServicesException, requestResult.HttpStatusCode, requestResult.Contents);
143 |
144 | _log.LogError(message);
145 |
146 | throw new Exception(message);
147 | }
148 |
149 | }
150 |
151 | private string GetVisionOperationParameters(VisionAnalysisRequest request)
152 | {
153 | VisionAnalysisOptions options = request.Options;
154 |
155 | string optionsParam = string.Empty;
156 | string visualFeaturesParam = string.Empty;
157 | string detailsParam = string.Empty;
158 | string languageParam = "&language=en";
159 |
160 | if (options == VisionAnalysisOptions.All)
161 | {
162 | options = VisionAnalysisOptions.Categories |
163 | VisionAnalysisOptions.Celebrities |
164 | VisionAnalysisOptions.Color |
165 | VisionAnalysisOptions.Description |
166 | VisionAnalysisOptions.Faces |
167 | VisionAnalysisOptions.ImageType |
168 | VisionAnalysisOptions.Landmarks |
169 | VisionAnalysisOptions.Tags;
170 | }
171 |
172 |
173 | //Details Parameters
174 | if (options.HasFlag(VisionAnalysisOptions.Celebrities)
175 | || options.HasFlag(VisionAnalysisOptions.Landmarks))
176 | {
177 |
178 | List details = new List();
179 |
180 | if (options.HasFlag(VisionAnalysisOptions.Celebrities))
181 | {
182 | details.Add("Celebrities");
183 | }
184 |
185 | if (options.HasFlag(VisionAnalysisOptions.Landmarks))
186 | {
187 | details.Add("Landmarks");
188 | }
189 |
190 | detailsParam = $"&details={string.Join(",", details)}";
191 |
192 | //Remove the Details Flags from the options so they are not
193 | //included in subsequent operations
194 | options = options & ~(VisionAnalysisOptions.Celebrities | VisionAnalysisOptions.Landmarks);
195 |
196 | }
197 |
198 | //Visual Features Parameter
199 | visualFeaturesParam = options.ToString();
200 | visualFeaturesParam = visualFeaturesParam.Replace(" ", string.Empty);
201 | visualFeaturesParam = $"visualFeatures={visualFeaturesParam}";
202 |
203 | //Combine All parameter
204 | optionsParam = $"{visualFeaturesParam}{detailsParam}{languageParam}";
205 |
206 | return optionsParam;
207 | }
208 |
209 | private async Task MergeProperties(VisionAnalysisRequest operation, IVisionBinding config, VisionAnalysisAttribute attr)
210 | {
211 |
212 | var visionOperation = new VisionAnalysisRequest
213 | {
214 | Url = attr.VisionUrl ?? operation.Url,
215 | Key = attr.VisionKey ?? operation.Key,
216 | AutoResize = attr.AutoResize,
217 | Options = operation.Options,
218 | ImageUrl = string.IsNullOrEmpty(operation.ImageUrl) ? attr.ImageUrl : operation.ImageUrl,
219 | ImageBytes = operation.ImageBytes,
220 | };
221 |
222 | if(string.IsNullOrEmpty(visionOperation.Key))
223 | {
224 | _log.LogWarning(VisionExceptionMessages.KeyMissing);
225 | throw new ArgumentException(VisionExceptionMessages.KeyMissing);
226 | }
227 |
228 | return visionOperation;
229 |
230 | }
231 |
232 | }
233 |
234 | }
235 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Analysis/VisionAnalysisExtension.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Azure.WebJobs;
2 | using System;
3 |
4 |
5 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Analysis
6 | {
7 | public static class VisionAnalysisExtension
8 | {
9 | public static IWebJobsBuilder AddVisionAnalysis(this IWebJobsBuilder builder)
10 | {
11 | if (builder == null)
12 | {
13 | throw new ArgumentNullException(nameof(builder));
14 | }
15 |
16 | builder.AddExtension();
17 | return builder;
18 | }
19 |
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Analysis/VisionAnalysisModel.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Analysis
7 | {
8 | public class VisionAnalysisModel
9 | {
10 | [JsonProperty(PropertyName = "categories")]
11 | public IEnumerable Categories { get; set; }
12 |
13 | [JsonProperty(PropertyName = "tags")]
14 | public IEnumerable Tags { get; set; }
15 |
16 | [JsonProperty(PropertyName = "description")]
17 | public VisionDescription Description { get; set; }
18 |
19 | [JsonProperty(PropertyName = "faces")]
20 | public IEnumerable Faces { get; set; }
21 |
22 | [JsonProperty(PropertyName = "color")]
23 | public VisionColor Color { get; set; }
24 |
25 | [JsonProperty(PropertyName = "imageType")]
26 | public VisionImageType ImageType { get; set; }
27 |
28 | [JsonProperty(PropertyName = "metadata")]
29 | public VisionMetadata Metadata { get; set; }
30 |
31 | public override string ToString()
32 | {
33 | return JsonConvert.SerializeObject(this);
34 | }
35 |
36 | }
37 |
38 | public class VisionCategory
39 | {
40 | [JsonProperty(PropertyName = "name")]
41 | public string Name { get; set; }
42 |
43 | [JsonProperty(PropertyName = "score")]
44 | public double Score { get; set; }
45 |
46 | [JsonProperty(PropertyName = "detail")]
47 | public VisionDetail Detail { get; set; }
48 | }
49 |
50 | public class VisionDetail
51 | {
52 | [JsonProperty(PropertyName = "landmarks")]
53 | public IEnumerable Landmarks { get; set; }
54 |
55 | [JsonProperty(PropertyName = "celebrities")]
56 | public IEnumerable Celebrities { get; set; }
57 | }
58 |
59 | public class VisionLandmark
60 | {
61 | [JsonProperty(PropertyName = "name")]
62 | public string Name { get; set; }
63 |
64 | [JsonProperty(PropertyName = "confidence")]
65 | public double Confidence { get; set; }
66 | }
67 |
68 | public class VisionCelebrity
69 | {
70 | [JsonProperty(PropertyName = "name")]
71 | public string Name { get; set; }
72 |
73 | [JsonProperty(PropertyName = "confidence")]
74 | public double Confidence { get; set; }
75 |
76 | [JsonProperty(PropertyName = "faceRectangle")]
77 | public VisionFaceRectangle FaceRectangle { get; set; }
78 | }
79 |
80 | public class VisionTag
81 | {
82 | [JsonProperty(PropertyName = "name")]
83 | public string Name { get; set; }
84 |
85 | [JsonProperty(PropertyName = "confidence")]
86 | public double Confidence { get; set; }
87 | }
88 |
89 | public class VisionDescription
90 | {
91 | [JsonProperty(PropertyName = "tags")]
92 | public IEnumerable Tags { get; set; }
93 |
94 | [JsonProperty(PropertyName = "captions")]
95 | public IEnumerable Captions { get; set; }
96 |
97 | }
98 |
99 | public class VisionCaption
100 | {
101 | [JsonProperty(PropertyName = "text")]
102 | public string Text { get; set; }
103 |
104 | [JsonProperty(PropertyName = "confidence")]
105 | public double Confidence { get; set; }
106 | }
107 |
108 | public class VisionFace
109 | {
110 | [JsonProperty(PropertyName = "age")]
111 | public int Age { get; set; }
112 |
113 | [JsonProperty(PropertyName = "gender")]
114 | public string Gender { get; set; }
115 |
116 | [JsonProperty(PropertyName = "faceRectangle")]
117 | public VisionFaceRectangle FaceRectangle { get; set; }
118 | }
119 |
120 | public class VisionFaceRectangle
121 | {
122 | [JsonProperty(PropertyName = "top")]
123 | public int Top { get; set; }
124 |
125 | [JsonProperty(PropertyName = "left")]
126 | public int Left { get; set; }
127 |
128 | [JsonProperty(PropertyName = "width")]
129 | public int Width { get; set; }
130 |
131 | [JsonProperty(PropertyName = "length")]
132 | public int Length { get; set; }
133 | }
134 |
135 | public class VisionColor
136 | {
137 | [JsonProperty(PropertyName = "dominantColorForeground")]
138 | public string DominantColorForeground { get; set; }
139 |
140 | [JsonProperty(PropertyName = "dominantColorBackground")]
141 | public string DominantColorBackground { get; set; }
142 |
143 | [JsonProperty(PropertyName = "dominantColors")]
144 | public IEnumerable DominantColors { get; set; }
145 |
146 | [JsonProperty(PropertyName = "accentColor")]
147 | public string AccentColor { get; set; }
148 |
149 | [JsonProperty(PropertyName = "isBwImg")]
150 | public bool IsBwImg { get; set; }
151 | }
152 |
153 | public class VisionImageType
154 | {
155 | [JsonProperty(PropertyName = "clipArtType")]
156 | public int ClipArtType { get; set; }
157 |
158 | [JsonProperty(PropertyName = "lineDrawingType")]
159 | public int LineDrawingType { get; set; }
160 | }
161 |
162 | public class VisionMetadata
163 | {
164 | [JsonProperty(PropertyName = "height")]
165 | public int Height { get; set; }
166 |
167 | [JsonProperty(PropertyName = "width")]
168 | public int Width { get; set; }
169 |
170 | [JsonProperty(PropertyName = "format")]
171 | public string Format { get; set; }
172 | }
173 | }
174 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Analysis/VisionAnalysisRequest.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Text;
6 |
7 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Analysis
8 | {
9 | [Flags]
10 | public enum VisionAnalysisOptions
11 | {
12 | All = 0,
13 | Categories = 1,
14 | Tags = 2,
15 | Description = 4,
16 | Faces = 8,
17 | ImageType = 16,
18 | Color = 32,
19 | Adult = 64,
20 | Celebrities = 128,
21 | Landmarks = 256
22 | }
23 |
24 | public class VisionAnalysisRequest : VisionRequestBase
25 | {
26 | public VisionAnalysisRequest() { }
27 |
28 | public VisionAnalysisRequest(Stream image) : base(image) { }
29 |
30 | public VisionAnalysisRequest(byte[] image) : base(image) { }
31 |
32 | public VisionAnalysisRequest(string imageUrl) : base(imageUrl) { }
33 |
34 |
35 | [JsonProperty("options")]
36 | public VisionAnalysisOptions Options { get; set; } = VisionAnalysisOptions.All;
37 |
38 |
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Analysis/VisionAnalysisStartup.cs:
--------------------------------------------------------------------------------
1 | using AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Analysis;
2 | using Microsoft.Azure.WebJobs;
3 | using Microsoft.Azure.WebJobs.Hosting;
4 |
5 | [assembly: WebJobsStartup(typeof(VisionAnalysisWebJobsStartup))]
6 |
7 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Analysis
8 | {
9 | public class VisionAnalysisWebJobsStartup : IWebJobsStartup
10 | {
11 | public void Configure(IWebJobsBuilder builder)
12 | {
13 | builder.AddVisionAnalysis();
14 | }
15 | }
16 |
17 |
18 | }
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Describe/VisionDescribeAttribute.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Azure.WebJobs.Description;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Describe
7 | {
8 | [Binding]
9 | [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.ReturnValue)]
10 | public class VisionDescribeAttribute : VisionAttributeBase
11 | {
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Describe/VisionDescribeBinding.cs:
--------------------------------------------------------------------------------
1 | using AzureFunctions.Extensions.CognitiveServices.Config;
2 | using AzureFunctions.Extensions.CognitiveServices.Services;
3 | using Microsoft.Azure.WebJobs.Description;
4 | using Microsoft.Azure.WebJobs.Host.Config;
5 | using Microsoft.Extensions.Logging;
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Text;
9 |
10 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Describe
11 | {
12 |
13 | [Extension("VisionDescribe")]
14 | public class VisionDescribeBinding : IExtensionConfigProvider, IVisionBinding
15 | {
16 |
17 | public ICognitiveServicesClient Client { get; set; }
18 |
19 | internal ILoggerFactory _loggerFactory;
20 |
21 | public VisionDescribeBinding(ILoggerFactory loggerFactory, ICognitiveServicesClient client)
22 | {
23 | _loggerFactory = loggerFactory;
24 | this.Client = client;
25 | }
26 |
27 | public void Initialize(ExtensionConfigContext context)
28 | {
29 |
30 | LoadClient();
31 |
32 | var visionDescribeRule = context.AddBindingRule();
33 |
34 | visionDescribeRule.When(nameof(VisionDescribeAttribute.ImageSource), ImageSource.BlobStorage)
35 | .BindToInput(GetVisionDescribeModel);
36 |
37 | visionDescribeRule.When(nameof(VisionDescribeAttribute.ImageSource), ImageSource.Url)
38 | .BindToInput(GetVisionDescribeModel);
39 |
40 | visionDescribeRule.When(nameof(VisionDescribeAttribute.ImageSource), ImageSource.Client)
41 | .BindToInput(attr => new VisionDescribeClient(this, attr, _loggerFactory));
42 |
43 |
44 | }
45 |
46 | private void LoadClient()
47 | {
48 | if (Client == null)
49 | {
50 | Client = new CognitiveServicesClient(new RetryPolicy(), _loggerFactory);
51 | }
52 | }
53 |
54 | private VisionDescribeModel GetVisionDescribeModel(VisionDescribeAttribute attribute)
55 | {
56 |
57 | if (attribute.ImageSource == Bindings.ImageSource.Client)
58 | {
59 | throw new ArgumentException($"ImageSource of Client does not support binding to vision models. Use Url or BlobStorage instead. ");
60 | }
61 |
62 | attribute.Validate();
63 |
64 | var client = new VisionDescribeClient(this, attribute, _loggerFactory);
65 |
66 | VisionDescribeRequest request = new VisionDescribeRequest();
67 |
68 | if (attribute.ImageSource == ImageSource.BlobStorage)
69 | {
70 | var fileTask = StorageServices.GetFileBytes(attribute.BlobStoragePath, attribute.BlobStorageAccount);
71 | fileTask.Wait();
72 |
73 | request.ImageBytes = fileTask.Result;
74 | }
75 | else
76 | {
77 | request.ImageUrl = attribute.ImageUrl;
78 | }
79 |
80 | var result = client.DescribeAsync(request);
81 | result.Wait();
82 |
83 | return result.Result;
84 |
85 | }
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Describe/VisionDescribeClient.cs:
--------------------------------------------------------------------------------
1 | using AzureFunctions.Extensions.CognitiveServices.Config;
2 | using AzureFunctions.Extensions.CognitiveServices.Services;
3 | using AzureFunctions.Extensions.CognitiveServices.Services.Models;
4 | using Microsoft.Extensions.Logging;
5 | using Newtonsoft.Json;
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Diagnostics;
9 | using System.Net.Http;
10 | using System.Text;
11 | using System.Threading.Tasks;
12 |
13 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Describe
14 | {
15 | public class VisionDescribeClient
16 | {
17 | IVisionBinding _config;
18 | VisionDescribeAttribute _attr;
19 | ILogger _log;
20 |
21 | public VisionDescribeClient(IVisionBinding config, VisionDescribeAttribute attr, ILoggerFactory loggerFactory)
22 | {
23 | this._config = config;
24 | this._attr = attr;
25 | this._log = loggerFactory?.CreateLogger("Host.Bindings.VisionDescribe");
26 | }
27 |
28 | public async Task DescribeAsync(VisionDescribeRequest request)
29 | {
30 | try
31 | {
32 | Stopwatch imageResizeSW = null;
33 |
34 | var visionOperation = await MergeProperties(request, this._config, this._attr);
35 |
36 | if (request.IsUrlImageSource == false)
37 | {
38 |
39 | if (visionOperation.ImageBytes == null || visionOperation.ImageBytes.Length == 0)
40 | {
41 | _log.LogWarning(VisionExceptionMessages.FileMissing);
42 | throw new ArgumentException(VisionExceptionMessages.FileMissing);
43 | }
44 |
45 | if (ImageResizeService.IsImage(visionOperation.ImageBytes) == false)
46 | {
47 | _log.LogWarning(VisionExceptionMessages.InvalidFileType);
48 | throw new ArgumentException(VisionExceptionMessages.InvalidFileType);
49 | }
50 |
51 | if (visionOperation.Oversized == true && visionOperation.AutoResize == false)
52 | {
53 | var message = string.Format(VisionExceptionMessages.FileTooLarge,
54 | VisionConfiguration.MaximumFileSize, visionOperation.ImageBytes.Length);
55 | _log.LogWarning(message);
56 | throw new ArgumentException(message);
57 | }
58 | else if (visionOperation.Oversized == true && visionOperation.AutoResize == true)
59 | {
60 | _log.LogTrace("Resizing Image");
61 |
62 | imageResizeSW = new Stopwatch();
63 |
64 | imageResizeSW.Start();
65 |
66 | visionOperation.ImageBytes = ImageResizeService.ResizeImage(visionOperation.ImageBytes);
67 |
68 | imageResizeSW.Stop();
69 |
70 | _log.LogMetric("VisionAnalysisImageResizeDurationMillisecond", imageResizeSW.ElapsedMilliseconds);
71 |
72 | if (visionOperation.Oversized)
73 | {
74 | var message = string.Format(VisionExceptionMessages.FileTooLargeAfterResize,
75 | VisionConfiguration.MaximumFileSize, visionOperation.ImageBytes.Length);
76 | _log.LogWarning(message);
77 | throw new ArgumentException(message);
78 | }
79 |
80 | }
81 | }
82 |
83 | var result = await SubmitRequest(visionOperation);
84 |
85 | return result;
86 | }
87 | catch(Exception ex )
88 | {
89 | throw ex;
90 | }
91 | }
92 |
93 | private async Task SubmitRequest(VisionDescribeRequest request)
94 | {
95 | Stopwatch sw = new Stopwatch();
96 |
97 | string uri = $"{request.Url}/describe?maxCandidates={request.MaxCandidates}";
98 |
99 | ServiceResultModel requestResult = null;
100 |
101 | if (request.IsUrlImageSource)
102 | {
103 | _log.LogTrace($"Submitting Vision Describe Request");
104 |
105 | var urlRequest = new VisionUrlRequest { Url = request.ImageUrl };
106 | var requestContent = JsonConvert.SerializeObject(urlRequest);
107 |
108 | var content = new StringContent(requestContent);
109 |
110 | sw.Start();
111 |
112 | requestResult = await this._config.Client.PostAsync(uri, request.Key, content, ReturnType.String);
113 |
114 | sw.Stop();
115 |
116 | _log.LogMetric("VisionRequestDurationMillisecond", sw.ElapsedMilliseconds);
117 |
118 | }
119 | else
120 | {
121 | using (ByteArrayContent content = new ByteArrayContent(request.ImageBytes))
122 | {
123 | requestResult = await this._config.Client.PostAsync(uri, request.Key, content, ReturnType.String);
124 | }
125 | }
126 |
127 | if (requestResult.HttpStatusCode == (int)System.Net.HttpStatusCode.OK)
128 | {
129 | _log.LogTrace($"Describe Request Results: {requestResult.Contents}");
130 |
131 | VisionDescribeModel result = JsonConvert.DeserializeObject(requestResult.Contents);
132 |
133 | return result;
134 | }
135 | else if (requestResult.HttpStatusCode == (int)System.Net.HttpStatusCode.BadRequest)
136 | {
137 |
138 | VisionErrorModel error = JsonConvert.DeserializeObject(requestResult.Contents);
139 | var message = string.Format(VisionExceptionMessages.CognitiveServicesException, error.Code, error.Message);
140 |
141 | _log.LogWarning(message);
142 |
143 | throw new Exception(message);
144 | }
145 | else
146 | {
147 | var message = string.Format(VisionExceptionMessages.CognitiveServicesException, requestResult.HttpStatusCode, requestResult.Contents);
148 |
149 | _log.LogError(message);
150 |
151 | throw new Exception(message);
152 | }
153 |
154 | }
155 |
156 | private async Task MergeProperties(VisionDescribeRequest operation, IVisionBinding config, VisionDescribeAttribute attr)
157 | {
158 |
159 | var visionOperation = new VisionDescribeRequest
160 | {
161 | Url = attr.VisionUrl ?? operation.Url,
162 | Key = attr.VisionKey ?? operation.Key,
163 | AutoResize = attr.AutoResize,
164 | MaxCandidates = operation.MaxCandidates,
165 | ImageUrl = string.IsNullOrEmpty(operation.ImageUrl) ? attr.ImageUrl : operation.ImageUrl,
166 | ImageBytes = operation.ImageBytes,
167 | };
168 |
169 |
170 | if (string.IsNullOrEmpty(visionOperation.Key))
171 | {
172 | _log.LogWarning(VisionExceptionMessages.KeyMissing);
173 | throw new ArgumentException(VisionExceptionMessages.KeyMissing);
174 | }
175 |
176 |
177 | return visionOperation;
178 |
179 | }
180 |
181 | }
182 | }
183 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Describe/VisionDescribeExtension.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Azure.WebJobs;
2 | using System;
3 |
4 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Describe
5 | {
6 | public static class VisionDescribeExtension
7 | {
8 | public static IWebJobsBuilder AddVisionDescribe(this IWebJobsBuilder builder)
9 | {
10 | if (builder == null)
11 | {
12 | throw new ArgumentNullException(nameof(builder));
13 | }
14 |
15 | builder.AddExtension();
16 | return builder;
17 | }
18 |
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Describe/VisionDescribeModel.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Describe
7 | {
8 | public class VisionDescribeModel
9 | {
10 |
11 | [JsonProperty(PropertyName = "description")]
12 | public VisionDescribeDescription Description { get; set; }
13 |
14 | [JsonProperty(PropertyName = "metadata")]
15 | public VisionDescribeMetadata Metadata { get; set; }
16 |
17 | public override string ToString()
18 | {
19 | return JsonConvert.SerializeObject(this);
20 | }
21 |
22 | }
23 |
24 | public class VisionDescribeDescription
25 | {
26 | [JsonProperty(PropertyName = "tags")]
27 | public IEnumerable Tags { get; set; }
28 |
29 | [JsonProperty(PropertyName = "captions")]
30 | public IEnumerable Captions { get; set; }
31 | }
32 |
33 | public class VisionDescribeCaption
34 | {
35 | [JsonProperty(PropertyName = "text")]
36 | public string Text { get; set; }
37 |
38 | [JsonProperty(PropertyName = "confidence")]
39 | public double Confidence { get; set; }
40 | }
41 |
42 | public class VisionDescribeMetadata
43 | {
44 | [JsonProperty(PropertyName = "height")]
45 | public int Height { get; set; }
46 |
47 | [JsonProperty(PropertyName = "width")]
48 | public int Width { get; set; }
49 |
50 | [JsonProperty(PropertyName = "format")]
51 | public string Format { get; set; }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Describe/VisionDescribeRequest.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Text;
6 |
7 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Describe
8 | {
9 | public class VisionDescribeRequest : VisionRequestBase
10 | {
11 | public VisionDescribeRequest() { }
12 |
13 | public VisionDescribeRequest(Stream image) : base(image) { }
14 |
15 | public VisionDescribeRequest(byte[] image) : base(image) { }
16 |
17 | public VisionDescribeRequest(string imageUrl) : base(imageUrl) { }
18 |
19 | [JsonProperty("maxCandidates")]
20 | public int MaxCandidates { get; set; } = 1;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Describe/VisionDescribeStartup.cs:
--------------------------------------------------------------------------------
1 | using AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Analysis;
2 | using AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Describe;
3 | using Microsoft.Azure.WebJobs;
4 | using Microsoft.Azure.WebJobs.Hosting;
5 |
6 | [assembly: WebJobsStartup(typeof(VisionDescribeWebJobsStartup))]
7 |
8 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Describe
9 | {
10 |
11 | public class VisionDescribeWebJobsStartup : IWebJobsStartup
12 | {
13 | public void Configure(IWebJobsBuilder builder)
14 | {
15 | builder.AddVisionDescribe();
16 | }
17 | }
18 |
19 |
20 | }
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Domain/VisionDomainAttribute.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Azure.WebJobs.Description;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Domain
7 | {
8 |
9 | [Binding]
10 | [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.ReturnValue)]
11 | public class VisionDomainAttribute : VisionAttributeBase
12 | {
13 |
14 | ///
15 | /// String representation of VisionDomainOptions so we can set
16 | /// options settings via the attribute which only supports strings
17 | ///
18 | public string Domain { get; set; }
19 |
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Domain/VisionDomainBinding.cs:
--------------------------------------------------------------------------------
1 | using AzureFunctions.Extensions.CognitiveServices.Config;
2 | using AzureFunctions.Extensions.CognitiveServices.Services;
3 | using Microsoft.Azure.WebJobs.Description;
4 | using Microsoft.Azure.WebJobs.Host.Config;
5 | using Microsoft.Extensions.Logging;
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Text;
9 |
10 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Domain
11 | {
12 |
13 | [Extension("VisionDomain")]
14 | public class VisionDomainBinding : IExtensionConfigProvider, IVisionBinding
15 | {
16 | internal ILoggerFactory _loggerFactory;
17 |
18 | public VisionDomainBinding(ILoggerFactory loggerFactory, ICognitiveServicesClient client)
19 | {
20 | _loggerFactory = loggerFactory;
21 | this.Client = client;
22 | }
23 |
24 | public ICognitiveServicesClient Client { get; set; }
25 |
26 | public void Initialize(ExtensionConfigContext context)
27 | {
28 |
29 | LoadClient();
30 |
31 |
32 | var visionDomainRule = context.AddBindingRule();
33 |
34 | visionDomainRule.When(nameof(VisionDomainAttribute.ImageSource), ImageSource.BlobStorage)
35 | .BindToInput(GetVisionLandmarkModel);
36 |
37 | visionDomainRule.When(nameof(VisionDomainAttribute.ImageSource), ImageSource.Url)
38 | .BindToInput(GetVisionLandmarkModel);
39 |
40 | visionDomainRule.When(nameof(VisionDomainAttribute.ImageSource), ImageSource.BlobStorage)
41 | .BindToInput(GetVisionCelebrityModel);
42 |
43 | visionDomainRule.When(nameof(VisionDomainAttribute.ImageSource), ImageSource.Url)
44 | .BindToInput(GetVisionCelebrityModel);
45 |
46 | visionDomainRule.When(nameof(VisionDomainAttribute.ImageSource), ImageSource.Client)
47 | .BindToInput(attr => new VisionDomainClient(this, attr, _loggerFactory));
48 |
49 | }
50 |
51 | private void LoadClient()
52 | {
53 | if (Client == null)
54 | {
55 | Client = new CognitiveServicesClient(new RetryPolicy(), _loggerFactory);
56 | }
57 | }
58 |
59 | private VisionDomainCelebrityModel GetVisionCelebrityModel(VisionDomainAttribute attribute)
60 | {
61 |
62 | if (attribute.ImageSource == Bindings.ImageSource.Client)
63 | {
64 | throw new ArgumentException($"ImageSource of Client does not support binding to vision models. Use Url or BlobStorage instead. ");
65 | }
66 |
67 | attribute.Validate();
68 |
69 | var client = new VisionDomainClient(this, attribute, _loggerFactory);
70 | var request = BuildRequest(attribute);
71 |
72 | var result = client.AnalyzeCelebrityAsync(request);
73 | result.Wait();
74 |
75 | return result.Result;
76 |
77 | }
78 |
79 | private VisionDomainLandmarkModel GetVisionLandmarkModel(VisionDomainAttribute attribute)
80 | {
81 |
82 | if (attribute.ImageSource == Bindings.ImageSource.Client)
83 | {
84 | throw new ArgumentException($"ImageSource of Client does not support binding to vision models. Use Url or BlobStorage instead. ");
85 | }
86 |
87 | attribute.Validate();
88 |
89 | var client = new VisionDomainClient(this, attribute, _loggerFactory);
90 | var request = BuildRequest(attribute);
91 |
92 | var result = client.AnalyzeLandmarkAsync(request);
93 | result.Wait();
94 |
95 | return result.Result;
96 |
97 | }
98 |
99 | private VisionDomainRequest BuildRequest(VisionDomainAttribute attribute)
100 | {
101 | VisionDomainRequest request = new VisionDomainRequest();
102 |
103 | if (attribute.ImageSource == ImageSource.BlobStorage)
104 | {
105 | var fileTask = StorageServices.GetFileBytes(attribute.BlobStoragePath, attribute.BlobStorageAccount);
106 | fileTask.Wait();
107 |
108 | request.ImageBytes = fileTask.Result;
109 | }
110 | else
111 | {
112 | request.ImageUrl = attribute.ImageUrl;
113 | }
114 |
115 | return request;
116 |
117 | }
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Domain/VisionDomainCelebrityModel.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Domain
7 | {
8 | public class FaceRectangle
9 | {
10 |
11 | [JsonProperty("top")]
12 | public int Top { get; set; }
13 |
14 | [JsonProperty("left")]
15 | public int Left { get; set; }
16 |
17 | [JsonProperty("width")]
18 | public int Width { get; set; }
19 |
20 | [JsonProperty("height")]
21 | public int Height { get; set; }
22 | }
23 |
24 | public class Celebrity
25 | {
26 |
27 | [JsonProperty("faceRectangle")]
28 | public FaceRectangle FaceRectangle { get; set; }
29 |
30 | [JsonProperty("name")]
31 | public string Name { get; set; }
32 |
33 | [JsonProperty("confidence")]
34 | public double Confidence { get; set; }
35 | }
36 |
37 | public class CelebrityResult
38 | {
39 |
40 | [JsonProperty("celebrities")]
41 | public IList Celebrities { get; set; }
42 | }
43 |
44 | public class CelebrityMetadata
45 | {
46 |
47 | [JsonProperty("height")]
48 | public int Height { get; set; }
49 |
50 | [JsonProperty("width")]
51 | public int Width { get; set; }
52 |
53 | [JsonProperty("format")]
54 | public string Format { get; set; }
55 | }
56 |
57 | public class VisionDomainCelebrityModel
58 | {
59 |
60 | [JsonProperty("result")]
61 | public CelebrityResult Result { get; set; }
62 |
63 | [JsonProperty("requestId")]
64 | public string RequestId { get; set; }
65 |
66 | [JsonProperty("metadata")]
67 | public CelebrityMetadata Metadata { get; set; }
68 |
69 | public override string ToString()
70 | {
71 | return JsonConvert.SerializeObject(this);
72 | }
73 | }
74 | }
75 |
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Domain/VisionDomainClient.cs:
--------------------------------------------------------------------------------
1 | using AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Analysis;
2 | using AzureFunctions.Extensions.CognitiveServices.Config;
3 | using AzureFunctions.Extensions.CognitiveServices.Services;
4 | using AzureFunctions.Extensions.CognitiveServices.Services.Models;
5 | using Microsoft.Extensions.Logging;
6 | using Newtonsoft.Json;
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Diagnostics;
10 | using System.Net.Http;
11 | using System.Text;
12 | using System.Threading.Tasks;
13 |
14 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Domain
15 | {
16 | public class VisionDomainClient
17 | {
18 | IVisionBinding _config;
19 | VisionDomainAttribute _attr;
20 | ILogger _log;
21 |
22 | public VisionDomainClient(IVisionBinding config, VisionDomainAttribute attr, ILoggerFactory loggerFactory)
23 | {
24 | this._config = config;
25 | this._attr = attr;
26 | this._log = loggerFactory?.CreateLogger("Host.Bindings.VisionDomain");
27 | }
28 |
29 | public async Task AnalyzeCelebrityAsync(VisionDomainRequest request)
30 | {
31 | var result = await AnalyzeAsync(request);
32 |
33 | return result;
34 | }
35 |
36 | public async Task AnalyzeLandmarkAsync(VisionDomainRequest request)
37 | {
38 | var result = await AnalyzeAsync(request);
39 |
40 | return result;
41 | }
42 |
43 | private async Task AnalyzeAsync(VisionDomainRequest request)
44 | {
45 | Stopwatch imageResizeSW = null;
46 |
47 | var visionOperation = await MergeProperties(request, this._config, this._attr);
48 |
49 | if (request.IsUrlImageSource == false)
50 | {
51 |
52 | if (visionOperation.ImageBytes == null || visionOperation.ImageBytes.Length == 0)
53 | {
54 | _log.LogWarning(VisionExceptionMessages.FileMissing);
55 | throw new ArgumentException(VisionExceptionMessages.FileMissing);
56 | }
57 |
58 | if (ImageResizeService.IsImage(visionOperation.ImageBytes) == false)
59 | {
60 | _log.LogWarning(VisionExceptionMessages.InvalidFileType);
61 | throw new ArgumentException(VisionExceptionMessages.InvalidFileType);
62 | }
63 |
64 | if (visionOperation.Oversized == true && visionOperation.AutoResize == false)
65 | {
66 | var message = string.Format(VisionExceptionMessages.FileTooLarge,
67 | VisionConfiguration.MaximumFileSize, visionOperation.ImageBytes.Length);
68 | _log.LogWarning(message);
69 | throw new ArgumentException(message);
70 | }
71 | else if (visionOperation.Oversized == true && visionOperation.AutoResize == true)
72 | {
73 | _log.LogTrace("Resizing Image");
74 |
75 | imageResizeSW = new Stopwatch();
76 |
77 | imageResizeSW.Start();
78 |
79 | visionOperation.ImageBytes = ImageResizeService.ResizeImage(visionOperation.ImageBytes);
80 |
81 | imageResizeSW.Stop();
82 |
83 | _log.LogMetric("VisionAnalysisImageResizeDurationMillisecond", imageResizeSW.ElapsedMilliseconds);
84 |
85 | if (visionOperation.Oversized)
86 | {
87 | var message = string.Format(VisionExceptionMessages.FileTooLargeAfterResize,
88 | VisionConfiguration.MaximumFileSize, visionOperation.ImageBytes.Length);
89 | _log.LogWarning(message);
90 | throw new ArgumentException(message);
91 | }
92 |
93 | }
94 | }
95 |
96 | var result = await SubmitRequest(visionOperation);
97 |
98 | return result;
99 | }
100 |
101 | private async Task SubmitRequest(VisionDomainRequest request)
102 | {
103 | Stopwatch sw = new Stopwatch();
104 |
105 | string requestParameters = GetVisionOperationParameters(request);
106 |
107 | string uri = $"{request.Url}/{requestParameters}";
108 |
109 | ServiceResultModel requestResult = null;
110 |
111 | if (request.IsUrlImageSource)
112 | {
113 | _log.LogTrace($"Submitting Vision Domain Request");
114 |
115 | var urlRequest = new VisionUrlRequest { Url = request.ImageUrl };
116 | var requestContent = JsonConvert.SerializeObject(urlRequest);
117 |
118 | var content = new StringContent(requestContent);
119 |
120 | sw.Start();
121 |
122 | requestResult = await this._config.Client.PostAsync(uri, request.Key, content, ReturnType.String);
123 |
124 | sw.Stop();
125 |
126 | _log.LogMetric("VisionDomainRequestDurationMillisecond", sw.ElapsedMilliseconds);
127 |
128 | }
129 | else
130 | {
131 | using (ByteArrayContent content = new ByteArrayContent(request.ImageBytes))
132 | {
133 | requestResult = await this._config.Client.PostAsync(uri, request.Key, content, ReturnType.String);
134 | }
135 | }
136 |
137 | if (requestResult.HttpStatusCode == (int)System.Net.HttpStatusCode.OK)
138 | {
139 | _log.LogTrace($"Analysis Request Results: {requestResult.Contents}");
140 |
141 | var result = JsonConvert.DeserializeObject(requestResult.Contents);
142 |
143 | return result;
144 | }
145 | else if (requestResult.HttpStatusCode == (int)System.Net.HttpStatusCode.BadRequest)
146 | {
147 |
148 | VisionErrorModel error = JsonConvert.DeserializeObject(requestResult.Contents);
149 | var message = string.Format(VisionExceptionMessages.CognitiveServicesException, error.Code, error.Message);
150 |
151 | _log.LogWarning(message);
152 |
153 | throw new Exception(message);
154 | }
155 | else
156 | {
157 | var message = string.Format(VisionExceptionMessages.CognitiveServicesException, requestResult.HttpStatusCode, requestResult.Contents);
158 |
159 | _log.LogError(message);
160 |
161 | throw new Exception(message);
162 | }
163 |
164 | }
165 |
166 | private string GetVisionOperationParameters(VisionDomainRequest request)
167 | {
168 |
169 | string optionsParam = string.Empty;
170 |
171 | switch (request.Domain)
172 | {
173 | case VisionDomainOptions.Celebrity:
174 | optionsParam = "models/celebrities/analyze";
175 | break;
176 |
177 | case VisionDomainOptions.Landmark:
178 | optionsParam = "models/landmarks/analyze ";
179 | break;
180 | }
181 |
182 | return optionsParam;
183 | }
184 |
185 | private async Task MergeProperties(VisionDomainRequest operation, IVisionBinding config, VisionDomainAttribute attr)
186 | {
187 | //Attributes do not allow for enum types so we have to validate
188 | //the string passed into the attribute to ensure it matches
189 | //a valid VisionDomainOption.
190 | VisionDomainOptions attrDomain = VisionDomainOptions.None;
191 |
192 | if (!string.IsNullOrEmpty(attr.Domain))
193 | {
194 | var valid = Enum.TryParse(attr.Domain, out attrDomain);
195 |
196 | if (!valid)
197 | {
198 | var message = string.Format(VisionExceptionMessages.InvalidDomainName, attr.Domain);
199 | _log.LogWarning(message);
200 |
201 | throw new ArgumentException(message);
202 | }
203 | }
204 | else
205 | {
206 | if(operation.Domain == VisionDomainOptions.None)
207 | {
208 | var message = string.Format(VisionExceptionMessages.InvalidDomainName, "None");
209 | _log.LogWarning(message);
210 |
211 | throw new ArgumentException(message);
212 | }
213 | }
214 |
215 |
216 | var visionOperation = new VisionDomainRequest
217 | {
218 | Url = attr.VisionUrl ?? operation.Url,
219 | Key = attr.VisionKey ?? operation.Key,
220 | AutoResize = attr.AutoResize,
221 | Domain = attrDomain == VisionDomainOptions.None ? operation.Domain : attrDomain,
222 | ImageUrl = string.IsNullOrEmpty(operation.ImageUrl) ? attr.ImageUrl : operation.ImageUrl,
223 | ImageBytes = operation.ImageBytes,
224 | };
225 |
226 | if (string.IsNullOrEmpty(visionOperation.Key))
227 | {
228 | _log.LogWarning(VisionExceptionMessages.KeyMissing);
229 | throw new ArgumentException(VisionExceptionMessages.KeyMissing);
230 | }
231 |
232 | return visionOperation;
233 |
234 | }
235 |
236 | }
237 |
238 |
239 | }
240 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Domain/VisionDomainExtension.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Azure.WebJobs;
2 | using System;
3 |
4 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Domain
5 | {
6 | public static class VisionDomainExtension
7 | {
8 | public static IWebJobsBuilder AddVisionDomain(this IWebJobsBuilder builder)
9 | {
10 | if (builder == null)
11 | {
12 | throw new ArgumentNullException(nameof(builder));
13 | }
14 |
15 | builder.AddExtension();
16 | return builder;
17 | }
18 |
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Domain/VisionDomainLandmarkModel.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Domain
7 | {
8 | public class Landmark
9 | {
10 |
11 | [JsonProperty("name")]
12 | public string Name { get; set; }
13 |
14 | [JsonProperty("confidence")]
15 | public double Confidence { get; set; }
16 | }
17 |
18 | public class Result
19 | {
20 |
21 | [JsonProperty("landmarks")]
22 | public IList Landmarks { get; set; }
23 | }
24 |
25 | public class LandmarkMetadata
26 | {
27 |
28 | [JsonProperty("height")]
29 | public int Height { get; set; }
30 |
31 | [JsonProperty("width")]
32 | public int Width { get; set; }
33 |
34 | [JsonProperty("format")]
35 | public string Format { get; set; }
36 | }
37 |
38 | public class VisionDomainLandmarkModel
39 | {
40 |
41 | [JsonProperty("result")]
42 | public Result Result { get; set; }
43 |
44 | [JsonProperty("requestId")]
45 | public string RequestId { get; set; }
46 |
47 | [JsonProperty("metadata")]
48 | public LandmarkMetadata Metadata { get; set; }
49 |
50 | public override string ToString()
51 | {
52 | return JsonConvert.SerializeObject(this);
53 | }
54 | }
55 |
56 |
57 |
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Domain/VisionDomainRequest.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Text;
6 |
7 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Domain
8 | {
9 | public enum VisionDomainOptions
10 | {
11 | None=0,
12 | Landmark=1,
13 | Celebrity=2
14 | }
15 |
16 | public class VisionDomainRequest : VisionRequestBase
17 | {
18 | public const string CELEBRITY_DOMAIN = "Celebrity";
19 | public const string LANDMARK_DOMAIN = "Landmark";
20 |
21 | public VisionDomainRequest() { }
22 |
23 | public VisionDomainRequest(Stream image) : base(image) { }
24 |
25 | public VisionDomainRequest(byte[] image) : base(image) { }
26 |
27 | public VisionDomainRequest(string imageUrl) : base(imageUrl) { }
28 |
29 |
30 | [JsonProperty("options")]
31 | public VisionDomainOptions Domain { get; set; } = VisionDomainOptions.None;
32 |
33 |
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Domain/VisionDomainStartup.cs:
--------------------------------------------------------------------------------
1 | using AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Analysis;
2 | using AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Domain;
3 | using Microsoft.Azure.WebJobs;
4 | using Microsoft.Azure.WebJobs.Hosting;
5 |
6 | [assembly: WebJobsStartup(typeof(VisionDomainWebJobsStartup))]
7 |
8 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Domain
9 | {
10 |
11 | public class VisionDomainWebJobsStartup : IWebJobsStartup
12 | {
13 | public void Configure(IWebJobsBuilder builder)
14 | {
15 | builder.AddVisionDomain();
16 | }
17 | }
18 |
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Handwriting/VisionHandwritingAttribute.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Azure.WebJobs.Description;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Handwriting
7 | {
8 | [Binding]
9 | [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.ReturnValue)]
10 |
11 | public class VisionHandwritingAttribute : VisionAttributeBase
12 | {
13 |
14 | public bool? Handwriting { get; set; } = true;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Handwriting/VisionHandwritingBinding.cs:
--------------------------------------------------------------------------------
1 | using AzureFunctions.Extensions.CognitiveServices.Config;
2 | using AzureFunctions.Extensions.CognitiveServices.Services;
3 | using Microsoft.Azure.WebJobs.Description;
4 | using Microsoft.Azure.WebJobs.Host.Config;
5 | using Microsoft.Extensions.Logging;
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Text;
9 |
10 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Handwriting
11 | {
12 | [Extension("VisionHandwriting")]
13 | public class VisionHandwritingBinding : IExtensionConfigProvider, IVisionBinding
14 | {
15 |
16 | public ICognitiveServicesClient Client { get; set; }
17 |
18 | internal ILoggerFactory _loggerFactory;
19 |
20 | public VisionHandwritingBinding(ILoggerFactory factory, ICognitiveServicesClient client)
21 | {
22 | _loggerFactory = factory;
23 | this.Client = client;
24 | }
25 |
26 | public void Initialize(ExtensionConfigContext context)
27 | {
28 |
29 | LoadClient();
30 |
31 | var visionRule = context.AddBindingRule();
32 |
33 | visionRule.When(nameof(VisionHandwritingAttribute.ImageSource), ImageSource.BlobStorage)
34 | .BindToInput(GetVisionHandwritingModel);
35 |
36 | visionRule.When(nameof(VisionHandwritingAttribute.ImageSource), ImageSource.Url)
37 | .BindToInput(GetVisionHandwritingModel);
38 |
39 | visionRule.When(nameof(VisionHandwritingAttribute.ImageSource), ImageSource.Client)
40 | .BindToInput(attr => new VisionHandwritingClient(this, attr, _loggerFactory));
41 |
42 | }
43 |
44 | private void LoadClient()
45 | {
46 | if (Client == null)
47 | {
48 | Client = new CognitiveServicesClient(new RetryPolicy(), _loggerFactory);
49 | }
50 | }
51 |
52 | private VisionHandwritingModel GetVisionHandwritingModel(VisionHandwritingAttribute attribute)
53 | {
54 |
55 | if (attribute.ImageSource == Bindings.ImageSource.Client)
56 | {
57 | throw new ArgumentException($"ImageSource of Client does not support binding to vision models. Use Url or BlobStorage instead. ");
58 | }
59 |
60 | attribute.Validate();
61 |
62 | var client = new VisionHandwritingClient(this, attribute, _loggerFactory);
63 |
64 | VisionHandwritingRequest request = new VisionHandwritingRequest();
65 |
66 | if (attribute.ImageSource == ImageSource.BlobStorage)
67 | {
68 | var fileTask = StorageServices.GetFileBytes(attribute.BlobStoragePath, attribute.BlobStorageAccount);
69 | fileTask.Wait();
70 |
71 | request.ImageBytes = fileTask.Result;
72 |
73 | }
74 | else
75 | {
76 | request.ImageUrl = attribute.ImageUrl;
77 | }
78 |
79 | var result = client.HandwritingAsync(request);
80 | result.Wait();
81 |
82 | return result.Result;
83 |
84 | }
85 |
86 |
87 |
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Handwriting/VisionHandwritingExtension.cs:
--------------------------------------------------------------------------------
1 | using AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Handwriting;
2 | using Microsoft.Azure.WebJobs;
3 | using System;
4 |
5 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Handwriting
6 | {
7 | public static class VisionHandwritingExtension
8 | {
9 | public static IWebJobsBuilder AddVisionHandwriting(this IWebJobsBuilder builder)
10 | {
11 | if (builder == null)
12 | {
13 | throw new ArgumentNullException(nameof(builder));
14 | }
15 |
16 | builder.AddExtension();
17 | return builder;
18 | }
19 |
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Handwriting/VisionHandwritingModel.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Handwriting
7 | {
8 |
9 | public class Word
10 | {
11 |
12 | [JsonProperty("boundingBox")]
13 | public IList BoundingBox { get; set; }
14 |
15 | [JsonProperty("text")]
16 | public string Text { get; set; }
17 | }
18 |
19 | public class Line
20 | {
21 |
22 | [JsonProperty("boundingBox")]
23 | public IList BoundingBox { get; set; }
24 |
25 | [JsonProperty("text")]
26 | public string Text { get; set; }
27 |
28 | [JsonProperty("words")]
29 | public IList Words { get; set; }
30 | }
31 |
32 | public class RecognitionResult
33 | {
34 |
35 | [JsonProperty("lines")]
36 | public IList Lines { get; set; }
37 | }
38 |
39 | public class VisionHandwritingModel
40 | {
41 |
42 | [JsonProperty("status")]
43 | public string Status { get; set; }
44 |
45 | [JsonProperty("succeeded")]
46 | public bool Succeeded { get; set; }
47 |
48 | [JsonProperty("failed")]
49 | public bool Failed { get; set; }
50 |
51 | [JsonProperty("finished")]
52 | public bool Finished { get; set; }
53 |
54 | [JsonProperty("recognitionResult")]
55 | public RecognitionResult RecognitionResult { get; set; }
56 |
57 | public override string ToString()
58 | {
59 | return JsonConvert.SerializeObject(this);
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Handwriting/VisionHandwritingRequest.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Text;
6 |
7 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Handwriting
8 | {
9 | public class VisionHandwritingRequest : VisionRequestBase
10 | {
11 |
12 | public VisionHandwritingRequest() { }
13 |
14 | public VisionHandwritingRequest(Stream image) : base(image) { }
15 |
16 | public VisionHandwritingRequest(byte[] image) : base(image) { }
17 |
18 | public VisionHandwritingRequest(string imageUrl) : base(imageUrl) { }
19 |
20 | [JsonProperty("handwriting")]
21 | public bool Handwriting { get; set; } = true;
22 |
23 | }
24 |
25 |
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Handwriting/VisionHandwritingStartup.cs:
--------------------------------------------------------------------------------
1 | using AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Domain;
2 | using AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Handwriting;
3 | using Microsoft.Azure.WebJobs;
4 | using Microsoft.Azure.WebJobs.Hosting;
5 |
6 | [assembly: WebJobsStartup(typeof(VisionHandwritingWebJobsStartup))]
7 |
8 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Handwriting
9 | {
10 |
11 | public class VisionHandwritingWebJobsStartup : IWebJobsStartup
12 | {
13 | public void Configure(IWebJobsBuilder builder)
14 | {
15 | builder.AddVisionHandwriting();
16 | }
17 | }
18 |
19 |
20 | }
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/IVisionBinding.cs:
--------------------------------------------------------------------------------
1 | using AzureFunctions.Extensions.CognitiveServices.Services;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision
7 | {
8 | public interface IVisionBinding
9 | {
10 | ICognitiveServicesClient Client { get; set; }
11 |
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Ocr/VisionOCRAttribute.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Azure.WebJobs.Description;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Ocr
7 | {
8 | [Binding]
9 | [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.ReturnValue)]
10 | public class VisionOcrAttribute : VisionAttributeBase
11 | {
12 |
13 | public bool? DetectOrientation { get; set; }
14 |
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Ocr/VisionOCRBinding.cs:
--------------------------------------------------------------------------------
1 | using AzureFunctions.Extensions.CognitiveServices.Config;
2 | using AzureFunctions.Extensions.CognitiveServices.Services;
3 | using Microsoft.Azure.WebJobs.Description;
4 | using Microsoft.Azure.WebJobs.Host.Config;
5 | using Microsoft.Extensions.Logging;
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Text;
9 |
10 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Ocr
11 | {
12 |
13 | [Extension("VisionOcr")]
14 | public class VisionOcrBinding : IExtensionConfigProvider, IVisionBinding
15 | {
16 |
17 | public ICognitiveServicesClient Client { get; set; }
18 |
19 | internal ILoggerFactory _loggerFactory;
20 | internal ILogger _log;
21 |
22 |
23 | public VisionOcrBinding(ILoggerFactory loggerFactory, ICognitiveServicesClient client)
24 | {
25 | _loggerFactory = loggerFactory;
26 | this.Client = client;
27 | }
28 |
29 | public void Initialize(ExtensionConfigContext context)
30 | {
31 |
32 | LoadClient();
33 |
34 | var visionRule = context.AddBindingRule();
35 |
36 | visionRule.When(nameof(VisionOcrAttribute.ImageSource), ImageSource.BlobStorage)
37 | .BindToInput(GetVisionOcrModel);
38 |
39 | visionRule.When(nameof(VisionOcrAttribute.ImageSource), ImageSource.Url)
40 | .BindToInput(GetVisionOcrModel);
41 |
42 | visionRule.When(nameof(VisionOcrAttribute.ImageSource), ImageSource.Client)
43 | .BindToInput(attr => new VisionOcrClient(this, attr, _loggerFactory));
44 |
45 | }
46 |
47 | private void LoadClient()
48 | {
49 | if (Client == null)
50 | {
51 | Client = new CognitiveServicesClient(new RetryPolicy(), _loggerFactory);
52 | }
53 | }
54 |
55 | private VisionOcrModel GetVisionOcrModel(VisionOcrAttribute attribute)
56 | {
57 |
58 | if (attribute.ImageSource == Bindings.ImageSource.Client)
59 | {
60 | throw new ArgumentException($"ImageSource of Client does not support binding to vision models. Use Url or BlobStorage instead. ");
61 | }
62 |
63 | attribute.Validate();
64 |
65 | var client = new VisionOcrClient(this, attribute, _loggerFactory);
66 |
67 | VisionOcrRequest request = new VisionOcrRequest();
68 |
69 | if (attribute.ImageSource == ImageSource.BlobStorage)
70 | {
71 | var fileTask = StorageServices.GetFileBytes(attribute.BlobStoragePath, attribute.BlobStorageAccount);
72 | fileTask.Wait();
73 |
74 | request.ImageBytes = fileTask.Result;
75 |
76 | }
77 | else
78 | {
79 | request.ImageUrl = attribute.ImageUrl;
80 | }
81 |
82 | var result = client.OCRAsync(request);
83 | result.Wait();
84 |
85 | return result.Result;
86 |
87 | }
88 |
89 |
90 |
91 | }
92 | }
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Ocr/VisionOCRClient.cs:
--------------------------------------------------------------------------------
1 | using AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Thumbnail;
2 | using AzureFunctions.Extensions.CognitiveServices.Config;
3 | using AzureFunctions.Extensions.CognitiveServices.Services;
4 | using AzureFunctions.Extensions.CognitiveServices.Services.Models;
5 | using Microsoft.Extensions.Logging;
6 | using Newtonsoft.Json;
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Diagnostics;
10 | using System.Net.Http;
11 | using System.Text;
12 | using System.Threading.Tasks;
13 |
14 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Ocr
15 | {
16 | public class VisionOcrClient
17 | {
18 | IVisionBinding _config;
19 | VisionOcrAttribute _attr;
20 | ILogger _log;
21 |
22 | public VisionOcrClient(IVisionBinding config, VisionOcrAttribute attr, ILoggerFactory loggerFactory)
23 | {
24 | this._config = config;
25 | this._attr = attr;
26 | this._log = loggerFactory?.CreateLogger("Host.Bindings.VisionOcr");
27 | }
28 |
29 | public async Task OCRAsync(VisionOcrRequest request)
30 | {
31 | Stopwatch imageResizeSW = null;
32 |
33 | var visionOperation = await MergeProperties(request, this._config, this._attr);
34 |
35 | if (request.IsUrlImageSource == false)
36 | {
37 |
38 | if (visionOperation.ImageBytes == null || visionOperation.ImageBytes.Length == 0)
39 | {
40 | _log.LogWarning(VisionExceptionMessages.FileMissing);
41 | throw new ArgumentException(VisionExceptionMessages.FileMissing);
42 | }
43 |
44 |
45 | if (ImageResizeService.IsImage(visionOperation.ImageBytes) == false)
46 | {
47 | _log.LogWarning(VisionExceptionMessages.InvalidFileType);
48 | throw new ArgumentException(VisionExceptionMessages.InvalidFileType);
49 | }
50 |
51 | if (visionOperation.Oversized == true && visionOperation.AutoResize == false)
52 | {
53 | var message = string.Format(VisionExceptionMessages.FileTooLarge,
54 | VisionConfiguration.MaximumFileSize, visionOperation.ImageBytes.Length);
55 | _log.LogWarning(message);
56 | throw new ArgumentException(message);
57 | }
58 | else if (visionOperation.Oversized == true && visionOperation.AutoResize == true)
59 | {
60 | _log.LogTrace("Resizing Image");
61 |
62 | imageResizeSW = new Stopwatch();
63 |
64 | imageResizeSW.Start();
65 |
66 | visionOperation.ImageBytes = ImageResizeService.ResizeImage(visionOperation.ImageBytes);
67 |
68 | imageResizeSW.Stop();
69 |
70 | _log.LogMetric("VisionOcrImageResizeDurationMillisecond", imageResizeSW.ElapsedMilliseconds);
71 |
72 | if (visionOperation.Oversized)
73 | {
74 | var message = string.Format(VisionExceptionMessages.FileTooLargeAfterResize,
75 | VisionConfiguration.MaximumFileSize, visionOperation.ImageBytes.Length);
76 | _log.LogWarning(message);
77 | throw new ArgumentException(message);
78 | }
79 |
80 | }
81 | }
82 |
83 | var result = await SubmitRequest(visionOperation);
84 |
85 | return result;
86 | }
87 |
88 | private async Task SubmitRequest(VisionOcrRequest request)
89 | {
90 | Stopwatch sw = new Stopwatch();
91 |
92 | //ocr/language=unk&detectOrientation=true
93 | string uri = $"{request.Url}/ocr?detectOrientation={request.DetectOrientation.ToString()}";
94 |
95 | ServiceResultModel requestResult = null;
96 |
97 | if (request.IsUrlImageSource)
98 | {
99 | _log.LogTrace($"Submitting Vision Ocr Request");
100 |
101 | var urlRequest = new VisionUrlRequest { Url = request.ImageUrl };
102 | var requestContent = JsonConvert.SerializeObject(urlRequest);
103 |
104 | var content = new StringContent(requestContent);
105 |
106 | sw.Start();
107 |
108 | requestResult = await this._config.Client.PostAsync(uri, request.Key, content, ReturnType.String);
109 |
110 | sw.Stop();
111 |
112 | _log.LogMetric("VisionOCRDurationMillisecond", sw.ElapsedMilliseconds);
113 |
114 | }
115 | else
116 | {
117 | using (ByteArrayContent content = new ByteArrayContent(request.ImageBytes))
118 | {
119 | requestResult = await this._config.Client.PostAsync(uri, request.Key, content, ReturnType.String);
120 | }
121 | }
122 |
123 | if (requestResult.HttpStatusCode == (int)System.Net.HttpStatusCode.OK)
124 | {
125 | _log.LogTrace($"OCR Request Results: {requestResult.Contents}");
126 |
127 | VisionOcrModel result = JsonConvert.DeserializeObject(requestResult.Contents);
128 |
129 | return result;
130 | }
131 | else if (requestResult.HttpStatusCode == (int)System.Net.HttpStatusCode.BadRequest)
132 | {
133 |
134 | VisionErrorModel error = JsonConvert.DeserializeObject(requestResult.Contents);
135 | var message = string.Format(VisionExceptionMessages.CognitiveServicesException, error.Code, error.Message);
136 |
137 | _log.LogWarning(message);
138 |
139 | throw new Exception(message);
140 | }
141 | else
142 | {
143 | var message = string.Format(VisionExceptionMessages.CognitiveServicesException, requestResult.HttpStatusCode, requestResult.Contents);
144 |
145 | _log.LogError(message);
146 |
147 | throw new Exception(message);
148 | }
149 |
150 | }
151 |
152 | private async Task MergeProperties(VisionOcrRequest operation, IVisionBinding config, VisionOcrAttribute attr)
153 | {
154 |
155 | var visionOperation = new VisionOcrRequest
156 | {
157 | Url = attr.VisionUrl ?? operation.Url,
158 | Key = attr.VisionKey ?? operation.Key,
159 | AutoResize = attr.AutoResize,
160 | ImageUrl = string.IsNullOrEmpty(operation.ImageUrl) ? attr.ImageUrl : operation.ImageUrl,
161 | ImageBytes = operation.ImageBytes,
162 | DetectOrientation = attr.DetectOrientation.HasValue ? attr.DetectOrientation.Value : operation.DetectOrientation
163 | };
164 |
165 |
166 | if (string.IsNullOrEmpty(visionOperation.Key))
167 | {
168 | _log.LogWarning(VisionExceptionMessages.KeyMissing);
169 | throw new ArgumentException(VisionExceptionMessages.KeyMissing);
170 | }
171 |
172 | return visionOperation;
173 |
174 | }
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Ocr/VisionOCRExtension.cs:
--------------------------------------------------------------------------------
1 |
2 | using Microsoft.Azure.WebJobs;
3 | using System;
4 |
5 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Ocr
6 | {
7 | public static class VisionOcrExtension
8 | {
9 | public static IWebJobsBuilder AddVisionOcr(this IWebJobsBuilder builder)
10 | {
11 | if (builder == null)
12 | {
13 | throw new ArgumentNullException(nameof(builder));
14 | }
15 |
16 | builder.AddExtension();
17 | return builder;
18 | }
19 |
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Ocr/VisionOCRRequest.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Text;
6 |
7 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Ocr
8 | {
9 | public class VisionOcrRequest : VisionRequestBase
10 | {
11 |
12 | public VisionOcrRequest() { }
13 |
14 | public VisionOcrRequest(Stream image) : base(image) { }
15 |
16 | public VisionOcrRequest(byte[] image) : base(image) { }
17 |
18 | public VisionOcrRequest(string imageUrl) : base(imageUrl) { }
19 |
20 | [JsonProperty("detectOrientation")]
21 | public bool DetectOrientation { get; set; } = false;
22 |
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Ocr/VisionOCRStartup.cs:
--------------------------------------------------------------------------------
1 | using AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Ocr;
2 | using Microsoft.Azure.WebJobs;
3 | using Microsoft.Azure.WebJobs.Hosting;
4 |
5 | [assembly: WebJobsStartup(typeof(VisionOcrWebJobsStartup))]
6 |
7 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Ocr
8 | {
9 |
10 | public class VisionOcrWebJobsStartup : IWebJobsStartup
11 | {
12 | public void Configure(IWebJobsBuilder builder)
13 | {
14 | builder.AddVisionOcr();
15 | }
16 | }
17 |
18 |
19 | }
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Ocr/VisionOcrModel.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Ocr
7 | {
8 |
9 | public class Word
10 | {
11 |
12 | [JsonProperty("boundingBox")]
13 | public string BoundingBox { get; set; }
14 |
15 | [JsonProperty("text")]
16 | public string Text { get; set; }
17 | }
18 |
19 | public class Line
20 | {
21 |
22 | [JsonProperty("boundingBox")]
23 | public string BoundingBox { get; set; }
24 |
25 | [JsonProperty("words")]
26 | public IList Words { get; set; }
27 | }
28 |
29 | public class Region
30 | {
31 |
32 | [JsonProperty("boundingBox")]
33 | public string BoundingBox { get; set; }
34 |
35 | [JsonProperty("lines")]
36 | public IList Lines { get; set; }
37 | }
38 |
39 | public class VisionOcrModel
40 | {
41 |
42 | [JsonProperty("textAngle")]
43 | public double TextAngle { get; set; }
44 |
45 | [JsonProperty("orientation")]
46 | public string Orientation { get; set; }
47 |
48 | [JsonProperty("language")]
49 | public string Language { get; set; }
50 |
51 | [JsonProperty("regions")]
52 | public IList Regions { get; set; }
53 |
54 | public override string ToString()
55 | {
56 | return JsonConvert.SerializeObject(this);
57 | }
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Thumbnail/VisionThumbnailAttribute.cs:
--------------------------------------------------------------------------------
1 | using AzureFunctions.Extensions.CognitiveServices.Config;
2 | using Microsoft.Azure.WebJobs.Description;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.ComponentModel.DataAnnotations;
6 | using System.Text;
7 |
8 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Thumbnail
9 | {
10 | [Binding]
11 | [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.ReturnValue)]
12 | public class VisionThumbnailAttribute : VisionAttributeBase
13 | {
14 | [AutoResolve()]
15 | public string Width { get; set; }
16 |
17 | [AutoResolve()]
18 | public string Height { get; set; }
19 |
20 | public bool SmartCropping { get; set; }
21 | }
22 | }
23 |
24 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Thumbnail/VisionThumbnailBinding.cs:
--------------------------------------------------------------------------------
1 | using AzureFunctions.Extensions.CognitiveServices.Config;
2 | using AzureFunctions.Extensions.CognitiveServices.Services;
3 | using Microsoft.Azure.WebJobs.Description;
4 | using Microsoft.Azure.WebJobs.Host.Config;
5 | using Microsoft.Extensions.Logging;
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Text;
9 |
10 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Thumbnail
11 | {
12 |
13 | [Extension("VisionThumbnail")]
14 | public class VisionThumbnailBinding : IExtensionConfigProvider, IVisionBinding
15 | {
16 |
17 | public ICognitiveServicesClient Client { get; set; }
18 |
19 | internal ILoggerFactory _loggerFactory;
20 |
21 | public VisionThumbnailBinding(ILoggerFactory loggerFactory, ICognitiveServicesClient client)
22 | {
23 | _loggerFactory = loggerFactory;
24 | this.Client = client;
25 | }
26 |
27 | public void Initialize(ExtensionConfigContext context)
28 | {
29 |
30 | LoadClient();
31 |
32 | var visionRule = context.AddBindingRule();
33 |
34 | visionRule.When(nameof(VisionThumbnailAttribute.ImageSource), ImageSource.BlobStorage)
35 | .BindToInput(GetVisionDescribeModel);
36 |
37 | visionRule.When(nameof(VisionThumbnailAttribute.ImageSource), ImageSource.Url)
38 | .BindToInput(GetVisionDescribeModel);
39 |
40 | visionRule.When(nameof(VisionThumbnailAttribute.ImageSource), ImageSource.Client)
41 | .BindToInput(attr => new VisionThumbnailClient(this, attr, _loggerFactory));
42 |
43 |
44 | }
45 |
46 | private void LoadClient()
47 | {
48 | if (Client == null)
49 | {
50 | Client = new CognitiveServicesClient(new RetryPolicy(), _loggerFactory);
51 | }
52 | }
53 |
54 | private Byte[] GetVisionDescribeModel(VisionThumbnailAttribute attribute)
55 | {
56 |
57 | if (attribute.ImageSource == Bindings.ImageSource.Client)
58 | {
59 | throw new ArgumentException($"ImageSource of Client does not support binding to vision models. Use Url or BlobStorage instead. ");
60 | }
61 |
62 | attribute.Validate();
63 |
64 | var client = new VisionThumbnailClient(this, attribute, _loggerFactory);
65 |
66 | VisionThumbnailRequest request = new VisionThumbnailRequest();
67 |
68 | if (attribute.ImageSource == ImageSource.BlobStorage)
69 | {
70 | var fileTask = StorageServices.GetFileBytes(attribute.BlobStoragePath, attribute.BlobStorageAccount);
71 | fileTask.Wait();
72 |
73 | request.ImageBytes = fileTask.Result;
74 | }
75 | else
76 | {
77 | request.ImageUrl = attribute.ImageUrl;
78 | }
79 |
80 | var result = client.ThumbnailAsync(request);
81 | result.Wait();
82 |
83 | return result.Result;
84 |
85 | }
86 | }
87 | }
88 |
89 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Thumbnail/VisionThumbnailClient.cs:
--------------------------------------------------------------------------------
1 | using AzureFunctions.Extensions.CognitiveServices.Config;
2 | using AzureFunctions.Extensions.CognitiveServices.Services;
3 | using AzureFunctions.Extensions.CognitiveServices.Services.Models;
4 | using Microsoft.Extensions.Logging;
5 | using Newtonsoft.Json;
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Diagnostics;
9 | using System.Net.Http;
10 | using System.Text;
11 | using System.Threading.Tasks;
12 |
13 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Thumbnail
14 | {
15 | public class VisionThumbnailClient
16 | {
17 | IVisionBinding _config;
18 | VisionThumbnailAttribute _attr;
19 | ILogger _log;
20 |
21 | public VisionThumbnailClient(IVisionBinding config, VisionThumbnailAttribute attr, ILoggerFactory loggerFactory)
22 | {
23 | this._config = config;
24 | this._attr = attr;
25 | this._log = loggerFactory?.CreateLogger("Host.Bindings.VisionThumbnail");
26 | }
27 |
28 | public async Task ThumbnailAsync(VisionThumbnailRequest request)
29 | {
30 | Stopwatch imageResizeSW = null;
31 |
32 | var visionOperation = await MergeProperties(request, this._config, this._attr);
33 |
34 | if (request.IsUrlImageSource == false)
35 | {
36 |
37 | if (visionOperation.ImageBytes == null || visionOperation.ImageBytes.Length == 0)
38 | {
39 | _log.LogWarning(VisionExceptionMessages.FileMissing);
40 | throw new ArgumentException(VisionExceptionMessages.FileMissing);
41 | }
42 |
43 | if (ImageResizeService.IsImage(visionOperation.ImageBytes) == false)
44 | {
45 | _log.LogWarning(VisionExceptionMessages.InvalidFileType);
46 | throw new ArgumentException(VisionExceptionMessages.InvalidFileType);
47 | }
48 |
49 |
50 | if (visionOperation.Oversized == true && visionOperation.AutoResize == false)
51 | {
52 | var message = string.Format(VisionExceptionMessages.FileTooLarge,
53 | VisionConfiguration.MaximumFileSize, visionOperation.ImageBytes.Length);
54 | _log.LogWarning(message);
55 | throw new ArgumentException(message);
56 | }
57 | else if (visionOperation.Oversized == true && visionOperation.AutoResize == true)
58 | {
59 | _log.LogTrace("Resizing Image");
60 |
61 | imageResizeSW = new Stopwatch();
62 |
63 | imageResizeSW.Start();
64 |
65 | visionOperation.ImageBytes = ImageResizeService.ResizeImage(visionOperation.ImageBytes);
66 |
67 | imageResizeSW.Stop();
68 |
69 | _log.LogMetric("VisionAnalysisImageResizeDurationMillisecond", imageResizeSW.ElapsedMilliseconds);
70 |
71 | if (visionOperation.Oversized)
72 | {
73 | var message = string.Format(VisionExceptionMessages.FileTooLargeAfterResize,
74 | VisionConfiguration.MaximumFileSize, visionOperation.ImageBytes.Length);
75 | _log.LogWarning(message);
76 | throw new ArgumentException(message);
77 | }
78 |
79 | }
80 | }
81 |
82 | var result = await SubmitRequest(visionOperation);
83 |
84 | return result;
85 | }
86 |
87 | private async Task SubmitRequest(VisionThumbnailRequest request)
88 | {
89 | Stopwatch sw = new Stopwatch();
90 |
91 | string uri = $"{request.Url}/generateThumbnail?width={request.Width}&height={request.Height}&smartCropping={request.SmartCropping.ToString()}";
92 |
93 | ServiceResultModel requestResult = null;
94 |
95 | if (request.IsUrlImageSource)
96 | {
97 | _log.LogTrace($"Submitting Vision Thumbnail Request");
98 |
99 | var urlRequest = new VisionUrlRequest { Url = request.ImageUrl };
100 | var requestContent = JsonConvert.SerializeObject(urlRequest);
101 |
102 | var content = new StringContent(requestContent);
103 |
104 | sw.Start();
105 |
106 | requestResult = await this._config.Client.PostAsync(uri, request.Key, content, ReturnType.Binary);
107 |
108 | sw.Stop();
109 |
110 | _log.LogMetric("VisionRequestDurationMillisecond", sw.ElapsedMilliseconds);
111 |
112 | }
113 | else
114 | {
115 | using (ByteArrayContent content = new ByteArrayContent(request.ImageBytes))
116 | {
117 | requestResult = await this._config.Client.PostAsync(uri, request.Key, content, ReturnType.Binary);
118 | }
119 | }
120 |
121 | if (requestResult.HttpStatusCode == (int)System.Net.HttpStatusCode.OK)
122 | {
123 | _log.LogTrace($"Thumbnail Request Results");
124 |
125 | byte[] fileResult = requestResult.Binary;
126 |
127 | return fileResult;
128 | }
129 | else if (requestResult.HttpStatusCode == (int)System.Net.HttpStatusCode.BadRequest)
130 | {
131 |
132 | VisionErrorModel error = JsonConvert.DeserializeObject(requestResult.Contents);
133 | var message = string.Format(VisionExceptionMessages.CognitiveServicesException, error.Code, error.Message);
134 |
135 | _log.LogWarning(message);
136 |
137 | throw new Exception(message);
138 | }
139 | else
140 | {
141 | var message = string.Format(VisionExceptionMessages.CognitiveServicesException, requestResult.HttpStatusCode, requestResult.Contents);
142 |
143 | _log.LogError(message);
144 |
145 | throw new Exception(message);
146 | }
147 |
148 | }
149 |
150 | private async Task MergeProperties(VisionThumbnailRequest operation, IVisionBinding config, VisionThumbnailAttribute attr)
151 | {
152 |
153 | var visionOperation = new VisionThumbnailRequest
154 | {
155 | Url = attr.VisionUrl ?? operation.Url,
156 | Key = attr.VisionKey ?? operation.Key,
157 | AutoResize = attr.AutoResize,
158 | Height = attr.Height,
159 | Width = attr.Width,
160 | SmartCropping = attr.SmartCropping,
161 | ImageUrl = string.IsNullOrEmpty(operation.ImageUrl) ? attr.ImageUrl : operation.ImageUrl,
162 | ImageBytes = operation.ImageBytes,
163 | };
164 |
165 |
166 | if (string.IsNullOrEmpty(visionOperation.Key))
167 | {
168 | _log.LogWarning(VisionExceptionMessages.KeyMissing);
169 | throw new ArgumentException(VisionExceptionMessages.KeyMissing);
170 | }
171 |
172 | return visionOperation;
173 |
174 | }
175 |
176 | }
177 | }
178 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Thumbnail/VisionThumbnailExtension.cs:
--------------------------------------------------------------------------------
1 | using AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Thumbnail;
2 | using Microsoft.Azure.WebJobs;
3 | using System;
4 |
5 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Thumbnail
6 | {
7 | public static class VisionThumbnailExtension
8 | {
9 | public static IWebJobsBuilder AddVisionThumbnail(this IWebJobsBuilder builder)
10 | {
11 | if (builder == null)
12 | {
13 | throw new ArgumentNullException(nameof(builder));
14 | }
15 |
16 | builder.AddExtension();
17 | return builder;
18 | }
19 |
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Thumbnail/VisionThumbnailRequest.cs:
--------------------------------------------------------------------------------
1 | using AzureFunctions.Extensions.CognitiveServices.Config;
2 | using Microsoft.Azure.WebJobs.Description;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.ComponentModel.DataAnnotations;
6 | using System.IO;
7 | using System.Text;
8 |
9 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Thumbnail
10 | {
11 | public class VisionThumbnailRequest : VisionRequestBase
12 | {
13 |
14 | public VisionThumbnailRequest() { }
15 |
16 | public VisionThumbnailRequest(Stream image) : base(image) { }
17 |
18 | public VisionThumbnailRequest(byte[] image) : base(image) { }
19 |
20 | public VisionThumbnailRequest(string imageUrl) : base(imageUrl) { }
21 |
22 |
23 | [AutoResolve()]
24 | [Required(ErrorMessage = VisionExceptionMessages.WidthMissing)]
25 | [Range(1, 1024, ErrorMessage = VisionExceptionMessages.ImageSizeOutOfRange)]
26 | public string Width { get; set; }
27 |
28 | [AutoResolve()]
29 | [Required(ErrorMessage = VisionExceptionMessages.HeightMissing)]
30 | [Range(1, 1024, ErrorMessage = VisionExceptionMessages.ImageSizeOutOfRange)]
31 | public string Height { get; set; }
32 |
33 | public bool SmartCropping { get; set; }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/Thumbnail/VisionThumbnailStartup.cs:
--------------------------------------------------------------------------------
1 | using AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Ocr;
2 | using AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Thumbnail;
3 | using Microsoft.Azure.WebJobs;
4 | using Microsoft.Azure.WebJobs.Hosting;
5 |
6 | [assembly: WebJobsStartup(typeof(VisionThumbnailWebJobsStartup))]
7 |
8 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Thumbnail
9 | {
10 |
11 | public class VisionThumbnailWebJobsStartup : IWebJobsStartup
12 | {
13 | public void Configure(IWebJobsBuilder builder)
14 | {
15 | builder.AddVisionThumbnail();
16 | }
17 | }
18 |
19 |
20 | }
21 |
22 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/VisionAttributeBase.cs:
--------------------------------------------------------------------------------
1 | using AzureFunctions.Extensions.CognitiveServices.Config;
2 | using AzureFunctions.Extensions.CognitiveServices.Services;
3 | using Microsoft.Azure.WebJobs.Description;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.ComponentModel.DataAnnotations;
7 | using System.Text;
8 |
9 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings
10 | {
11 |
12 | ///
13 | /// Determines the source of the image being analyzed. Each Image Source
14 | /// has varied required properties.
15 | ///
16 | public enum ImageSource
17 | {
18 | ///
19 | /// Image source is a publically accessible url
20 | ///
21 | Url,
22 | ///
23 | /// Image source is from Blob Storage
24 | ///
25 | BlobStorage,
26 | ///
27 | /// Image source is specified within the client binding
28 | ///
29 | Client
30 | }
31 |
32 | public abstract class VisionAttributeBase : Attribute
33 | {
34 |
35 | ///
36 | /// Vision Service URL. Defaults to an appSettings of VisionUrl
37 | ///
38 | [AppSetting(Default = "VisionUrl")]
39 | public string VisionUrl { get; set; }
40 |
41 | ///
42 | /// Authentication Key for Vision Service. Defaults to an appsettings
43 | /// of VisionKey
44 | ///
45 | [AppSetting(Default = "VisionKey")]
46 | public string VisionKey { get; set; }
47 |
48 |
49 | ///
50 | /// The source of the image being analyzed.
51 | ///
52 | public ImageSource ImageSource { get; set; } = ImageSource.Client;
53 |
54 | ///
55 | /// Whether the image being analyzed will automatically
56 | /// downscale and resize to achieve the cognitive services
57 | /// file size limit.
58 | ///
59 | public bool AutoResize { get; set; } = true;
60 |
61 | ///
62 | /// Vision Service URL. Defaults to a appsetting of VisionStorage
63 | ///
64 | [AppSetting(Default = "StorageAccount")]
65 | public string BlobStorageAccount { get; set; }
66 |
67 | ///
68 | /// Path to the file being analyzed in BlobStorage. May be set
69 | /// at runtime with dynamic parameters
70 | ///
71 | [AutoResolve()]
72 | public string BlobStoragePath { get; set; }
73 |
74 | ///
75 | /// A Url to the image being analyzed. Must be accessible without authentication
76 | ///
77 | [AutoResolve()]
78 | public string ImageUrl { get; set; }
79 |
80 |
81 | internal void Validate()
82 | {
83 |
84 | if (string.IsNullOrEmpty(VisionUrl))
85 | {
86 | throw new ArgumentException($"A value for VisionUrl must be provided for a VisionAttribute.");
87 | }
88 |
89 | if (string.IsNullOrEmpty(VisionKey))
90 | {
91 | throw new ArgumentException($"A value for VisionKey must be provided for a VisionAttribute.");
92 | }
93 |
94 | switch (ImageSource)
95 | {
96 | case ImageSource.Client:
97 | break;
98 |
99 | case ImageSource.BlobStorage:
100 |
101 | if (string.IsNullOrEmpty(BlobStorageAccount))
102 | {
103 | throw new ArgumentException($"A value for BlobStorageConnection must be provided for an image source of BlobStorage");
104 | }
105 |
106 | if (string.IsNullOrEmpty(BlobStoragePath))
107 | {
108 | throw new ArgumentException($"A value for BlobStoragePath must be provided for an image source of BlobStorage");
109 | }
110 |
111 | break;
112 |
113 | case ImageSource.Url:
114 |
115 | if (string.IsNullOrEmpty(ImageUrl))
116 | {
117 | throw new ArgumentException($"A value for ImageUrl must be provided for an image source of BlobStorage");
118 | }
119 |
120 | break;
121 | }
122 |
123 | }
124 |
125 | }
126 | }
127 |
128 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/VisionErrorModel.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision
7 | {
8 | public class VisionErrorModel
9 | {
10 | [JsonProperty(PropertyName = "code")]
11 | public string Code { get; set; }
12 |
13 | [JsonProperty(PropertyName = "requestId")]
14 | public string RequestId { get; set; }
15 |
16 | [JsonProperty(PropertyName = "message")]
17 | public string Message { get; set; }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/VisionRequestBase.cs:
--------------------------------------------------------------------------------
1 | using AzureFunctions.Extensions.CognitiveServices.Config;
2 | using Newtonsoft.Json;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.IO;
6 | using System.Text;
7 |
8 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision
9 | {
10 | public abstract class VisionRequestBase
11 | {
12 | public VisionRequestBase() { }
13 |
14 | public VisionRequestBase(Stream image)
15 | {
16 | this.ImageStream = image;
17 | }
18 |
19 | public VisionRequestBase(byte[] image)
20 | {
21 | this.ImageBytes = image;
22 | }
23 | public VisionRequestBase(string imageUrl)
24 | {
25 | this.ImageUrl = ImageUrl;
26 | }
27 |
28 | public Byte[] ImageBytes { get; set; }
29 |
30 | public Stream ImageStream
31 | {
32 | set
33 | {
34 | using (BinaryReader reader = new BinaryReader(value))
35 | {
36 | this.ImageBytes = reader.ReadBytes((int)value.Length);
37 | }
38 | }
39 | }
40 |
41 | [JsonProperty("autoResizePhoto")]
42 | public bool AutoResize { get; set; }
43 |
44 | [JsonProperty("key")]
45 | public string Key { get; set; }
46 |
47 | [JsonProperty("url")]
48 | public string Url { get; set; }
49 |
50 | [JsonProperty("language")]
51 | public string Language { get; set; } = "en";
52 |
53 | [JsonProperty("imageUrl")]
54 | public string ImageUrl { get; set; }
55 |
56 | public bool Oversized
57 | {
58 | get
59 | {
60 | var maxFileSize = VisionConfiguration.MaximumFileSize * 1024f * 1024f;
61 |
62 | if (ImageBytes.Length > maxFileSize)
63 | {
64 | return true;
65 | }
66 |
67 | return false;
68 | }
69 | }
70 |
71 | public bool IsUrlImageSource
72 | {
73 | get
74 | {
75 | if (ImageBytes == null || ImageBytes.Length == 0)
76 | {
77 |
78 | bool validUrl = Uri.TryCreate(ImageUrl, UriKind.Absolute, out Uri uriResult)
79 | && (uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps);
80 |
81 | if (validUrl)
82 | {
83 | return true;
84 | }
85 |
86 | }
87 |
88 | return false;
89 | }
90 | }
91 |
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Bindings/Vision/VisionUrlRequest.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace AzureFunctions.Extensions.CognitiveServices.Bindings.Vision
7 | {
8 | public class VisionUrlRequest
9 | {
10 |
11 | [JsonProperty(PropertyName = "url")]
12 | public string Url { get; set; }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Config/RetryPolicy.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace AzureFunctions.Extensions.CognitiveServices.Config
6 | {
7 | public class RetryPolicy
8 | {
9 | public int MaxRetryAttemptsAfterThrottle { get; set; } = 3;
10 |
11 | public int MaxRetryWaitTimeInSeconds { get; set; } = 90;
12 | }
13 |
14 | public class PollingPolicy
15 | {
16 | public int MaxRetryAttempts { get; set; } = 10;
17 |
18 | public int WaitBetweenRetry { get; set; } = 1;
19 |
20 | public int MaxRetryWaitTimeInSeconds { get; set; } = 120;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Config/VisionConfiguration.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace AzureFunctions.Extensions.CognitiveServices.Config
6 | {
7 | public static class VisionConfiguration
8 | {
9 | public static readonly int MaximumFileSize = 4;
10 | public static readonly int DefaultResizeQuality = 70;
11 | }
12 |
13 | public static class VisionExceptionMessages
14 | {
15 | public const string CognitiveServicesException = "The following exception was returned from Cognitive Services. Code: {0} Message: {1}";
16 | public const string InvalidFileType = "The file type you provided is not valid. Only jpg, gif, bmp, and png are supported.";
17 | public const string FileMissing = "Image File Missing";
18 | public const string FileTooLarge = "Files must be {0} mb or smaller for the cognitive service vision API. Your file size is {1} bytes.";
19 | public const string FileTooLargeAfterResize = "Files must be {0} mb or smaller for the cognitive service vision API. After an autoresize attempt your file is still too large at {1} bytes.";
20 | public const string ImageSizeOutOfRange = "Must be between 1 and 1024. Recommended minimum of 50.";
21 | public const string WidthMissing = "Width is required.";
22 | public const string HeightMissing = "Height is required.";
23 | public const string SubscriptionUrlRequired = "The url for Cognitive Services endpoint is missing. This can be found in your Azure Subscription.";
24 | public const string SubscriptionKeyMissing = "The key for the Cognitive Services subscription is missing.This can be found in your Azure Subscription.";
25 | public const string KeyMissing = "The cognitives services key is missing. You must set the Key or SecureKey property.";
26 | public const string InvalidDomainName = "The provided domain option {0} is invalid. Domain must be Celebrity or Landmark. Use Domain constants for better accuracy.";
27 | public const string KeyvaultException = "An exception occured while attempting to obtain a keyvault value: {0}";
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 | [assembly: InternalsVisibleTo("AzureFunctions.Extensions.CognitiveServices.Tests")]
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Services/CognitiveServicesClient.cs:
--------------------------------------------------------------------------------
1 | using AzureFunctions.Extensions.CognitiveServices.Config;
2 | using AzureFunctions.Extensions.CognitiveServices.Services.Models;
3 | using Microsoft.Extensions.Logging;
4 | using Polly;
5 | using Polly.Timeout;
6 | using Polly.Wrap;
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Net;
10 | using System.Net.Http;
11 | using System.Net.Http.Headers;
12 | using System.Text;
13 | using System.Threading.Tasks;
14 |
15 | namespace AzureFunctions.Extensions.CognitiveServices.Services
16 | {
17 | public class CognitiveServicesClient : ICognitiveServicesClient
18 | {
19 | private static HttpClient _client = new HttpClient();
20 | private PolicyWrap _retryPolicyWrapper;
21 | private ILogger _log;
22 |
23 |
24 | public HttpClient GetHttpClientInstance()
25 | {
26 | return _client;
27 | }
28 |
29 | public CognitiveServicesClient(RetryPolicy retryPolicy, ILoggerFactory loggerFactory)
30 | {
31 | this._log = loggerFactory?.CreateLogger("Host.Bindings.CognitiveServicesClient");
32 |
33 | Random jitter = new Random();
34 |
35 | var timeoutPolicy = Policy
36 | .TimeoutAsync(TimeSpan.FromSeconds(retryPolicy.MaxRetryWaitTimeInSeconds), TimeoutStrategy.Pessimistic);
37 |
38 | var throttleRetryPolicy = Policy
39 | .HandleResult(r => r.StatusCode == (HttpStatusCode)429)
40 | .WaitAndRetryAsync(retryPolicy.MaxRetryAttemptsAfterThrottle,
41 | retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)) + TimeSpan.FromMilliseconds(jitter.Next(0, 1000)),
42 | onRetry: (exception, retryCount, context) =>
43 | {
44 | _log.LogWarning($"Cognitive Service - Retry {retryCount} of {context.PolicyKey}, due to 429 throttling.");
45 | }
46 | );
47 |
48 |
49 | _retryPolicyWrapper = timeoutPolicy.WrapAsync(throttleRetryPolicy);
50 |
51 | }
52 |
53 | public async Task PostAsync(string uri, string key, StringContent content, ReturnType returnType)
54 | {
55 | var httpResponse = await _retryPolicyWrapper.ExecuteAsync(async () => {
56 |
57 | _client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", key);
58 |
59 | content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
60 | var requestMessage = new HttpRequestMessage(HttpMethod.Post, uri);
61 |
62 | var response = await _client.PostAsync(uri, content);
63 |
64 | return response;
65 |
66 | });
67 |
68 | var result = new ServiceResultModel { HttpStatusCode = (int)httpResponse.StatusCode };
69 |
70 | if (returnType == ReturnType.String)
71 | {
72 | result.Contents = await httpResponse.Content.ReadAsStringAsync();
73 | result.Headers = httpResponse.Headers;
74 | }
75 |
76 | if (returnType == ReturnType.Binary)
77 | {
78 | result.Binary = await httpResponse.Content.ReadAsByteArrayAsync();
79 | result.Headers = httpResponse.Headers;
80 | }
81 |
82 |
83 | return result;
84 |
85 |
86 | }
87 |
88 | public async Task PostAsync(string uri, string key, ByteArrayContent content, ReturnType returnType)
89 | {
90 | var httpResponse = await _retryPolicyWrapper.ExecuteAsync(async () => {
91 |
92 | _client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", key);
93 |
94 | content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
95 | var requestMessage = new HttpRequestMessage(HttpMethod.Post, uri);
96 |
97 | var response = await _client.PostAsync(uri, content);
98 |
99 | return response;
100 |
101 | });
102 |
103 | var result = new ServiceResultModel { HttpStatusCode = (int)httpResponse.StatusCode };
104 |
105 | if (returnType == ReturnType.String)
106 | {
107 | result.Contents = await httpResponse.Content.ReadAsStringAsync();
108 | result.Headers = httpResponse.Headers;
109 | }
110 |
111 | if (returnType == ReturnType.Binary)
112 | {
113 | result.Binary = await httpResponse.Content.ReadAsByteArrayAsync();
114 | result.Headers = httpResponse.Headers;
115 | }
116 |
117 |
118 | return result;
119 | }
120 |
121 | public async Task GetAsync(string uri, string key, ReturnType returnType)
122 | {
123 | var httpResponse = await _retryPolicyWrapper.ExecuteAsync(async () => {
124 |
125 | _client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", key);
126 |
127 | var response = await _client.GetAsync(uri);
128 |
129 | return response;
130 |
131 | });
132 |
133 | var result = new ServiceResultModel { HttpStatusCode = (int)httpResponse.StatusCode };
134 |
135 | if (returnType == ReturnType.String)
136 | {
137 | result.Headers = httpResponse.Headers;
138 | result.Contents = await httpResponse.Content.ReadAsStringAsync();
139 | }
140 |
141 | if (returnType == ReturnType.Binary)
142 | {
143 | result.Headers = httpResponse.Headers;
144 | result.Binary = await httpResponse.Content.ReadAsByteArrayAsync();
145 | }
146 |
147 | return result;
148 | }
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Services/ICognitiveServicesClient.cs:
--------------------------------------------------------------------------------
1 | using AzureFunctions.Extensions.CognitiveServices.Services.Models;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Net.Http;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace AzureFunctions.Extensions.CognitiveServices.Services
9 | {
10 | public enum ReturnType
11 | {
12 | String,
13 | Binary
14 | }
15 |
16 | public interface ICognitiveServicesClient
17 | {
18 |
19 | HttpClient GetHttpClientInstance();
20 |
21 | Task PostAsync(string uri, string key, StringContent content, ReturnType returnType);
22 |
23 | Task PostAsync(string uri, string key, ByteArrayContent content, ReturnType returnType);
24 |
25 | Task GetAsync(string uri, string key, ReturnType returnType);
26 |
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Services/ImageResizeService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Text;
6 | using AzureFunctions.Extensions.CognitiveServices.Config;
7 | using SixLabors.ImageSharp;
8 | using SixLabors.ImageSharp.Formats.Jpeg;
9 | using SixLabors.ImageSharp.Formats.Png;
10 | using SixLabors.ImageSharp.Processing;
11 | using SixLabors.ImageSharp.Processing.Transforms;
12 | using SixLabors.Primitives;
13 |
14 | namespace AzureFunctions.Extensions.CognitiveServices.Services
15 | {
16 |
17 | public class ImageResizeService
18 | {
19 | private const string JPG_HEADER = "FFD8FF";
20 | private const string BMP_HEADER = "424D";
21 | private const string GIF_HEADER = "474946";
22 | private const string PNG_HEADER = "89504E470D0A1A0A";
23 |
24 | ///
25 | /// Use the known header approach to identify if a file is an image
26 | /// (more reliable then just looking at the extension)
27 | ///
28 | ///
29 | ///
30 | public static bool IsImage(Byte[] file)
31 | {
32 | byte[] fileHeaderBuffer = new byte[8];
33 |
34 | string header = string.Format("{0}{1}{2}{3}{4}{5}{6}{7}",
35 | file[0].ToString("X2"),
36 | file[1].ToString("X2"),
37 | file[2].ToString("X2"),
38 | file[3].ToString("X2"),
39 | file[4].ToString("X2"),
40 | file[5].ToString("X2"),
41 | file[6].ToString("X2"),
42 | file[7].ToString("X2"));
43 |
44 | if (header.StartsWith(JPG_HEADER) ||
45 | header.StartsWith(GIF_HEADER) ||
46 | header.StartsWith(BMP_HEADER) ||
47 | header.StartsWith(PNG_HEADER))
48 | {
49 | return true;
50 | }
51 |
52 | return false;
53 |
54 | }
55 |
56 | ///
57 | /// Resizes an image with the goal of getting the file under the default file size limit for Cognitive Services
58 | ///
59 | ///
60 | ///
61 | public static byte[] ResizeImage(Byte[] file)
62 | {
63 |
64 | using (var img = Image.Load(file))
65 | {
66 | var jpegEncoder = new JpegEncoder() { Quality = VisionConfiguration.DefaultResizeQuality };
67 |
68 | using (var resizedImage = new MemoryStream())
69 | {
70 |
71 | var options = new ResizeOptions
72 | {
73 | Size = new Size(img.Width / 2, img.Height / 2),
74 | Mode = ResizeMode.Max
75 | };
76 |
77 | img.Mutate(x => x.Resize(options));
78 |
79 | img.SaveAsJpeg(resizedImage, jpegEncoder);
80 |
81 | byte[] results = resizedImage.ToArray();
82 |
83 | return results;
84 | }
85 |
86 | }
87 |
88 | }
89 |
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Services/Models/ServiceResultModel.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Net.Http.Headers;
5 | using System.Text;
6 |
7 | namespace AzureFunctions.Extensions.CognitiveServices.Services.Models
8 | {
9 | public class ServiceResultModel
10 | {
11 |
12 | public int HttpStatusCode { get; set; }
13 |
14 | public string Contents { get; set; }
15 |
16 | public byte[] Binary { get; set; }
17 |
18 | public HttpResponseHeaders Headers { get; set; }
19 |
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/AzureFunctions.Extensions.CognitiveServices/Services/StorageServices.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.WindowsAzure.Storage;
2 | using System;
3 | using System.IO;
4 | using System.Threading.Tasks;
5 |
6 | namespace AzureFunctions.Extensions.CognitiveServices.Services
7 | {
8 | public class StorageServices
9 | {
10 |
11 | public static async Task GetFileBytes(string blobPath, string blobConnection)
12 | {
13 | CloudStorageAccount storageAccount;
14 |
15 | if (CloudStorageAccount.TryParse(blobConnection, out storageAccount))
16 | {
17 | var path = Path.GetDirectoryName(blobPath);
18 | var filename = Path.GetFileName(blobPath);
19 |
20 | var blobClient = storageAccount.CreateCloudBlobClient();
21 | var container = blobClient.GetContainerReference(path);
22 | var blob = container.GetBlockBlobReference(filename);
23 |
24 | using (MemoryStream memStream = new MemoryStream())
25 | {
26 | await blob.DownloadToStreamAsync(memStream);
27 |
28 | var fileBytes = memStream.ToArray();
29 |
30 | return fileBytes;
31 | }
32 |
33 | }
34 | else
35 | {
36 | throw new ArgumentException($"The storage account connection you provided is not valid.");
37 | }
38 |
39 | }
40 |
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/tests/AzureFunctions.Extensions.CognitiveServices.Tests/AzureFunctions.Extensions.CognitiveServices.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.0
5 | false
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | all
16 | runtime; build; native; contentfiles; analyzers
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | True
28 | True
29 | MockResults.resx
30 |
31 |
32 |
33 |
34 |
35 | ResXFileCodeGenerator
36 | MockResults.Designer.cs
37 |
38 |
39 |
40 |
41 |
42 | PreserveNewest
43 | Never
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/tests/AzureFunctions.Extensions.CognitiveServices.Tests/Common/ExplicitTypeLocator.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Azure.WebJobs;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 |
7 | namespace AzureFunctions.Extensions.CognitiveServices.Tests.Common
8 | {
9 | public class ExplicitTypeLocator : ITypeLocator
10 | {
11 | private readonly IReadOnlyList types;
12 |
13 | public ExplicitTypeLocator(params Type[] types)
14 | {
15 | this.types = types.ToList().AsReadOnly();
16 | }
17 |
18 | public IReadOnlyList GetTypes()
19 | {
20 | return types;
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/tests/AzureFunctions.Extensions.CognitiveServices.Tests/Common/FunctionHost.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Azure.WebJobs;
2 | using Microsoft.Azure.WebJobs.Host;
3 | using Microsoft.Extensions.Primitives;
4 | using Moq;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.IO;
8 | using System.Text;
9 | using System.Threading;
10 | using System.Threading.Tasks;
11 |
12 | namespace AzureFunctions.Extensions.CognitiveServices.Tests.TestHelpers
13 | {
14 | public abstract class FunctionHost
15 | {
16 | protected TraceWriter log = new VerboseDiagnosticsTraceWriter();
17 |
18 | //public HttpRequest HttpRequestSetup(Dictionary query, string body)
19 | //{
20 | // var reqMock = new Mock();
21 |
22 | // reqMock.Setup(req => req.Query).Returns(new QueryCollection(query));
23 | // var stream = new MemoryStream();
24 | // var writer = new StreamWriter(stream);
25 | // writer.Write(body);
26 | // writer.Flush();
27 | // stream.Position = 0;
28 | // reqMock.Setup(req => req.Body).Returns(stream);
29 | // return reqMock.Object;
30 | //}
31 |
32 | }
33 |
34 | public class AsyncCollector : IAsyncCollector
35 | {
36 | public readonly List Items = new List();
37 |
38 | public Task AddAsync(T item, CancellationToken cancellationToken = default(CancellationToken))
39 | {
40 |
41 | Items.Add(item);
42 |
43 | return Task.FromResult(true);
44 | }
45 |
46 | public Task FlushAsync(CancellationToken cancellationToken = default(CancellationToken))
47 | {
48 | return Task.FromResult(true);
49 | }
50 | }
51 | }
52 |
53 |
--------------------------------------------------------------------------------
/tests/AzureFunctions.Extensions.CognitiveServices.Tests/Common/LogMessage.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Logging;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace AzureFunctions.Extensions.CognitiveServices.Tests.Common
7 | {
8 | public class LogMessage
9 | {
10 | public LogLevel Level { get; set; }
11 |
12 | public EventId EventId { get; set; }
13 |
14 | public IEnumerable> State { get; set; }
15 |
16 | public Exception Exception { get; set; }
17 |
18 | public string FormattedMessage { get; set; }
19 |
20 | public string Category { get; set; }
21 |
22 | public DateTime Timestamp { get; set; }
23 |
24 | public override string ToString() => $"[{Timestamp.ToString("HH:mm:ss.fff")}] [{Category}] {FormattedMessage} {Exception}";
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/tests/AzureFunctions.Extensions.CognitiveServices.Tests/Common/TestCognitiveServicesClient.cs:
--------------------------------------------------------------------------------
1 | using AzureFunctions.Extensions.CognitiveServices.Services;
2 | using AzureFunctions.Extensions.CognitiveServices.Services.Models;
3 | using AzureFunctions.Extensions.CognitiveServices.Tests.Resources;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Net.Http;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace AzureFunctions.Extensions.CognitiveServices.Tests
11 | {
12 | public class TestCognitiveServicesClient : ICognitiveServicesClient
13 | {
14 | public Task GetAsync(string uri, string key, ReturnType returnType)
15 | {
16 | throw new NotImplementedException();
17 | }
18 |
19 | public HttpClient GetHttpClientInstance()
20 | {
21 | return new HttpClient();
22 | }
23 |
24 | public Task PostAsync(string uri, string key, StringContent content, ReturnType returnType)
25 | {
26 | ServiceResultModel result = null;
27 |
28 | if (uri.Contains("analyze") == true)
29 | {
30 | result = new ServiceResultModel { HttpStatusCode = 200, Contents = MockResults.VisionAnalysisResults };
31 | }
32 |
33 | if (uri.Contains("vision") == true)
34 | {
35 | result = new ServiceResultModel { HttpStatusCode = 200, Contents = MockResults.VisionAnalysisResults };
36 | }
37 |
38 | if (uri.Contains("describe") == true)
39 | {
40 | result = new ServiceResultModel { HttpStatusCode = 200, Contents = MockResults.VisionDescribeResults };
41 | }
42 |
43 | if (returnType == ReturnType.Binary)
44 | {
45 | result = new ServiceResultModel { HttpStatusCode = 200, Binary = MockResults.SamplePhoto };
46 |
47 | }
48 |
49 | return Task.FromResult(result);
50 | }
51 |
52 | public Task PostAsync(string uri, string key, ByteArrayContent content, ReturnType returnType)
53 | {
54 | ServiceResultModel result = null;
55 |
56 | if (returnType == ReturnType.String)
57 | {
58 | if (uri.Contains("analyze") == true)
59 | {
60 | result = new ServiceResultModel { HttpStatusCode = 200, Contents = MockResults.VisionAnalysisResults };
61 | }
62 |
63 | if (uri.Contains("vision") == true)
64 | {
65 | result = new ServiceResultModel { HttpStatusCode = 200, Contents = MockResults.VisionAnalysisResults };
66 | }
67 |
68 | if (uri.Contains("describe") == true)
69 | {
70 | result = new ServiceResultModel { HttpStatusCode = 200, Contents = MockResults.VisionDescribeResults };
71 | }
72 |
73 | }
74 |
75 | if (returnType == ReturnType.Binary)
76 | {
77 | result = new ServiceResultModel { HttpStatusCode = 200, Binary = MockResults.SamplePhoto };
78 |
79 | }
80 |
81 | return Task.FromResult(result);
82 | }
83 |
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/tests/AzureFunctions.Extensions.CognitiveServices.Tests/Common/TestHelper.cs:
--------------------------------------------------------------------------------
1 | using AzureFunctions.Extensions.CognitiveServices.Services;
2 | using Microsoft.Azure.WebJobs;
3 | using Microsoft.Azure.WebJobs.Host;
4 | using Microsoft.Azure.WebJobs.Host.Config;
5 | using Microsoft.Extensions.Configuration;
6 | using Microsoft.Extensions.DependencyInjection;
7 | using Microsoft.Extensions.Hosting;
8 | using Moq;
9 | using System;
10 | using System.Collections.Generic;
11 | using System.Diagnostics;
12 | using System.Text;
13 | using System.Threading.Tasks;
14 |
15 | namespace AzureFunctions.Extensions.CognitiveServices.Tests.Common
16 | {
17 | public static class TestHelper
18 | {
19 | private static readonly IConfiguration _emptyConfig = new ConfigurationBuilder().Build();
20 |
21 | public static Task Await(Func condition, int timeout = 60 * 1000, int pollingInterval = 2 * 1000, bool throwWhenDebugging = false)
22 | {
23 | return Await(() => Task.FromResult(condition()), timeout, pollingInterval, throwWhenDebugging);
24 | }
25 |
26 | public static async Task Await(Func> condition, int timeout = 60 * 1000, int pollingInterval = 2 * 1000, bool throwWhenDebugging = false)
27 | {
28 | DateTime start = DateTime.Now;
29 | while (!await condition())
30 | {
31 | await Task.Delay(pollingInterval);
32 |
33 | bool shouldThrow = !Debugger.IsAttached || (Debugger.IsAttached && throwWhenDebugging);
34 | if (shouldThrow && (DateTime.Now - start).TotalMilliseconds > timeout)
35 | {
36 | throw new ApplicationException("Condition not reached within timeout.");
37 | }
38 | }
39 | }
40 |
41 | public static JobHost GetJobHost(this IHost host)
42 | {
43 | return host.Services.GetService() as JobHost;
44 | }
45 |
46 | public static ExtensionConfigContext CreateExtensionConfigContext(INameResolver resolver)
47 | {
48 | var mockWebHookProvider = new Mock();
49 | var mockExtensionRegistry = new Mock();
50 |
51 | // TODO: ConverterManager needs to be fixed but this will work for now.
52 | IHost host = new HostBuilder()
53 | .ConfigureWebJobs()
54 | .Build();
55 |
56 | var converterManager = host.Services.GetRequiredService();
57 |
58 | return new ExtensionConfigContext(_emptyConfig, resolver, converterManager, mockWebHookProvider.Object, mockExtensionRegistry.Object);
59 | }
60 |
61 | [Obsolete()]
62 | public static async Task ExecuteFunction(ICognitiveServicesClient client,
63 | string functionReference)
64 | {
65 | }
66 |
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/tests/AzureFunctions.Extensions.CognitiveServices.Tests/Common/TestLogger.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Logging;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 |
7 | namespace AzureFunctions.Extensions.CognitiveServices.Tests.Common
8 | {
9 | public class TestLogger : ILogger
10 | {
11 | private readonly Action _logAction;
12 | private IList _logMessages = new List();
13 |
14 | // protect against changes to logMessages while enumerating
15 | private object _syncLock = new object();
16 |
17 | public TestLogger(string category, Action logAction = null)
18 | {
19 | Category = category;
20 | _logAction = logAction;
21 | }
22 |
23 | public string Category { get; private set; }
24 |
25 | public IDisposable BeginScope(TState state)
26 | {
27 | return null;
28 | }
29 |
30 | public bool IsEnabled(LogLevel logLevel)
31 | {
32 | return true;
33 | }
34 |
35 | public IList GetLogMessages()
36 | {
37 | lock (_syncLock)
38 | {
39 | return _logMessages.ToList();
40 | }
41 | }
42 |
43 | public void ClearLogMessages()
44 | {
45 | lock (_syncLock)
46 | {
47 | _logMessages.Clear();
48 | }
49 | }
50 |
51 | public virtual void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter)
52 | {
53 | if (!IsEnabled(logLevel))
54 | {
55 | return;
56 | }
57 |
58 | var logMessage = new LogMessage
59 | {
60 | Level = logLevel,
61 | EventId = eventId,
62 | State = state as IEnumerable>,
63 | Exception = exception,
64 | FormattedMessage = formatter(state, exception),
65 | Category = Category,
66 | Timestamp = DateTime.UtcNow
67 | };
68 |
69 | lock (_syncLock)
70 | {
71 | _logMessages.Add(logMessage);
72 | }
73 |
74 | _logAction?.Invoke(logMessage);
75 | }
76 |
77 | public override string ToString()
78 | {
79 | return Category;
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/tests/AzureFunctions.Extensions.CognitiveServices.Tests/Common/TestLoggerProvider.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Logging;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Text.RegularExpressions;
7 |
8 | namespace AzureFunctions.Extensions.CognitiveServices.Tests.Common
9 | {
10 | public class TestLoggerProvider : ILoggerProvider
11 | {
12 | private readonly LoggerFilterOptions _filter;
13 | private readonly Action _logAction;
14 | private readonly Regex userCategoryRegex = new Regex(@"^Function\.\w+\.User$");
15 | private readonly Dictionary _loggerCache = new Dictionary();
16 |
17 | public TestLoggerProvider(Action logAction = null)
18 | {
19 | _filter = new LoggerFilterOptions();
20 | _logAction = logAction;
21 | }
22 |
23 | public IList CreatedLoggers => _loggerCache.Values.ToList();
24 |
25 | public ILogger CreateLogger(string categoryName)
26 | {
27 | if (!_loggerCache.TryGetValue(categoryName, out TestLogger logger))
28 | {
29 | logger = new TestLogger(categoryName, _logAction);
30 | _loggerCache.Add(categoryName, logger);
31 | }
32 |
33 | return logger;
34 | }
35 |
36 | public IEnumerable GetAllLogMessages() => CreatedLoggers.SelectMany(l => l.GetLogMessages()).OrderBy(p => p.Timestamp);
37 |
38 | public IEnumerable GetAllUserLogMessages()
39 | {
40 | return GetAllLogMessages().Where(p => userCategoryRegex.IsMatch(p.Category));
41 | }
42 |
43 | public string GetLogString() => string.Join(Environment.NewLine, GetAllLogMessages());
44 |
45 | public void ClearAllLogMessages()
46 | {
47 | foreach (TestLogger logger in CreatedLoggers)
48 | {
49 | logger.ClearLogMessages();
50 | }
51 | }
52 |
53 | public void Dispose()
54 | {
55 | }
56 | }
57 |
58 |
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/tests/AzureFunctions.Extensions.CognitiveServices.Tests/Common/TestNameResolver.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Azure.WebJobs;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace AzureFunctions.Extensions.CognitiveServices.Tests.Common
7 | {
8 | public class TestNameResolver : INameResolver
9 | {
10 | private readonly Dictionary _values = new Dictionary();
11 | private bool _throwException;
12 |
13 | public TestNameResolver(bool throwNotImplementedException = false)
14 | {
15 | // DefaultNameResolver throws so this helps simulate that for testing
16 | _throwException = throwNotImplementedException;
17 | }
18 |
19 | public Dictionary Values
20 | {
21 | get
22 | {
23 | return _values;
24 | }
25 | }
26 |
27 | public string Resolve(string name)
28 | {
29 | if (_throwException)
30 | {
31 | throw new NotImplementedException("INameResolver must be supplied to resolve '%" + name + "%'.");
32 | }
33 |
34 | string value = null;
35 | Values.TryGetValue(name, out value);
36 | return value;
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/tests/AzureFunctions.Extensions.CognitiveServices.Tests/Resources/MockResults.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace AzureFunctions.Extensions.CognitiveServices.Tests.Resources {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class MockResults {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal MockResults() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AzureFunctions.Extensions.CognitiveServices.Tests.Resources.MockResults", typeof(MockResults).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 |
63 | ///
64 | /// Looks up a localized resource of type System.Byte[].
65 | ///
66 | internal static byte[] SamplePhoto {
67 | get {
68 | object obj = ResourceManager.GetObject("SamplePhoto", resourceCulture);
69 | return ((byte[])(obj));
70 | }
71 | }
72 |
73 | ///
74 | /// Looks up a localized resource of type System.Byte[].
75 | ///
76 | internal static byte[] SamplePhotoTooBig {
77 | get {
78 | object obj = ResourceManager.GetObject("SamplePhotoTooBig", resourceCulture);
79 | return ((byte[])(obj));
80 | }
81 | }
82 |
83 | ///
84 | /// Looks up a localized string similar to {
85 | /// "tags": [
86 | /// {
87 | /// "name": "outdoor",
88 | /// "score": 0.976
89 | /// },
90 | /// {
91 | /// "name": "bird",
92 | /// "score": 0.95
93 | /// }
94 | /// ],
95 | /// "description": {
96 | /// "tags": [
97 | /// "outdoor",
98 | /// "bird"
99 | /// ],
100 | /// "captions": [
101 | /// {
102 | /// "text": "partridge in a pear tree",
103 | /// "confidence": 0.96
104 | /// }
105 | /// ]
106 | /// }
107 | ///}.
108 | ///
109 | internal static string VisionAnalysisResults {
110 | get {
111 | return ResourceManager.GetString("VisionAnalysisResults", resourceCulture);
112 | }
113 | }
114 |
115 | ///
116 | /// Looks up a localized string similar to {
117 | /// "description": {
118 | /// "tags": [
119 | /// "person",
120 | /// "man",
121 | /// "outdoor",
122 | /// "window",
123 | /// "glasses"
124 | /// ],
125 | /// "captions": [
126 | /// {
127 | /// "text": "Satya Nadella sitting on a bench",
128 | /// "confidence": 0.48293603002174407
129 | /// },
130 | /// {
131 | /// "text": "Satya Nadella is sitting on a bench",
132 | /// "confidence": 0.40037006815422832
133 | /// },
134 | /// {
135 | /// "text": "Satya Nadella sitting in front of a building",
136 | /// "confidence": 0.38035155997373377
137 | /// }
138 | /// ] [rest of string was truncated]";.
139 | ///
140 | internal static string VisionDescribeResults {
141 | get {
142 | return ResourceManager.GetString("VisionDescribeResults", resourceCulture);
143 | }
144 | }
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/tests/AzureFunctions.Extensions.CognitiveServices.Tests/Resources/MockResults.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 |
122 | samplephoto.jpeg;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
123 |
124 |
125 | samplephototoobig.jpg;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
126 |
127 |
128 | visionanalysisresults.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8
129 |
130 |
131 | visiondescriberesults.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8
132 |
133 |
--------------------------------------------------------------------------------
/tests/AzureFunctions.Extensions.CognitiveServices.Tests/Resources/SamplePhoto.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joshdcar/azure-functions-extensions-cognitive-services/f6dea9eff6c8d5a9cd1bb99fe21aa63efefac895/tests/AzureFunctions.Extensions.CognitiveServices.Tests/Resources/SamplePhoto.jpeg
--------------------------------------------------------------------------------
/tests/AzureFunctions.Extensions.CognitiveServices.Tests/Resources/SamplePhotoTooBig.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joshdcar/azure-functions-extensions-cognitive-services/f6dea9eff6c8d5a9cd1bb99fe21aa63efefac895/tests/AzureFunctions.Extensions.CognitiveServices.Tests/Resources/SamplePhotoTooBig.jpg
--------------------------------------------------------------------------------
/tests/AzureFunctions.Extensions.CognitiveServices.Tests/Resources/VisionAnalysisResults.json:
--------------------------------------------------------------------------------
1 | {
2 | "tags": [
3 | {
4 | "name": "outdoor",
5 | "score": 0.976
6 | },
7 | {
8 | "name": "bird",
9 | "score": 0.95
10 | }
11 | ],
12 | "description": {
13 | "tags": [
14 | "outdoor",
15 | "bird"
16 | ],
17 | "captions": [
18 | {
19 | "text": "partridge in a pear tree",
20 | "confidence": 0.96
21 | }
22 | ]
23 | }
24 | }
--------------------------------------------------------------------------------
/tests/AzureFunctions.Extensions.CognitiveServices.Tests/Resources/VisionDescribeResults.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": {
3 | "tags": [
4 | "person",
5 | "man",
6 | "outdoor",
7 | "window",
8 | "glasses"
9 | ],
10 | "captions": [
11 | {
12 | "text": "Satya Nadella sitting on a bench",
13 | "confidence": 0.48293603002174407
14 | },
15 | {
16 | "text": "Satya Nadella is sitting on a bench",
17 | "confidence": 0.40037006815422832
18 | },
19 | {
20 | "text": "Satya Nadella sitting in front of a building",
21 | "confidence": 0.38035155997373377
22 | }
23 | ]
24 | },
25 | "requestId": "ed2de1c6-fb55-4686-b0da-4da6e05d283f",
26 | "metadata": {
27 | "width": 1500,
28 | "height": 1000,
29 | "format": "Jpeg"
30 | }
31 | }
--------------------------------------------------------------------------------
/tests/AzureFunctions.Extensions.CognitiveServices.Tests/TestHelper.cs:
--------------------------------------------------------------------------------
1 | using AzureFunctions.Extensions.CognitiveServices.Bindings.Vision;
2 | using AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Analysis;
3 | using AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Describe;
4 | using AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Handwriting;
5 | using AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Ocr;
6 | using AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Thumbnail;
7 | using AzureFunctions.Extensions.CognitiveServices.Services;
8 | using Microsoft.Azure.WebJobs;
9 | using Microsoft.Azure.WebJobs.Host.Config;
10 | using Microsoft.Extensions.Configuration;
11 | using Microsoft.Extensions.Hosting;
12 | using System;
13 | using System.Collections.Generic;
14 | using System.Threading.Tasks;
15 | using Microsoft.Extensions.DependencyInjection;
16 | using Microsoft.Extensions.Logging;
17 | using AzureFunctions.Extensions.CognitiveServices.Tests.Common;
18 |
19 | namespace AzureFunctions.Extensions.CognitiveServices.Tests
20 | {
21 | public class TestHelper2
22 | {
23 | private static string functionOut = null;
24 |
25 | public static async Task ExecuteFunction(ICognitiveServicesClient client,
26 | Type hostType,
27 | string functionReference)
28 | {
29 |
30 |
31 | //IExtensionConfigProvider binding = null;
32 |
33 | //if (typeof(BindingType) == typeof(VisionAnalysisBinding))
34 | //{
35 | // binding = new VisionAnalysisBinding();
36 | //}
37 |
38 | //if (typeof(BindingType) == typeof(VisionDescribeBinding))
39 | //{
40 | // binding = new VisionDescribeBinding();
41 | //}
42 |
43 | //if (typeof(BindingType) == typeof(VisionHandwritingBinding))
44 | //{
45 | // binding = new VisionHandwritingBinding();
46 | //}
47 |
48 | //if (typeof(BindingType) == typeof(VisionOcrBinding))
49 | //{
50 | // binding = new VisionOcrBinding();
51 | //}
52 |
53 | //if (typeof(BindingType) == typeof(VisionThumbnailBinding))
54 | //{
55 | // binding = new VisionThumbnailBinding();
56 | //}
57 |
58 | //(binding as IVisionBinding).Client = client;
59 |
60 |
61 | //var jobHost = NewHost(binding);
62 |
63 | //var args = new Dictionary();
64 | //await jobHost.CallAsync(functionReference, args);
65 |
66 | //Dummy data to use later
67 | //var args = new Dictionary{
68 | // //{ "fileName", testFileName }
69 | //};
70 |
71 | //// make sure we can write the file to data lake store
72 | //using (var host = await StartHostAsync(hostType))
73 | //{
74 | // await host.GetJobHost().CallAsync(functionReference, args);
75 | // functionOut = null;
76 | //}
77 |
78 |
79 |
80 | }
81 |
82 | //public static JobHost NewHost(IExtensionConfigProvider ext)
83 | //{
84 | // var builder = new HostBuilder().ConfigureWebJobs(b =>
85 | // b.AddAzureStorageCoreServices());
86 |
87 | // var host = new JobHost()
88 |
89 |
90 | // //JobHostConfiguration config = new JobHostConfiguration();
91 | // //config.HostId = Guid.NewGuid().ToString("n");
92 | // //config.StorageConnectionString = null;
93 | // //config.DashboardConnectionString = null;
94 | // //config.TypeLocator = new FakeTypeLocator();
95 | // //config.AddExtension(ext);
96 | // //config.NameResolver = new NameResolver();
97 |
98 | // //var host = new JobHost()
99 |
100 | // //return host;
101 | // }
102 |
103 | //public static JobHost CreateJobHost(ILoggerProvider loggerProvider,INameResolver nameResolver)
104 | //{
105 | // IHost host = new HostBuilder()
106 | // .ConfigureLogging(
107 | // loggingBuilder =>
108 | // {
109 | // loggingBuilder.AddProvider(loggerProvider);
110 | // })
111 | // .ConfigureWebJobs(
112 | // webJobsBuilder =>
113 | // {
114 | // webJobsBuilder.AddAzureStorage();
115 | // })
116 | // .ConfigureServices(
117 | // serviceCollection =>
118 | // {
119 | // ITypeLocator typeLocator = GetTypeLocator();
120 | // serviceCollection.AddSingleton(typeLocator);
121 | // serviceCollection.AddSingleton(nameResolver);
122 | // })
123 | // .Build();
124 |
125 | // return (JobHost)host.Services.GetService();
126 | //}
127 |
128 |
129 |
130 | }
131 |
132 | public class NameResolver : INameResolver
133 | {
134 | IConfigurationRoot _config;
135 |
136 | public NameResolver()
137 | {
138 | _config = new ConfigurationBuilder()
139 | .AddJsonFile("local.settings.json")
140 | .Build();
141 |
142 | }
143 | public string Resolve(string name)
144 | {
145 | name = $"Values:{name}";
146 |
147 | var value = _config[name].ToString();
148 |
149 | return value;
150 | }
151 | }
152 |
153 | public class FakeTypeLocator : ITypeLocator
154 | {
155 | public IReadOnlyList Types => new Type[] { typeof(T) };
156 | public IReadOnlyList GetTypes()
157 | {
158 | return Types;
159 | }
160 | }
161 |
162 | }
163 |
--------------------------------------------------------------------------------
/tests/AzureFunctions.Extensions.CognitiveServices.Tests/TestHelpers/VerboseDiagnosticsTraceWriter.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Azure.WebJobs.Host;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Diagnostics;
5 | using System.Text;
6 |
7 | namespace AzureFunctions.Extensions.CognitiveServices.Tests.TestHelpers
8 | {
9 | public class VerboseDiagnosticsTraceWriter : TraceWriter
10 | {
11 |
12 | public VerboseDiagnosticsTraceWriter() : base(TraceLevel.Verbose)
13 | {
14 |
15 | }
16 | public override void Trace(TraceEvent traceEvent)
17 | {
18 | Debug.WriteLine(traceEvent.Message);
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/tests/AzureFunctions.Extensions.CognitiveServices.Tests/VisionAnalysisTests.cs:
--------------------------------------------------------------------------------
1 |
2 | using AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Analysis;
3 | using AzureFunctions.Extensions.CognitiveServices.Config;
4 | using AzureFunctions.Extensions.CognitiveServices.Services;
5 | using AzureFunctions.Extensions.CognitiveServices.Tests.Common;
6 | using AzureFunctions.Extensions.CognitiveServices.Tests.Resources;
7 | using FluentAssertions;
8 | using Microsoft.Azure.WebJobs;
9 | using Microsoft.Extensions.Configuration;
10 | using Microsoft.Extensions.DependencyInjection;
11 | using Microsoft.Extensions.Hosting;
12 | using Microsoft.Extensions.Logging;
13 | using Newtonsoft.Json;
14 | using System;
15 | using System.Collections.Generic;
16 | using System.Threading.Tasks;
17 | using Xunit;
18 |
19 | namespace AzureFunctions.Extensions.CognitiveServices.Tests
20 | {
21 |
22 | public class VisionAnalysisTests
23 | {
24 |
25 | private static VisionAnalysisModel visionAnalysisUrlResult;
26 | private static VisionAnalysisModel visionAnalysisImageBytesResult;
27 | private static VisionAnalysisModel visionAnalysisImageBytesResizeResult;
28 |
29 | private static readonly TestLoggerProvider _loggerProvider = new TestLoggerProvider();
30 |
31 |
32 | private static async Task RunTestAsync(string testName, object argument = null)
33 | {
34 | Type testType = typeof(VisionFunctions);
35 | var locator = new ExplicitTypeLocator(testType);
36 | ILoggerFactory loggerFactory = new LoggerFactory();
37 | loggerFactory.AddProvider(_loggerProvider);
38 | ICognitiveServicesClient testCognitiveServicesClient = new TestCognitiveServicesClient();
39 |
40 | var arguments = new Dictionary();
41 | var resolver = new TestNameResolver();
42 |
43 | IHost host = new HostBuilder()
44 | .ConfigureWebJobs(builder =>
45 | {
46 | builder.AddVisionAnalysis();
47 | })
48 | .ConfigureServices(services =>
49 | {
50 | services.AddSingleton(testCognitiveServicesClient);
51 | services.AddSingleton(resolver);
52 | services.AddSingleton(locator);
53 | })
54 | .ConfigureLogging(logging =>
55 | {
56 | logging.ClearProviders();
57 | logging.AddProvider(_loggerProvider);
58 | })
59 | .ConfigureAppConfiguration(c =>
60 | {
61 | c.Sources.Clear();
62 |
63 | var collection = new Dictionary
64 | {
65 | { "VisionKey", "1234XYZ" },
66 | { "VisionUrl", "http://url" }
67 | };
68 |
69 | c.AddInMemoryCollection(collection);
70 | })
71 | .Build();
72 |
73 | var method = testType.GetMethod(testName);
74 |
75 | await host.GetJobHost().CallAsync(method, arguments);
76 | }
77 |
78 |
79 | [Fact]
80 | public static async Task TestVisionAnalysisWithUrl()
81 | {
82 |
83 | var mockResult = JsonConvert.DeserializeObject(MockResults.VisionAnalysisResults);
84 |
85 | await RunTestAsync("VisionAnalysisWithUrl", null);
86 |
87 | var expectedResult = JsonConvert.SerializeObject(mockResult);
88 | var actualResult = JsonConvert.SerializeObject(visionAnalysisUrlResult);
89 |
90 | Assert.Equal(expectedResult, actualResult);
91 | }
92 |
93 | [Fact]
94 | public static async Task TestVisionAnalysisWithImageBytes()
95 | {
96 |
97 | var mockResult = JsonConvert.DeserializeObject(MockResults.VisionAnalysisResults);
98 |
99 | await RunTestAsync("VisionAnalysisWithImageBytes", null);
100 |
101 | var expectedResult = JsonConvert.SerializeObject(mockResult);
102 | var actualResult = JsonConvert.SerializeObject(visionAnalysisImageBytesResult);
103 |
104 | Assert.Equal(expectedResult, actualResult);
105 | }
106 |
107 | [Fact]
108 | public static async Task TestVisionAnalysisWithImageWithResize()
109 | {
110 |
111 | var mockResult = JsonConvert.DeserializeObject(MockResults.VisionAnalysisResults);
112 |
113 | await RunTestAsync("VisionAnalysisWithTooBigImageBytesWithResize", null);
114 |
115 | var expectedResult = JsonConvert.SerializeObject(mockResult);
116 | var actualResult = JsonConvert.SerializeObject(visionAnalysisImageBytesResizeResult);
117 |
118 | Assert.Equal(expectedResult, actualResult);
119 | }
120 |
121 | [Fact]
122 | public static async Task TestVisionAnalysisImageBytesTooLarge()
123 | {
124 |
125 | string exceptionMessage = "or smaller for the cognitive service vision API";
126 |
127 | var exception = await Record.ExceptionAsync(() => RunTestAsync("VisionAnalysisWithTooBigImageBytes", null));
128 |
129 | exception.Should().NotBeNull();
130 | exception.InnerException.Should().NotBeNull();
131 | exception.InnerException.Should().BeOfType();
132 | exception.InnerException.Message.Should().Contain(exceptionMessage);
133 |
134 | }
135 |
136 | [Fact]
137 | public static async Task TestVisionAnalysisMissingFile()
138 | {
139 |
140 | var exception = await Record.ExceptionAsync(() => RunTestAsync("VisionAnalysisMissingFile", null));
141 |
142 | exception.Should().NotBeNull();
143 | exception.InnerException.Should().NotBeNull();
144 | exception.InnerException.Should().BeOfType();
145 | exception.InnerException.Message.Should().Contain(VisionExceptionMessages.FileMissing);
146 |
147 | }
148 |
149 | private class VisionFunctions
150 | {
151 |
152 | public static async Task VisionAnalysisWithUrl(
153 | [VisionAnalysis()] VisionAnalysisClient client)
154 | {
155 |
156 | var request = new VisionAnalysisRequest();
157 | request.ImageUrl = "http://www.blah";
158 |
159 | var result = await client.AnalyzeAsync(request);
160 |
161 | visionAnalysisUrlResult = result;
162 | }
163 |
164 | public static async Task VisionAnalysisWithImageBytes(
165 | [VisionAnalysis()]
166 | VisionAnalysisClient client)
167 | {
168 | var request = new VisionAnalysisRequest();
169 | request.ImageBytes = MockResults.SamplePhoto;
170 |
171 | var result = await client.AnalyzeAsync(request);
172 |
173 | visionAnalysisImageBytesResult = result;
174 | }
175 |
176 | public static async Task VisionAnalysisWithTooBigImageBytes(
177 | [VisionAnalysis(AutoResize = false)]
178 | VisionAnalysisClient client)
179 | {
180 |
181 | var request = new VisionAnalysisRequest();
182 |
183 | request.ImageBytes = MockResults.SamplePhotoTooBig;
184 |
185 | var result = await client.AnalyzeAsync(request);
186 |
187 | }
188 |
189 | public static async Task VisionAnalysisWithTooBigImageBytesWithResize(
190 | [VisionAnalysis(AutoResize = true)]
191 | VisionAnalysisClient client)
192 | {
193 |
194 | var request = new VisionAnalysisRequest();
195 | request.ImageBytes = MockResults.SamplePhotoTooBig;
196 |
197 | var result = await client.AnalyzeAsync(request);
198 |
199 | visionAnalysisImageBytesResizeResult = result;
200 |
201 | }
202 |
203 | public static async Task VisionAnalysisMissingFile(
204 | [VisionAnalysis()]
205 | VisionAnalysisClient client)
206 | {
207 |
208 | var request = new VisionAnalysisRequest();
209 |
210 | var result = await client.AnalyzeAsync(request);
211 |
212 | }
213 |
214 | public static async Task VisionAnalysisKeyvault(
215 | [VisionAnalysis()]
216 | VisionAnalysisClient client)
217 | {
218 |
219 | var request = new VisionAnalysisRequest();
220 |
221 | var result = await client.AnalyzeAsync(request);
222 |
223 | }
224 | }
225 |
226 | }
227 |
228 |
229 |
230 | }
231 |
--------------------------------------------------------------------------------
/tests/AzureFunctions.Extensions.CognitiveServices.Tests/VisionDescribeTests.cs:
--------------------------------------------------------------------------------
1 | using AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Analysis;
2 | using AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Describe;
3 | using AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Thumbnail;
4 | using AzureFunctions.Extensions.CognitiveServices.Config;
5 | using AzureFunctions.Extensions.CognitiveServices.Services;
6 | using AzureFunctions.Extensions.CognitiveServices.Tests.Common;
7 | using AzureFunctions.Extensions.CognitiveServices.Tests.Resources;
8 | using FluentAssertions;
9 | using Microsoft.Azure.WebJobs;
10 | using Microsoft.Extensions.Configuration;
11 | using Microsoft.Extensions.DependencyInjection;
12 | using Microsoft.Extensions.Hosting;
13 | using Microsoft.Extensions.Logging;
14 | using Newtonsoft.Json;
15 | using System;
16 | using System.Collections.Generic;
17 | using System.Text;
18 | using System.Threading.Tasks;
19 | using Xunit;
20 |
21 | namespace AzureFunctions.Extensions.CognitiveServices.Tests
22 | {
23 | public class VisionDescribeTests
24 | {
25 | private static VisionDescribeModel visionDescribeUrlResult;
26 | private static VisionDescribeModel visionDescribeImageBytesResult;
27 | private static VisionDescribeModel visionDescribeImageBytesResizeResult;
28 |
29 | private static readonly TestLoggerProvider _loggerProvider = new TestLoggerProvider();
30 |
31 |
32 | private static async Task RunTestAsync(string testName, object argument = null)
33 | {
34 | Type testType = typeof(VisionFunctions);
35 | var locator = new ExplicitTypeLocator(testType);
36 | ILoggerFactory loggerFactory = new LoggerFactory();
37 | loggerFactory.AddProvider(_loggerProvider);
38 | ICognitiveServicesClient testCognitiveServicesClient = new TestCognitiveServicesClient();
39 |
40 | var arguments = new Dictionary();
41 | var resolver = new TestNameResolver();
42 |
43 | IHost host = new HostBuilder()
44 | .ConfigureWebJobs(builder =>
45 | {
46 | builder.AddVisionDescribe();
47 | })
48 | .ConfigureServices(services =>
49 | {
50 | services.AddSingleton(testCognitiveServicesClient);
51 | services.AddSingleton(resolver);
52 | services.AddSingleton(locator);
53 | })
54 | .ConfigureLogging(logging =>
55 | {
56 | logging.ClearProviders();
57 | logging.AddProvider(_loggerProvider);
58 | })
59 | .ConfigureAppConfiguration(c =>
60 | {
61 | c.Sources.Clear();
62 |
63 | var collection = new Dictionary
64 | {
65 | { "VisionKey", "1234XYZ" },
66 | { "VisionUrl", "http://url" }
67 | };
68 |
69 | c.AddInMemoryCollection(collection);
70 | })
71 | .Build();
72 |
73 | var method = testType.GetMethod(testName);
74 |
75 | await host.GetJobHost().CallAsync(method, arguments);
76 | }
77 |
78 |
79 | [Fact]
80 | public static async Task TestVisionAnalysisWithUrl()
81 | {
82 |
83 | var mockResult = JsonConvert.DeserializeObject(MockResults.VisionDescribeResults);
84 |
85 | await RunTestAsync("VisionDescribeWithUrl", null);
86 |
87 | var expectedResult = JsonConvert.SerializeObject(mockResult);
88 | var actualResult = JsonConvert.SerializeObject(visionDescribeUrlResult);
89 |
90 | Assert.Equal(expectedResult, actualResult);
91 | }
92 |
93 | [Fact]
94 | public static async Task TestVisionDescribeWithImageBytes()
95 | {
96 |
97 | var mockResult = JsonConvert.DeserializeObject(MockResults.VisionDescribeResults);
98 |
99 | await RunTestAsync("VisionDescribeWithImageBytes", null);
100 |
101 | var expectedResult = JsonConvert.SerializeObject(mockResult);
102 | var actualResult = JsonConvert.SerializeObject(visionDescribeImageBytesResult);
103 |
104 | Assert.Equal(expectedResult, actualResult);
105 | }
106 |
107 | [Fact]
108 | public static async Task TestVisionDescribeWithImageWithResize()
109 | {
110 | var mockResult = JsonConvert.DeserializeObject(MockResults.VisionDescribeResults);
111 |
112 | await RunTestAsync("VisionDescribeWithTooBigImageBytesWithResize", null);
113 |
114 | var expectedResult = JsonConvert.SerializeObject(mockResult);
115 | var actualResult = JsonConvert.SerializeObject(visionDescribeImageBytesResizeResult);
116 |
117 | Assert.Equal(expectedResult, actualResult);
118 | }
119 |
120 | [Fact]
121 | public static async Task TestVisionDescribeImageBytesTooLarge()
122 | {
123 |
124 | string exceptionMessage = "or smaller for the cognitive service vision API";
125 |
126 | var exception = await Record.ExceptionAsync(() => RunTestAsync("VisionDescribeWithTooBigImageBytes", null));
127 |
128 | exception.Should().NotBeNull();
129 | exception.InnerException.Should().NotBeNull();
130 | exception.InnerException.Should().BeOfType();
131 | exception.InnerException.Message.Should().Contain(exceptionMessage);
132 |
133 | }
134 |
135 |
136 | [Fact]
137 | public static async Task TestVisionDescribeMissingFile()
138 | {
139 |
140 | var exception = await Record.ExceptionAsync(() => RunTestAsync("VisionDescribeMissingFile", null));
141 |
142 | exception.Should().NotBeNull();
143 | exception.InnerException.Should().NotBeNull();
144 | exception.InnerException.Should().BeOfType();
145 | exception.InnerException.Message.Should().Contain(VisionExceptionMessages.FileMissing);
146 |
147 | }
148 |
149 | private class VisionFunctions
150 | {
151 |
152 | public async Task VisionDescribeWithUrl(
153 | [VisionDescribe()]
154 | VisionDescribeClient client)
155 | {
156 | var request = new VisionDescribeRequest();
157 | request.ImageUrl = "http://www.blah";
158 |
159 | var result = await client.DescribeAsync(request);
160 |
161 | visionDescribeUrlResult = result;
162 | }
163 |
164 | public async Task VisionDescribeWithImageBytes(
165 | [VisionDescribe()]
166 | VisionDescribeClient client)
167 | {
168 | var request = new VisionDescribeRequest();
169 | request.ImageBytes = Resources.MockResults.SamplePhoto;
170 |
171 | var result = await client.DescribeAsync(request);
172 |
173 | visionDescribeImageBytesResult = result;
174 | }
175 |
176 | public async Task VisionDescribeWithTooBigImageBytes(
177 | [VisionDescribe(AutoResize=false)]
178 | VisionDescribeClient client)
179 | {
180 |
181 | var request = new VisionDescribeRequest();
182 | request.AutoResize = false;
183 | request.ImageBytes = MockResults.SamplePhotoTooBig;
184 |
185 | var result = await client.DescribeAsync(request);
186 |
187 | }
188 |
189 | public async Task VisionDescribeWithTooBigImageBytesWithResize(
190 | [VisionDescribe()]
191 | VisionDescribeClient client)
192 | {
193 |
194 | var request = new VisionDescribeRequest();
195 | request.ImageBytes = MockResults.SamplePhotoTooBig;
196 |
197 | var result = await client.DescribeAsync(request);
198 |
199 | visionDescribeImageBytesResizeResult = result;
200 |
201 | }
202 |
203 | public async Task VisionDescribeMissingFile(
204 | [VisionDescribe()]
205 | VisionDescribeClient client)
206 | {
207 |
208 | var request = new VisionDescribeRequest();
209 |
210 | var result = await client.DescribeAsync(request);
211 |
212 | }
213 |
214 | public async Task VisionDescribeKeyvault(
215 | [VisionDescribe()]
216 | VisionDescribeClient client)
217 | {
218 |
219 | var request = new VisionDescribeRequest();
220 |
221 | var result = await client.DescribeAsync(request);
222 |
223 | }
224 | }
225 | }
226 | }
227 |
--------------------------------------------------------------------------------
/tests/AzureFunctions.Extensions.CognitiveServices.Tests/VisionDomainTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace AzureFunctions.Extensions.CognitiveServices.Tests
6 | {
7 | class VisionDomainTests
8 | {
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/tests/AzureFunctions.Extensions.CognitiveServices.Tests/VisionHandwritingTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace AzureFunctions.Extensions.CognitiveServices.Tests
6 | {
7 | class VisionHandwritingTests
8 | {
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/tests/AzureFunctions.Extensions.CognitiveServices.Tests/VisionOcrTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace AzureFunctions.Extensions.CognitiveServices.Tests
6 | {
7 | class VisionOcrTests
8 | {
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/tests/AzureFunctions.Extensions.CognitiveServices.Tests/VisionThumbnailTests.cs:
--------------------------------------------------------------------------------
1 | using AzureFunctions.Extensions.CognitiveServices.Bindings.Vision.Thumbnail;
2 | using AzureFunctions.Extensions.CognitiveServices.Config;
3 | using AzureFunctions.Extensions.CognitiveServices.Services;
4 | using AzureFunctions.Extensions.CognitiveServices.Tests.Common;
5 | using AzureFunctions.Extensions.CognitiveServices.Tests.Resources;
6 | using FluentAssertions;
7 | using Microsoft.Azure.WebJobs;
8 | using Microsoft.Extensions.Configuration;
9 | using Microsoft.Extensions.DependencyInjection;
10 | using Microsoft.Extensions.Hosting;
11 | using Microsoft.Extensions.Logging;
12 | using Newtonsoft.Json;
13 | using System;
14 | using System.Collections.Generic;
15 | using System.Text;
16 | using System.Threading.Tasks;
17 | using Xunit;
18 |
19 | namespace AzureFunctions.Extensions.CognitiveServices.Tests
20 | {
21 | public class VisionThumbnailTests
22 | {
23 | private static byte[] visionThumbnailResult;
24 |
25 | private static readonly TestLoggerProvider _loggerProvider = new TestLoggerProvider();
26 |
27 |
28 | private static async Task RunTestAsync(string testName, object argument = null)
29 | {
30 | Type testType = typeof(VisionFunctions);
31 | var locator = new ExplicitTypeLocator(testType);
32 | ILoggerFactory loggerFactory = new LoggerFactory();
33 | loggerFactory.AddProvider(_loggerProvider);
34 | ICognitiveServicesClient testCognitiveServicesClient = new TestCognitiveServicesClient();
35 |
36 | var arguments = new Dictionary();
37 | var resolver = new TestNameResolver();
38 |
39 | IHost host = new HostBuilder()
40 | .ConfigureWebJobs(builder =>
41 | {
42 | builder.AddVisionThumbnail();
43 | })
44 | .ConfigureServices(services =>
45 | {
46 | services.AddSingleton(testCognitiveServicesClient);
47 | services.AddSingleton(resolver);
48 | services.AddSingleton(locator);
49 | })
50 | .ConfigureLogging(logging =>
51 | {
52 | logging.ClearProviders();
53 | logging.AddProvider(_loggerProvider);
54 | })
55 | .ConfigureAppConfiguration(c =>
56 | {
57 | c.Sources.Clear();
58 |
59 | var collection = new Dictionary
60 | {
61 | { "VisionKey", "1234XYZ" },
62 | { "VisionUrl", "http://url" }
63 | };
64 |
65 | c.AddInMemoryCollection(collection);
66 | })
67 | .Build();
68 |
69 | var method = testType.GetMethod(testName);
70 |
71 | await host.GetJobHost().CallAsync(method, arguments);
72 | }
73 |
74 |
75 | [Fact]
76 | public static async Task TestVisionThumbnailWithUrl()
77 | {
78 | await RunTestAsync("VisionThumbnailWithUrl", null);
79 |
80 | Assert.Equal(MockResults.SamplePhoto.Length, visionThumbnailResult.Length);
81 | }
82 |
83 | [Fact]
84 | public static async Task TestVisionThumbnailWithImageBytes()
85 | {
86 | await RunTestAsync("VisionThumbnailWithImageBytes", null);
87 |
88 | Assert.Equal(MockResults.SamplePhoto.Length, visionThumbnailResult.Length);
89 | }
90 |
91 | [Fact]
92 | public static async Task TestVisionThumbnailWithImageWithResize()
93 | {
94 | await RunTestAsync("VisionThumbnailWithTooBigImageBytesWithResize", null);
95 |
96 | Assert.Equal(MockResults.SamplePhoto.Length, visionThumbnailResult.Length);
97 |
98 | }
99 |
100 | [Fact]
101 | public static async Task TestVisionThumbnailImageBytesTooLarge()
102 | {
103 |
104 | string exceptionMessage = "or smaller for the cognitive service vision API";
105 |
106 | var exception = await Record.ExceptionAsync(() => RunTestAsync("VisionThumbnailWithTooBigImageBytes", null));
107 |
108 | exception.Should().NotBeNull();
109 | exception.InnerException.Should().NotBeNull();
110 | exception.InnerException.Should().BeOfType();
111 | exception.InnerException.Message.Should().Contain(exceptionMessage);
112 |
113 | }
114 |
115 | [Fact]
116 | public static async Task TestVisionThumbnailMissingFile()
117 | {
118 |
119 | var exception = await Record.ExceptionAsync(() => RunTestAsync("VisionThumbnailMissingFile", null));
120 |
121 | exception.Should().NotBeNull();
122 | exception.InnerException.Should().NotBeNull();
123 | exception.InnerException.Should().BeOfType();
124 | exception.InnerException.Message.Should().Contain(VisionExceptionMessages.FileMissing);
125 |
126 | }
127 |
128 | private class VisionFunctions
129 | {
130 |
131 | public async Task VisionThumbnailWithUrl(
132 | [VisionThumbnail( Width ="100", Height="100")]
133 | VisionThumbnailClient client)
134 | {
135 | var request = new VisionThumbnailRequest();
136 | request.ImageUrl = "http://www.blah";
137 |
138 | var result = await client.ThumbnailAsync(request);
139 |
140 | visionThumbnailResult = result;
141 | }
142 |
143 | public async Task VisionThumbnailWithImageBytes(
144 | [VisionThumbnail(Width ="100", Height="100")]
145 | VisionThumbnailClient client)
146 | {
147 | var request = new VisionThumbnailRequest();
148 | request.ImageBytes = MockResults.SamplePhoto;
149 |
150 | var result = await client.ThumbnailAsync(request);
151 |
152 | visionThumbnailResult = result;
153 | }
154 |
155 | public async Task VisionThumbnailWithTooBigImageBytes(
156 | [VisionThumbnail(AutoResize = false, Width ="100", Height="100")]
157 | VisionThumbnailClient client)
158 | {
159 |
160 | var request = new VisionThumbnailRequest();
161 | request.ImageBytes = MockResults.SamplePhotoTooBig;
162 |
163 | var result = await client.ThumbnailAsync(request);
164 |
165 | }
166 |
167 | public async Task VisionThumbnailWithTooBigImageBytesWithResize(
168 | [VisionThumbnail(AutoResize = true, Width ="100", Height="100")]
169 | VisionThumbnailClient client)
170 | {
171 |
172 | var request = new VisionThumbnailRequest();
173 | request.ImageBytes = MockResults.SamplePhotoTooBig;
174 |
175 | var result = await client.ThumbnailAsync(request);
176 |
177 | visionThumbnailResult = result;
178 |
179 | }
180 |
181 | public async Task VisionThumbnailMissingFile(
182 | [VisionThumbnail(Width ="100", Height="100")]
183 | VisionThumbnailClient client)
184 | {
185 |
186 | var request = new VisionThumbnailRequest();
187 |
188 | var result = await client.ThumbnailAsync(request);
189 |
190 | }
191 |
192 | public async Task VisionThumbnailKeyvault(
193 | [VisionThumbnail(Width ="100", Height="100")]
194 | VisionThumbnailClient client)
195 | {
196 |
197 | var request = new VisionThumbnailRequest();
198 |
199 | var result = await client.ThumbnailAsync(request);
200 |
201 | }
202 | }
203 | }
204 | }
205 |
--------------------------------------------------------------------------------
/tests/AzureFunctions.Extensions.CognitiveServices.Tests/local.settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "IsEncrypted": false,
3 | "Values": {
4 | "AzureWebJobsStorage": "UseDevelopmentStorage=true",
5 | "AzureWebJobsDashboard": "UseDevelopmentStorage=true",
6 | "FUNCTIONS_WORKER_RUNTIME": "dotnet",
7 | "VisionKey": "XXXXXXXXXXXXXXXXXXXXXX",
8 | "VisionUrl": "XXXXXXXXXXXXXXXXXXXXXX"
9 | }
10 | }
--------------------------------------------------------------------------------