viewo-talk 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- viewo_talk/__init__.py +24 -0
- viewo_talk/__main__.py +13 -0
- viewo_talk/action.py +102 -0
- viewo_talk/api/__init__.py +23 -0
- viewo_talk/api/present.py +50 -0
- viewo_talk/app.py +77 -0
- viewo_talk/config.py +16 -0
- viewo_talk/main.py +17 -0
- viewo_talk/plan/__init__.py +8 -0
- viewo_talk/plan/welcome.py +35 -0
- viewo_talk/static/basic.js +30 -0
- viewo_talk/static/mbox.js +68 -0
- viewo_talk/talk.py +166 -0
- viewo_talk/templates/base.html +20 -0
- viewo_talk/templates/mbox.html +40 -0
- viewo_talk/view.py +17 -0
- viewo_talk-1.0.0.dist-info/METADATA +21 -0
- viewo_talk-1.0.0.dist-info/RECORD +21 -0
- viewo_talk-1.0.0.dist-info/WHEEL +5 -0
- viewo_talk-1.0.0.dist-info/entry_points.txt +2 -0
- viewo_talk-1.0.0.dist-info/top_level.txt +1 -0
viewo_talk/__init__.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#==============================================================================
|
|
2
|
+
# C O P Y R I G H T
|
|
3
|
+
#------------------------------------------------------------------------------
|
|
4
|
+
# Copyright (c) 2021-2023 by Helmut Konrad Schewe. All rights reserved.
|
|
5
|
+
# This file is property of Helmut Konrad Schewe. Any unauthorized copy,
|
|
6
|
+
# use or distribution is an offensive act against international law and may
|
|
7
|
+
# be prosecuted under federal law. Its content is company confidential.
|
|
8
|
+
#==============================================================================
|
|
9
|
+
|
|
10
|
+
import importlib.metadata
|
|
11
|
+
import os
|
|
12
|
+
|
|
13
|
+
__version__ = importlib.metadata.version('viewo-talk')
|
|
14
|
+
|
|
15
|
+
ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
|
|
16
|
+
|
|
17
|
+
# pylint:disable=C0413
|
|
18
|
+
from viewo_talk.action import ActionMixin # isort:skip
|
|
19
|
+
from viewo_talk.action import Message # isort:skip
|
|
20
|
+
from viewo_talk.action import Question # isort:skip
|
|
21
|
+
from viewo_talk.action import pth # isort:skip
|
|
22
|
+
from viewo_talk.api import api_talk # isort:skip
|
|
23
|
+
from viewo_talk.app import register_talkme # isort:skip
|
|
24
|
+
from viewo_talk.talk import update # isort:skip
|
viewo_talk/__main__.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# C O P Y R I G H T
|
|
3
|
+
# -----------------------------------------------------------------------------
|
|
4
|
+
# Copyright (c) 2021-2023 by Helmut Konrad Schewe. All rights reserved.
|
|
5
|
+
# This file is property of Helmut Konrad Schewe. Any unauthorized copy,
|
|
6
|
+
# use or distribution is an offensive act against international law and may
|
|
7
|
+
# be prosecuted under federal law. Its content is company confidential.
|
|
8
|
+
# =============================================================================
|
|
9
|
+
|
|
10
|
+
import viewo_talk.app
|
|
11
|
+
|
|
12
|
+
if __name__ == "__main__":
|
|
13
|
+
app = viewo_talk.app.create_app() # pylint:disable=C0103
|
viewo_talk/action.py
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# C O P Y R I G H T
|
|
3
|
+
# -----------------------------------------------------------------------------
|
|
4
|
+
# Copyright (c) 2021-2023 by Helmut Konrad Schewe. All rights reserved.
|
|
5
|
+
# This file is property of Helmut Konrad Schewe. Any unauthorized copy,
|
|
6
|
+
# use or distribution is an offensive act against international law and may
|
|
7
|
+
# be prosecuted under federal law. Its content is company confidential.
|
|
8
|
+
# =============================================================================
|
|
9
|
+
|
|
10
|
+
import dataclasses
|
|
11
|
+
|
|
12
|
+
import viewo_talk.config
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclasses.dataclass
|
|
16
|
+
class Action:
|
|
17
|
+
user: int = None
|
|
18
|
+
time: int = None
|
|
19
|
+
msgid: int = None
|
|
20
|
+
path: str = None
|
|
21
|
+
data: str = None
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclasses.dataclass
|
|
25
|
+
class Answer(Action):
|
|
26
|
+
question: int = None
|
|
27
|
+
answer: bool = False
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclasses.dataclass
|
|
31
|
+
class Message:
|
|
32
|
+
user: int = None
|
|
33
|
+
time: int = None
|
|
34
|
+
msgid: int = None
|
|
35
|
+
title: str = None
|
|
36
|
+
content: str = None
|
|
37
|
+
index: str = None
|
|
38
|
+
|
|
39
|
+
def json(self) -> dict:
|
|
40
|
+
result = {
|
|
41
|
+
'name': self.__class__.__name__.upper(),
|
|
42
|
+
'title': self.title,
|
|
43
|
+
'content': self.content,
|
|
44
|
+
}
|
|
45
|
+
return result
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@dataclasses.dataclass
|
|
49
|
+
class Question(Message):
|
|
50
|
+
"""\
|
|
51
|
+
>>> Question(title='Magst du Brot?', index=10).json()
|
|
52
|
+
{'name': 'QUESTION', 'title': 'Magst du Brot?', 'content': None, 'index': 10}
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
def json(self) -> dict:
|
|
56
|
+
result = super().json()
|
|
57
|
+
result['index'] = self.index
|
|
58
|
+
return result
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class ActionMixin:
|
|
62
|
+
|
|
63
|
+
def __init__(self, routes: list = None):
|
|
64
|
+
self.routes = routes if routes else []
|
|
65
|
+
|
|
66
|
+
def run(self, item):
|
|
67
|
+
pass
|
|
68
|
+
|
|
69
|
+
def register(self, talker):
|
|
70
|
+
self.send_msg = talker.send_msg
|
|
71
|
+
self.send_question = talker.send_question
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def answer_split(raw: str):
|
|
75
|
+
raw = raw.strip()
|
|
76
|
+
return raw.split('\n\n', maxsplit=1)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def fromrequest(request) -> Action:
|
|
80
|
+
action = Action(
|
|
81
|
+
user=request.hashed,
|
|
82
|
+
time=request.time,
|
|
83
|
+
path=(request.method, request.path),
|
|
84
|
+
data=request.data,
|
|
85
|
+
msgid=msgid(path=request.path, method=request.method),
|
|
86
|
+
)
|
|
87
|
+
return action
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def pth(path: str):
|
|
91
|
+
return f'{viewo_talk.config.API_PREFIX}{path}'
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
API_LISTEN = pth('/talktome')
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def msgid(path, method='GET') -> str:
|
|
98
|
+
if method == 'POST':
|
|
99
|
+
return 'POST'
|
|
100
|
+
if path == API_LISTEN:
|
|
101
|
+
return 'LISTEN'
|
|
102
|
+
return None
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# C O P Y R I G H T
|
|
3
|
+
# -----------------------------------------------------------------------------
|
|
4
|
+
# Copyright (c) 2021-2023 by Helmut Konrad Schewe. All rights reserved.
|
|
5
|
+
# This file is property of Helmut Konrad Schewe. Any unauthorized copy,
|
|
6
|
+
# use or distribution is an offensive act against international law and may
|
|
7
|
+
# be prosecuted under federal law. Its content is company confidential.
|
|
8
|
+
# =============================================================================
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
|
|
12
|
+
import flask
|
|
13
|
+
|
|
14
|
+
import viewo_talk
|
|
15
|
+
|
|
16
|
+
api_talk = flask.Blueprint(
|
|
17
|
+
name='api_talk',
|
|
18
|
+
import_name=__name__,
|
|
19
|
+
static_folder=os.path.join(viewo_talk.ROOT, 'viewo_talk/static'),
|
|
20
|
+
template_folder=os.path.join(viewo_talk.ROOT, 'viewo_talk/templates'),
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
__all__ = ['api_talk', 'present']
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# C O P Y R I G H T
|
|
3
|
+
# -----------------------------------------------------------------------------
|
|
4
|
+
# Copyright (c) 2021-2023 by Helmut Konrad Schewe. All rights reserved.
|
|
5
|
+
# This file is property of Helmut Konrad Schewe. Any unauthorized copy,
|
|
6
|
+
# use or distribution is an offensive act against international law and may
|
|
7
|
+
# be prosecuted under federal law. Its content is company confidential.
|
|
8
|
+
# =============================================================================
|
|
9
|
+
|
|
10
|
+
import flask
|
|
11
|
+
import viewo_api
|
|
12
|
+
|
|
13
|
+
import viewo_talk.action
|
|
14
|
+
import viewo_talk.api
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@viewo_talk.api.api_talk.route('/talktome', methods=['GET'])
|
|
18
|
+
def receive_message() -> str:
|
|
19
|
+
userid = viewo_api.user_current()
|
|
20
|
+
messages = flask.current_app.talker.answers_pop(userid)
|
|
21
|
+
# convert to JSON
|
|
22
|
+
messages = [item.json() for item in messages]
|
|
23
|
+
data = {"messages": messages} if messages else {}
|
|
24
|
+
result = flask.jsonify(data)
|
|
25
|
+
return result
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@viewo_talk.api.api_talk.route('/talktome', methods=['POST'])
|
|
29
|
+
def receive_answer() -> str:
|
|
30
|
+
try:
|
|
31
|
+
question = int(flask.request.form.get('question', None))
|
|
32
|
+
except (TypeError, ValueError):
|
|
33
|
+
return viewo_api.bad('invalid question')
|
|
34
|
+
answer = bool(flask.request.form.get('answer', None))
|
|
35
|
+
todo = create_answer(question, answer)
|
|
36
|
+
flask.current_app.talker.append(todo)
|
|
37
|
+
return 'done', 200
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def create_answer(question: int, answer: bool):
|
|
41
|
+
request = viewo_api.request()
|
|
42
|
+
result = viewo_talk.action.Answer(
|
|
43
|
+
user=request.hashed,
|
|
44
|
+
time=request.time,
|
|
45
|
+
path=(request.method, request.path),
|
|
46
|
+
data=request.data,
|
|
47
|
+
answer=answer,
|
|
48
|
+
question=question,
|
|
49
|
+
)
|
|
50
|
+
return result
|
viewo_talk/app.py
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# C O P Y R I G H T
|
|
3
|
+
# -----------------------------------------------------------------------------
|
|
4
|
+
# Copyright (c) 2021-2023 by Helmut Konrad Schewe. All rights reserved.
|
|
5
|
+
# This file is property of Helmut Konrad Schewe. Any unauthorized copy,
|
|
6
|
+
# use or distribution is an offensive act against international law and may
|
|
7
|
+
# be prosecuted under federal law. Its content is company confidential.
|
|
8
|
+
# =============================================================================
|
|
9
|
+
|
|
10
|
+
import flask
|
|
11
|
+
import flask_bootstrap
|
|
12
|
+
import viewo_api
|
|
13
|
+
|
|
14
|
+
import viewo_talk
|
|
15
|
+
import viewo_talk.action
|
|
16
|
+
import viewo_talk.config
|
|
17
|
+
import viewo_talk.talk
|
|
18
|
+
from viewo_talk.api.present import * # pylint:disable=W0401,W0614
|
|
19
|
+
from viewo_talk.view import welcome
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Application(flask.Flask):
|
|
23
|
+
|
|
24
|
+
def __init__(self, sources: list = None):
|
|
25
|
+
super().__init__(__name__)
|
|
26
|
+
register_talkme(self, sources=sources)
|
|
27
|
+
self.register()
|
|
28
|
+
self.create_view()
|
|
29
|
+
|
|
30
|
+
def register(self):
|
|
31
|
+
self.register_blueprint(welcome)
|
|
32
|
+
|
|
33
|
+
def create_view(self):
|
|
34
|
+
self.config.setdefault('BOOTSTRAP_SERVE_LOCAL', True)
|
|
35
|
+
# configure extensions
|
|
36
|
+
flask_bootstrap.Bootstrap(app=self)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def register_talkme(app, prefix: str = None, sources: list = None):
|
|
40
|
+
talker = viewo_talk.talk.create(sources=sources)
|
|
41
|
+
app.talker = talker
|
|
42
|
+
|
|
43
|
+
start_talker_before_first_request(app, talker)
|
|
44
|
+
|
|
45
|
+
@app.teardown_appcontext
|
|
46
|
+
def teardown(exception): # pylint:disable=W0613
|
|
47
|
+
talker.stop()
|
|
48
|
+
|
|
49
|
+
@app.before_request
|
|
50
|
+
def talker_push():
|
|
51
|
+
request = viewo_api.request()
|
|
52
|
+
action = viewo_talk.action.fromrequest(request)
|
|
53
|
+
talker.append(action)
|
|
54
|
+
|
|
55
|
+
url_prefix = prefix if prefix else viewo_talk.config.API_PREFIX
|
|
56
|
+
# data API
|
|
57
|
+
app.register_blueprint(viewo_talk.api.api_talk, url_prefix=url_prefix)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def start_talker_before_first_request(app, talker):
|
|
61
|
+
# This method is necessary after upgrading flask which removes
|
|
62
|
+
# before_first_request
|
|
63
|
+
# TODO: VERIFY LATER
|
|
64
|
+
# app.before_first_request(talker.start)
|
|
65
|
+
started = False
|
|
66
|
+
# TODO: INVESTGATE LATER
|
|
67
|
+
@app.before_request
|
|
68
|
+
def start_talker():
|
|
69
|
+
nonlocal started
|
|
70
|
+
if not started:
|
|
71
|
+
talker.start()
|
|
72
|
+
started = True
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def create_app(sources: list = None) -> flask.Flask:
|
|
76
|
+
appx = Application(sources=sources)
|
|
77
|
+
return appx
|
viewo_talk/config.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# C O P Y R I G H T
|
|
3
|
+
# -----------------------------------------------------------------------------
|
|
4
|
+
# Copyright (c) 2021-2023 by Helmut Konrad Schewe. All rights reserved.
|
|
5
|
+
# This file is property of Helmut Konrad Schewe. Any unauthorized copy,
|
|
6
|
+
# use or distribution is an offensive act against international law and may
|
|
7
|
+
# be prosecuted under federal law. Its content is company confidential.
|
|
8
|
+
# =============================================================================
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
|
|
12
|
+
import configos
|
|
13
|
+
|
|
14
|
+
SECRET_KEY = configos.env('CHANIA_SECRET_KEY', default=os.urandom(64))
|
|
15
|
+
|
|
16
|
+
API_PREFIX = configos.env('CHANIA_API_PREFIX', default='/api/v0')
|
viewo_talk/main.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# C O P Y R I G H T
|
|
3
|
+
# -----------------------------------------------------------------------------
|
|
4
|
+
# Copyright (c) 2021-2023 by Helmut Konrad Schewe. All rights reserved.
|
|
5
|
+
# This file is property of Helmut Konrad Schewe. Any unauthorized copy,
|
|
6
|
+
# use or distribution is an offensive act against international law and may
|
|
7
|
+
# be prosecuted under federal law. Its content is company confidential.
|
|
8
|
+
# =============================================================================
|
|
9
|
+
|
|
10
|
+
import utilo
|
|
11
|
+
|
|
12
|
+
import viewo_talk.talk
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@utilo.cacheme(maxsize=1)
|
|
16
|
+
def talker():
|
|
17
|
+
return viewo_talk.talk.create()
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# C O P Y R I G H T
|
|
3
|
+
# -----------------------------------------------------------------------------
|
|
4
|
+
# Copyright (c) 2021-2023 by Helmut Konrad Schewe. All rights reserved.
|
|
5
|
+
# This file is property of Helmut Konrad Schewe. Any unauthorized copy,
|
|
6
|
+
# use or distribution is an offensive act against international law and may
|
|
7
|
+
# be prosecuted under federal law. Its content is company confidential.
|
|
8
|
+
# =============================================================================
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# C O P Y R I G H T
|
|
3
|
+
# -----------------------------------------------------------------------------
|
|
4
|
+
# Copyright (c) 2021-2023 by Helmut Konrad Schewe. All rights reserved.
|
|
5
|
+
# This file is property of Helmut Konrad Schewe. Any unauthorized copy,
|
|
6
|
+
# use or distribution is an offensive act against international law and may
|
|
7
|
+
# be prosecuted under federal law. Its content is company confidential.
|
|
8
|
+
# =============================================================================
|
|
9
|
+
|
|
10
|
+
import utilo
|
|
11
|
+
|
|
12
|
+
import viewo_talk.action
|
|
13
|
+
|
|
14
|
+
TITLE, CONTENT = viewo_talk.action.answer_split("""\
|
|
15
|
+
Willkommen auf checkitweg.de
|
|
16
|
+
|
|
17
|
+
Bei Fragen schauen Sie <<hier>>.
|
|
18
|
+
""")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Welcome(viewo_talk.action.ActionMixin):
|
|
22
|
+
|
|
23
|
+
def __init__(self):
|
|
24
|
+
super().__init__()
|
|
25
|
+
self.done = utilo.Single()
|
|
26
|
+
|
|
27
|
+
def run(self, item: viewo_talk.action.Action):
|
|
28
|
+
user = item.user
|
|
29
|
+
if self.done.contains(user):
|
|
30
|
+
return
|
|
31
|
+
self.send_msg(
|
|
32
|
+
user=user,
|
|
33
|
+
title=TITLE,
|
|
34
|
+
content=CONTENT,
|
|
35
|
+
)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const API = '/api/v0'
|
|
2
|
+
|
|
3
|
+
const rpc = function (url, callback, error = undefined) {
|
|
4
|
+
let call = `${API}${url}`
|
|
5
|
+
$.ajax(call, {
|
|
6
|
+
dataType: 'json',
|
|
7
|
+
success: function (response) {
|
|
8
|
+
callback(response)
|
|
9
|
+
},
|
|
10
|
+
error: function (response) {
|
|
11
|
+
if (error != undefined) {
|
|
12
|
+
error()
|
|
13
|
+
} else {
|
|
14
|
+
console.log(`error: ${call}`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const rpc_post = function (url, data, callback) {
|
|
21
|
+
let call = `${API}${url}`
|
|
22
|
+
$.ajax(call, {
|
|
23
|
+
type: 'POST',
|
|
24
|
+
data: data,
|
|
25
|
+
success: function (response) {
|
|
26
|
+
callback(response)
|
|
27
|
+
},
|
|
28
|
+
}
|
|
29
|
+
);
|
|
30
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
const WAITFOR = 5.0
|
|
2
|
+
|
|
3
|
+
const listen = function () {
|
|
4
|
+
rpc(`/talktome`, function (response) {
|
|
5
|
+
let messages = response.messages
|
|
6
|
+
if (messages != undefined) {
|
|
7
|
+
evaluate_messages(messages)
|
|
8
|
+
}
|
|
9
|
+
setTimeout(() => listen(), WAITFOR * 1000);
|
|
10
|
+
})
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const evaluate_messages = function (messages) {
|
|
14
|
+
for (let message of messages) {
|
|
15
|
+
if (message.name == 'MESSAGE') {
|
|
16
|
+
mbox_show_info(message.title, message.content)
|
|
17
|
+
} else if (message.name == 'QUESTION') {
|
|
18
|
+
mbox_show_question(message.title, message.content, message.index)
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const mbox_hide = function () {
|
|
24
|
+
$('#mbox').addClass('hidden')
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const mbox_show_info = function (headline, content) {
|
|
28
|
+
$('#mbox_question').addClass('hidden')
|
|
29
|
+
$('#mbox_headline').text(headline)
|
|
30
|
+
$('#mbox_content').text(content)
|
|
31
|
+
$('#mbox').removeClass('hidden')
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const mbox_show_question = function (headline, question, index) {
|
|
35
|
+
QUESTION = index
|
|
36
|
+
$('#mbox_question').removeClass('hidden')
|
|
37
|
+
$('#mbox_headline').text(headline)
|
|
38
|
+
$('#mbox_content').text(question)
|
|
39
|
+
$('#mbox').removeClass('hidden')
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
let QUESTION = null
|
|
43
|
+
|
|
44
|
+
const register = function () {
|
|
45
|
+
$(`#mbox_close`).click(function () {
|
|
46
|
+
mbox_hide()
|
|
47
|
+
});
|
|
48
|
+
$(`#mbox_question_yes`).click(function () {
|
|
49
|
+
rpc_post('/talktome', {
|
|
50
|
+
question: QUESTION,
|
|
51
|
+
answer: 1,
|
|
52
|
+
})
|
|
53
|
+
mbox_hide()
|
|
54
|
+
});
|
|
55
|
+
$(`#mbox_question_no`).click(function () {
|
|
56
|
+
rpc_post('/talktome', {
|
|
57
|
+
question: QUESTION,
|
|
58
|
+
answer: 0,
|
|
59
|
+
})
|
|
60
|
+
mbox_hide()
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
$(document).ready(function () {
|
|
65
|
+
register()
|
|
66
|
+
// start after 3 seconds
|
|
67
|
+
setTimeout(() => listen(), 3000);
|
|
68
|
+
})
|
viewo_talk/talk.py
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# C O P Y R I G H T
|
|
3
|
+
# -----------------------------------------------------------------------------
|
|
4
|
+
# Copyright (c) 2021-2023 by Helmut Konrad Schewe. All rights reserved.
|
|
5
|
+
# This file is property of Helmut Konrad Schewe. Any unauthorized copy,
|
|
6
|
+
# use or distribution is an offensive act against international law and may
|
|
7
|
+
# be prosecuted under federal law. Its content is company confidential.
|
|
8
|
+
# =============================================================================
|
|
9
|
+
|
|
10
|
+
import collections
|
|
11
|
+
import os
|
|
12
|
+
import queue
|
|
13
|
+
import threading
|
|
14
|
+
|
|
15
|
+
import utilo
|
|
16
|
+
|
|
17
|
+
import viewo_talk.action
|
|
18
|
+
import viewo_talk.plan
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Talker:
|
|
22
|
+
|
|
23
|
+
def __init__(self, skip: callable = None):
|
|
24
|
+
self.tasks = []
|
|
25
|
+
self.running = False
|
|
26
|
+
self.todo = queue.Queue()
|
|
27
|
+
self.msg = collections.defaultdict(list)
|
|
28
|
+
self.skip = skip if skip else skipper
|
|
29
|
+
|
|
30
|
+
def append(self, item: viewo_talk.action.Action):
|
|
31
|
+
if self.skip(item.path):
|
|
32
|
+
return
|
|
33
|
+
self.todo.put(item)
|
|
34
|
+
|
|
35
|
+
def answers_pop(self, user: int = None) -> list:
|
|
36
|
+
if self.msg[user]:
|
|
37
|
+
result = list(self.msg[user])
|
|
38
|
+
self.msg[user].clear()
|
|
39
|
+
return result
|
|
40
|
+
return []
|
|
41
|
+
|
|
42
|
+
def consume(self, wait: bool = True) -> bool:
|
|
43
|
+
# use wait:false for unit testing
|
|
44
|
+
if wait:
|
|
45
|
+
job = self.todo.get()
|
|
46
|
+
else:
|
|
47
|
+
try:
|
|
48
|
+
job = self.todo.get_nowait()
|
|
49
|
+
except queue.Empty:
|
|
50
|
+
# nothing todo
|
|
51
|
+
return False
|
|
52
|
+
if job is None:
|
|
53
|
+
# empty job to signal to end processing
|
|
54
|
+
return False
|
|
55
|
+
for task in self.tasks:
|
|
56
|
+
if not route_matches(job.path, task.routes):
|
|
57
|
+
continue
|
|
58
|
+
if isinstance(job, viewo_talk.action.Answer):
|
|
59
|
+
if hasattr(task, 'yes') and job.answer:
|
|
60
|
+
task.yes(job)
|
|
61
|
+
continue
|
|
62
|
+
if hasattr(task, 'no') and not job.answer:
|
|
63
|
+
task.no(job)
|
|
64
|
+
continue
|
|
65
|
+
task.run(job)
|
|
66
|
+
return True
|
|
67
|
+
|
|
68
|
+
def run(self):
|
|
69
|
+
while self.running:
|
|
70
|
+
self.consume()
|
|
71
|
+
|
|
72
|
+
def start(self):
|
|
73
|
+
# TODO: HOW TO TEAR DOWN THIS THREAD? IS IT GONE AFTER SETTING
|
|
74
|
+
# RUNNING=FALSE
|
|
75
|
+
self.running = True
|
|
76
|
+
threading.Thread(target=self.run).start()
|
|
77
|
+
|
|
78
|
+
def stop(self):
|
|
79
|
+
self.running = False
|
|
80
|
+
# ensure that waiting ends
|
|
81
|
+
self.todo.put(None)
|
|
82
|
+
|
|
83
|
+
def send_msg(self, user: str, title: str, content: str = None):
|
|
84
|
+
msg = viewo_talk.action.Message(
|
|
85
|
+
user=user,
|
|
86
|
+
time=utilo.now(),
|
|
87
|
+
title=title,
|
|
88
|
+
content=content,
|
|
89
|
+
)
|
|
90
|
+
self.msg[user].append(msg)
|
|
91
|
+
|
|
92
|
+
def send_question(self, user: str, title: str, content: str = None):
|
|
93
|
+
msg = viewo_talk.action.Question(
|
|
94
|
+
user=user,
|
|
95
|
+
time=utilo.now(),
|
|
96
|
+
title=title,
|
|
97
|
+
content=content,
|
|
98
|
+
)
|
|
99
|
+
self.msg[user].append(msg)
|
|
100
|
+
|
|
101
|
+
def register(self, task):
|
|
102
|
+
self.tasks.append(task)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
SKIP = ('GET', f'{viewo_talk.config.API_PREFIX}/talktome')
|
|
106
|
+
ICON = ('GET', '/favicon.ico')
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def skipper(item) -> bool:
|
|
110
|
+
if item == SKIP:
|
|
111
|
+
# do not invoke action as a result of message receiving
|
|
112
|
+
return True
|
|
113
|
+
if item == ICON:
|
|
114
|
+
return True
|
|
115
|
+
if item[1].startswith('/static/'):
|
|
116
|
+
return True
|
|
117
|
+
return False
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def route_matches(path, routes) -> bool:
|
|
121
|
+
if not routes:
|
|
122
|
+
return True
|
|
123
|
+
mymethod, mypath = path
|
|
124
|
+
for method, url in routes:
|
|
125
|
+
if method != mymethod:
|
|
126
|
+
continue
|
|
127
|
+
if mypath.startswith(url):
|
|
128
|
+
# TODO: IMPROVE THIS
|
|
129
|
+
return True
|
|
130
|
+
return False
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def collect(packages) -> list:
|
|
134
|
+
if not utilo.iterable(packages):
|
|
135
|
+
packages = [packages]
|
|
136
|
+
result = []
|
|
137
|
+
for package in packages:
|
|
138
|
+
source = os.path.split(package.__file__)[0]
|
|
139
|
+
for module in utilo.file_list(source, include='py', absolute=True):
|
|
140
|
+
if module.endswith('__init__.py'):
|
|
141
|
+
continue
|
|
142
|
+
loaded = utilo.load_module(module)
|
|
143
|
+
for value in vars(loaded).values():
|
|
144
|
+
if not hasattr(value, 'mro'):
|
|
145
|
+
continue
|
|
146
|
+
if viewo_talk.action.ActionMixin not in value.__mro__:
|
|
147
|
+
continue
|
|
148
|
+
result.append(value)
|
|
149
|
+
return result
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def create(sources=None) -> Talker:
|
|
153
|
+
talker = Talker()
|
|
154
|
+
if sources is None:
|
|
155
|
+
sources = [viewo_talk.plan]
|
|
156
|
+
talker = update(talker, sources)
|
|
157
|
+
return talker
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def update(talker, sources):
|
|
161
|
+
talker.tasks.clear()
|
|
162
|
+
for ctor in collect(sources):
|
|
163
|
+
constructred = ctor()
|
|
164
|
+
constructred.register(talker)
|
|
165
|
+
talker.register(constructred)
|
|
166
|
+
return talker
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{% extends "bootstrap/base.html" %}
|
|
2
|
+
|
|
3
|
+
{% block title %}Willkommen - Marhaban{% endblock %}
|
|
4
|
+
|
|
5
|
+
{% block styles %}
|
|
6
|
+
{{ super() }}
|
|
7
|
+
{% endblock %}
|
|
8
|
+
|
|
9
|
+
{% block content %}
|
|
10
|
+
{% endblock %}
|
|
11
|
+
|
|
12
|
+
{% block scripts %}
|
|
13
|
+
{{ super() }}
|
|
14
|
+
<script type="text/javascript" src="{{url_for('static', filename='basic.js')}}"></script>
|
|
15
|
+
<script type="text/javascript" src="{{url_for('static', filename='mbox.js')}}"></script>
|
|
16
|
+
{% endblock %}
|
|
17
|
+
|
|
18
|
+
{% block navbar %}
|
|
19
|
+
{% include "mbox.html" %}
|
|
20
|
+
{% endblock %}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<style>
|
|
2
|
+
#mbox {
|
|
3
|
+
bottom: 50px;
|
|
4
|
+
left: 30%;
|
|
5
|
+
margin-left: auto;
|
|
6
|
+
margin-right: auto;
|
|
7
|
+
position: fixed;
|
|
8
|
+
border: 2px solid black;
|
|
9
|
+
padding: 30px;
|
|
10
|
+
width: 350px;
|
|
11
|
+
min-height: 200px;
|
|
12
|
+
background-color: chocolate;
|
|
13
|
+
z-index: 1030;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
#mbox_close {
|
|
17
|
+
position: relative;
|
|
18
|
+
top: -30px;
|
|
19
|
+
right: -30px;
|
|
20
|
+
float: right;
|
|
21
|
+
border-radius: 0px;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.hidden {
|
|
25
|
+
visibility: hidden;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
</style>
|
|
29
|
+
|
|
30
|
+
<div id="mbox" class="hidden">
|
|
31
|
+
<button id="mbox_close" class="btn btn-sm btn-primary">X</button>
|
|
32
|
+
<h3 id="mbox_headline">...</h3>
|
|
33
|
+
<p id="mbox_content">
|
|
34
|
+
...
|
|
35
|
+
</p>
|
|
36
|
+
<p id="mbox_question" class="hidden">
|
|
37
|
+
<button id="mbox_question_yes" class="btn btn-primary">Ja</button>
|
|
38
|
+
<button id="mbox_question_no" class="btn btn-primary">Nein</button>
|
|
39
|
+
</p>
|
|
40
|
+
</div>
|
viewo_talk/view.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# C O P Y R I G H T
|
|
3
|
+
# -----------------------------------------------------------------------------
|
|
4
|
+
# Copyright (c) 2021-2023 by Helmut Konrad Schewe. All rights reserved.
|
|
5
|
+
# This file is property of Helmut Konrad Schewe. Any unauthorized copy,
|
|
6
|
+
# use or distribution is an offensive act against international law and may
|
|
7
|
+
# be prosecuted under federal law. Its content is company confidential.
|
|
8
|
+
# =============================================================================
|
|
9
|
+
|
|
10
|
+
import flask
|
|
11
|
+
|
|
12
|
+
welcome = flask.Blueprint('welcome', __name__) # pylint:disable=invalid-name
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@welcome.route('/')
|
|
16
|
+
def show_welcome():
|
|
17
|
+
return flask.render_template('base.html')
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: viewo_talk
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Author-email: Helmut Konrad Schewe <helmutus@outlook.com>
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/anaticulae/viewo_talk
|
|
7
|
+
Project-URL: Repository, https://github.com/anaticulae/viewo_talk
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
11
|
+
Requires-Python: >=3.12
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
Requires-Dist: flask-bootstrap<4.0.0.0,>=3.3.7.1
|
|
14
|
+
Requires-Dist: flask<4.0.0,>=3.1.3
|
|
15
|
+
Requires-Dist: utilo<3.0.0,>=2.112.1
|
|
16
|
+
Requires-Dist: viewo_api<2.0.0,>=1.0.1
|
|
17
|
+
Provides-Extra: dev
|
|
18
|
+
Requires-Dist: selenium<5.0.0,>=4.51.0; extra == "dev"
|
|
19
|
+
Requires-Dist: utilotest<2.0.0,>=1.1.1; extra == "dev"
|
|
20
|
+
|
|
21
|
+
# viewo_talk
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
viewo_talk/__init__.py,sha256=YrJE96sMA6ZnA2EZRNzOgr86gUDEvz34XtZ2MZzQmwg,1105
|
|
2
|
+
viewo_talk/__main__.py,sha256=m2zQedTEiCf9bIEdkPxpo_VeamnHjAMLcTRAAnKpIYM,665
|
|
3
|
+
viewo_talk/action.py,sha256=6lUWPNSVrr5rikr3e6NJtaZrdAHpf3GIo6q8d9Bq8TQ,2444
|
|
4
|
+
viewo_talk/app.py,sha256=H2IXFf-WGfC4jOPXd3_zD8sqvtf9nVLXeY2CC27G9Mk,2410
|
|
5
|
+
viewo_talk/config.py,sha256=PhtVIaZNpOc-6H2pjbvTj1-WSSB8V_5MEnPrwf6cR-E,719
|
|
6
|
+
viewo_talk/main.py,sha256=n-gjcVJ243rQlOqDKLxGLXdbVcJjEqcZ13EqqFhy9fE,668
|
|
7
|
+
viewo_talk/talk.py,sha256=FA68DrvWdQxOIPDUdOX1ZqWCvyNFl2IBjVrXQfnuYyI,4809
|
|
8
|
+
viewo_talk/view.py,sha256=0-YrphflvdnN9xGnHj9Zg34QYeKQGycxE4geZ0T46H4,733
|
|
9
|
+
viewo_talk/api/__init__.py,sha256=bs6bcHfsgol2SuydzqRiifF3aQTYu5oGxeQm0ChhgJk,854
|
|
10
|
+
viewo_talk/api/present.py,sha256=kFWrrpASTmMiMWZLt5MFthNDwh2jElGnE8DbcK_vWKk,1742
|
|
11
|
+
viewo_talk/plan/__init__.py,sha256=ZnAmZoM8YS7O_aZREOZiaHHCsO1ctWvQVu__JGFNWCc,552
|
|
12
|
+
viewo_talk/plan/welcome.py,sha256=59n8wRylqUEDzEwPkZmmW-ThCiQvdVT__-8hZLojK0c,1092
|
|
13
|
+
viewo_talk/static/basic.js,sha256=Y5E6GEA7FPKxoSvVvWFam-pAv95XoG-6ufdOahWn5MU,676
|
|
14
|
+
viewo_talk/static/mbox.js,sha256=6eQjRAqMwsCzGGxId_Syb0_rGXg8fWrjN5w_BC1qjyM,1733
|
|
15
|
+
viewo_talk/templates/base.html,sha256=c5ZNsL24n8fymPF9LoI11Cmf1B443WdBy2W-o0odVdE,465
|
|
16
|
+
viewo_talk/templates/mbox.html,sha256=jU6DnFU7bDL9jThwanii4YoEwc5fxF-7d0Z66GNQAWs,910
|
|
17
|
+
viewo_talk-1.0.0.dist-info/METADATA,sha256=7NUEo4vg1nwTk9FdjfA4baLb6GMy1S3MykxElbqyvno,787
|
|
18
|
+
viewo_talk-1.0.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
|
|
19
|
+
viewo_talk-1.0.0.dist-info/entry_points.txt,sha256=_eoQ7wGx6DuhMRFKHoVieEU_pdpVQW92Wf_LDjAD7n4,51
|
|
20
|
+
viewo_talk-1.0.0.dist-info/top_level.txt,sha256=A_KYSnbSCF7EYzQKD_eiLIJnbQX5ZkRvHe9c84JePhs,11
|
|
21
|
+
viewo_talk-1.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
viewo_talk
|