Skip to content

Commit

Permalink
Split the query and history dbus implementations
Browse files Browse the repository at this point in the history
This will allow us to interact separatedly in dbus for the query and
history commands. Having their own implementation, context and etc...

This will allow for more control over the next iterations
  • Loading branch information
r0x0d committed Dec 16, 2024
1 parent 95b28cc commit d82e15e
Show file tree
Hide file tree
Showing 19 changed files with 558 additions and 193 deletions.
16 changes: 11 additions & 5 deletions command_line_assistant/commands/history.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import logging
from argparse import Namespace
from pathlib import Path

from command_line_assistant.history import handle_history_write
from dasbus.error import DBusError

from command_line_assistant.dbus.constants import HISTORY_IDENTIFIER
from command_line_assistant.utils.cli import BaseCLICommand, SubParsersAction

logger = logging.getLogger(__name__)
Expand All @@ -14,10 +15,15 @@ def __init__(self, clear: bool) -> None:
super().__init__()

def run(self) -> None:
proxy = HISTORY_IDENTIFIER.get_proxy()

if self._clear:
logger.info("Clearing history of conversation")
# TODO(r0x0d): Rewrite this.
handle_history_write(Path("/tmp/test_history.json"), [], "")
try:
logger.info("Cleaning the history.")
proxy.ClearHistory()
except DBusError as e:
logger.info("Failed to clean the history: %s", e)
raise e


def register_subcommand(parser: SubParsersAction):
Expand Down
13 changes: 6 additions & 7 deletions command_line_assistant/commands/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

from dasbus.error import DBusError

from command_line_assistant.dbus.constants import SERVICE_IDENTIFIER
from command_line_assistant.dbus.definitions import MessageInput, MessageOutput
from command_line_assistant.dbus.constants import QUERY_IDENTIFIER
from command_line_assistant.dbus.structures import Message
from command_line_assistant.rendering.decorators.colors import ColorDecorator
from command_line_assistant.rendering.decorators.text import (
EmojiDecorator,
Expand Down Expand Up @@ -68,16 +68,15 @@ def __init__(self, query_string: str) -> None:
super().__init__()

def run(self) -> None:
proxy = SERVICE_IDENTIFIER.get_proxy()

input_query = MessageInput()
proxy = QUERY_IDENTIFIER.get_proxy()
input_query = Message()
input_query.message = self._query

output = "Nothing to see here..."
try:
with self._spinner_renderer:
proxy.ProcessQuery(MessageInput.to_structure(input_query))
output = MessageOutput.from_structure(proxy.RetrieveAnswer).message
proxy.ProcessQuery(input_query.to_structure(input_query))
output = Message.from_structure(proxy.RetrieveAnswer).message

self._legal_renderer.render(LEGAL_NOTICE)
self._text_renderer.render(output)
Expand Down
4 changes: 2 additions & 2 deletions command_line_assistant/daemon/http/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def submit(query: str, config: Config) -> str:
query = handle_caret(query, config)
# NOTE: Add more query handling here

query_endpoint = f"{config.backend.endpoint}/infer"
query_endpoint = f"{config.backend.endpoint}/v1/query"
payload = {"query": query}

try:
Expand All @@ -33,7 +33,7 @@ def submit(query: str, config: Config) -> str:

response.raise_for_status()
data = response.json()
return data.get("answer", "")
return data.get("response", "")
except RequestException as e:
logger.error("Failed to get response from AI: %s", e)
raise
11 changes: 9 additions & 2 deletions command_line_assistant/dbus/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,14 @@

SERVICE_NAMESPACE = ("com", "redhat", "lightspeed")

QUERY_NAMESAPCE = (*SERVICE_NAMESPACE, "query")
HISTORY_NAMESPACE = (*SERVICE_NAMESPACE, "history")

# Define the service identifier for a query
SERVICE_IDENTIFIER = DBusServiceIdentifier(
namespace=SERVICE_NAMESPACE, message_bus=SESSION_BUS
QUERY_IDENTIFIER = DBusServiceIdentifier(
namespace=QUERY_NAMESAPCE, message_bus=SESSION_BUS
)
# Define the service identifier for a history
HISTORY_IDENTIFIER = DBusServiceIdentifier(
namespace=HISTORY_NAMESPACE, message_bus=SESSION_BUS
)
46 changes: 46 additions & 0 deletions command_line_assistant/dbus/context.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
from typing import Optional

from dasbus.signal import Signal

from command_line_assistant.config import Config
from command_line_assistant.dbus.structures import Message


class BaseContext:
def __init__(self, config: Config) -> None:
self._config = config

@property
def config(self) -> Config:
"""Return the configuration from this context."""
return self._config


class QueryContext(BaseContext):
"""This is the process context that will handle anything query related"""

def __init__(self, config: Config) -> None:
self._input_query: Optional[Message] = None
self._query_changed = Signal()
super().__init__(config)

@property
def query(self) -> Optional[Message]:
"""Make it accessible publicly"""
return self._input_query

@property
def query_changed(self) -> Signal:
return self._query_changed

def process_query(self, input_query: Message) -> None:
"""Emit the signal that the query has changed"""
self._input_query = input_query
self._query_changed.emit()


class HistoryContext(BaseContext):
"""This is the process context that will handle anything query related"""

def __init__(self, config: Config) -> None:
super().__init__(config)
97 changes: 0 additions & 97 deletions command_line_assistant/dbus/definitions.py

This file was deleted.

50 changes: 50 additions & 0 deletions command_line_assistant/dbus/interfaces.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from dasbus.server.interface import dbus_interface
from dasbus.server.property import emits_properties_changed
from dasbus.server.template import InterfaceTemplate
from dasbus.typing import Structure

from command_line_assistant.daemon.http.query import submit
from command_line_assistant.dbus.constants import HISTORY_IDENTIFIER, QUERY_IDENTIFIER
from command_line_assistant.dbus.structures import (
HistoryEntry,
Message,
)
from command_line_assistant.history import handle_history_read, handle_history_write


@dbus_interface(QUERY_IDENTIFIER.interface_name)
class QueryInterface(InterfaceTemplate):
"""The DBus interface of a query."""

def connect_signals(self) -> None:
"""Connect the signals."""
# Watch for property changes based on the query_changed method.
self.watch_property("RetrieveAnswer", self.implementation.query_changed)

@property
def RetrieveAnswer(self) -> Structure:
"""This method is mainly called by the client to retrieve it's answer."""
output = Message()
llm_response = submit(
self.implementation.query.message, self.implementation.config
)
print("llm_response", llm_response)
output.message = llm_response
return Message.to_structure(output)

@emits_properties_changed
def ProcessQuery(self, query: Structure) -> None:
"""Process the given query."""
self.implementation.process_query(Message.from_structure(query))


@dbus_interface(HISTORY_IDENTIFIER.interface_name)
class HistoryInterface(InterfaceTemplate):
@property
def GetHistory(self) -> Structure:
history = HistoryEntry()
history.entries = handle_history_read(self.implementation.config)
return history.to_structure(history)

def ClearHistory(self) -> None:
handle_history_write(self.implementation.config.history.file, [], "")
20 changes: 15 additions & 5 deletions command_line_assistant/dbus/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@
from dasbus.loop import EventLoop

from command_line_assistant.config import Config
from command_line_assistant.dbus.constants import SERVICE_IDENTIFIER, SESSION_BUS
from command_line_assistant.dbus.definitions import ProcessContext, QueryInterface
from command_line_assistant.dbus.constants import (
HISTORY_IDENTIFIER,
QUERY_IDENTIFIER,
SESSION_BUS,
)
from command_line_assistant.dbus.context import HistoryContext, QueryContext
from command_line_assistant.dbus.interfaces import HistoryInterface, QueryInterface

logger = logging.getLogger(__name__)

Expand All @@ -14,16 +19,21 @@ def serve(config: Config):
"""Start the daemon."""
logger.info("Starting clad!")
try:
process_context = ProcessContext(config=config)
SESSION_BUS.publish_object(
SERVICE_IDENTIFIER.object_path, QueryInterface(process_context)
QUERY_IDENTIFIER.object_path, QueryInterface(QueryContext(config))
)
SESSION_BUS.publish_object(
HISTORY_IDENTIFIER.object_path, HistoryInterface(HistoryContext(config))
)

# The flag DBUS_NAME_FLAG_REPLACE_EXISTING is needed during development
# so ew can replace the existing bus.
# TODO(r0x0d): See what to do with it later.
SESSION_BUS.register_service(
SERVICE_IDENTIFIER.service_name, flags=DBUS_NAME_FLAG_REPLACE_EXISTING
QUERY_IDENTIFIER.service_name, flags=DBUS_NAME_FLAG_REPLACE_EXISTING
)
SESSION_BUS.register_service(
HISTORY_IDENTIFIER.service_name, flags=DBUS_NAME_FLAG_REPLACE_EXISTING
)
loop = EventLoop()
loop.run()
Expand Down
32 changes: 32 additions & 0 deletions command_line_assistant/dbus/structures.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from dasbus.structure import DBusData
from dasbus.typing import Str


class Message(DBusData):
"""Base class for message input and output"""

def __init__(self) -> None:
self._message: Str = ""
super().__init__()

@property
def message(self) -> Str:
return self._message

@message.setter
def message(self, value: Str) -> None:
self._message = value


class HistoryEntry(DBusData):
def __init__(self) -> None:
self._entries: list[str] = []
super().__init__()

@property
def entries(self) -> list[str]:
return self._entries

@entries.setter
def entries(self, value: list[str]) -> None:
self._entries = value
2 changes: 1 addition & 1 deletion data/development/config/command_line_assistant/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ file = "~/.local/share/command-line-assistant/command-line-assistant_history.jso
max_size = 100

[backend]
endpoint = "https://rlsrag-rhel-lightspeed--runtime-int.apps.int.spoke.preprod.us-east-1.aws.paas.redhat.com"
endpoint = "https://rcs-rhel-lightspeed--runtime-int.apps.int.spoke.preprod.us-east-1.aws.paas.redhat.com"

[backend.auth]
cert_file = "data/development/certificate/fake-certificate.pem"
Expand Down
Loading

0 comments on commit d82e15e

Please sign in to comment.