DEV Community

Ahmed Fouad
Ahmed Fouad

Posted on • Originally published at Medium on

How you can use Artifical Intelligence in your xamarin apps (a real-world example)

For most of the mobile/web developers, AI is not an option while some have studied it in the university or have tried to read about it. They keep staking with the problem of applicability “How and what to apply”

In this article, we will use make a News App and we will make use of the K-means algorithm to group our news. If you like the article and wanna more of AI topics for xamarin or mobile development please clap it, share it everywhere so I can see that more people want this topic.

Our app in a news app that shows some articles from newsapi.org and we need to group these articles by date in a way that makes sense to the user.

A way that makes sense means that depending on the data itself we will generate the groups and the groups.

We will use the K-means algorithm to do this, let me explain first how it works but anyways it is already implemented in Accord.net framework so we will not implement it but ourselves.

1- Pick random centroids which will be the centers of your groups

2- measure the distance of each element and the centroid.

3- recalculate the centroids so the distance is minimized

4- keep doing this for a number of iteration or until the distance within each group reaches a threshold that you already defined.

the nuggets packages that we will need to implement our app are

https://www.nuget.org/packages/Accord.MachineLearning

for AI

public async void Init()

{

var news=await GetNews().ToArrayAsync();

var points = news.Select(x => new double[] {x.PublishedAt.ToUnixTimeSeconds()}).ToArray();

var kmeans = new KMeans(5);

var clusters = kmeans.Learn(points);

var labels = clusters.Decide(points);

Articles = news.Select((value, index) => (value, clusters[labels[index]]))

.OrderByDescending(x => x.Item2.Centroid[0])

.Select(x => new ArticleViewModel()

{

Title = x.value.Title,

Description = x.value.Description,

Image = x.value.UrlToImage?.ToString(),

Group = DateTimeOffset.FromUnixTimeSeconds((long) x.Item2.Centroid[0]).Humanize()

}).ToList();

}

so at first, I get all the news articles in an array and I mapped every news item to an array of a single double which represents the publishing date.

var kmeans = new KMeans(5);

create a kmeans object that will cluster our points in 5 clusters (you can change 5 to anything you want).

var clusters = kmeans.Learn(points);

will generate the 5 centroids for our date.

var labels = clusters.Decide(points);

will group the data in the previously generated clusters.

Articles = news.Select((value, index) => (value, clusters[labels[index]]))

will return a list of value tuples that contain (Article, Centroid in Unix millisecond)

.Select(x => new ArticleViewModel()

{

Title = x.value.Title,

Description = x.value.Description,

Image = x.value.UrlToImage?.ToString(),

Group = DateTimeOffset.FromUnixTimeSeconds((long) x.Item2.Centroid[0]).Humanize()

}).ToList();

we create a view model for each article that contains the Title, Description, Image and the humanized form of it is centroid using Humanizer.

The full view model

using System;

using System.Collections.Concurrent;

using System.Collections.Generic;

using System.ComponentModel;

using System.Diagnostics;

using System.Linq;

using System.Net.Http;

using System.Runtime.CompilerServices;

using System.Text;

using System.Threading.Tasks;

using Accord.MachineLearning;

using App9.Annotations;

using Dasync.Collections;

using Humanizer;

using Newtonsoft.Json;

using QuickType;

using Xamarin.Forms;

namespace App9

{

public class ArticleViewModel

{

public string Group { get; set; }

public string Title { get; set; }

public string Image { get; set; }

public ImageSource ImageSource => Image != null ? ImageSource.FromUri(new Uri(Image,UriKind.RelativeOrAbsolute)) : null;

public string Description { get; set; }

}

class MainPageViewModel:INotifyPropertyChanged

{

private List<ArticleViewModel> \_articles;

public List<ArticleViewModel> Articles

{

get => \_articles;

set

{

\_articles = value;

OnPropertyChanged();

}

}

public async void Init()

{

var news=await GetNews().ToArrayAsync();

var points = news.Select(x => new double[] {x.PublishedAt.ToUnixTimeSeconds()}).ToArray();

var kmeans = new KMeans(5);

var clusters = kmeans.Learn(points);

var labels = clusters.Decide(points);

Articles = news.Select((value, index) => (value, clusters[labels[index]]))

.OrderByDescending(x => x.Item2.Centroid[0])

.Select(x => new ArticleViewModel()

{

Title = x.value.Title,

Description = x.value.Description,

Image = x.value.UrlToImage?.ToString(),

Group = DateTimeOffset.FromUnixTimeSeconds((long) x.Item2.Centroid[0]).Humanize()

}).ToList();

}

private async IAsyncEnumerable<Article> GetNews()

{

using (var httpClient = new HttpClient())

{

var rawResponse = await httpClient.GetStringAsync(

"https://newsapi.org/v2/top-headlines?sortBy=popularity&pageSize=100&country=us&apiKey=dd652e7605d54451a4179d0b28d3f928");

var response = JsonConvert.DeserializeObject<Response>(rawResponse);

foreach(var article in response.Articles)

{

yield return article;

}

}

}

public event PropertyChangedEventHandler PropertyChanged;

[NotifyPropertyChangedInvocator]

protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)

{

PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

}

}

}

The view

<?xml version="1.0" encoding="utf-8" ?>

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"

xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"

xmlns:d="http://xamarin.com/schemas/2014/forms/design"

xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

mc:Ignorable="d"

xmlns:syncfusion="clr-namespace:Syncfusion.ListView.XForms;assembly=Syncfusion.SfListView.XForms"

xmlns:data="clr-namespace:Syncfusion.DataSource;assembly=Syncfusion.DataSource.Portable"

x:Class="App9.MainPage">

<StackLayout>

<syncfusion:SfListView ItemSize="100" ItemSpacing="20" ItemsSource="{Binding Articles}" >

<syncfusion:SfListView.DataSource>

<data:DataSource>

<data:DataSource.GroupDescriptors>

<data:GroupDescriptor PropertyName="Group"/>

</data:DataSource.GroupDescriptors>

</data:DataSource>

</syncfusion:SfListView.DataSource>

<syncfusion:SfListView.ItemTemplate>

<DataTemplate>

<Grid ColumnSpacing="5">

<Grid.ColumnDefinitions>

<ColumnDefinition Width="3\*"></ColumnDefinition>

<ColumnDefinition Width="7\*"></ColumnDefinition>

</Grid.ColumnDefinitions>

<Image Source="{Binding ImageSource}" VerticalOptions="Start" Grid.Column="0"/>

<StackLayout Grid.Column="1" Spacing="10">

<Label Text="{Binding Title}" FontSize="Title" MaxLines="1" />

<Label Text="{Binding Description}" FontSize="Body" MaxLines="3" />

</StackLayout>

</Grid>

</DataTemplate>

</syncfusion:SfListView.ItemTemplate>

</syncfusion:SfListView>

</StackLayout>

</ContentPage>

Top comments (0)