Skip to content

Commit 4b52010

Browse files
authored
Merge pull request #11 from jgwill/coaia-10-add-fetch-command
Add fetch command to retrieve memory keys from Redis
2 parents a1a0fb8 + 5818beb commit 4b52010

File tree

5 files changed

+146
-4
lines changed

5 files changed

+146
-4
lines changed

.github/workflows/python-ci.yml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
name: Python CI
2+
3+
on:
4+
push:
5+
branches: [main, "**"]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
13+
strategy:
14+
matrix:
15+
python-version: [3.11]
16+
17+
steps:
18+
- name: Checkout code
19+
uses: actions/checkout@v3
20+
21+
- name: Set up Python ${{ matrix.python-version }}
22+
uses: actions/setup-python@v4
23+
with:
24+
python-version: ${{ matrix.python-version }}
25+
26+
- name: Install dependencies
27+
run: |
28+
python -m pip install --upgrade pip
29+
pip install -r requirements.txt
30+
pip install pytest
31+
32+
- name: Run tests
33+
run: |
34+
pytest -v

README.md

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,32 @@ Example:
111111
coaia tash my_key --f path/to/value/file.txt
112112
```
113113

114+
#### Fetch Value from Redis
115+
116+
To fetch a value from Redis by key:
117+
118+
```bash
119+
coaia fetch <key>
120+
```
121+
122+
Example:
123+
124+
```bash
125+
coaia fetch my_key
126+
```
127+
128+
To fetch a value from Redis and save it to a file:
129+
130+
```bash
131+
coaia fetch <key> --output <file_path>
132+
```
133+
134+
Example:
135+
136+
```bash
137+
coaia fetch my_key --output path/to/output/file.txt
138+
```
139+
114140
#### Process Custom Tags
115141

116142
Enable custom quick addons for assistants or bots using process tags. To add a new process tag to `coaia.json`, include entries like:
@@ -129,4 +155,3 @@ Contributions are welcome! Please open an issue or submit a pull request for any
129155
## License
130156

131157
This project is licensed under the MIT License. See the LICENSE file for more details.
132-

coaiapy/coaiacli.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
1010

11-
from coaiamodule import read_config, transcribe_audio, summarizer, tash, abstract_process_send, initial_setup
11+
from coaiamodule import read_config, transcribe_audio, summarizer, tash, abstract_process_send, initial_setup, fetch_key_val
1212
from cofuse import (
1313
get_comments, post_comment,
1414
create_session_and_save, add_trace_node_and_save,
@@ -157,6 +157,11 @@ def main():
157157
parser_ds_items_create.add_argument('-e','--expected', help="Expected output")
158158
parser_ds_items_create.add_argument('-m','--metadata', help="Optional metadata as JSON string")
159159

160+
# Subparser for 'fetch' command
161+
parser_fetch = subparsers.add_parser('fetch', help='Fetch a value from Redis by key.')
162+
parser_fetch.add_argument('key', type=str, help="The key to fetch.")
163+
parser_fetch.add_argument('-O', '--output', type=str, help="Filename to save the fetched value.")
164+
160165
args = parser.parse_args()
161166

162167
if args.command == 'init':
@@ -210,6 +215,8 @@ def main():
210215
f.write(summary)
211216
else:
212217
print(f"{summary}")
218+
elif args.command == 'fetch':
219+
fetch_key_val(args.key, args.output)
213220
elif args.command == 'fuse':
214221
if args.fuse_command == 'comments':
215222
if args.action == 'list':

coaiapy/coaiamodule.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ def remove_placeholder_lines(text):
9191
# Split the text into lines
9292
lines = text.split('\n')
9393
# Iterate over the lines and remove lines starting with "Placeholder"
94-
cleaned_lines = [line for line in lines if not line.startswith("Placeholder")]
94+
cleaned_lines = [line for line for line in lines if not line.startswith("Placeholder")]
9595

9696
# Join the cleaned lines back into a string
9797
cleaned_text = '\n'.join(cleaned_lines)
@@ -261,7 +261,7 @@ def d2s_send(input_message, temperature=None,pre=''):
261261

262262
temperature = config['d2s_default_temperature'] if temperature is None else temperature
263263

264-
system_instruction = config.get('d2s_instruction', 'You do : Receive a text that requires to put details into shapes. you keep the essence of what is discussed foreach elements you observe and able yo group in the inout text.')
264+
system_instruction = config.get('d2s_instruction', 'You do : Receive a text that requires to put details into shapes. you group elements of different nature and summarize them. REMEMBER: Dont introduce nor conclude, just output results. No comments.')
265265

266266

267267
# Concatenate preprompt_instruction with input_message
@@ -605,6 +605,31 @@ def tash(k:str,v:str,ttl=None,quiet=True):
605605
if not quiet: print('Stashing failed')
606606
return result
607607

608+
def fetch_key_val(key, output_file=None):
609+
try:
610+
jtalecnf = read_config()['jtaleconf']
611+
_r = _newjtaler(jtalecnf)
612+
if _r is None:
613+
print("Error: Redis connection failed.")
614+
sys.exit(2)
615+
value = _r.get(key)
616+
if value is None:
617+
print(f"Error: Key '{key}' not found in Redis memory.")
618+
sys.exit(1)
619+
value = value.decode('utf-8')
620+
if output_file:
621+
with open(output_file, 'w') as file:
622+
file.write(value)
623+
print(f"Key: {key} fetched and saved to {output_file}")
624+
else:
625+
print(value)
626+
except redis.ConnectionError:
627+
print("Error: Redis connection failed.")
628+
sys.exit(2)
629+
except Exception as e:
630+
print(f"Error: {str(e)}")
631+
sys.exit(1)
632+
608633
def initial_setup():
609634
sample_config = {
610635
"username": "SSH_USER",

coaiapy/test_cli_fetch.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import pytest
2+
from unittest.mock import patch, MagicMock
3+
import sys
4+
import os
5+
import io
6+
import redis
7+
from coaiapy.coaiacli import fetch_key_val
8+
9+
# Mock Redis fixture
10+
@pytest.fixture
11+
def mock_redis(monkeypatch):
12+
mock_redis_instance = MagicMock()
13+
monkeypatch.setattr('redis.Redis', lambda *args, **kwargs: mock_redis_instance)
14+
return mock_redis_instance
15+
16+
# Mock broken Redis fixture
17+
@pytest.fixture
18+
def mock_broken_redis(monkeypatch):
19+
mock_redis_instance = MagicMock()
20+
mock_redis_instance.get.side_effect = redis.ConnectionError
21+
monkeypatch.setattr('redis.Redis', lambda *args, **kwargs: mock_redis_instance)
22+
return mock_redis_instance
23+
24+
def test_fetch_stdout_key_found(mock_redis):
25+
mock_redis.get.return_value = b'This is a memory snippet.'
26+
with patch('sys.stdout', new_callable=io.StringIO) as mock_stdout, \
27+
patch('coaiapy.coaiamodule._newjtaler') as mock_newjtaler:
28+
mock_newjtaler.return_value = mock_redis
29+
fetch_key_val('mykey')
30+
assert mock_stdout.getvalue().strip() == 'This is a memory snippet.'
31+
32+
def test_fetch_output_file_key_found(mock_redis):
33+
mock_redis.get.return_value = b'This is a memory snippet.'
34+
output_file = 'memory.txt'
35+
fetch_key_val('mykey', output_file)
36+
with open(output_file, 'r') as file:
37+
assert file.read().strip() == 'This is a memory snippet.'
38+
os.remove(output_file)
39+
40+
def test_fetch_key_not_found_exits_1(mock_redis):
41+
mock_redis.get.return_value = None
42+
with pytest.raises(SystemExit) as pytest_wrapped_e:
43+
fetch_key_val('mykey')
44+
assert pytest_wrapped_e.type == SystemExit
45+
assert pytest_wrapped_e.value.code == 1
46+
47+
def test_fetch_redis_down_exits_2(mock_broken_redis):
48+
with pytest.raises(SystemExit) as pytest_wrapped_e:
49+
fetch_key_val('mykey')
50+
assert pytest_wrapped_e.type == SystemExit
51+
assert pytest_wrapped_e.value.code == 2

0 commit comments

Comments
 (0)