Skip to content

Commit

Permalink
Merge pull request #102 from fractalego/interrupt-speech
Browse files Browse the repository at this point in the history
Interrupt speech
  • Loading branch information
fractalego committed Jul 20, 2024
2 parents b6180d4 + 6d1af81 commit 61808a9
Show file tree
Hide file tree
Showing 17 changed files with 180 additions and 229 deletions.
1 change: 1 addition & 0 deletions documentation/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Welcome to WAFL's 0.0.90 documentation!
configuration
running_WAFL
facts_and_rules
indexing_files
modify_the_prompt
examples
testcases
Expand Down
16 changes: 16 additions & 0 deletions documentation/source/indexing_files.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Indexing Files
==============

There is a special file called `indices.yaml` that is used to define the paths for the files
that need to be indexed.
The indexed files can be queried from the interface in a RAG fashion.
At the moment, the only supported file types are `txt` and `pdf`.

.. code-block:: yaml
paths:
- /path/to/files/
From the command line you can manually add a path as in the following

.. code-block:: bash
$ wafl add /path/to/files/
26 changes: 11 additions & 15 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
flask[async]==2.0.1
flask-cors==3.0.10
flask_dropzone==1.6.0
nltk==3.6.2
gensim==4.3.1
flask[async]==3.0.3
flask-cors==4.0.1
nltk==3.8.1
gensim==4.3.3
sklearn==0.0
python-Levenshtein==0.12.2
wave==0.0.2
python-Levenshtein==0.25.1
fuzzywuzzy==0.18.0
PyAudio==0.2.13
num2words==0.5.12
PyAudio==0.2.14
num2words==0.5.13
word2number==1.1
aiohttp==3.8.4
werkzeug==2.1.2
sphinx==6.1.3
sphinx-rtd-theme==1.2.0
bluepy==1.3.0
einops==0.6.1
aiohttp==3.9.5
werkzeug==3.0.3
sphinx==7.4.6
sphinx-rtd-theme==2.0.0
g2p-en==2.1.0
pyyaml==6.0.1
joblib==1.4.2
Expand Down
26 changes: 13 additions & 13 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"wafl.connectors.clients",
"wafl.connectors.factories",
"wafl.connectors.remote",
"wafl.dataclasses",
"wafl.events",
"wafl.extractors",
"wafl.handlers",
Expand All @@ -29,6 +30,7 @@
"wafl.listener",
"wafl.logger",
"wafl.parsing",
"wafl.readers",
"wafl.retriever",
"wafl.runners",
"wafl.scheduler",
Expand All @@ -44,22 +46,20 @@
],
},
install_requires=[
"flask[async]==2.0.1",
"flask-cors==3.0.10",
"flask_dropzone==1.6.0",
"werkzeug==2.1.2",
"nltk==3.6.2",
"gensim==4.3.1",
"flask[async]==3.0.3",
"flask-cors==4.0.1",
"nltk==3.8.1",
"gensim==4.3.3",
"sklearn==0.0",
"python-Levenshtein==0.12.2",
"wave==0.0.2",
"python-Levenshtein==0.25.1",
"fuzzywuzzy==0.18.0",
"PyAudio==0.2.13",
"pyctcdecode==0.2.1",
"num2words==0.5.12",
"PyAudio==0.2.14",
"num2words==0.5.13",
"word2number==1.1",
"aiohttp==3.8.4",
"einops==0.6.1",
"aiohttp==3.9.5",
"werkzeug==3.0.3",
"sphinx==7.4.6",
"sphinx-rtd-theme==2.0.0",
"g2p-en==2.1.0",
"pyyaml==6.0.1",
"joblib==1.4.2",
Expand Down
6 changes: 5 additions & 1 deletion todo.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
* interruptible speech
* dependabot!!!
* update readme with index.

* use poetry


/* interruptible speech

* upload to hetzner and make it work for some retrieval tasks
* develop more rules + use-cases for voice and other

Expand Down
4 changes: 3 additions & 1 deletion wafl/command_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@ def print_help():
print("> wafl run-audio: Run a voice-powered version of the chatbot")
print("> wafl run-server: Run a webserver version of the chatbot")
print("> wafl run-tests: Run the tests in testcases.txt")
print("> wafl add <PATH>: Add the file or folder at <PATH> to the index")
print(
"> wafl run-action <ACTION_NAME>: Run the action <ACTION_NAME> from actions.yaml"
)
print("> wafl help: Show this help message")
print()


Expand All @@ -50,7 +52,7 @@ def process_cli():
create_initial_files()
download_models()

if command == "run":
elif command == "run":
run_app()
remove_preprocessed("/")

Expand Down
8 changes: 4 additions & 4 deletions wafl/interface/list_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ async def output(self, text: str, silent: bool = False):
)

async def input(self) -> str:
done, pending = await asyncio.wait(
[interface.input() for interface in self._interfaces_list],
return_when=asyncio.FIRST_COMPLETED,
)
tasks = [interface.input() for interface in self._interfaces_list]
done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
for task in pending:
task.cancel()
return done.pop().result()

async def insert_input(self, text: str):
Expand Down
8 changes: 4 additions & 4 deletions wafl/interface/voice_interface.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import asyncio
import os
import random
import re

import nltk

from wafl.events.utils import remove_text_between_brackets
from wafl.interface.base_interface import BaseInterface
from wafl.interface.utils import not_good_enough
Expand Down Expand Up @@ -57,14 +56,15 @@ async def output(self, text: str, silent: bool = False):
text = text
self._insert_utterance(speaker="bot", text=text)
print(COLOR_START + "bot> " + text + COLOR_END)
for sentence in nltk.sent_tokenize(text):
await self._speaker.speak(sentence)
await self._speaker.speak(text)
self.bot_has_spoken(True)

async def input(self) -> str:
text = ""
while not text:
text = await self._listener.input()
if not text.strip():
continue
text = self.__remove_activation_word_and_normalize(text)
hotword = await self._listener.get_hotword_if_present()
if hotword:
Expand Down
3 changes: 3 additions & 0 deletions wafl/knowledge/indexing_implementation.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@

async def _add_indices_to_knowledge(knowledge, text):
indices = yaml.safe_load(text)
if "paths" not in indices or not indices["paths"]:
return knowledge

for path in indices["paths"]:
for root, _, files in os.walk(path):
for file in files:
Expand Down
162 changes: 94 additions & 68 deletions wafl/runners/routes.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import os

from flask import Flask
from flask import Flask, abort
from flask_cors import CORS

_path = os.path.dirname(__file__)
Expand All @@ -12,75 +12,101 @@
)
CORS(app)

_routes_dict = {}


def get_app():
return app


def add_new_rules(app: Flask, conversation_id: int, web_server_loop: "WebLoop"):
app.add_url_rule(
f"/{conversation_id}/",
f"index_{conversation_id}",
web_server_loop.index,
methods=["GET"],
)
app.add_url_rule(
f"/{conversation_id}/reset_conversation",
f"reset_conversation_{conversation_id}",
web_server_loop.reset_conversation,
methods=["POST"],
)
app.add_url_rule(
f"/{conversation_id}/reload_rules",
f"reload_rules_{conversation_id}",
web_server_loop.reload_rules,
methods=["POST"],
)
app.add_url_rule(
f"/{conversation_id}/check_new_messages",
f"check_new_messages_{conversation_id}",
web_server_loop.check_for_new_messages,
methods=["POST"],
)
app.add_url_rule(
f"/{conversation_id}/load_messages",
f"load_messages_{conversation_id}",
web_server_loop.load_messages,
methods=["POST", "GET"],
)
app.add_url_rule(
f"/{conversation_id}/input",
f"input_{conversation_id}",
web_server_loop.handle_input,
methods=["POST", "GET"],
)
app.add_url_rule(
f"/{conversation_id}/output",
f"output_{conversation_id}",
web_server_loop.handle_output,
methods=["POST"],
)
app.add_url_rule(
f"/{conversation_id}/thumbs_up",
f"thumbs_up_{conversation_id}",
web_server_loop.thumbs_up,
methods=["POST"],
)
app.add_url_rule(
f"/{conversation_id}/thumbs_down",
f"thumbs_down_{conversation_id}",
web_server_loop.thumbs_down,
methods=["POST"],
)
app.add_url_rule(
f"/{conversation_id}/toggle_logs",
f"toggle_logs_{conversation_id}",
web_server_loop.toggle_logs,
methods=["POST"],
)
app.add_url_rule(
f"/{conversation_id}/get_info",
f"get_info_{conversation_id}",
web_server_loop.get_info,
methods=["POST"],
)
@app.route("/<conversation_id>/index", methods=["GET"])
async def get_index(conversation_id: str):
if conversation_id not in _routes_dict:
abort(404)
return await _routes_dict[conversation_id]["index"]()


@app.route("/<conversation_id>/reset_conversation", methods=["POST"])
async def reset_conversation(conversation_id: str):
if conversation_id not in _routes_dict:
abort(404)
return await _routes_dict[conversation_id]["reset_conversation"]()


@app.route("/<conversation_id>/reload_rules", methods=["POST"])
async def reload_rules(conversation_id: str):
if conversation_id not in _routes_dict:
abort(404)
return await _routes_dict[conversation_id]["reload_rules"]()


@app.route("/<conversation_id>/check_new_messages", methods=["POST"])
async def check_new_messages(conversation_id: str):
if conversation_id not in _routes_dict:
abort(404)
return await _routes_dict[conversation_id]["check_new_messages"]()


@app.route("/<conversation_id>/load_messages", methods=["POST", "GET"])
async def load_messages(conversation_id: str):
if conversation_id not in _routes_dict:
abort(404)
return await _routes_dict[conversation_id]["load_messages"]()


@app.route("/<conversation_id>/input", methods=["POST", "GET"])
async def input(conversation_id: str):
if conversation_id not in _routes_dict:
abort(404)
return await _routes_dict[conversation_id]["input"]()


@app.route("/<conversation_id>/output", methods=["POST"])
async def output(conversation_id: str):
if conversation_id not in _routes_dict:
abort(404)
return await _routes_dict[conversation_id]["output"]()


@app.route("/<conversation_id>/thumbs_up", methods=["POST"])
async def thumbs_up(conversation_id: str):
if conversation_id not in _routes_dict:
abort(404)
return await _routes_dict[conversation_id]["thumbs_up"]()


@app.route("/<conversation_id>/thumbs_down", methods=["POST"])
async def thumbs_down(conversation_id: str):
if conversation_id not in _routes_dict:
abort(404)
return await _routes_dict[conversation_id]["thumbs_down"]()


@app.route("/<conversation_id>/toggle_logs", methods=["POST"])
async def toggle_logs(conversation_id: str):
if conversation_id not in _routes_dict:
abort(404)
return await _routes_dict[conversation_id]["toggle_logs"]()


@app.route("/<conversation_id>/get_info", methods=["POST"])
async def get_info(conversation_id: str):
if conversation_id not in _routes_dict:
abort(404)
return await _routes_dict[conversation_id]["get_info"]()


def add_new_routes(conversation_id: str, web_server_handler: "WebHandler"):
_routes_dict[str(conversation_id)] = {
"index": web_server_handler.index,
"reset_conversation": web_server_handler.reset_conversation,
"reload_rules": web_server_handler.reload_rules,
"check_new_messages": web_server_handler.check_for_new_messages,
"load_messages": web_server_handler.load_messages,
"input": web_server_handler.handle_input,
"output": web_server_handler.handle_output,
"thumbs_up": web_server_handler.thumbs_up,
"thumbs_down": web_server_handler.thumbs_down,
"toggle_logs": web_server_handler.toggle_logs,
"get_info": web_server_handler.get_info,
}
Loading

0 comments on commit 61808a9

Please sign in to comment.