Skip to content

Commit

Permalink
Merge pull request #73 from piglei/v1.3.0
Browse files Browse the repository at this point in the history
V1.3.0
  • Loading branch information
piglei authored Dec 27, 2024
2 parents 6c32dd6 + ad9c1f0 commit 4efbe1d
Show file tree
Hide file tree
Showing 14 changed files with 493 additions and 91 deletions.
25 changes: 24 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "ai-vocabulary-builder"
version = "1.2.2"
version = "1.3.0"
description = "An AI-powered smart vocabulary tool with features like One-click vocabulary building and story-based memorization."
readme = "README.md"
authors = ["piglei <[email protected]>"]
Expand Down Expand Up @@ -38,6 +38,7 @@ nox = "^2024.10.9"
pytest = "^8.3.4"
mypy = "^1.13.0"
types-requests = "^2.32.0.20241016"
pytest-asyncio = "^0.25.0"

[build-system]
requires = ["poetry-core>=1.0.0"]
Expand Down
164 changes: 164 additions & 0 deletions tests/builder/test_ai_svc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
from types import SimpleNamespace
from unittest import mock

import pytest

from voc_builder.builder.ai_svc import (
ManuallyWordQuerier,
RareWordQuerier,
WordChoiceModelResp,
)
from voc_builder.exceptions import AIServiceError
from voc_builder.infras.ai import AIResultMode

# A valid JSON word reply
VALID_JSON_REPLY = """{
"word": "synergy",
"word_base_form": "synergy",
"definitions": "[noun] 协同作用,协同效应",
"pronunciation": "ˈsɪnərdʒi"
}"""

# A valid pydantic word reply
VALID_PYDANTIC_REPLY = WordChoiceModelResp(
word="synergy",
word_base_form="synergy",
definitions="[noun] 协同作用,协同效应",
pronunciation="ˈsɪnərdʒi",
)


@pytest.mark.asyncio
class TestRareWordQuerierJsonResult:
@pytest.mark.parametrize(
"data",
[
# The API sometimes returns the JSON string with triple quotes
f"""```json\n{VALID_JSON_REPLY}\n```""",
VALID_JSON_REPLY,
],
)
@mock.patch("voc_builder.builder.ai_svc.JsonWordDefGetter.agent_request")
async def test_json_valid_response(self, mocker, data):
mocker.return_value = SimpleNamespace(data=data)

word = await RareWordQuerier(None, result_mode=AIResultMode.JSON).query(
"The team's synergy was evident in their performance.",
set(),
"Simplified Chinese",
)

# Check the prompt
prompt = mocker.call_args[0][1]
assert all(
keyword in prompt.system
for keyword in [
"rarely encountered word",
"JSON OUTPUT",
"List all possible definitions",
]
)
assert all(keyword in prompt.user for keyword in ["Word List:", "synergy"])

# Check the word object
assert word.word == "synergy"
assert word.definitions == ["[noun] 协同作用,协同效应"]

@mock.patch("voc_builder.builder.ai_svc.JsonWordDefGetter.agent_request")
async def test_invalid_response(self, mocker):
mocker.return_value = SimpleNamespace(data="not a valid json")

with pytest.raises(AIServiceError):
await RareWordQuerier(None, result_mode=AIResultMode.JSON).query(
"The team's synergy was evident in their performance.",
set(),
"Simplified Chinese",
)


@pytest.mark.asyncio
class TestRareWordQuerierPydanticResult:
@mock.patch("voc_builder.builder.ai_svc.PydanticWordDefGetter.agent_request")
async def test_normal(self, mocker):
mocker.return_value = SimpleNamespace(data=VALID_PYDANTIC_REPLY)

word = await RareWordQuerier(None, result_mode=AIResultMode.PYDANTIC).query(
"The team's synergy was evident in their performance.",
set(),
"Simplified Chinese",
)

# Check the prompt
prompt = mocker.call_args[0][1]
assert all(
keyword in prompt.system
for keyword in [
"rarely encountered word",
"List all possible definitions",
]
)
assert all(keyword in prompt.user for keyword in ["Word List:", "synergy"])
assert "JSON OUTPUT" not in prompt.system

# Check the word object
assert word.word == "synergy"
assert word.definitions == ["[noun] 协同作用,协同效应"]


@pytest.mark.asyncio
class TestManuallyWordQuerierJSONResult:
@mock.patch("voc_builder.builder.ai_svc.JsonWordDefGetter.agent_request")
async def test_valid_json_result(self, mocker):
data = f"""```json\n{VALID_JSON_REPLY}\n```"""
mocker.return_value = SimpleNamespace(data=data)

word = await ManuallyWordQuerier(None, result_mode=AIResultMode.JSON).query(
"The team's synergy was evident in their performance.",
"synergy",
"Simplified Chinese",
)

# Check the prompt
prompt = mocker.call_args[0][1]
assert all(
keyword in prompt.system
for keyword in [
"an english word",
"JSON OUTPUT",
"List all possible definitions",
]
)
assert all(keyword in prompt.user for keyword in ["Word:", "synergy"])

# Check the word object
assert word.word == "synergy"
assert word.definitions == ["[noun] 协同作用,协同效应"]


@pytest.mark.asyncio
class TestManuallyWordQuerierPydanticResult:
@mock.patch("voc_builder.builder.ai_svc.PydanticWordDefGetter.agent_request")
async def test_valid_pydantic_result(self, mocker):
mocker.return_value = SimpleNamespace(data=VALID_PYDANTIC_REPLY)

word = await ManuallyWordQuerier(None, result_mode=AIResultMode.PYDANTIC).query(
"The team's synergy was evident in their performance.",
"synergy",
"Simplified Chinese",
)

# Check the prompt
prompt = mocker.call_args[0][1]
assert all(
keyword in prompt.system
for keyword in [
"an english word",
"List all possible definitions",
]
)
assert "JSON OUTPUT" not in prompt.system
assert all(keyword in prompt.user for keyword in ["Word:", "synergy"])

# Check the word object
assert word.word == "synergy"
assert word.definitions == ["[noun] 协同作用,协同效应"]
2 changes: 1 addition & 1 deletion voc_builder/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "1.2.2"
__version__ = "1.3.0"
Loading

0 comments on commit 4efbe1d

Please sign in to comment.