Compare commits
8 Commits
f5b185505e
...
b88a6b9a92
| Author | SHA1 | Date | |
|---|---|---|---|
| b88a6b9a92 | |||
| 6eca2003a1 | |||
| 922e66e4ee | |||
| 68a2e99c3c | |||
| 2c589281b9 | |||
| 029e54ac14 | |||
| fa5d88f7a1 | |||
| 4b54e96ab5 |
@ -60,17 +60,13 @@ class Chat:
|
||||
@dataclass
|
||||
class ChatDir(Chat):
|
||||
"""
|
||||
A 'Chat' class that is bound to a given directory structure. Supports reading
|
||||
and writing messages from / to that structure. Such a structure consists of
|
||||
two directories: a 'cache directory', where all messages are temporarily
|
||||
stored, and a 'DB' directory, where selected messages can be stored
|
||||
persistently.
|
||||
A Chat class that is bound to a given directory. Supports reading
|
||||
and writing messages from / to that directory.
|
||||
"""
|
||||
|
||||
default_file_suffix: ClassVar[str] = '.txt'
|
||||
|
||||
cache_path: pathlib.Path
|
||||
db_path: pathlib.Path
|
||||
directory: pathlib.Path
|
||||
# a MessageFilter that all messages must match (if given)
|
||||
mfilter: Optional[MessageFilter] = None
|
||||
file_suffix: str = default_file_suffix
|
||||
@ -79,24 +75,17 @@ class ChatDir(Chat):
|
||||
|
||||
@classmethod
|
||||
def from_dir(cls: Type[ChatDirInst],
|
||||
cache_path: pathlib.Path,
|
||||
db_path: pathlib.Path,
|
||||
path: pathlib.Path,
|
||||
glob: Optional[str] = None,
|
||||
mfilter: Optional[MessageFilter] = None) -> ChatDirInst:
|
||||
"""
|
||||
Create a 'ChatDir' instance from the given directory structure.
|
||||
Reads all messages from 'db_path' into the local message list.
|
||||
Parameters:
|
||||
* 'cache_path': path to the directory for temporary messages
|
||||
* 'db_path': path to the directory for persistent messages
|
||||
* 'glob' fs specified, files will be filtered using 'path.glob()',
|
||||
otherwise it uses 'path.iterdir()'.
|
||||
* 'mfilter': use with 'Message.from_file()' to filter messages
|
||||
when reading them.
|
||||
Create a ChatDir instance from the given directory. If 'glob' is specified,
|
||||
files will be filtered using 'path.glob()', otherwise it uses 'path.iterdir()'.
|
||||
Messages are created using 'Message.from_file()' and the optional MessageFilter.
|
||||
"""
|
||||
messages: list[Message] = []
|
||||
message_files: set[str] = set()
|
||||
file_iter = db_path.glob(glob) if glob else db_path.iterdir()
|
||||
file_iter = path.glob(glob) if glob else path.iterdir()
|
||||
for file_path in sorted(file_iter):
|
||||
if file_path.is_file():
|
||||
try:
|
||||
@ -106,12 +95,11 @@ class ChatDir(Chat):
|
||||
message_files.add(file_path.name)
|
||||
except MessageError as e:
|
||||
print(f"Error processing message in '{file_path}': {str(e)}")
|
||||
return cls(messages, cache_path, db_path, mfilter, cls.default_file_suffix, message_files)
|
||||
return cls(messages, path, mfilter, cls.default_file_suffix, message_files)
|
||||
|
||||
@classmethod
|
||||
def from_messages(cls: Type[ChatDirInst],
|
||||
cache_path: pathlib.Path,
|
||||
db_path: pathlib.Path,
|
||||
path: pathlib.Path,
|
||||
messages: list[Message],
|
||||
mfilter: Optional[MessageFilter]) -> ChatDirInst:
|
||||
"""
|
||||
@ -120,10 +108,10 @@ class ChatDir(Chat):
|
||||
in order to synchronize the messages. 'update()' is not
|
||||
supported until after the first 'dump()'.
|
||||
"""
|
||||
return cls(messages, cache_path, db_path, mfilter)
|
||||
return cls(messages, path, mfilter)
|
||||
|
||||
def get_next_fid(self) -> int:
|
||||
next_fname = self.db_path / '.next'
|
||||
next_fname = self.directory / '.next'
|
||||
try:
|
||||
with open(next_fname, 'r') as f:
|
||||
return int(f.read()) + 1
|
||||
@ -131,16 +119,18 @@ class ChatDir(Chat):
|
||||
return 1
|
||||
|
||||
def set_next_fid(self, fid: int) -> None:
|
||||
next_fname = self.db_path / '.next'
|
||||
next_fname = self.directory / '.next'
|
||||
with open(next_fname, 'w') as f:
|
||||
f.write(f'{fid}')
|
||||
|
||||
def dump(self, to_db: bool = False, force_all: bool = False) -> None:
|
||||
def dump(self, force_all: bool = False) -> None:
|
||||
"""
|
||||
Writes all messages to the 'cache_path' or 'db_path'. If a message has no file_path,
|
||||
it will create a new one. By default, only messages that have not been written
|
||||
(or read) before will be dumped. Use 'force_all' to force writing all message files.
|
||||
Writes all messages to the bound directory. If a message has no file_path,
|
||||
it will create a new one. By default, only messages that have not been
|
||||
written (or read) before will be dumped. Use 'force_all' to force writing
|
||||
all message files.
|
||||
"""
|
||||
# FIXME: write to 'db' subfolder or given folder
|
||||
for message in self.messages:
|
||||
# skip messages that we have already written (or read)
|
||||
if message.file_path and message.file_path in self.message_files and not force_all:
|
||||
@ -148,7 +138,6 @@ class ChatDir(Chat):
|
||||
file_path = message.file_path
|
||||
if not file_path:
|
||||
fid = self.get_next_fid()
|
||||
fname = f"{fid:04d}{self.file_suffix}"
|
||||
file_path = self.db_path / fname if to_db else self.cache_path / fname
|
||||
file_path = self.directory / f"{fid:04d}{self.file_suffix}"
|
||||
self.set_next_fid(fid)
|
||||
message.to_file(file_path)
|
||||
|
||||
@ -187,7 +187,7 @@ class Message():
|
||||
and a file path.
|
||||
"""
|
||||
question: Question
|
||||
answer: Optional[Answer] = None
|
||||
answer: Optional[Answer] = None # FIXME: support multiple answers
|
||||
tags: Optional[set[Tag]] = None
|
||||
ai: Optional[str] = None
|
||||
model: Optional[str] = None
|
||||
@ -409,15 +409,5 @@ class Message():
|
||||
return False
|
||||
return True
|
||||
|
||||
def file_id(self) -> str:
|
||||
"""
|
||||
Returns an ID that is unique within the directory of this message.
|
||||
Currently this is simply the file name.
|
||||
"""
|
||||
if self.file_path:
|
||||
return self.file_path.name
|
||||
else:
|
||||
raise MessageError("Can't create file ID without a file path")
|
||||
|
||||
def as_dict(self) -> dict[str, Any]:
|
||||
return asdict(self)
|
||||
|
||||
@ -575,23 +575,3 @@ This is an answer.
|
||||
def test_tags_from_file_yaml(self) -> None:
|
||||
tags = Message.tags_from_file(self.file_path_yaml)
|
||||
self.assertSetEqual(tags, {Tag('tag1'), Tag('tag2')})
|
||||
|
||||
|
||||
class MessageFileIDTxtTestCase(CmmTestCase):
|
||||
def setUp(self) -> None:
|
||||
self.file = tempfile.NamedTemporaryFile(delete=False, suffix='.txt')
|
||||
self.file_path = pathlib.Path(self.file.name)
|
||||
self.message = Message(Question('This is a question.'),
|
||||
file_path=self.file_path)
|
||||
self.message_no_file_path = Message(Question('This is a question.'))
|
||||
|
||||
def tearDown(self) -> None:
|
||||
self.file.close()
|
||||
self.file_path.unlink()
|
||||
|
||||
def test_file_id_txt(self) -> None:
|
||||
self.assertEqual(self.message.file_id(), self.file_path.name)
|
||||
|
||||
def test_file_id_txt_exception(self) -> None:
|
||||
with self.assertRaises(MessageError):
|
||||
self.message_no_file_path.file_id()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user