Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Many improvements #3

Merged
merged 11 commits into from
Apr 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,5 @@ jobs:
pip install -r requirements.txt

- name: Run unit tests
env:
NLTK_DATA: ${{ secrets.NLTK_DATA }}
TWITCH_CLIENT_ID: ${{ secrets.TWITCH_CLIENT_ID }}
TWITCH_CLIENT_SECRET: ${{ secrets.TWITCH_CLIENT_SECRET }}
run: |
python -m unittest discover -s src/tests -p 'test_*.py'
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ thefuzz==0.22.1
torch==2.2.2
transformers==4.39.2
accelerate==0.28.0
mock==5.1.0
5 changes: 4 additions & 1 deletion resources/form.scss
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ $font-size: 16px;

.QLineEdit {
color: $secondary-accent-color;
border:none;
border: none;
border-bottom: 2px solid $accent-color;
padding-bottom: 2px;
background: $main-color;
Expand All @@ -27,14 +27,17 @@ $font-size: 16px;
border-radius: 5px;
color: $accent-color;
background-color: $main-color;

&:hover {
border: 2px solid $secondary-color;
background-color: $secondary-color;
}

&:pressed {
border: 2px solid $accent-color;
background-color: $accent-color;
}

&:disabled {
color: $main-color;
background-color: $main-color;
Expand Down
9 changes: 5 additions & 4 deletions src/image/character_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@
"/animagine-xl-3.1/raw/main/wildcard/characterfull.txt")


def get_all_characters():
def get_all_characters() -> list[str]:
"""
Get all characters from the character list.
"""
with requests.get(CHARACTER_LIST_URL, timeout=3) as response:
response.raise_for_status()
return response.text.split("\n")
response = requests.get(CHARACTER_LIST_URL, timeout=3)
response.raise_for_status()
text: list[str] = response.text.split("\n")
return text


def get_closest_character(name):
Expand Down
2 changes: 1 addition & 1 deletion src/image/game_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ def authenticate(self):
"""
if self.token and time.time() - self.authentication_time < self.token['expires_in']:
return

url = "https://id.twitch.tv/oauth2/token"
payload = {
"client_id": self.client_id,
Expand All @@ -84,6 +83,7 @@ def authenticate(self):
response.raise_for_status()
self.token = response.json()
self.authentication_time = time.time()
return

def get_game_info(self, name):
"""
Expand Down
3 changes: 3 additions & 0 deletions src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,10 @@ def generate_image(self):
"Please enter an anime character name.")
return
self.input_controls["generate_button"].setDisabled(True)

input_values = {key: widget.text().lower().replace(',', ' ').lstrip().rstrip()
for key, widget in self.inputs.items()}

threading.Thread(target=self.image_generator.process_image,
args=(input_values, self)).start()

Expand All @@ -215,6 +217,7 @@ def show_image(self):

for item in self.image_controls.values():
item.show()

if len(self.image_generator.images) != 1:
for item in self.image_navigation_buttons.values():
item.show()
Expand Down
71 changes: 64 additions & 7 deletions src/tests/test_character_info.py
Original file line number Diff line number Diff line change
@@ -1,33 +1,90 @@
import unittest
from unittest.mock import patch, Mock
from src.image.character_info import (
get_all_characters, get_closest_character, get_closest_characters
)


class TestCharacterFunctions(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.character_list = ["souryuu asuka langley", "warrior of light (ff14)"]
def __init__(self, methodName: str = "runTest") -> None:
super().__init__(methodName)
self.character_list = ["souryuu asuka langley", "warrior of light (ff14)"]

@patch('requests.get')
def test_get_all_characters(self, mock_get):
mock_response = Mock()
response_body = ("1girl, souryuu asuka langley, neon genesis evangelion\n"
"1girl, warrior of light \\(ff14\\), final fantasy\n"
"1girl, akiyama mio, k-on!\n"
"1girl, tifa lockhart, final fantasy\n"
"1girl, 2b \\(nier:automata\\), nier \\(series\\)\n"
"1girl, nakano azusa, k-on!\n"
"1girl, rem \\(re:zero\\), re:zero kara hajimeru isekai seikatsu\n"
"1girl, hirasawa yui, k-on!\n"
"1girl, gotoh hitori, bocchi the rock!\n"
"1girl, ayanami rei, neon genesis evangelion\n"
"1boy, male focus, joseph joestar, jojo no kimyou na bouken\n"
"1girl, matoi ryuuko, kill la kill\n"
"1girl, yor briar, spy x family\n"
"1girl, tainaka ritsu, k-on!\n")
mock_response.text = response_body
mock_get.return_value = mock_response

def test_get_all_characters(self):
characters = get_all_characters()

self.assertIsInstance(characters, list)
self.assertTrue(all(isinstance(c, str) for c in characters))

def test_get_closest_character(self):
@patch('requests.get')
def test_get_closest_character(self, mock_get):
mock_response = Mock()
response_body = ("1girl, souryuu asuka langley, neon genesis evangelion\n"
"1girl, warrior of light \\(ff14\\), final fantasy\n"
"1girl, akiyama mio, k-on!\n"
"1girl, tifa lockhart, final fantasy\n"
"1girl, 2b \\(nier:automata\\), nier \\(series\\)\n"
"1girl, nakano azusa, k-on!\n"
"1girl, rem \\(re:zero\\), re:zero kara hajimeru isekai seikatsu\n"
"1girl, hirasawa yui, k-on!\n"
"1girl, gotoh hitori, bocchi the rock!\n"
"1girl, ayanami rei, neon genesis evangelion\n"
"1boy, male focus, joseph joestar, jojo no kimyou na bouken\n"
"1girl, matoi ryuuko, kill la kill\n"
"1girl, yor briar, spy x family\n"
"1girl, tainaka ritsu, k-on!\n")
mock_response.text = response_body
mock_get.return_value = mock_response
closest_name = get_closest_character("Asuka Langley")

self.assertEqual(closest_name, "1girl, souryuu asuka langley, neon genesis evangelion")

def test_get_closest_characters(self):
@patch('requests.get')
def test_get_closest_characters(self, mock_get):
mock_response = Mock()
response_body = ("1boy, male focus, uzumaki naruto, naruto \\(series\\)\n"
"1boy, male focus, uzumaki boruto, naruto \\(series\\)\n"
"1girl, uzumaki himawari, naruto \\(series\\)\n"
"1girl, carrot \\(one piece\\), one piece\n"
"1girl, uzumaki kushina, naruto \\(series\\)\n")
mock_response.text = response_body
mock_get.return_value = mock_response

closest_names = get_closest_characters("Naruto Uzumaki", 3)

self.assertEqual(closest_names, ['1boy, male focus, uzumaki naruto, naruto \\(series\\)',
'1boy, male focus, uzumaki boruto, naruto \\(series\\)',
'1girl, uzumaki himawari, naruto \\(series\\)'])

def test_get_closest_character_not_found(self):
@patch('requests.get')
def test_get_closest_character_not_found(self, mock_get):
mock_response = Mock()
response_body = ("1boy, male focus, uzumaki naruto, naruto \\(series\\)\n"
"1boy, male focus, uzumaki boruto, naruto \\(series\\)\n"
"1girl, uzumaki himawari, naruto \\(series\\)\n"
"1girl, carrot \\(one piece\\), one piece\n"
"1girl, uzumaki kushina, naruto \\(series\\)\n")
mock_response.text = response_body
mock_get.return_value = mock_response
closest_name = get_closest_character("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")

self.assertIsNone(closest_name)
Expand Down
116 changes: 86 additions & 30 deletions src/tests/test_game_info.py
Original file line number Diff line number Diff line change
@@ -1,51 +1,107 @@
import time
import unittest
from unittest.mock import patch, Mock
from src.image.game_info import (
GameInfo, get_year_recency,
get_summary_keywords, is_relevant_adjective
)

TEKKEN_GAME_INFO = {
'id': 7498,
'first_release_date': 1424217600,
'genres': [4],
'name': 'Tekken 7',
'summary': ('Experience the epic conclusion of the Mishima clan and unravel '
'the reasons behind each step of their ceaseless fight. '
'Powered by Unreal Engine 4, Tekken 7 features stunning '
'story-driven cinematic battles and intense duels that '
'can be enjoyed with friends and rivals alike through '
'innovative fight mechanics.')
}


class TestGameInfo(unittest.TestCase):
def setUp(self):
def __init__(self, methodName: str = "runTest") -> None:
super().__init__(methodName)
self.game_info = GameInfo()

def test_authenticate(self):
@patch('requests.post')
def test_authenticate(self, mock_post):
"""
Test Twitch API Authentication
"""
mock_response = Mock()
response_body = {
"access_token": "someAccessToken",
"expires_in": 9112004,
"token_type": "bearer"
}
mock_response.json.return_value = response_body
mock_post.return_value = mock_response

self.game_info.authenticate()

self.assertIsNotNone(self.game_info.token)
self.assertIsNotNone(self.game_info.authentication_time)
self.assertTrue(time.time() - self.game_info.authentication_time
< self.game_info.token['expires_in'])

def test_get_game_info(self):
game_data = self.game_info.get_game_info('Tekken 7')

self.assertIsNotNone(game_data)
self.assertEqual(game_data['name'], 'Tekken 7')
self.assertEqual(game_data['first_release_date'], 1424217600)
self.assertEqual(game_data['genres'], [4])
self.assertEqual(game_data['summary'], 'Experience the epic conclusion of the '
'Mishima clan and unravel the '
'reasons behind each step of their ceaseless fight. '
'Powered by Unreal '
'Engine 4, Tekken 7 features stunning story-driven '
'cinematic battles '
'and intense duels that can be enjoyed with friends '
'and rivals alike '
'through innovative fight mechanics.')

def test_get_genres(self):
genres = self.game_info.get_genres([4])

self.assertEqual(genres, ['Fighting'])
self.assertTrue(time.time() - response_body["expires_in"]
< self.game_info.authentication_time)

@patch("requests.post")
@patch("src.image.game_info.GameInfo.authenticate", Mock())
def test_get_game_info(self, mock_post_info):
"""
Test IGDB Response on https://api.igdb.com/v4/games
"""
mock_response = Mock()
response_body = [TEKKEN_GAME_INFO, {}]
mock_response.json.return_value = response_body
mock_post_info.return_value = mock_response
self.game_info.token = {
"access_token": "someAccessToken",
"expires_in": 9112004,
"token_type": "bearer"
}
info = self.game_info.get_game_info("Tekken 7")

self.assertEqual(response_body[0], info)

@patch("requests.post")
@patch("src.image.game_info.GameInfo.authenticate", Mock())
def test_get_genres(self, mock_post):
"""
Test IGDB Response on https://api.igdb.com/v4/genres
"""
mock_response = Mock()
response_body = [{
"id": 4,
"name": "Fighting"
}]
mock_response.json.return_value = response_body
mock_post.return_value = mock_response
self.game_info.token = {
"access_token": "someAccessToken",
"expires_in": 9112004,
"token_type": "bearer"
}
self.game_info.get_genres([4])

self.assertEqual(response_body[0]["name"], 'Fighting')

@patch("src.image.game_info.GameInfo.get_game_info", Mock(return_value=TEKKEN_GAME_INFO))
@patch("src.image.game_info.GameInfo.get_genres", Mock(return_value=['Fighting']))
@patch("src.image.game_info.GameInfo.authenticate", Mock())
def test_get_game_keywords(self):
"""
Test IGDB Response on https://api.igdb.com/v4/genres
"""
self.game_info.token = {
"access_token": "someAccessToken",
"expires_in": 9112004,
"token_type": "bearer"
}
keywords = self.game_info.get_game_keywords('Tekken 7')
K0ntr4 marked this conversation as resolved.
Show resolved Hide resolved

self.assertIsNotNone(keywords)
self.assertEqual(keywords[0], 'mid')
# The order of the keywords may vary
self.assertIn('Fighting', keywords[1])
self.assertIn("Fighting", keywords[1])

def test_get_year_recency(self):
self.assertEqual(get_year_recency(time.time()), 'newest')
Expand Down