Added OCR support via the ocr.space API. Closes #93

This commit is contained in:
Manuel Cortez 2017-01-03 08:30:58 -06:00
parent 516acb501a
commit ec58d02bb3
10 changed files with 78 additions and 6 deletions

View File

@ -10,6 +10,7 @@
* Retweets should be displayed normally again when the originating tweet is a Twishort's long tweet. * Retweets should be displayed normally again when the originating tweet is a Twishort's long tweet.
* Changed the way TWBlue saves user timelines in configuration. Now it uses user IDS instead usernames. With user IDS, if an user changes the username, TWBlue still will create his/her timeline. This was not possible by using usernames. * Changed the way TWBlue saves user timelines in configuration. Now it uses user IDS instead usernames. With user IDS, if an user changes the username, TWBlue still will create his/her timeline. This was not possible by using usernames.
* Added a new setting in the account settings dialogue that makes TWBlue to show twitter usernames instead the full name. * Added a new setting in the account settings dialogue that makes TWBlue to show twitter usernames instead the full name.
* Added OCR in twitter pictures. There is a new item in the tweet menu that allows you to extract and display text in images. Also the keystroke alt+Win+o has been added for the same purpose from the invisible interface.
## Changes in version 0.87 ## Changes in version 0.87

View File

@ -129,6 +129,7 @@ Visually, Towards the top of the main application window, can be found a menu ba
* Show tweet: opens up a dialogue box where you can read the tweet, direct message, friend or follower which has focus. You can read the text with the arrow keys. It's a similar dialog box as used for composing tweets, without the ability to send the tweet, file attachment and autocompleting capabilities. It does however include a retweets and favourites count. If you are in the followers or the friends list, it will only contain a read-only edit box with the information in the focused item and a close button. * Show tweet: opens up a dialogue box where you can read the tweet, direct message, friend or follower which has focus. You can read the text with the arrow keys. It's a similar dialog box as used for composing tweets, without the ability to send the tweet, file attachment and autocompleting capabilities. It does however include a retweets and favourites count. If you are in the followers or the friends list, it will only contain a read-only edit box with the information in the focused item and a close button.
* View address: If the selected tweet has geographical information, TWBlue may display a dialogue box where you can read the tweet address. This address is retrieved by sending the geographical coordinates of the tweet to Google maps. * View address: If the selected tweet has geographical information, TWBlue may display a dialogue box where you can read the tweet address. This address is retrieved by sending the geographical coordinates of the tweet to Google maps.
* View conversation: If you are focusing a tweet with a mention, it opens a buffer where you can view the whole conversation. * View conversation: If you are focusing a tweet with a mention, it opens a buffer where you can view the whole conversation.
* Read text in pictures: Attempt to apply OCR technology to the image attached to the tweet. The result will be displayed in another dialog.
* Delete: permanently removes the tweet or direct message which has focus from Twitter and from your lists. Bear in mind that Twitter only allows you to delete tweets you have posted yourself. * Delete: permanently removes the tweet or direct message which has focus from Twitter and from your lists. Bear in mind that Twitter only allows you to delete tweets you have posted yourself.
##### User menu ##### User menu
@ -254,6 +255,7 @@ The invisible interface of TWBlue can be customised by using a keymap. Every key
* Control + Windows + Shift + G: Display the tweet's geolocation in a dialogue. * Control + Windows + Shift + G: Display the tweet's geolocation in a dialogue.
* Control + Windows + T: Create a trending topics' buffer. * Control + Windows + T: Create a trending topics' buffer.
* Control + Windows + {: Find a string in the current buffer. * Control + Windows + {: Find a string in the current buffer.
* Alt + Windows + O: Extracts text from the picture and display the result in a dialog.
## Configuration ## Configuration

View File

@ -6,7 +6,7 @@ if system == "Windows":
from update import updater from update import updater
from wxUI import (view, dialogs, commonMessageDialogs, sysTrayIcon) from wxUI import (view, dialogs, commonMessageDialogs, sysTrayIcon)
import settings import settings
from extra import SoundsTutorial from extra import SoundsTutorial, ocr
import keystrokeEditor import keystrokeEditor
from keyboard_handler.wx_handler import WXKeyboardHandler from keyboard_handler.wx_handler import WXKeyboardHandler
import userActionsController import userActionsController
@ -142,7 +142,7 @@ class Controller(object):
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.find, menuitem=self.view.find) widgetUtils.connect_event(self.view, widgetUtils.MENU, self.find, menuitem=self.view.find)
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.accountConfiguration, menuitem=self.view.account_settings) widgetUtils.connect_event(self.view, widgetUtils.MENU, self.accountConfiguration, menuitem=self.view.account_settings)
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.configuration, menuitem=self.view.prefs) widgetUtils.connect_event(self.view, widgetUtils.MENU, self.configuration, menuitem=self.view.prefs)
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.ocr_image, menuitem=self.view.ocr)
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.learn_sounds, menuitem=self.view.sounds_tutorial) widgetUtils.connect_event(self.view, widgetUtils.MENU, self.learn_sounds, menuitem=self.view.sounds_tutorial)
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.exit, menuitem=self.view.close) widgetUtils.connect_event(self.view, widgetUtils.MENU, self.exit, menuitem=self.view.close)
widgetUtils.connect_event(self.view, widgetUtils.CLOSE_EVENT, self.exit) widgetUtils.connect_event(self.view, widgetUtils.CLOSE_EVENT, self.exit)
@ -1520,6 +1520,32 @@ class Controller(object):
buffer_index = self.view.search(buffer.name, buffer.account) buffer_index = self.view.search(buffer.name, buffer.account)
self.view.set_page_title(buffer_index, title) self.view.set_page_title(buffer_index, title)
def ocr_image(self, *args, **kwargs):
buffer = self.get_current_buffer()
if hasattr(buffer, "get_right_tweet") == False:
output.speak(_(u"Invalid buffer"))
return
tweet = buffer.get_right_tweet()
if tweet.has_key("entities") == False or tweet["entities"].has_key("media") == False:
output.speak(_(u"This tweet doesn't contain images"))
return
if len(tweet["entities"]["media"]) > 1:
image_list = [_(u"Picture {0}").format(i,) for i in xrange(0, len(tweet["entities"]["media"]))]
dialog = dialogs.urlList.urlList(title=_(u"Select the picture"))
if dialog.get_response() == widgetUtils.OK:
img = tweet["entities"]["media"][dialog.get_item()]
else:
return
else:
img = tweet["entities"]["media"][0]
api = ocr.OCRSpace.OCRSpaceAPI()
try:
text = api.OCR_URL(img["media_url"])
except ocr.OCRSpace.APIError as er:
output.speak(_(u"Unable to extract text"))
return
msg = messages.viewTweet(text["ParsedText"], [], False)
def save_data_in_db(self): def save_data_in_db(self):
for i in session_.sessions: for i in session_.sessions:
session_.sessions[i].shelve() session_.sessions[i].shelve()

37
src/extra/ocr/OCRSpace.py Normal file
View File

@ -0,0 +1,37 @@
# -*- coding: utf-8 -*-
""" original module taken and modified from https://github.com/ctoth/cloudOCR"""
import requests
class APIError(Exception):
pass
class OCRSpaceAPI(object):
def __init__(self, key="4e72ae996f88957", url='https://api.ocr.space/parse/image'):
self.key = key
self.url = url
def OCR_URL(self, url, overlay=False):
payload = {
'url': url,
'isOverlayRequired': overlay,
'apikey': self.key,
}
r = requests.post(self.url, data=payload)
result = r.json()['ParsedResults'][0]
if result['ErrorMessage']:
raise APIError(result['ErrorMessage'])
return result
def OCR_file(self, fileobj, overlay=False):
payload = {
'isOverlayRequired': overlay,
'apikey': self.key,
'lang': 'es',
}
r = requests.post(self.url, data=payload, files={'file': fileobj})
results = r.json()['ParsedResults']
if results[0]['ErrorMessage']:
raise APIError(results[0]['ErrorMessage'])
return results

View File

@ -0,0 +1,2 @@
# -*- coding: utf-8 -*-
import OCRSpace

View File

@ -54,3 +54,4 @@ list_manager = string(default="alt+win+shift+l")
configuration = string(default="control+win+o") configuration = string(default="control+win+o")
accountConfiguration = string(default="control+win+shift+o") accountConfiguration = string(default="control+win+shift+o")
update_buffer = string(default="control+alt+shift+u") update_buffer = string(default="control+alt+shift+u")
ocr_image = string(default="win+alt+o")

View File

@ -55,3 +55,4 @@ list_manager = string(default="control+win+shift+l")
configuration = string(default="control+win+o") configuration = string(default="control+win+o")
accountConfiguration = string(default="control+win+shift+o") accountConfiguration = string(default="control+win+shift+o")
update_buffer = string(default="control+win+shift+u") update_buffer = string(default="control+win+shift+u")
ocr_image = string(default="win+alt+o")

View File

@ -52,4 +52,5 @@ actions = {
"accountConfiguration": _(u"Opens the account settings dialogue"), "accountConfiguration": _(u"Opens the account settings dialogue"),
"audio": _(u"Try to play an audio file"), "audio": _(u"Try to play an audio file"),
"update_buffer": _(u"Updates the buffer and retrieves possible lost items there."), "update_buffer": _(u"Updates the buffer and retrieves possible lost items there."),
"ocr_image": _(u"Extracts the text from a picture and displays the result in a dialog."),
} }

View File

@ -2,8 +2,8 @@
import wx import wx
class urlList(wx.Dialog): class urlList(wx.Dialog):
def __init__(self): def __init__(self, title=_(u"Select URL")):
super(urlList, self).__init__(parent=None, title=_(u"Select URL")) super(urlList, self).__init__(parent=None, title=title)
panel = wx.Panel(self) panel = wx.Panel(self)
self.lista = wx.ListBox(panel, -1) self.lista = wx.ListBox(panel, -1)
self.lista.SetFocus() self.lista.SetFocus()

View File

@ -32,6 +32,7 @@ class mainFrame(wx.Frame):
self.view = tweet.Append(wx.NewId(), _(u"&Show tweet")) self.view = tweet.Append(wx.NewId(), _(u"&Show tweet"))
self.view_coordinates = tweet.Append(wx.NewId(), _(u"View &address")) self.view_coordinates = tweet.Append(wx.NewId(), _(u"View &address"))
self.view_conversation = tweet.Append(wx.NewId(), _(u"View conversa&tion")) self.view_conversation = tweet.Append(wx.NewId(), _(u"View conversa&tion"))
self.ocr = tweet.Append(wx.NewId(), _(u"Read text in pictures"))
self.delete = tweet.Append(wx.NewId(), _(u"&Delete")) self.delete = tweet.Append(wx.NewId(), _(u"&Delete"))
# User menu # User menu