Selamlar,
Önceki yazımda RESTful api tasarlama ilkelerinden bahsetmiştim. Bu yazımda ise bu ilkeleri kullanarak bir api geliştireceğiz. Microsoft’un fotoğraf analizleri için geliştirdiği ve azure platformu üzerinde bizlere sunduğu Computer Vision API’sini kullanacağız. Projemizde kullanacağımız ekipmanlar ise şöyle;
- .NET Core 1.1 Web API
- Swagger
- Azure Blob
- Azure Computer Vision API
Projemiz API üzerinden bize post edilen imajı Azure Blob’a atacak. Bu esnada bu imaj Vision API aracılığıyla işlenecek ve taglenecek. Sonrasında biz bu imajları kategorilerine göre sınıflandırabileceğiz ya da tagler üzerinden arama yapabileceğiz.
Hadi başlayalım.
Öncelikler .NET Core Web API projesi oluşturalım. Daha sonra projemize RESTful apiler için dokümantasyon aracı olan Swagger’i kuralım.
Packege Manage Console’a aşağıdaki komutu verelim
Install-Package Swashbuckle.AspNetCore
Sonrasında Startup.cs içerisindeki gerekli yerlere eklemeleri yapalım.
public void ConfigureServices(IServiceCollection services) { // Add framework services. services.AddMvc(); services.AddLogging(); // Add our repository type services.AddSingleton<ITodoRepository, TodoRepository>(); // Register the Swagger generator, defining one or more Swagger documents services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new Info { Title = "My API", Version = "v1" }); }); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { app.UseMvcWithDefaultRoute(); // Enable middleware to serve generated Swagger as a JSON endpoint. app.UseSwagger(); // Enable middleware to serve swagger-ui (HTML, JS, CSS etc.), specifying the Swagger JSON endpoint. app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1"); }); }
Swagger aracını yüklemiş olduk. http://localhost:portNo/swagger/ adresine gittiğimizde aşağıdaki gibi bir ekranla karşılaşmamız lazım.
Şimdi ImageController isminde bir conroller oluşuralım. Sadece get ve post metotları olsun.
[Produces("application/json")] [Route("api/Image")] [Consumes("multipart/form-data")] public class ImageController : Controller { // POST: api/Image [HttpPost] [Route("upload")] public async Task<string> PostAsync(IFormFile file) { } [HttpGet] public async Task<List<Images>> Get(string req) { } }
Swagger eklentimizde. Fotoğraflarımızı upload etmek için ufak birkaç değişiklik yapmamız gerekiyor ki aşağıdaki gibi dosyayı seçebilelim.
FileOperation isimli bir class oluşturalım. Startup.cs içinde aşağıdaki değişikleri yapalım.
public class FileOperation : IOperationFilter { public void Apply(Operation operation, OperationFilterContext context) { if (operation.OperationId.ToLower() == "apiımageuploadpost") { operation.Parameters.Clear();//Clearing parameters operation.Parameters.Add(new NonBodyParameter { Name = "File", In = "formData", Description = "Uplaod Image", Required = true, Type = "file" }); operation.Consumes.Add("application/form-data"); } } }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { // Add framework services. services.AddMvc(); services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new Info { Title = "My API", Version = "v1" }); c.OperationFilter<FileOperation>(); }); services.ConfigureSwaggerGen(options => { options.DescribeAllEnumsAsStrings(); options.OperationFilter<FileOperation>(); //Register File Upload Operation Filter }); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); } app.UseStaticFiles(); app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); // Enable middleware to serve generated Swagger as a JSON endpoint. app.UseSwagger(); // Enable middleware to serve swagger-ui (HTML, JS, CSS etc.), specifying the Swagger JSON endpoint. app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1"); }); }
Swagger aracındaki gerekli ayarlamaları yaptıktan sonra azure üzerinde blob yaratalım.
New>Storage>Storage Account
Sonrasında ise Blob Service içinde profileimages isminde bir container yaratalım. Aynı şekilde bir tane de computer vision api oluşturalım.
New>AI+Cognitive Services>Computer Vision API
Şimdi kodlarımızı yazmaya başlayabiliriz.
Blob container içine resmi upload edecek ve resmi çağırınca getirecek bir class yazalım.
NOT: Azure üzerinde blob oluşturduğumuzda blob ismini, konteyner ismini ve keyimizi bir yere not edelim ve aşağıdaki classta gerekli yerlere yazalım.
public class BlobManager { #region PrivateMember private string _accountName = ""; private string _containerName = ""; private string _accountKey = ""; private CloudStorageAccount _storageAccount; private CloudBlobClient _blobClient; private CloudBlobContainer _container; private CloudBlockBlob _blockBlob; private Stream _stream; private List<Images> _blobs; private BlobContinuationToken _token = null; private ComputerVisionManager _manager; #endregion #region PublicMember //public string BlobName { get => _blobName; set => _blobName = value; } //public string ContainerName { get => _containerName; set => _containerName = value; } //public string AccountKey { get => _accountKey; set => _accountKey = value; } #endregion #region Constructor public BlobManager() { _storageAccount = new CloudStorageAccount( new Microsoft.WindowsAzure.Storage.Auth.StorageCredentials( _accountName, _accountKey), true); _blobClient = _storageAccount.CreateCloudBlobClient(); _container = _blobClient.GetContainerReference(_containerName); _manager = new ComputerVisionManager(); } #endregion public async Task<string> UploadImageAsBlob(IFormFile file) { if (file != null && file.ContentType.StartsWith("image")) { _stream = file.OpenReadStream(); _blockBlob = _container.GetBlockBlobReference(FileNameHelper.CreateFileName()); await _blockBlob.UploadFromStreamAsync(_stream); var result = _manager.ImageTag(_blockBlob); if (await result) return _blockBlob.Uri.ToString(); } return null; } public async Task<List<Images>> GetImagesAsync(string term) { _blobs = new List<Images>(); _container = _blobClient.GetContainerReference("profileimages"); do { BlobResultSegment resultSegment = await _container.ListBlobsSegmentedAsync(_token); _token = resultSegment.ContinuationToken; foreach (IListBlobItem item in resultSegment.Results) { var blob = item as CloudBlockBlob; if (blob != null) { await blob.FetchAttributesAsync(); // Get blob metadata foreach (var items in blob.Metadata) { if (items.Key.StartsWith("Tag") && items.Value.Equals(term, StringComparison.CurrentCultureIgnoreCase)) { var caption = blob.Metadata.ContainsKey("Caption") ? blob.Metadata["Caption"] : blob.Name; var categories = blob.Metadata.ContainsKey("Categories") ? blob.Metadata["Categories"] : blob.Name; _blobs.Add(new Images() { ImageUri = blob.Uri.ToString(), Categories = categories, Caption = caption }); } } } } } while (_token != null); return _blobs; } }
Yukarıdaki classta yükleyeceğimiz resmin ismini benzersiz yapmalıyız. Aksi taktirde aynı isimle resim yüklenirse çakışma olabilir bunu için FileNameHelper isimli bir class yazdım. Basitçe bir guid oluşturuyor.
public class FileNameHelper { public static string CreateFileName() { return Guid.NewGuid().ToString().Replace("-", "") + ".jpg"; } }
Şimdi ise vision api ile yüklenen resmin taglemek için gerekli işlemleri yapan classımızı yazalım.
public class ComputerVisionManager { private VisionServiceClient _vision; private VisualFeature[] _features; private readonly string key = ""; public ComputerVisionManager() { _vision=new VisionServiceClient(key); _features= new VisualFeature[] { VisualFeature.Description, VisualFeature.Categories }; } public async Task<bool> ImageTag(CloudBlockBlob blockBlob) { var result = await _vision.AnalyzeImageAsync(blockBlob.Uri.ToString(), _features); blockBlob.Metadata.Add("Caption", result.Description.Captions[0].Text); blockBlob.Metadata.Add("Categories", result.Categories.FirstOrDefault().Name.ToString()); for (int i = 0; i < result.Description.Tags.Length; i++) { string key = String.Format("Tag{0}", i); blockBlob.Metadata.Add(key, result.Description.Tags[i]); } await blockBlob.SetMetadataAsync(); return true; } }
Son olarak endpointlerimizde yukarıda yazdığımız classları çağıralım.
[Produces("application/json")] [Route("api/Image")] [Consumes("multipart/form-data")] public class ImageController : Controller { // POST: api/Image [HttpPost] [Route("upload")] public async Task<string> PostAsync(IFormFile file) { BlobManager manager =new BlobManager(); var imageUrl = manager.UploadImageAsBlob(file); return await imageUrl; } [HttpGet] public async Task<List<Images>> Get(string req) { BlobManager manager = new BlobManager(); List<Images> img = await manager.GetImagesAsync(req); return img; } }
Aşağıdaki resmi upload edelim ve taglarine bakalım.
Sonuçlarımıza bakalım.
Caption değerimiz : a young boy sitting at a table with a plate of food with broccoli
Categories: people_young ve fotoğrafra 20’ye yakın tag oluşturdu şimdi ise bu taglerden birisi ile arama yapalım. Bakalım API miz bize bu fotoğrafın bilgilerini geri dönecek mi?
Projeyi buradan indirebilirisiniz
Bir yanıt yazın