1

Please help. What code would it take to make a simple text clock application with python and flask to demonstrate how flask streaming works? Ideally the app would show text time in place, overwriting on screen, from the once per second updating stream.

The clock stream is a simplified case of a real time text stream. The real underlying need is for a server to push out simultaneous video & text streams (no audio) like Miguel Grinberg's Video Streaming with Flask and to show both updates on screen on the client side. Miguel's video stream demo works. However I do not yet know how to get a simultaneous text stream to work.

I have tried the code below and there are some quirks:

  1. The html p element is just a place holder for text. It could be changed to anything that might work better.
  2. http://localhost:5000 shows '/time_feed' when I want it to instead show the time string contents of /time_feed.
  3. http://localhost:5000/time_feed shows nothing at all while the flask server is running. When the flask server is stopped all of the sudden a bunch of updates appear in the browser like:

    2018.11.01|20:29:272018.11.01|20:29:282018.11.01|20:29:292018.11.01|20:29:302018.11.01|20:29:312018.11.01|20:29:322018.11.01|20:29:33

I tried Streaming data with Python and Flask but do not understand how to apply either the javascript or jinga answers to my clock's code. I am new learning web and flask development.

app.py:

#!python3 Flask 
# streaming clock per http://flask.pocoo.org/docs/1.0/patterns/streaming

from flask import Flask, Response, render_template, url_for
from datetime import datetime
import time

app = Flask(__name__)

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/time_feed')
def time_feed():
    def generate():
        while True:
            yield datetime.now().strftime("%Y.%m.%d|%H:%M:%S")
            time.sleep(1)
    return Response(generate(), mimetype='text')

if __name__ == '__main__':
    app.run(debug=True, threaded=True)

./templates/index.html:

<title>Clock</title>
<h1>Clock</h1>
<p>{{ url_for('time_feed') }}</p>
SpeedCoder5
  • 8,188
  • 6
  • 33
  • 34
  • 1
    Using JS to poll like the accepted solution is correct in your case. But using another http client you could see your method works as well, like with curl: `curl -vN "127.0.0.1:5000/time_feed"` – Kim Nov 08 '19 at 22:01

2 Answers2

3

in view you can avoid while and sleep in that example:

@app.route('/time_feed')
def time_feed():
    def generate():
        yield datetime.now().strftime("%Y.%m.%d|%H:%M:%S")  # return also will work
    return Response(generate(), mimetype='text') 

in template:

<p id="clock">Here will be date|time</p>

<script>
    var clock = document.getElementById("clock");

    setInterval(() => {
        fetch("{{ url_for('time_feed') }}")
        .then(response => {
                response.text().then(t => {clock.innerHTML = t})
            });
        }, 1000);  
</script>

in your example with video streem it is just trick, it is not solution for real video streaming, just because not provide audio. If you need for real video stream you need to use webRTC with Kurento-media-server for example. For python look on aiortc lib.

Andrey Topoleov
  • 1,591
  • 15
  • 20
  • Thank you. That could work entirely client side. And I actually do have text data that is updating on the server that I need to push out to the client. Does this need to be combined with websockets to push text from the server or is there a way to do it with a stream? I will be pushing video and text from the server and no audio. Requirement is text must be in a seperate stream from the video. – SpeedCoder5 Nov 02 '18 at 04:49
  • 1
    yes you can use your method for stream video without audio, and use `fetch` (JS method) for update your string. With `yeld` functions or without. – Andrey Topoleov Nov 02 '18 at 05:08
  • 1
    @SpeedCoder5 you can use it without websockets, just `fetch() ` – Andrey Topoleov Nov 02 '18 at 05:32
  • Thanks. Tried the code. The flask server console window prints 7 GETs received then in the browser the "clock"

    gets filled with `[object Response]` instead of a time string. I modified the code to `{clock.innerHTML = response.text()}` and still got the same `[object Response]` result.

    – SpeedCoder5 Nov 07 '18 at 20:26
  • 1
    @SpeedCoder5 answer updated again. Yes, `.text()` it is [promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) function. It fixed. – Andrey Topoleov Nov 08 '18 at 12:12
  • Yes. Thank you. That code now works & updates via client JavaScript polling (no stream.) With server side stream `yield`, `while True`, & `sleep` code in the

    just keeps adding text to the right creating a forever growing

    . Can the stream be kept with overwriting the

    with each new value in place? (Modified OP to show underlying need.) Perhaps the final code answer needs a multipart mime stream, webRTC, aiortc, or [Websockets or SSE](https://stackoverflow.com/a/5326159)? I do not yet see how to code it.

    – SpeedCoder5 Nov 08 '18 at 16:38
  • 1
    Apparently i don't unserstand the question. My english is not well. For stream video via webRTC you shood use media server like Kurento or [Janus](https://janus.conf.meetecho.com/docs/). They allow you streaming video (from file on server, or RTP from Gstreamer or FFmpg, or RTSP from live IPcam) and they provide transport data-chanal (webRTC chanel to send/receive data like text and other). Both soluthions have "hello world" examples for simplify understanding. Note: Kurento is more frendly for Node.js users. I'm use Janus with flask. Hope it helps for you. – Andrey Topoleov Nov 08 '18 at 16:48
0

You totally misunderstand how it works. streaming doesn't mean it can transport data intermittently, but means it can transport huge data while don't need to load it all at the beginning.

So while using stream, you are still using just one request. This request is a whole one, your browser can only deal with the response after the whole data is transported. In your case, as you are using an infinite loop, your browser will just waiting for the data forever.

To achieve what you want, you have two options:

  1. Use js to keep sending request per second.
  2. Use websocket.

update

It turns out that some elements can work with special mimetype multipart/x-mixed-replace to achieve long polling. As I am not a front-end guy, maybe someone can supply or correct my answer.

Community
  • 1
  • 1
Sraw
  • 18,892
  • 11
  • 54
  • 87
  • Ok and thank you for helping. How does this [flask video server](https://blog.miguelgrinberg.com/post/video-streaming-with-flask) stream different frames in real time using an infinite loop with yield? – SpeedCoder5 Nov 02 '18 at 01:57
  • 1
    Hum, I shouldn't answer this question... It is a totally front-end question while I am a backend guy... But basically the point is the `mimetype`, `multipart/x-mixed-replace` is a special mimetype. Although it works with `img` element, I believe it doesn't work with all elements. Or at least won't work with `p`, as there isn't a logic for `p` to pull data. – Sraw Nov 02 '18 at 02:22
  • 1
    Not true, clients can read and output the data from a Response directly and don't have to wait before it is finished. With curl for example: `curl -vN "127.0.0.1:5000/time_feed"` – Kim Nov 08 '19 at 21:59