Introduction
Mobile applications have become an integral part of the way we work.
Today, we are going to create an Android mobile app for WordsAPI.
This will be a powerful app that will cover the chosen API and extend it with some additional NLP features.
As the main project instrument, we will use Python.
We also have the opportunity of working with a cross-platform UI framework for this language, called Kivy.
In the final result, our application will process word requests and propose semantic analysis for texts.
WordsAPI explanation
Let’s establish how interactions with WordsAPI work. This interface can be used in various ways for “digging” for words. Here are a few example scenarios:
- word definitions
- antonyms/synonyms
- pronunciations
- word-usage among regions
How to Get a WordsAPI API Key
1. Sign Up for a RapidAPI Key
RapidAPI is a powerful API hub, which consists of more than 10,000 accessible APIs. Not only are they available for your personal use but you also have the opportunity of adding new ones, making you a part of the team of 1,000,000+ responsive developer community.
2. Navigate to the WordsAPI Page
3. Subscribe to the API
4. Test the Endpoints
Voila! You now have access to the WordsAPI. You can find your API Key under “X-RapidAPI-Key.”
Our main task is the implementation of such API inside of mobile applications.
We will give a brief explanation of the endpoints structure.
There are two groups of endpoints: words and related words.
The former is about basic word properties. Here you can find the frequency of the word, or even try to get rhymes for it. You can try and test some endpoints for this group, which can be done with the RapidAPI console.
A latter group dedicated to the related words’ features. There is a lot of useful information about the word popularity region, similarity, etc. Take a look at the example:
The result of this request returns all semantic objects, which include the transmitted word. In the displayed case you will see that ‘finger’ is a part of ‘hand’, ‘glove’ and a few more.
How to build a Word Application for Android
Requirements
Python is a very popular and powerful language. However, there is a stereotype that it is good only for scripting tasks. So today we will try to debunk the false idea and create a fully working visual application.
First of all, let’s install all the important libraries. It is quite obvious that your machine should have Python. But we also need to create a virtual environment. It will separate project data from your PC storage. Then, we need to install three required system modules:
- kivy – a multi-platformed framework for creating the graphical user interface (GUI). It supports all the beauty and simplicity of Python. Users can create adaptive programs with ease for various operating systems. The main advantage – you don’t need to do anything after you’ve created the desktop version. If the program is ready on one platform, you can easily convert it to any other. For example, from Android to iOS.
- buildozer – a special utility that assists with building packages. Actually, basic Kivy doesn’t create a final application. This part of the job lays on the proverbial shoulders of buildozer. It’s important to keep in mind that sometimes, it can be difficult to install this module correctly. So it is highly recommended to work with virtual environments.
- textblob – a library, which has many pre-trained models for text analysis. It will be very useful for natural language processing (NLP). You’ll need NLP because the application doesn’t make any sense without advanced features. We aren’t interested in copying blind API requests. The app should be reasonably practical.
Python + Kivy NUI
Now let’s talk about the application.
In the world of poem-writing, even the most talented poets have problems with rhymes.
Our application will solve this problem.
It is easy to understand that all ‘dirty’ jobs will be done via WordsAPI, but we won’t just return all suggested rhymes for the word.
The app will be able to send the desired word and return some rhymes for it.
And the final feature is a poem process. As an example of NLP problems, we will take a look at the sentiment analysis.
Sentiment analysis is a way to understand how positive or negative your text is. This is a really important aspect of marketing.
Big companies can analyze all reviews by the ML model for improving it. Usually, it’s a time-wasting process, which includes many stages, but we will use the TextBlob pre-trained model.
TextBlob was trained on movie reviews and can be very helpful in our case.
But let’s start with the design creating. Kivy supports the natural user interface (NUI), which is a portable version for a graphical one.
If you completed all the steps in the installation process, you should be able to run the virtual environment and create your first Python file. Let’s call it main.py.
Here is where we will do all backend processes in the future, but right now, we can start from the standard ‘Hello world!’ application.
Paste the following lines:
import kivy kivy.require('1.0.6') # replace with your current kivy version ! from kivy.app import App from kivy.uix.label import Label class MyApp(App): def build(self): return Label(text='Hello world') if __name__ == '__main__': MyApp().run()
If you are familiar with Python, this code shouldn’t be difficult at all.
Here, we import the App object, which will be a base for a custom application class.
Also, we add a label with a world-famous greeting.
Run this file and you should see next output:
By default, we can add new graphical elements directly from the Python file, but it can be very risky for project structure. That’s why Kivy proposes a custom markup language Kv.
It allows you to distinguish your layouts and visualization for functionality. The principle of this language is very simple as it consists of a nested elements description.
As you can see, there are two buttons:
- ‘Sentiment analysis’
- and ‘Get rhymes’.
Further down you’ll find a text input field for poem lyrics.
If you click on the left button, our app will return results for polarity (indicate how positive the text is from -1 to +1) and subjectivity (how much the text represents personal opinion or judgment opposed to factual information).
And when the user highlights an exact word and clicks on the button to the right, it will redirect him/her to the second screen with rhymes.
Each rhyme will be represented in the scrolling text area with some primary explanation.
Here, users can choose one of them and the list of rhymes will drop down from the right side.
If rhymes aren’t good enough, the user can just return back.
Chosen rhymes (if any) will be added to the current text on the main screen.
So once we’ve built a rough markup, we can implement the real one. Create a file main.kv and paste the next snippet:
#:kivy 1.11.1 <MainScreen>: BoxLayout: orientation: 'vertical' padding: 25 spacing: 10 BoxLayout: size_hint: 1, 0.15 orientation: 'horizontal' spacing: 10 Button: text: 'Sentiment analysis' Button: text: 'Get rhymes' ScrollView: id: scrlv size_hint: 1, 0.65 TextInput: id: poem_text text: 'Cellar door' size_hint: 1, None height: max(self.minimum_height, scrlv.height)
This all about the previously demonstrated markup.
Here we will create two segments for the screen.
- The first is for buttons using the BoxLayout container.
- Second is a scrolling text input with a custom option (id: scrlv), which helps to control TextInput size.
Now we need to connect this markup with our Python file.
Open main.py and modify it:
from kivy.app import App from kivy.uix.screenmanager import ScreenManager, Screen, SwapTransition # Create both screens. Please note the root.manager.current: this is how # you can control the ScreenManager from kv. Each screen has by default a # property manager that gives you the instance of the ScreenManager used. class MainScreen(Screen): pass sm = ScreenManager(transition=SwapTransition()) class MainApp(App): def build(self): sm.add_widget(MainScreen(name='main')) sm.current = 'main' return sm if __name__ == '__main__': MainApp().run()
The most important change – adding ScreenManager.
This object has to control all existing frames. As we will have 2 screens, it will help with navigation and data sending. Also, we will create an empty (for now) MainScreen class, where we will work with events a little later on.
Keep in mind that our app class still has the MainApp title. It is important because Kivy will look for the name-without-App.kv as a markup description. Now run the program..
#:kivy 1.11.1 <MainScreen>: BoxLayout: orientation: 'vertical' padding: 25 spacing: 10 BoxLayout: size_hint: 1, 0.15 orientation: 'horizontal' spacing: 10 Button: text: 'Sentiment analysis' Button: text: 'Get rhymes' on_press: root.manager.current = 'rhymes' ScrollView: id: scrlv size_hint: 1, 0.65 TextInput: id: poem_text text: 'Ginger Pinger' size_hint: 1, None height: max(self.minimum_height, scrlv.height) <RhymesScreen>: BoxLayout: orientation: 'vertical' padding: 25 spacing: 10 ScrollView: id: scrlv size_hint: 1, 0.65 TextInput: id: rhymes_text text: '' size_hint: 1, None height: max(self.minimum_height, scrlv.height) BoxLayout: size_hint: 1, 0.15 orientation: 'horizontal' spacing: 10 Button: text: 'Back' on_release: root.manager.current = 'main' Button: text: 'Choose one'
Here we have two important modifications:
- We created the markup for a Rhymes Screen – very similar to the Main, but with replaced buttons and text input.
- And the second improvement touches the navigation. We pointed out actions for transferring buttons. It was done by an on_release option for them.
Now we can include our second screen using the main.py file.
from kivy.app import App from kivy.uix.screenmanager import ScreenManager, Screen, SwapTransition # Create both screens. Please note the root.manager.current: this is how # you can control the ScreenManager from kv. Each screen has by default a # property manager that gives you the instance of the ScreenManager used. class MainScreen(Screen): pass class RhymesScreen(Screen): pass sm = ScreenManager(transition=SwapTransition()) class MainApp(App): def build(self): sm.add_widget(MainScreen(name='main')) sm.add_widget(RhymesScreen(name='rhymes')) sm.current = 'main' return sm if __name__ == '__main__': MainApp().run()
This looks very similar, but there is one more screen.
Now execute the Python file and try to click on the Get Rhymes button.
The next phase is about creating events. There we will set up all functionality and complete the desktop version of the app.
Creating Events
Now we need to fill our application with actions. This is done with the events and properties of Kivy. The workflow is next:
- A developer pins the property value for a single visual object;
- The entire screen gets the ID of that property. This is a unique way to work with the object within a custom screen class in Python.
- Each call-able object in the markup takes a pointer on action and method for it. For example, if the button was pressed, then do the method button_press().
- Events handler is a general Python function inside of the screen class, that works and changes needed data.
Now we need to make these words real. First of all, we need to set all properties and define event handlers.
To do this, open the main.kv file and paste next code:
#:kivy 1.11.1 <MainScreen>: input_widget: poem_text BoxLayout: orientation: 'vertical' padding: 25 spacing: 10 BoxLayout: size_hint: 1, 0.15 orientation: 'horizontal' spacing: 10 Button: text: 'Sentiment analysis' on_release: root.get_sentiments() Button: text: 'Get rhymes' on_press: root.manager.current = 'rhymes' ScrollView: id: scrlv size_hint: 1, 0.65 TextInput: id: poem_text text: 'Cellar door' size_hint: 1, None height: max(self.minimum_height, scrlv.height) <RhymesScreen>: on_pre_enter: root.feed_rhymes() input_widget: rhymes_text button_widget: rhymes_button BoxLayout: orientation: 'vertical' padding: 25 spacing: 10 ScrollView: id: scrlv size_hint: 1, 0.65 TextInput: id: rhymes_text text: '' size_hint: 1, None height: max(self.minimum_height, scrlv.height) BoxLayout: size_hint: 1, 0.15 orientation: 'horizontal' spacing: 10 Button: text: 'Back' on_release: root.manager.current = 'main' Button: id: rhymes_button text: 'Choose one'
We created all properties by linking to the basic text field and the rhymes button/text objects.
We also wrote event pointers for all missing buttons and screens.
So the button Sentiment analysis has an on_release action, which is done with the get_sentiments() method. The same structure is used for a second screen.
And the final step is to perform all these handlers. Open Python file and paste the next code version:
from kivy.app import App from kivy.lang import Builder from kivy.uix.screenmanager import ScreenManager, Screen, SwapTransition from kivy.uix.boxlayout import BoxLayout from kivy.uix.popup import Popup from kivy.uix.label import Label from kivy.uix.dropdown import DropDown from kivy.uix.button import Button from kivy.network.urlrequest import UrlRequest from textblob import TextBlob import nltk try: nltk.data.find('corpora/movie_reviews') except LookupError: nltk.download('movie_reviews') try: nltk.data.find('tokenizers/punkt') except LookupError: nltk.download('punkt') headers = { 'x-rapidapi-host': "wordsapiv1.p.rapidapi.com", 'x-rapidapi-key': "<YOUR_RAPID_API_KEY>" } # Create both screens. Please note the root.manager.current: this is how # you can control the ScreenManager from kv. Each screen has by default a # property manager that gives you the instance of the ScreenManager used. class MainScreen(Screen): def get_sentiments(self): sntms = TextBlob(self.input_widget.text).sentiment msg = ''' Polarity: {0}, Subjectivity: {1}. '''.format(sntms.polarity, sntms.subjectivity) popup = Popup(title='Sentiment results', content=Label(text=msg), size_hint=(0.6, 0.6)) popup.open() class RhymesScreen(Screen): def send_rhyme(self, instance, x): poem = sm.get_screen('main').input_widget poem.text = poem.text + " " + x sm.current = 'main' instance.dismiss() self.button_widget.unbind(on_release=instance.open) def get_rhymes_info(self, word): rhymes_endpoint = "https://wordsapiv1.p.rapidapi.com/words/{0}/rhymes".format(word) rhymes = UrlRequest(rhymes_endpoint, method='GET', req_headers=headers) rhymes.wait() rhymes_info = {} for rhyme in rhymes.result['rhymes']['all']: if ' ' not in rhyme: rhyme_info = {} freq_endpoint = "https://wordsapiv1.p.rapidapi.com/words/{0}/frequency".format(rhyme) frequency = UrlRequest(freq_endpoint, method='GET', req_headers=headers) frequency.wait() frequency = frequency.result rhyme_info['frequency'] = frequency['frequency']['zipf'] if 'frequency' in frequency else 0 defin_endpoint = "https://wordsapiv1.p.rapidapi.com/words/{0}/definitions".format(rhyme) definition = UrlRequest(defin_endpoint, method='GET', req_headers=headers) definition.wait() definition = definition.result if ('definitions' in definition): if (len(definition['definitions']) > 0): rhyme_info['definition'] = definition['definitions'][0]['definition'] if 'definition' in definition['definitions'][0] else 'No definition' rhyme_info['partOfSpeech'] = definition['definitions'][0]['partOfSpeech'] if 'partOfSpeech' in definition['definitions'][0] else 'No part of speech' else: rhyme_info['definition'] = 'No definition' rhyme_info['partOfSpeech'] = 'No part of speech' rhymes_info[rhyme] = rhyme_info return rhymes_info def feed_rhymes(self): self.input_widget.text = "" rhymes_info = self.get_rhymes_info(sm.get_screen('main').input_widget.selection_text) dropdown = DropDown() for k, v in rhymes_info.items(): text = '''{0} Frequency: {1} Definition: {2} Part of speech: {3} '''.format(k, v['frequency'], v['definition'], v['partOfSpeech']) self.input_widget.text = self.input_widget.text + "n" + text btn = Button(text=k, size_hint_y=None, height=44) btn.bind(on_release=lambda btn: dropdown.select(btn.text)) dropdown.add_widget(btn) self.button_widget.bind(on_release=dropdown.open) dropdown.bind(on_select=self.send_rhyme) sm = ScreenManager(transition=SwapTransition()) class MainApp(App): def build(self): sm.add_widget(MainScreen(name='main')) sm.add_widget(RhymesScreen(name='rhymes')) sm.current = 'main' return sm if __name__ == '__main__': MainApp().run()
Next stage is the main screen.
There is only one method: get_sentiments().
It takes all text in the input_widget (property of the text field in the display) and does a sentiment analysis.
The result will be shown in the Popup object.
That sums up all events programming.
First of all, we check the nltk module (it was installed with TextBlob) for pre-trained models. If they are absent, we can download them.
The rhymes screen has a more complicated structure. All work is done in the background of the first screen demonstration. We pinned it via the on_pre_enter event.
As it is a big process, we will talk about each method:
- get_rhymes_info – the most difficult method for computation. Here we make all API requests. Keep in mind that it is done by a URLRequest object. It is a part of Kivy original modules, and that’s why there won’t be any problems. Here we request all rhymes for words. Finally, we get the dictionary for each element. One particular key is a unique rhyme, while the value is a dict with all details.
- send_rhyme – when the rhyme is chosen, this method sends it to the main screen.
- feed_rhymes – entry point of all procedures. It is the main method that connects all previous ones. Here we use get_rhymes_info and receive all data. Next, we print it in the text area and create a Dropdown option for Choose One button. So when the user ticks descriptions and makes a choice, data will be sent to the send_rhyme.
Looks like all the jobs were done, so we can test our desktop application.
Android deploy
When the application is ready, we can simply build it for different platforms. As our goal is an Android, let’s do this.
Open the terminal in the project folder and run a virtual environment. We need to set a deploy package. And this is where buildozer comes in, which is exactly why installation (including all its dependencies) is essential.
Now execute this command:
$ buildozer init
If your modules are good, you should get a new file. It is called buildozer.spec. This is a specification file, which allows you to set the deploy package. In our case, it is almost ideal. One important change is adding requirements. Find # (list) Application requirements. Replace the underlying section with the next lines:
# comma separated e.g. requirements = sqlite3,kivy requirements = python3,textblob,openssl,nltk,kivy==master
Here we added all required libraries. Important note: OpenSSL and nltk are optional. Other data in this file is good for our app, so we can start building. Run this command in the terminal:
$ buildozer -v android debug
If it is the first debug, building time can take a while. If there are any problems, you can always try to solve it with guides.
However, you’ll probably be able to find a built APK (format of Android application) file within the bin folder.
If it is there, our mobile program is ready to run. Now you can send it to your smartphone and test it.
Here is a video example of the Poem Generator usage.
Conclusion
As you can see, Python is very handy for mobile development. We have created a cool application with strong services. It can analyze your text and even propose some rhymes to it.
With some refinement, you can probably add some more features (like push notifications or in-app purchases) and list it under word game apps on the Google Play store.
This is it for today, but you can always plunge deeper into the world of APIs. There are so many cool ideas and features that can enhance your own and the lives of those around you.
Leave a Reply