Skip to content

Commit

Permalink
Improve markdown formatting
Browse files Browse the repository at this point in the history
  • Loading branch information
yorevs committed Mar 27, 2024
1 parent 7401304 commit 7deb5f3
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 50 deletions.
2 changes: 1 addition & 1 deletion src/main/askai/core/askai.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ def reply(self, message: str) -> None:
if self.is_speak:
self.engine.text_to_speech(message, f"{shared.nickname}: ")
else:
display_text(f"%GREEN%{message}%NC%", f"{shared.nickname}: ")
display_text(message, f"{shared.nickname}: ")

def reply_error(self, message: str) -> None:
"""Reply API or system errors.
Expand Down
96 changes: 96 additions & 0 deletions src/main/askai/core/support/text_formatter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import re
from random import randint
from textwrap import dedent
from typing import Any

from hspylib.core.metaclass.singleton import Singleton
from hspylib.core.tools.commons import sysout
from hspylib.modules.cli.vt100.vt_code import VtCode
from hspylib.modules.cli.vt100.vt_color import VtColor
from rich.console import Console
from rich.highlighter import RegexHighlighter, Highlighter
from rich.markdown import Markdown


class TextFormatter(metaclass=Singleton):
"""TODO"""

INSTANCE: 'TextFormatter' = None

CHAT_ICONS = {
'': '\n%RED% Error: ',
'': '\n>  *Hints & Tips:* ',
'': '\n>  *Analysis:* ',
'': '\n>  *Summary:* ',
'': '\n>  *Joke:* ',
'': '\n>  *Fun-Fact:* ',
'': '\n>  *Advice:* ',
}

def __init__(self):
self._console: Console = Console(soft_wrap=True)

@property
def console(self) -> Console:
return self._console

def beautify(self, text: Any) -> str:
"""Beautify the provided text with icons and other formatting improvements.
:param text: The text to be beautified.
"""
# fmt: off
re_url = (
r'(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|'
r'www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))'
r'[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})'
)
text = dedent(str(text))
text = re.sub(r"Errors?[-:\s]\s+", self.CHAT_ICONS[''], text)
text = re.sub(r"[Hh]ints?( (and|&) [Tt]ips)?[-:\s]\s+", self.CHAT_ICONS[''], text)
text = re.sub(r"[Aa]nalysis[-:\s]\s+", self.CHAT_ICONS[''], text)
text = re.sub(r"[Ss]ummary[-:\s]\s+", self.CHAT_ICONS[''], text)
text = re.sub(r"[Ff]un [Ff]acts?[-:\s]\s+", self.CHAT_ICONS[''], text)
text = re.sub(r"([Jj]oke( [Tt]ime)?)[-:\s]\s+", self.CHAT_ICONS[''], text)
text = re.sub(r"[Aa]dvice[-:\s]\s+", self.CHAT_ICONS[''], text)
mat = re.search(r"%\w+%", text)
fg = mat.group() if mat else ''
text = re.sub(re_url, r' \1', text)
# fmt: on

return text.strip()

def display_markdown(self, text: str) -> None:
colorized: str = VtColor.colorize(VtCode.decode(self.beautify(text)))
self.console.print(Markdown(colorized), highlight=True)

def display_text(self, text: str) -> None:
sysout(self.beautify(text))


assert (text_formatter := TextFormatter().INSTANCE) is not None


class RainbowHighlighter(Highlighter):
def highlight(self, text):
for index in range(len(text)):
text.stylize(f"color({randint(16, 255)})", index, index + 1)


class Highlighter(RegexHighlighter):
base_style = "help."
highlights = [r"(?P<cmd>!help\b)", r"(?P<cmd2>\'|\"[\w]+\"|\')"]


if __name__ == '__main__':
s = dedent("""
Error: This should be red
Advice: This should be yellow
Hint: This should be blue
Joke: This should be magenta
Analysis: This should be yellow
This is not OK because it has failed to be a success!
For more details access: https://askai.github.io/askai Enjoy!
""")
text_formatter.display_markdown(s)
52 changes: 10 additions & 42 deletions src/main/askai/core/support/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import re
from os.path import basename, dirname
from pathlib import Path
from textwrap import dedent
from typing import Any, Optional, Tuple

import pause
Expand All @@ -28,46 +27,11 @@
from hspylib.core.tools.commons import file_is_not_empty, sysout
from hspylib.core.tools.text_tools import ensure_endswith
from hspylib.modules.cli.vt100.vt_color import VtColor
from rich.console import Console
from rich.markdown import Markdown

from askai.core.support.presets import Presets
from askai.core.support.text_formatter import text_formatter
from askai.language.language import Language

CHAT_ICONS = {
'': '\n Error: ',
'': '\n\n Hints & Tips: ',
'': '\n\n Analysis: ',
'': '\n\n Summary: ',
'': '\n\n Joke: ',
'': '\n\n Fun-Fact: ',
'': '\n\n Advice: ',
}


def beautify(text: Any) -> str:
"""Beautify the provided text with icons and other formatting improvements.
:param text: The text to be beautified.
"""
# fmt: off
re_url = (
r'(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|'
r'www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))'
r'[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})')
text = dedent(str(text))
text = re.sub(r"Errors?[-:\s][ \n\t]+", CHAT_ICONS[''], text)
text = re.sub(r"[Hh]ints?( and tips)?[-:\s][ \n\t]+", CHAT_ICONS[''], text)
text = re.sub(r"[Aa]nalysis[-:\s][ \n\t]+", CHAT_ICONS[''], text)
text = re.sub(r"[Ss]ummary[-:\s][ \n\t]+", CHAT_ICONS[''], text)
text = re.sub(r"([Jj]oke( [Tt]ime)?)[-:\s][ \n\t]+", CHAT_ICONS[''], text)
text = re.sub(r"[Ff]un [Ff]acts?[-:\s][ \n\t]+", CHAT_ICONS[''], text)
text = re.sub(r"[Aa]dvice[-:\s][ \n\t]+", CHAT_ICONS[''], text)
# Format links
text = re.sub(re_url, r' \1', text)
# fmt: on

return text.strip()


def display_text(
text: Any,
Expand All @@ -83,12 +47,10 @@ def display_text(
"""
if erase_last:
Cursor.INSTANCE.erase_line()
sysout(f"{str(prefix)}", end="")
if markdown:
console = Console(force_terminal=False, no_color=True)
console.print(Markdown(beautify(text)))
text_formatter.display_markdown(f"{str(prefix)}{text}")
else:
sysout(beautify(text))
text_formatter.display_text(f"{str(prefix)}{text}")


def stream_text(
Expand All @@ -104,7 +66,7 @@ def stream_text(
:param tempo: the speed multiplier of the typewriter effect. Defaults to 1.
:param language: the language used to stream the text. Defaults to en_US.
"""
text: str = beautify(text)
text: str = text_formatter.beautify(text)
presets: Presets = Presets.get(language.language, tempo=tempo)
word_count: int = 0
ln: str = os.linesep
Expand Down Expand Up @@ -226,6 +188,10 @@ def extract_command(markdown_text: str, flags: int = re.IGNORECASE | re.MULTILIN
Or json block
Error: This should be red
Advice: This should be orange
Hint: This should be blue
```json
{
"status": "success",
Expand All @@ -246,5 +212,7 @@ def extract_command(markdown_text: str, flags: int = re.IGNORECASE | re.MULTILIN
```
## you can find the code at https://github.com/yorevs
### Emailto: yorevs@example.com
"""
display_text(s)
2 changes: 1 addition & 1 deletion src/main/askai/language/language.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ def __init__(self, locale: str, name: str, country: str):
self._language, self._territory = lang[0], lang[1]

def __str__(self):
return f"'{self.name}' / '{self.country}' Encoding: '{self.encoding}'"
return f"{self.name} - '{self.country}' encoding: '{self.encoding}'"

@property
def locale(self) -> tuple:
Expand Down
4 changes: 2 additions & 2 deletions src/main/askai/resources/assets/prompts/analysis-prompt.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ Before responding to the user, it is imperative that you follow the step-by-step

4. Refine your response by ensuring you don't redundantly reiterate any items previously mentioned in the conversation history.

5. When the output includes a list, limit showing 5 items and append a summary (Example: \nTotal files:33, Omitted:5\n). Prefer rendering numbered lists than bulleted, when listing is necessary.
5. Start your response with the phrase: "Analysing the provided data\n"

6. Start your response with the phrase: Analysing the provided data\n
6. When the output includes a list, limit showing 5 items and append to the end of it a summary (Example: \n`Total files: 33, Omitted: 5`\n). Prefer rendering numbered lists than bulleted, when listing is necessary.

7. Wrap up your reply by offering a summarized analysis about the content; prefix with: 'Analysis:'.
9 changes: 5 additions & 4 deletions src/main/askai/resources/assets/prompts/output-prompt.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ Before responding to the user, it is imperative that you follow the step-by-step

3. Create a summarized and accessible version of its content.

4. When the output includes a list, limit showing 5 items and append a summary (Example: \nTotal files:33, Omitted:5\n). Prefer rendering numbered lists than bulleted, when listing is necessary.
4. Start your response with the phrase: "Here is a summarized version\n"

5. When the provided output contains files or folders listing, specify whether each item is a file or folder, and its size.
5. When the output includes a list, limit showing 5 items and append to the end of it a summary (Example: \n`Total files: 33, Omitted: 5`\n). Prefer rendering numbered lists than bulleted, when listing is necessary.

6. When the provided output does not contain files or folders listing, create a small analysis of the provided data.
6. When the provided output contains files or folders listing, specify whether each item is a file or folder, and its size.

7. When the provided output does not contain files or folders listing, create a small analysis of the provided data.

7. Start your response with the phrase: Here is a summarized version\n\n

8. Wrap up your reply by offering a succinct hint or tip related to the answer; prefix with: 'Hints:'.

0 comments on commit 7deb5f3

Please sign in to comment.