fix: Fix merge conflicts

Refs: OPS-64
This commit is contained in:
Alivecow 2025-03-23 18:12:45 +01:00
commit 1691a7c04b
6 changed files with 152 additions and 43 deletions

25
poetry.lock generated
View file

@ -1,4 +1,4 @@
# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand.
# This file is automatically @generated by Poetry 2.0.1 and should not be changed by hand.
[[package]]
name = "alabaster"
@ -25,7 +25,7 @@ files = [
]
[package.extras]
dev = ["backports.zoneinfo ; python_version < \"3.9\"", "freezegun (>=1.0,<2.0)", "jinja2 (>=3.0)", "pytest (>=6.0)", "pytest-cov", "pytz", "setuptools", "tzdata ; sys_platform == \"win32\""]
dev = ["backports.zoneinfo", "freezegun (>=1.0,<2.0)", "jinja2 (>=3.0)", "pytest (>=6.0)", "pytest-cov", "pytz", "setuptools", "tzdata"]
[[package]]
name = "blinker"
@ -255,7 +255,7 @@ files = [
]
[package.extras]
toml = ["tomli ; python_full_version <= \"3.11.0a6\""]
toml = ["tomli"]
[[package]]
name = "docutils"
@ -514,6 +514,21 @@ tomli = {version = ">=1", markers = "python_version < \"3.11\""}
[package.extras]
dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
[[package]]
name = "pytest-httpserver"
version = "1.1.2"
description = "pytest-httpserver is a httpserver for pytest"
optional = false
python-versions = ">=3.9"
groups = ["main"]
files = [
{file = "pytest_httpserver-1.1.2-py3-none-any.whl", hash = "sha256:93009d79574fc982301e8494fdea0884f21bb0caf3bcc719151dfbd1e3a943ea"},
{file = "pytest_httpserver-1.1.2.tar.gz", hash = "sha256:38d0b726580d05c47cbd0ced1ecb36a51668ef1596cdc6d70a9cfa2b3cc00ebd"},
]
[package.dependencies]
Werkzeug = ">=2.0.0"
[[package]]
name = "requests"
version = "2.32.3"
@ -752,7 +767,7 @@ files = [
]
[package.extras]
brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""]
brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"]
h2 = ["h2 (>=4,<5)"]
socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
zstd = ["zstandard (>=0.18.0)"]
@ -778,4 +793,4 @@ watchdog = ["watchdog (>=2.3)"]
[metadata]
lock-version = "2.1"
python-versions = ">=3.10"
content-hash = "ce9cac7092447dc5d6b3920853bb10fcc166018bc4f48c50925ef09db74e7891"
content-hash = "76f74a5c2443d5c8e9db9433f0bdcc94a1d12c469f8b49dd325f3cc5a1b06f4e"

View file

@ -12,6 +12,7 @@ dependencies = [
"tinydb (>=3.1.0,<4.0.0)",
"requests (>=2.32.3,<3.0.0)",
"coverage (>=7.6.12,<8.0.0)",
"pytest-httpserver (>=1.1.2,<2.0.0)",
]

View file

@ -93,7 +93,7 @@ class Haiku:
return json.dumps(self.lines)
@staticmethod
def request_haiku(seed: str) -> 'Haiku':
def request_haiku(seed: str, url=AI_BASE_URL + AI_GEN_ENDPOINT) -> Haiku:
"""
Generates a haiku using an AI model based on the
provided seed text.
@ -104,6 +104,7 @@ class Haiku:
The function will retry until a valid haiku is generated.
:param seed: The input text used to inspire the haiku generation.
:param url: The URL to the AI endpoint
:type seed: str
:return: A new Haiku object containing the generated three lines.
:rtype: Haiku
@ -117,19 +118,35 @@ class Haiku:
"stream": False,
"eval_count": 20
}
tries = 0
while True:
tries += 1
try:
r = requests.post(url=AI_BASE_URL + AI_GEN_ENDPOINT,
r = requests.post(url=url,
json=ai_gen_request)
ai_response = str(r.json()["response"])
logging.warning(ai_response)
logging.debug(f"ai response: {ai_response}")
lines = ai_response.split("\n")
while len(lines) != 3:
lines.pop()
logging.warning(lines)
if len(lines) != 3:
logging.info(f"lines for haiku: {lines}")
if len(lines) < 3:
if tries < 20:
logging.warning("too few lines, trying again")
logging.debug(lines)
continue
else:
logging.warning("too many tries, aborting")
raise Exception(
"Generating the haiku took too many tries")
haiku = Haiku(
[
lines[0],
@ -137,8 +154,11 @@ class Haiku:
lines[2]
])
break
except json.JSONDecodeError:
continue
except json.JSONDecodeError as e:
logging.error(f"error while reading json from LLM: {e}")
raise e
return haiku

68
tests/test_haiku.py Normal file
View file

@ -0,0 +1,68 @@
# I do not trust python and it's tests, so I'm testing them. May not be worth
# much, but at least it shows me a few things.
from __future__ import annotations
import json
from pytest_httpserver import HTTPServer
import requests
# do not remove this import. This is needed for
# pytest fixtures to work
import pytest # noqa: F401
from senju.haiku import Haiku # noqa: F401
# Note: these weird arguments are an indicator of what should be dome
# before. For example, `temp_data_dir` is a function in `conftest.py`. If we
# put it in the arguments, it seems to run before our test, and the return
# value becomes a local. This is all very confusing for someone used to
# Rust's libtest
def test_create_haiku():
haiku = Haiku(["line number 1", "line number 2", "line number 3"])
assert haiku.lines[0] == "line number 1"
assert haiku.lines[1] == "line number 2"
assert haiku.lines[2] == "line number 3"
assert len(haiku.lines) == 3
def test_get_haiku_json():
haiku = Haiku(["line number 1", "line number 2", "line number 3"])
data_raw: str = haiku.get_json()
assert data_raw == '["line number 1", "line number 2", "line number 3"]'
data = json.loads(data_raw)
assert haiku.lines[0] == "line number 1"
assert haiku.lines[1] == "line number 2"
assert haiku.lines[2] == "line number 3"
assert len(haiku.lines) == 3
assert data == ['line number 1', 'line number 2', 'line number 3']
def test_request_haiku(httpserver: HTTPServer):
httpserver.expect_request(
"/testhaiku").respond_with_json({"response":
"The apparition of these\n"
"faces in a crowd; Petal\n"
"on a wet, black bough."
})
haiku = Haiku.request_haiku(
"apple banana papaya", url=httpserver.url_for("/testhaiku"))
assert haiku.lines[0] == "The apparition of these"
assert haiku.lines[1] == "faces in a crowd; Petal"
assert haiku.lines[2] == "on a wet, black bough."
assert len(haiku.lines) == 3
def test_request_haiku_respondse_bad(httpserver: HTTPServer):
with pytest.raises(requests.exceptions.JSONDecodeError):
httpserver.expect_request(
"/testhaiku").respond_with_data(
"this is completely wrong" + ("A" * 50 + "\n") * 20)
Haiku.request_haiku(
"apple banana papaya", url=httpserver.url_for("/testhaiku"))

View file

@ -3,11 +3,21 @@
from __future__ import annotations
import pytest # noqa: F401
import os
from senju.haiku import DEFAULT_HAIKU, Haiku
from senju.store_manager import StoreManager # noqa: F401
def test_temp_data_dir(temp_data_dir):
print(temp_data_dir)
testpath = temp_data_dir / "__test"
with open(testpath, "w") as f:
f.write("that dir actually works")
os.remove(testpath)
assert not os.path.exists(testpath)
def test_save_and_load_any(store_manager: StoreManager):
thing = {
"color": "blue",
@ -58,3 +68,28 @@ def test_load_latest_or_default_with_non_empty(temp_data_dir):
haiku = store.load_haiku(store.get_id_of_latest_haiku())
assert haiku != DEFAULT_HAIKU
assert haiku == nonsense_test_haiku
def test_load_latest_with_non_empty_store(temp_data_dir):
store = StoreManager(temp_data_dir / "empty_store.json")
store.save_haiku(Haiku(["hello", "world", "bananenkrokodil"]))
h = store.get_id_of_latest_haiku()
assert h is not None
assert h > 0
def test_create_store_with_bad_file(temp_data_dir):
with pytest.raises(Exception):
testpath = temp_data_dir / "non_empty.json"
with open(testpath, "w") as f:
f.write("BUT IT DOES NOT ACTUALLY HAVE JSON")
store = StoreManager(testpath)
store._save({"hello": 19})
def test_create_store_with_non_empty(temp_data_dir):
testpath = temp_data_dir / "non_empty.json"
with open(testpath, "w") as f:
f.write('{"this": ["is","valid","json"]}')
store = StoreManager(testpath)
store._save({"hello": 19})

View file

@ -1,30 +0,0 @@
# I do not trust python and it's tests, so I'm testing them. May not be worth
# much, but at least it shows me a few things.
from __future__ import annotations
import os
# do not remove this import. This is needed for
# pytest fixtures to work
import pytest # noqa: F401
import senju # noqa: F401
# Note: these weird arguments are an indicator of what should be dome
# before. For example, `temp_data_dir` is a function in `conftest.py`. If we
# put it in the arguments, it seems to run before our test, and the return
# value becomes a local. This is all very confusing for someone used to
# Rust's libtest
def test_tests_are_loaded():
assert True # if we make it here, they are
def test_temp_data_dir(temp_data_dir):
print(temp_data_dir)
testpath = temp_data_dir / "__test"
with open(testpath, "w") as f:
f.write("that dir actually works")
os.remove(testpath)