I am using speech_recognition module to identify a search query through voice and then open a google chrome page showing the result for the query. Basically, it's a replacement of the google voice search but it's initiated through the terminal. But I want to make this into a web-app. I created the flask app:
-Search(directory)
-search.py (opens a tab using terminal directly/works independently)
-app.py (main flask app)
-static(directory)
-templates (directory)
But since the app is hosted on the server, my search.py takes input from the server mic(in this case it's my PC's mic/ but on AWS, it won't work). How do I take input from the client browser and use it in speech.py? Should I delete this file and use it directly in my main app? What is the most effective way to execute this functionality?
Here is my search.py script if anyone wants to know:
It works through the terminal.
import subprocess
import speech_recognition as sr
browser_exe_path = "..."
r=sr.Recognizer()
with sr.Microphone() as source:
print("Listening!")
audio=r.listen(source)
try:
s_name=r.recognize_google(audio)
"""
Code to open browser and search the query
"""
except:
print("Error!")
These two would probably be the best ways:
make a module/package of your own speech recognition tool and import it into your flask app
integrate the functionality itself into the app.
If you plan on using it again, it might be a good idea to keep the speech recognition separate from the web app, because then you can use it again. But you can customise it much more if you integrate it with, for example, the view functions for your application. Also, you should probably put all your search.py logic in one function or class, so that you can call it. Otherwise, if you import it as it is now, it will immediately run.
Either way, you need a speech structure that looks something like this:
The user submits some speech, either live, recorded, or as a file. We'll call this speech file speech.wav (or any other file type, your choice)
speech.wav is read and parsed by your speech recognition tool. It might return a list of words, or maybe just a string. We'll call this output.
output is returned to the webpage and rendered as something for the user to read.
I suggest starting with a form submission and if you can get that to work, you can try a live speech recognition with AJAX. Start basic and just ask the user to add an audio file or record one. The following script will open up the file browser if on desktop, or get the user to record if on iOS or Android.
<input name="audio-recording" type="file" accept="audio/*" id="audio-recording" capture>
<label for="audio-recording">Add Audio</label>
<p id="output"></p>
So once they've got a file there you need to access it. You may want to customise it, but here is a basic script which will take control of the above audio. Credit for this script goes to google developers.
<script>
const recorder = document.getElementById('audio-recording');
recorder.addEventListener('change', function(e) {
const file = e.target.files[0];
const url = URL.createObjectURL(file);
// Do something with the audio file.
});
</script>
Where it says // Do something with the audio file, it might be a cool idea to make an AJAX GET request, which will return the sentence. But this is where it gets really tricky, because you need to give the information to flask in arguments, not an audio file. But because we've stored the place where the file exists at the constant url in our script, we can use that as the argument, for example:
from flask import request, jsonify
import search # this is your own search.py that you mentioned in your question.
#app.route("/process_audio")
def process_audio():
url = request.args.get("url")
text = search.a_function(url) #returns the text from the audio, which you've done, so I've omitted code
if text != None
return jsonify(result="success",text=text)
else:
return jsonify(result="fail")
This'll return data in something called JSON format, which is like the bridge between client side js and server side python. It might look something like this:
{
"result":"success",
"text":"This is a test voice recording"
}
Then, you need to have some jQuery (or any other js library, but jQuery is nice and easy) to manage the AJAX call:
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type=text/javascript>
const recorder = document.getElementById('audio-recording');
recorder.addEventListener('change', function(e) {
const file = e.target.files[0];
const url = URL.createObjectURL(file);
$.getJSON('/process_audio', {
url: url
}, function(data) {
$("#output").text(data.text);
});
return false;
</script>
Apologies for any bracketing errors there. So that should send a GET request for some JSON to the URL of "/audio_process", which will return what we saw earlier, and then it will output the "text" of the JSON to the "#output" HTML selector.
There may be some debugging needed, but that seems to do the trick.
Related
I want to make a website with a function similar to https://www.howmanypeopleareinspacerightnow.com/, where I have a website information display that refreshes regularly displaying the water flow of a river through town. I am scraping the data using Beautiful Soup and would like to create a website that uses my python-processed data to generate pre-determined website content (e.g. 'The water is high right now, it has a flow rate of XXX/s' or 'The water is low right now').
From what I've read, I could create a Python app that is hosted on heroku, but then I would have to make a GUI in the program, right? How can I turn my program into an information source for an html page without having to have a user run a program?
I feel like there is a name for this and yet my Googling has not turned up anything so far :(
It sounds like you want to build a dynamic SPA (Single Page App).
You'll want and app server to host the backend, which will handle routing and serving up the dynamic content (water flow rate).
Then you'll want some front end code to render a nice UI and display the content the backend provides.
It sounds like you want to use python (as per the question tag).
A fast way to achieve this is to create a python Flask app. Flask will allow you to build an app server. In addition Flask has a 'template engine', Jinja2, which allows you to create UIs by combing HTML and python objects.
For example:
Create a folder called waterproject and waterproject/templates/
Then create 2 files, waterproject/app.py and waterproject/templates/index.html
# waterproject/app.py
from flask import Flask, render_template
import json
app = Flask(__name__)
def read_water_level():
with open('/file/where/data/is/stored.txt') as file:
water_level = file.read()
return water_level
#app.route('/index', methods=['GET'])
def index():
render_template('index.html', water_level=read_water_level())
#pp.route('/waterlevel', methods=['GET'])
def get_water_level():
return json.dumpss({'waterlevel': read_water_level()})
if __name__ == "__main__":
app.run(host='localhost',debug=True)
Above we create 2 routes. One to serve the main page, and another an api endpoint that will only return the water level. This end point will be used to allow the frontend to automatically poll the backend for the water level, without having to re render (or refresh) the entire page.
Also it is assumed your web scraper is saving the water level in the file at '/file/where/data/is/stored.txt'
Then you would create the .html file (index.html) the above route renders.
# in /waterproject/templates/index.html
<!DOCTYPE html>
<html>
<head>
<script src="jquery-3.4.1.min.js"></script>
<title>Water Level of River</title>
<style>
body {
text-align: center;
}
#water {
color: blue;
}
</style>
<script>
var get_water_level = function() {
$.get( "/waterlevel", function( data ) {
$( "#water" ).html( data['waterlevel'] );
});
};
var interval = 1000 * 60 * X; // where X is your every X minutes
setInterval(get_water_level, interval);
</script>
</head>
<body>
<div id="water">
{{water_level}}
</div>
</body>
</html>
Notice how this html file has the {{water_level}} object embedded into the html. This is not proper html, but the template engine Flask employs allows us to effectively pass the water_level object from the app server's python code into the html document.
In addition, the .html page has some javascript in it to get the water level every X minutes, and update the page. So if a user visits your page and stays on it for 10 minutes, the page will automatically be refreshing every minute.
To deploy the app check out Flask's Documentation, there are some good options and instructions there, including instructions for Heroku.
https://flask.palletsprojects.com/en/1.0.x/deploying/
*Note I haven't actually run this code but it should give you a good starting point.
Also its good practice to organize your css, javascript, and html in different files, but for such a small app, and to keep things simple everything is shown in one file.
Look into Flask, you can generate your content through python and display it easily with Flask.
Django is the go-to way to create web pages with Python - it has a pretty comprehensive tutorial, and will handle all of the back-end stuff. You'll still need to figure out hosting; cloud-services (like AWS or Azure) play nicely with Django, or you can host from your own computer.
For front-end development, you can use a WYSIWYG (what you see is what you get) designer, which will let you drag and drop to create your page. You can then export your page and use it as a template in Django. If your site is more complex, you'll want to learn some basic text-based HTML skills.
I have been writing python code for quite some time to get CSGO gamestate_integration, but I currently need to write something in vb.net to do the same thing and it's not working.
tl;dr version: vb.net won't accept the post request from CSGO, but a simple python script can echo the post request to vb.net and it works. The vb.net application IS being run as administrator.
I have a simple class file (obviously my URIs are private):
Imports System.IO
Imports System.ServiceModel
Imports System.ServiceModel.Web
Imports JSONReceiver
<ServiceContract()>
Public Interface iJSONReceiver
<OperationContract>
<WebGet()>
Function get_stats(ByVal data As String) As String
<OperationContract()>
<WebInvoke(RequestFormat:=WebMessageFormat.Json)>
Function post_stats(ByVal request As Stream) As String
End Interface
Public Class JSONReceiver
Implements iJSONReceiver
Public Function post_stats(ByVal request As Stream) As String Implements iJSONReceiver.post_stats
Dim reader As New StreamReader(request)
Console.WriteLine("In post_stats")
Console.WriteLine(reader.ReadToEnd())
Console.WriteLine()
Return "OK"
End Function
Public Function get_stats(ByVal data As String) As String Implements iJSONReceiver.get_stats
Console.WriteLine("In get_stats")
Console.WriteLine(data)
Console.WriteLine()
Return "OK"
End Function
End Class
And simple code to test it:
Public host As WebServiceHost
Public post_ep As ServiceEndpoint
Public Sub main()
host = New WebServiceHost(GetType(JSONReceiver), New Uri("http://192.168.1.102:8080"))
post_ep = host.AddServiceEndpoint(GetType(iJSONReceiver), New WebHttpBinding(), "")
host.Open()
Console.WriteLine("Press enter to quit...")
Console.ReadLine()
host.Close()
End Sub
I can use a web browser to point to the get_stats() endpoint, and it works just fine, but I am trying to use CSGOs gamestate_integration functionality to post the data to my service, and it just doesn't seem to like it.
So what I did was ripped my old python code to simply echo the request to the vb.net web service, it it works... the python code receives the data and simply posts it to the vb.net service, and the vb.net service happily accepts it.
So I change the URI for the vb JSONReceiver to port 8081, and run this script on the original uri (192.168.1.102:8080)
import web
import urllib2
class Stats(object):
def POST(self):
json_data = web.data()
try:
echo(json_data)
except Exception, e:
print(e.__str__())
return "OK"
def echo(data):
request = urllib2.Request("http://192.168.1.102:8081/post_stats")
request.add_data(data)
f = urllib2.urlopen(request)
print f.read()
urls = (
'/post_stats', 'Stats',
)
if __name__ == "__main__":
app = web.application(urls, globals())
app.run()
In short, the URI CSGO is using to post to my service is http://192.168.1.102:8080, which hits my python service, which then echoes the request verbatim to http://192.168.1.102:8081 (again, these are private URIs).
I don't know why, but it works... but having to run a wrapper to get this data is not only weird, it's really not an acceptable solution to the problem... obviously vb.net is handling post requests just fine when it's coming from my python script; obviously CSGO is posting requests correctly, or my python script wouldn't be able to receive it, so I'm having a problem finding the disconnect...
Is Python adding something to the request that CSGO might not be?
Do I need to fall back to socket programming?
(unsure of how to phrase this question)
Essentially I'm working with Flask + Soundcloud and what I want to do is to request an http site (which i know will redirect me to a new site) and then i want to return that site (with the same headers and info i originally got). Maybe this explains it better:
#app.route('/play')
def SongURL2():
stream_url="https://api.soundcloud.com/tracks/91941888/stream?client_id=MYCLIENTID"
// newurl = HTTP_REQUEST(stream_url) <- This will redirect me to the actual song streaming link (which only lives for a little bit)
// return newurl;
This is because soundcloud's song's streaming url only live for a short period of time and the device I am using to call my RESTful api will not allow me to do a simple redirect to the newlink. So I need to somehow act like a proxy.
You can achieve this using the Request module:
import requests
#app.route('/play')
def SongURL2():
stream_url="https://api.soundcloud.com/tracks/91941888/stream?client_id=MYCLIENTID"
# Get the redirected url
r = request.get(stream_url)
return r.url
Found an interesting way to proxy through Flask, similar to what #Dauros was aiming at. http://flask.pocoo.org/snippets/118/ In the end bare in mind that this puts extra strain on the server.
editied original question:
Im trying to make a google appengine app which uses the g+ avatar and human name...
...
So it seems that i need the google-api-python-client library in my app.
...
to enable access to the profile scope so i can look up 'me' and grab the users name and avatar and chuck them in a couple of properties in my user objects (with a button to reload the values again or something).
So has anyone does this? Or has a working example (or even a pointer to which of the ways to authorise my app for scope=[profile])?
Discoveries:
I dont need the google-api-python-client library for this. The simple approach was to do the g+ access in pure js on the client and then lookup and push the results to my appengine app. It isnt as secure as doing via the backend, but it is only for displayname and icon (which can be set manually anyway).
I did need to make some other tweaks to make it work though...
following this workflow:
https://developers.google.com/+/web/signin/javascript-flow
Important things to note:
step1 should also state that you MUST fill out "APIs & auth" -> "Consent screen" field "PRODUCT NAME" and "EMAIL ADDRESS" or you get weird errors
You (might) have to do this before you generate the credential (or delete and recreate it)
(credit to answer: Error: invalid_client no application name)
set meta google-signin-scope to "profile" (or maybe "email")
remove the meta header for google-signin-requestvisibleactions (otherwise i got a frame sameorigin error)
obviously the button line from step4 needs to go after the body tag in your document
skip step2, the code from step2 is also included in step4
also on the workflow page, the 'working example' button on that page does not work (dont try it)
Once i did that I could put the following in the successful callback code and do a lookup:
gapi.client.load('plus','v1', function(){
var request = gapi.client.plus.people.get({ 'userId': 'me' });
request.execute(function(resp) {
console.log('Retrieved profile for:' + resp.displayName);
console.log(resp);
console.log(resp.result);
console.log(resp.result.displayName);
console.log(resp.result.image);
});
});
you can see here full example on how to use client library
https://code.google.com/p/google-api-python-client/source/browse/samples/plus/plus.py
i see a snippet of the code stating
try:
person = service.people().get(userId='me').execute()
print 'Got your ID: %s' % person['displayName']
https://developers.google.com/+/api/latest/people#resource
so basically person['image']['url'] will be your path to user's avatar.
full folder: https://code.google.com/p/google-api-python-client/source/browse/samples/plus/
I have a python routine which I call with an HTML Button. I cannot call from that button with AJAX. It has to be a call via a URL, something like
onClick="location.href='server/csvExport'">
But how do I refer to the server which issued the running HTML, since that server may be one of many servers issuing this site? Here is the Python side code which is an exposed method of the main object. The server running is based on CherryPy.
def csvExport(self, **kwargs):
sql = '''SELECT * FROM ...
"...
"...
xLine += f2+f3+f1+f6+f8+f4+"\n"
rtr = xLine
CSV_Filename = "ExportReport"
cherrypy.response.headers['content-type'] = 'text/csv'
cherrypy.response.headers['content-disposition'] = 'attachment; filename=%s.csv'% CSV_Filename
return rtr
csvExport.exposed = True
TIA
DK
The solution is to use the window.location.host DOM indirection to get the server reference and it has to be preceded by 'HTTP://' The two will produce a URL like HTTP://soandso.com:8050 with a port number to identify the running site. That site can now be supplemented with an object function like csvExport to get a final and full URL reference to the call you are trying to make. e.g. 'HTTP://soandso.com:8050/csvExport' and that is sufficient to refer to any server running this site.
Here is a practical way of planting this event into a button with jQuery:
dLoadCall = window.location.host+"/csvExport";
dLoadCall2 = "window.open('http://"+dLoadCall+"')";
$("#dload").attr("onClick",dLoadCall2);
The HTML button might look like this before the event insertion:
<input id="dload" type="button" value="Export CSV"/>
And this is how it would look afterward:
<input id="dload" type="button" value="Export CSV" onclick="window.open('http://192.168.19.249:8140/csvExport')">`
Now you can click on the button and call the Python method csvExport: on the server serving this site.
DK