Skip to content

Commit f8948d2

Browse files
committed
Change events.reply(_error) with message: str to reply: AIReply - Fixes
1 parent ebbd1bb commit f8948d2

File tree

8 files changed

+183
-115
lines changed

8 files changed

+183
-115
lines changed

src/main/askai/core/askai.py

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,22 @@
1212
1313
Copyright (c) 2024, HomeSetup
1414
"""
15+
import logging as log
16+
import os
17+
import re
18+
import sys
19+
from enum import Enum
20+
from pathlib import Path
21+
from typing import List, Optional, TypeAlias
22+
23+
from click import UsageError
24+
from hspylib.core.enums.charset import Charset
25+
from hspylib.core.tools.commons import file_is_not_empty, is_debugging
26+
from hspylib.core.zoned_datetime import DATE_FORMAT, now, TIME_FORMAT
27+
from hspylib.modules.application.exit_status import ExitStatus
28+
from hspylib.modules.eventbus.event import Event
29+
from openai import RateLimitError
30+
1531
from askai.__classpath__ import classpath
1632
from askai.core.askai_configs import configs
1733
from askai.core.askai_events import events
@@ -29,21 +45,6 @@
2945
from askai.exception.exceptions import (ImpossibleQuery, InaccurateResponse, IntelligibleAudioError,
3046
MaxInteractionsReached, TerminatingQuery)
3147
from askai.tui.app_icons import AppIcons
32-
from click import UsageError
33-
from enum import Enum
34-
from hspylib.core.enums.charset import Charset
35-
from hspylib.core.tools.commons import file_is_not_empty, is_debugging
36-
from hspylib.core.zoned_datetime import DATE_FORMAT, now, TIME_FORMAT
37-
from hspylib.modules.application.exit_status import ExitStatus
38-
from hspylib.modules.eventbus.event import Event
39-
from openai import RateLimitError
40-
from pathlib import Path
41-
from typing import AnyStr, List, Optional, TypeAlias
42-
43-
import logging as log
44-
import os
45-
import re
46-
import sys
4748

4849
QueryString: TypeAlias = str | List[str] | None
4950

@@ -196,15 +197,15 @@ def _create_console_file(self, overwrite: bool = True) -> None:
196197
)
197198
f_console.flush()
198199

199-
def _reply(self, message: AnyStr) -> None:
200+
def _reply(self, reply: AIReply) -> None:
200201
"""Reply to the user with the AI-generated response.
201-
:param message: The message to send as a reply to the user.
202+
:param reply: The reply message to send as a reply to the user.
202203
"""
203204
...
204205

205-
def _reply_error(self, message: AnyStr) -> None:
206+
def _reply_error(self, reply: AIReply) -> None:
206207
"""Reply to the user with an AI-generated error message or system error.
207-
:param message: The error message to be displayed to the user.
208+
:param reply: The error reply message to be displayed to the user.
208209
"""
209210
...
210211

src/main/askai/core/askai_cli.py

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,20 @@
1212
1313
Copyright (c) 2024, HomeSetup
1414
"""
15+
import logging as log
16+
import os
17+
from pathlib import Path
18+
from threading import Thread
19+
from typing import List, TypeAlias
20+
21+
import nltk
22+
import pause
23+
from clitt.core.term.cursor import cursor
24+
from clitt.core.term.screen import screen
25+
from clitt.core.tui.line_input.keyboard_input import KeyboardInput
26+
from hspylib.modules.eventbus.event import Event
27+
from rich.progress import Progress
28+
1529
from askai.core.askai import AskAi
1630
from askai.core.askai_configs import configs
1731
from askai.core.askai_events import *
@@ -25,19 +39,6 @@
2539
from askai.core.support.shared_instances import shared
2640
from askai.core.support.text_formatter import text_formatter
2741
from askai.core.support.utilities import display_text
28-
from clitt.core.term.cursor import cursor
29-
from clitt.core.term.screen import screen
30-
from clitt.core.tui.line_input.keyboard_input import KeyboardInput
31-
from hspylib.modules.eventbus.event import Event
32-
from pathlib import Path
33-
from rich.progress import Progress
34-
from threading import Thread
35-
from typing import AnyStr, List, TypeAlias
36-
37-
import logging as log
38-
import nltk
39-
import os
40-
import pause
4142

4243
QueryString: TypeAlias = str | List[str] | None
4344

@@ -87,26 +88,26 @@ def run(self) -> None:
8788
self._reply(msg.goodbye())
8889
display_text("", markdown=False)
8990

90-
def _reply(self, message: AnyStr) -> None:
91+
def _reply(self, reply: AIReply) -> None:
9192
"""Reply to the user with the AI-generated response.
92-
:param message: The message to send as a reply to the user.
93+
:param reply: The reply message to send as a reply to the user.
9394
"""
94-
if message and (text := msg.translate(message)):
95-
log.debug(message)
96-
if configs.is_speak:
95+
if reply and (text := msg.translate(reply.message)):
96+
log.debug(reply.message)
97+
if configs.is_speak and reply.is_speakable:
9798
self.engine.text_to_speech(text, f"{shared.nickname}")
9899
elif not configs.is_interactive:
99100
display_text(text_formatter.strip_format(text), f"{shared.nickname}", markdown=False)
100101
else:
101102
display_text(text, f"{shared.nickname}")
102103

103-
def _reply_error(self, message: AnyStr) -> None:
104+
def _reply_error(self, reply: AIReply) -> None:
104105
"""Reply to the user with an AI-generated error message or system error.
105-
:param message: The error message to be displayed to the user.
106+
:param reply: The error reply message to be displayed to the user.
106107
"""
107-
if message and (text := msg.translate(message)):
108-
log.error(message)
109-
if configs.is_speak:
108+
if reply and (text := msg.translate(reply.message)):
109+
log.error(reply.message)
110+
if configs.is_speak and reply.is_speakable:
110111
self.engine.text_to_speech(f"Error: {text}", f"{shared.nickname}")
111112
else:
112113
display_text(f"%RED%Error: {text}%NC%", f"{shared.nickname}")
@@ -124,12 +125,12 @@ def _cb_reply_event(self, ev: Event) -> None:
124125
reply: AIReply
125126
if reply := ev.args.reply:
126127
if reply.is_error:
127-
self._reply_error(str(reply))
128+
self._reply_error(reply)
128129
else:
129-
if ev.args.reply.verbosity <= 1 or configs.is_debug:
130+
if ev.args.reply.verbosity.match(configs.verbosity) or configs.is_debug:
130131
if ev.args.erase_last:
131132
cursor.erase_line()
132-
self._reply(str(reply))
133+
self._reply(reply)
133134

134135
def _cb_mic_listening_event(self, ev: Event) -> None:
135136
"""Callback to handle microphone listening events.

src/main/askai/core/askai_configs.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,17 @@
1212
1313
Copyright (c) 2024, HomeSetup
1414
"""
15-
from askai.__classpath__ import classpath
16-
from askai.core.askai_settings import settings
17-
from askai.language.language import Language
15+
import locale
16+
import os
17+
from shutil import which
18+
1819
from hspylib.core.enums.charset import Charset
1920
from hspylib.core.metaclass.singleton import Singleton
20-
from shutil import which
2121

22-
import locale
23-
import os
22+
from askai.__classpath__ import classpath
23+
from askai.core.askai_settings import settings
24+
from askai.core.enums.verbosity import Verbosity
25+
from askai.language.language import Language
2426

2527

2628
class AskAiConfigs(metaclass=Singleton):
@@ -98,6 +100,10 @@ def ttl(self) -> int:
98100
def ttl(self, value: int) -> None:
99101
settings.put("askai.cache.ttl.minutes", value)
100102

103+
@property
104+
def verbosity(self) -> Verbosity:
105+
return Verbosity.of_value(settings.get_int("askai.verbosity.level"))
106+
101107
@property
102108
def chunk_size(self) -> int:
103109
return settings.get_int("askai.text.splitter.chunk.size")

src/main/askai/core/askai_settings.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,22 @@
1212
1313
Copyright (c) 2024, HomeSetup
1414
"""
15-
from askai.__classpath__ import classpath
15+
import logging as log
16+
import os
17+
import re
1618
from contextlib import redirect_stdout
17-
from hspylib.core.metaclass.singleton import Singleton
18-
from hspylib.core.tools.commons import console_out, to_bool
1919
from io import StringIO
2020
from pathlib import Path
21+
from typing import Any, Optional
22+
23+
from hspylib.core.metaclass.singleton import Singleton
24+
from hspylib.core.tools.commons import console_out, to_bool
2125
from rich.table import Table
2226
from setman.settings.settings import Settings
2327
from setman.settings.settings_config import SettingsConfig
2428
from setman.settings.settings_entry import SettingsEntry
25-
from typing import Any, Optional
2629

27-
import logging as log
28-
import os
29-
import re
30+
from askai.__classpath__ import classpath
3031

3132
# AskAI config directory.
3233
ASKAI_DIR: Path = Path(f'{os.getenv("ASKAI_DIR", os.getenv("HHS_DIR", str(Path.home())))}/askai')
@@ -43,7 +44,7 @@ class AskAiSettings(metaclass=Singleton):
4344
INSTANCE: "AskAiSettings"
4445

4546
# Current settings version. Updating this value will trigger a database recreation using the defaults.
46-
_ACTUAL_VERSION: str = "0.1.91"
47+
_ACTUAL_VERSION: str = "0.1.92"
4748

4849
RESOURCE_DIR = str(classpath.resource_path())
4950

@@ -99,6 +100,7 @@ def defaults(self) -> None:
99100
self._settings.put("askai.preferred.language", "askai", "")
100101
self._settings.put("askai.default.engine", "askai", "openai")
101102
self._settings.put("askai.default.engine.model", "askai", "gpt-4o-mini")
103+
self._settings.put("askai.verbosity.level", "askai", 3)
102104
self._settings.put("askai.text.to.speech.tempo", "askai", 1)
103105
self._settings.put("askai.text.splitter.chunk.size", "askai", 1000)
104106
self._settings.put("askai.text.splitter.chunk.overlap", "askai", 100)

src/main/askai/core/component/audio_player.py

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,21 @@
1212
1313
Copyright (c) 2024, HomeSetup
1414
"""
15-
from askai.__classpath__ import classpath
16-
from askai.core.askai_configs import configs
17-
from clitt.core.term.terminal import Terminal
15+
import logging as log
16+
import time
1817
from functools import lru_cache
18+
from pathlib import Path
19+
from shutil import which
20+
from typing import Literal
21+
22+
from clitt.core.term.terminal import Terminal
1923
from hspylib.core.metaclass.singleton import Singleton
2024
from hspylib.core.preconditions import check_argument
2125
from hspylib.core.tools.commons import file_is_not_empty
2226
from hspylib.core.tools.text_tools import ensure_endswith
2327
from hspylib.modules.application.exit_status import ExitStatus
24-
from pathlib import Path
25-
from shutil import which
26-
from typing import Literal
2728

28-
import logging as log
29-
import time
29+
from askai.__classpath__ import classpath
3030

3131

3232
class AudioPlayer(metaclass=Singleton):
@@ -46,9 +46,7 @@ def play_audio_file(path_to_audio_file: str | Path, tempo: int = 1) -> bool:
4646
:param tempo: The playback speed (default is 1).
4747
:return: True if the audio file is played successfully, otherwise False.
4848
"""
49-
if not configs.is_speak:
50-
return True
51-
elif file_is_not_empty(str(path_to_audio_file)):
49+
if file_is_not_empty(str(path_to_audio_file)):
5250
try:
5351
out, code = Terminal.shell_exec(
5452
f'ffplay -af "atempo={tempo}" -v 0 -nodisp -autoexit {path_to_audio_file}'
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
from hspylib.core.enums.enumeration import Enumeration
2+
3+
4+
class Verbosity(Enumeration):
5+
"""Represents different verbosity levels for logging or output.
6+
Attributes:
7+
MINIMUM (int): The minimum verbosity level.
8+
LOW (int): A low verbosity level.
9+
NORMAL (int): The normal verbosity level.
10+
DETAILED (int): A detailed verbosity level.
11+
FULL (int): The full verbosity level.
12+
"""
13+
14+
# fmt: off
15+
MINIMUM = 1
16+
LOW = 2
17+
NORMAL = 3
18+
DETAILED = 4
19+
FULL = 5
20+
# fmt: on
21+
22+
@property
23+
def val(self) -> int:
24+
"""Gets the integer value of the verbosity level.
25+
:return: The integer representation of the verbosity level.
26+
"""
27+
return int(self.value)
28+
29+
def match(self, level: 'Verbosity') -> bool:
30+
"""Checks if the current verbosity level is less than or equal to the given level.
31+
:param level: The verbosity level to compare against.
32+
:return: True if the current level is less than or equal to the given level, otherwise False.
33+
"""
34+
return self.val <= level.val
35+

src/main/askai/core/model/ai_reply.py

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,44 +14,68 @@
1414
"""
1515

1616
from dataclasses import dataclass
17-
from typing import AnyStr, Literal, TypeAlias
17+
from typing import AnyStr
1818

19-
Verbosity: TypeAlias = Literal[1, 2, 3, 4, 5]
19+
from askai.core.enums.verbosity import Verbosity
2020

2121

2222
@dataclass(frozen=True)
2323
class AIReply:
24-
"""Data class that represents AI replies."""
24+
"""Data class that represents AI replies.
25+
:param message: The reply message.
26+
:param is_success: Indicates whether the reply is successful.
27+
:param is_debug: Indicates whether the reply is for debugging.
28+
:param verbosity: The verbosity level of the reply.
29+
:param is_speakable: Indicates whether the reply is speakable.
30+
"""
2531

2632
message: str = ""
2733
is_success: bool = True
2834
is_debug: bool = False
29-
verbosity: Verbosity = 1
35+
verbosity: Verbosity = Verbosity.MINIMUM
3036
is_speakable: bool = True
3137

3238
def __str__(self) -> str:
3339
return self.message
3440

3541
@staticmethod
36-
def info(message: AnyStr, verbosity: Verbosity = 1, speakable: bool = True) -> "AIReply":
37-
"""TODO"""
42+
def info(message: AnyStr, verbosity: Verbosity = Verbosity.NORMAL, speakable: bool = True) -> "AIReply":
43+
"""Creates an info reply.
44+
:param message: The reply message.
45+
:param verbosity: The verbosity level of the reply.
46+
:param speakable: Indicates whether the reply is speakable.
47+
:return: An AIReply instance with info settings.
48+
"""
3849
return AIReply(str(message), True, False, verbosity, speakable)
3950

4051
@staticmethod
4152
def error(message: AnyStr) -> "AIReply":
42-
"""TODO"""
43-
return AIReply(str(message), True, False, 1, False)
53+
"""Creates an error reply.
54+
:param message: The reply message.
55+
:return: An AIReply instance with error settings.
56+
"""
57+
return AIReply(str(message), False, False, Verbosity.NORMAL, False)
4458

4559
@staticmethod
4660
def debug(message: AnyStr) -> "AIReply":
47-
"""TODO"""
48-
return AIReply(str(message), True, True, 1, False)
61+
"""Creates a debug reply.
62+
:param message: The reply message.
63+
:return: An AIReply instance with debug settings.
64+
"""
65+
return AIReply(str(message), True, True, Verbosity.NORMAL, False)
4966

5067
@staticmethod
51-
def mute(message: AnyStr, verbosity: Verbosity = 1) -> "AIReply":
52-
"""TODO"""
68+
def mute(message: AnyStr, verbosity: Verbosity = Verbosity.NORMAL) -> "AIReply":
69+
"""Creates a mute reply.
70+
:param message: The reply message.
71+
:param verbosity: The verbosity level of the reply.
72+
:return: An AIReply instance with mute settings.
73+
"""
5374
return AIReply(str(message), True, False, verbosity, False)
5475

5576
@property
5677
def is_error(self) -> bool:
78+
"""Checks if the reply indicates an error.
79+
:return: True if the reply is not successful, otherwise False.
80+
"""
5781
return not self.is_success

0 commit comments

Comments
 (0)