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

Implementation of LLM-Assisted Translations Backend #3100

Merged
merged 5 commits into from
Feb 26, 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
37 changes: 37 additions & 0 deletions pontoon/machinery/management/commands/refine_translation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from django.core.management.base import BaseCommand
from pontoon.machinery.openai_service import OpenAIService


class Command(BaseCommand):
help = "Refines machine translations using OpenAI's GPT-4 API with specified characteristics"

def add_arguments(self, parser):
parser.add_argument(
"characteristic",
type=str,
choices=["informal", "formal", "alternative"],
help="The specified characteristic of the translation (informal, formal, alternative)",
)
parser.add_argument(
"english_text", type=str, help="The source string in English"
)
parser.add_argument(
"target_text", type=str, help="The machine-generated translation to refine"
)
parser.add_argument(
"language_name",
type=str,
help="The name of the target language for the translation",
)

def handle(self, *args, **options):
characteristic = options["characteristic"]
english_text = options["english_text"]
target_text = options["target_text"]
language_name = options["language_name"]

translator = OpenAIService()
translation = translator.get_translation(
english_text, target_text, characteristic, language_name
)
self.stdout.write(self.style.SUCCESS(translation))
68 changes: 68 additions & 0 deletions pontoon/machinery/openai_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
from openai import OpenAI
from pontoon.base.models import Locale


class OpenAIService:
def __init__(self):
self.client = OpenAI()

def get_translation(
self, english_text, translated_text, characteristic, target_language_name
):
try:
target_language = Locale.objects.get(name=target_language_name)
except Locale.DoesNotExist:
raise ValueError(
f"The target language '{target_language_name}' is not supported."
)

informal = (
f"You will be provided with text in English, along with its machine-generated translation in {target_language}. "
"Your objective is to revise the {target_language} translation to ensure it utilizes simpler language. Adhere to the following guidelines to achieve this:\n"
"- Clarity is Key: Ensure the translation conveys the original message in the clearest possible manner, without ambiguity or unnecessary complexity.\n"
"- Consistent Simplicity: Maintain a consistent level of simplicity throughout the translation.\n"
"The goal is to produce a translation that accurately reflects the original English text, but in a way that is more approachable and easier to understand for all {target_language} speakers."
)

formal = (
f"You will be provided with text in English, along with its machine-generated translation in {target_language}. "
"Your objective is to revise the {target_language} translation to ensure it utilizes a higher level of formality. Adhere to the following guidelines to achieve this:\n"
"- Adjust the Tone: Ensure the tone is respectful, polished, and devoid of colloquialisms or informal expressions commonly used in casual conversation.\n"
"- Formal Addressing: Where applicable, use formal modes of address.\n"
"- Consistency: Maintain a consistent level of formality throughout the translation, avoiding shifts in tone or style.\n"
"Your goal is to produce a translation that not only accurately conveys the meaning of the English text but also meets the expectations for formality in {target_language}-speaking professional or formal settings."
)

alternative = (
f"You will be provided with text in English, along with its machine-generated translation in {target_language}. "
"Your objective is to provide an alternative translation. Adhere to the following guidelines to achieve this:\n"
"- Cultural Nuances: Pay attention to cultural nuances and idiomatic expressions, ensuring they are appropriately translated for the {target_language}-speaking audience.\n"
"- Clarification and Accuracy: Where the source text is ambiguous or idiomatic, offer clarifications or alternative expressions in {target_language}.\n"
"Just provide the text for the alternative translation."
)

system_messages = {
"informal": informal,
"formal": formal,
"alternative": alternative,
}

system_message = system_messages.get(characteristic)
if system_message is None:
raise ValueError(f"Unrecognized characteristic: '{characteristic}'")

# Construct the user prompt with the language name
user_prompt = f"Refine the following {target_language} machine translation to make it {characteristic}: '{translated_text}' based on the original English text: '{english_text}'."

# Call the OpenAI API with the constructed prompt
response = self.client.chat.completions.create(
model="gpt-4-0125-preview",
messages=[
{"role": "system", "content": system_message},
{"role": "user", "content": user_prompt},
],
temperature=0, # Set temperature to 0 for deterministic output
top_p=1, # Set top_p to 1 to consider the full distribution
)

return response.choices[0].message.content.strip()
1 change: 1 addition & 0 deletions requirements/default.in
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ lxml==4.9.1
markupsafe==2.0.1
mercurial==6.4.2
newrelic==9.6.0
openai==1.12.0
parsimonious==0.10.0
polib==1.0.6
psycopg2==2.9.6
Expand Down
153 changes: 146 additions & 7 deletions requirements/default.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@ aniso8601==7.0.0 \
--hash=sha256:513d2b6637b7853806ae79ffaca6f3e8754bdd547048f5ccc1420aec4b714f1e \
--hash=sha256:d10a4bf949f619f719b227ef5386e31f49a2b6d453004b21f02661ccc8670c7b
# via graphene
annotated-types==0.6.0 \
--hash=sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43 \
--hash=sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d
# via pydantic
anyio==4.3.0 \
--hash=sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8 \
--hash=sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6
# via
# httpx
# openai
apscheduler==3.9.1.post1 \
--hash=sha256:b2bea0309569da53a7261bfa0ce19c67ddbfe151bda776a6a907579fdbd3eb2a \
--hash=sha256:c8c618241dbb2785ed5a687504b14cb1851d6f7b5a4edf3a51e39cc6a069967a
Expand Down Expand Up @@ -42,7 +52,10 @@ celery==5.2.6 \
certifi==2021.10.8 \
--hash=sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872 \
--hash=sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569
# via requests
# via
# httpcore
# httpx
# requests
cffi==1.15.0 \
--hash=sha256:00c878c90cb53ccfaae6b8bc18ad05d2036553e6d9d1d9dbcf323bbe83854ca3 \
--hash=sha256:0104fb5ae2391d46a4cb082abdd5c69ea4eab79d8d44eaaf79f1b1fd806ee4c2 \
Expand Down Expand Up @@ -155,6 +168,10 @@ defusedxml==0.7.1 \
--hash=sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69 \
--hash=sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61
# via python3-openid
distro==1.9.0 \
--hash=sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed \
--hash=sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2
# via openai
dj-database-url==0.3.0 \
--hash=sha256:ca01768fdecde134301f3170743226f60edff5c3935f12437378ebd911506353 \
--hash=sha256:f2e273ed34acbb560962d5cf12917936d8df02297df09bd3089b8546d4584138
Expand Down Expand Up @@ -216,6 +233,10 @@ django-pipeline==2.0.6 \
--hash=sha256:3ec726e2bf9f61f213f41ee4513f4191a02ab2f5df86c9e3751a9a607c814031 \
--hash=sha256:443c560000b3202dafa873cf9b9a49018ded4b2090979dec8e8858b8b1f867c0
# via -r requirements/default.in
exceptiongroup==1.2.0 \
--hash=sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14 \
--hash=sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68
# via anyio
fluent-syntax==0.19.0 \
--hash=sha256:920326d7f46864b9758f0044e9968e3112198bc826acee16ddd8f11d359004fd \
--hash=sha256:b352b3475fac6c6ed5f06527921f432aac073d764445508ee5218aeccc7cc5c4
Expand Down Expand Up @@ -323,10 +344,25 @@ gunicorn==19.9.0 \
--hash=sha256:aa8e0b40b4157b36a5df5e599f45c9c76d6af43845ba3b3b0efe2c70473c2471 \
--hash=sha256:fa2662097c66f920f53f70621c6c58ca4a3c4d3434205e608e121b5b3b71f4f3
# via -r requirements/default.in
h11==0.14.0 \
--hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \
--hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761
# via httpcore
httpcore==1.0.4 \
--hash=sha256:ac418c1db41bade2ad53ae2f3834a3a0f5ae76b56cf5aa497d2d033384fc7d73 \
--hash=sha256:cb2839ccfcba0d2d3c1131d3c3e26dfc327326fbe7a5dc0dbfe9f6c9151bb022
# via httpx
httpx==0.27.0 \
--hash=sha256:71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5 \
--hash=sha256:a0cb88a46f32dc874e04ee956e4c2764aba2aa228f650b06788ba6bda2962ab5
# via openai
idna==3.3 \
--hash=sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff \
--hash=sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d
# via requests
# via
# anyio
# httpx
# requests
jinja2==3.0.3 \
--hash=sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8 \
--hash=sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7
Expand Down Expand Up @@ -569,6 +605,10 @@ oauthlib==3.1.1 \
--hash=sha256:42bf6354c2ed8c6acb54d971fce6f88193d97297e18602a3a886603f9d7730cc \
--hash=sha256:8f0215fcc533dd8dd1bee6f4c412d4f0cd7297307d43ac61666389e3bc3198a3
# via requests-oauthlib
openai==1.12.0 \
--hash=sha256:99c5d257d09ea6533d689d1cc77caa0ac679fa21efef8893d8b0832a86877f1b \
--hash=sha256:a54002c814e05222e413664f651b5916714e4700d041d5cf5724d3ae1a3e3481
# via -r requirements/default.in
packaging==21.3 \
--hash=sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb \
--hash=sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522
Expand Down Expand Up @@ -649,6 +689,91 @@ pycparser==2.21 \
--hash=sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9 \
--hash=sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206
# via cffi
pydantic==2.6.1 \
--hash=sha256:0b6a909df3192245cb736509a92ff69e4fef76116feffec68e93a567347bae6f \
--hash=sha256:4fd5c182a2488dc63e6d32737ff19937888001e2a6d86e94b3f233104a5d1fa9
# via openai
pydantic-core==2.16.2 \
--hash=sha256:02906e7306cb8c5901a1feb61f9ab5e5c690dbbeaa04d84c1b9ae2a01ebe9379 \
--hash=sha256:0ba503850d8b8dcc18391f10de896ae51d37fe5fe43dbfb6a35c5c5cad271a06 \
--hash=sha256:16aa02e7a0f539098e215fc193c8926c897175d64c7926d00a36188917717a05 \
--hash=sha256:18de31781cdc7e7b28678df7c2d7882f9692ad060bc6ee3c94eb15a5d733f8f7 \
--hash=sha256:22c5f022799f3cd6741e24f0443ead92ef42be93ffda0d29b2597208c94c3753 \
--hash=sha256:2924b89b16420712e9bb8192396026a8fbd6d8726224f918353ac19c4c043d2a \
--hash=sha256:308974fdf98046db28440eb3377abba274808bf66262e042c412eb2adf852731 \
--hash=sha256:396fdf88b1b503c9c59c84a08b6833ec0c3b5ad1a83230252a9e17b7dfb4cffc \
--hash=sha256:3ac426704840877a285d03a445e162eb258924f014e2f074e209d9b4ff7bf380 \
--hash=sha256:3b052c753c4babf2d1edc034c97851f867c87d6f3ea63a12e2700f159f5c41c3 \
--hash=sha256:3fab4e75b8c525a4776e7630b9ee48aea50107fea6ca9f593c98da3f4d11bf7c \
--hash=sha256:406fac1d09edc613020ce9cf3f2ccf1a1b2f57ab00552b4c18e3d5276c67eb11 \
--hash=sha256:40a0bd0bed96dae5712dab2aba7d334a6c67cbcac2ddfca7dbcc4a8176445990 \
--hash=sha256:41dac3b9fce187a25c6253ec79a3f9e2a7e761eb08690e90415069ea4a68ff7a \
--hash=sha256:459c0d338cc55d099798618f714b21b7ece17eb1a87879f2da20a3ff4c7628e2 \
--hash=sha256:459d6be6134ce3b38e0ef76f8a672924460c455d45f1ad8fdade36796df1ddc8 \
--hash=sha256:46b0d5520dbcafea9a8645a8164658777686c5c524d381d983317d29687cce97 \
--hash=sha256:47924039e785a04d4a4fa49455e51b4eb3422d6eaacfde9fc9abf8fdef164e8a \
--hash=sha256:4bfcbde6e06c56b30668a0c872d75a7ef3025dc3c1823a13cf29a0e9b33f67e8 \
--hash=sha256:4f9ee4febb249c591d07b2d4dd36ebcad0ccd128962aaa1801508320896575ef \
--hash=sha256:55749f745ebf154c0d63d46c8c58594d8894b161928aa41adbb0709c1fe78b77 \
--hash=sha256:5864b0242f74b9dd0b78fd39db1768bc3f00d1ffc14e596fd3e3f2ce43436a33 \
--hash=sha256:5f60f920691a620b03082692c378661947d09415743e437a7478c309eb0e4f82 \
--hash=sha256:60eb8ceaa40a41540b9acae6ae7c1f0a67d233c40dc4359c256ad2ad85bdf5e5 \
--hash=sha256:69a7b96b59322a81c2203be537957313b07dd333105b73db0b69212c7d867b4b \
--hash=sha256:6ad84731a26bcfb299f9eab56c7932d46f9cad51c52768cace09e92a19e4cf55 \
--hash=sha256:6db58c22ac6c81aeac33912fb1af0e930bc9774166cdd56eade913d5f2fff35e \
--hash=sha256:70651ff6e663428cea902dac297066d5c6e5423fda345a4ca62430575364d62b \
--hash=sha256:72f7919af5de5ecfaf1eba47bf9a5d8aa089a3340277276e5636d16ee97614d7 \
--hash=sha256:732bd062c9e5d9582a30e8751461c1917dd1ccbdd6cafb032f02c86b20d2e7ec \
--hash=sha256:7924e54f7ce5d253d6160090ddc6df25ed2feea25bfb3339b424a9dd591688bc \
--hash=sha256:7afb844041e707ac9ad9acad2188a90bffce2c770e6dc2318be0c9916aef1469 \
--hash=sha256:7b883af50eaa6bb3299780651e5be921e88050ccf00e3e583b1e92020333304b \
--hash=sha256:7beec26729d496a12fd23cf8da9944ee338c8b8a17035a560b585c36fe81af20 \
--hash=sha256:7bf26c2e2ea59d32807081ad51968133af3025c4ba5753e6a794683d2c91bf6e \
--hash=sha256:7c31669e0c8cc68400ef0c730c3a1e11317ba76b892deeefaf52dcb41d56ed5d \
--hash=sha256:7e6231aa5bdacda78e96ad7b07d0c312f34ba35d717115f4b4bff6cb87224f0f \
--hash=sha256:870dbfa94de9b8866b37b867a2cb37a60c401d9deb4a9ea392abf11a1f98037b \
--hash=sha256:88646cae28eb1dd5cd1e09605680c2b043b64d7481cdad7f5003ebef401a3039 \
--hash=sha256:8aafeedb6597a163a9c9727d8a8bd363a93277701b7bfd2749fbefee2396469e \
--hash=sha256:8bde5b48c65b8e807409e6f20baee5d2cd880e0fad00b1a811ebc43e39a00ab2 \
--hash=sha256:8f9142a6ed83d90c94a3efd7af8873bf7cefed2d3d44387bf848888482e2d25f \
--hash=sha256:936a787f83db1f2115ee829dd615c4f684ee48ac4de5779ab4300994d8af325b \
--hash=sha256:98dc6f4f2095fc7ad277782a7c2c88296badcad92316b5a6e530930b1d475ebc \
--hash=sha256:9957433c3a1b67bdd4c63717eaf174ebb749510d5ea612cd4e83f2d9142f3fc8 \
--hash=sha256:99af961d72ac731aae2a1b55ccbdae0733d816f8bfb97b41909e143de735f522 \
--hash=sha256:9b5f13857da99325dcabe1cc4e9e6a3d7b2e2c726248ba5dd4be3e8e4a0b6d0e \
--hash=sha256:9d776d30cde7e541b8180103c3f294ef7c1862fd45d81738d156d00551005784 \
--hash=sha256:9da90d393a8227d717c19f5397688a38635afec89f2e2d7af0df037f3249c39a \
--hash=sha256:a3b7352b48fbc8b446b75f3069124e87f599d25afb8baa96a550256c031bb890 \
--hash=sha256:a477932664d9611d7a0816cc3c0eb1f8856f8a42435488280dfbf4395e141485 \
--hash=sha256:a7e41e3ada4cca5f22b478c08e973c930e5e6c7ba3588fb8e35f2398cdcc1545 \
--hash=sha256:a90fec23b4b05a09ad988e7a4f4e081711a90eb2a55b9c984d8b74597599180f \
--hash=sha256:a9e523474998fb33f7c1a4d55f5504c908d57add624599e095c20fa575b8d943 \
--hash=sha256:aa057095f621dad24a1e906747179a69780ef45cc8f69e97463692adbcdae878 \
--hash=sha256:aa6c8c582036275997a733427b88031a32ffa5dfc3124dc25a730658c47a572f \
--hash=sha256:ae34418b6b389d601b31153b84dce480351a352e0bb763684a1b993d6be30f17 \
--hash=sha256:b0d7a9165167269758145756db43a133608a531b1e5bb6a626b9ee24bc38a8f7 \
--hash=sha256:b30b0dd58a4509c3bd7eefddf6338565c4905406aee0c6e4a5293841411a1286 \
--hash=sha256:b8f9186ca45aee030dc8234118b9c0784ad91a0bb27fc4e7d9d6608a5e3d386c \
--hash=sha256:b94cbda27267423411c928208e89adddf2ea5dd5f74b9528513f0358bba019cb \
--hash=sha256:cc6f6c9be0ab6da37bc77c2dda5f14b1d532d5dbef00311ee6e13357a418e646 \
--hash=sha256:ce232a6170dd6532096cadbf6185271e4e8c70fc9217ebe105923ac105da9978 \
--hash=sha256:cf903310a34e14651c9de056fcc12ce090560864d5a2bb0174b971685684e1d8 \
--hash=sha256:d5362d099c244a2d2f9659fb3c9db7c735f0004765bbe06b99be69fbd87c3f15 \
--hash=sha256:dffaf740fe2e147fedcb6b561353a16243e654f7fe8e701b1b9db148242e1272 \
--hash=sha256:e0f686549e32ccdb02ae6f25eee40cc33900910085de6aa3790effd391ae10c2 \
--hash=sha256:e4b52776a2e3230f4854907a1e0946eec04d41b1fc64069ee774876bbe0eab55 \
--hash=sha256:e4ba0884a91f1aecce75202473ab138724aa4fb26d7707f2e1fa6c3e68c84fbf \
--hash=sha256:e6294e76b0380bb7a61eb8a39273c40b20beb35e8c87ee101062834ced19c545 \
--hash=sha256:ebb892ed8599b23fa8f1799e13a12c87a97a6c9d0f497525ce9858564c4575a4 \
--hash=sha256:eca58e319f4fd6df004762419612122b2c7e7d95ffafc37e890252f869f3fb2a \
--hash=sha256:ed957db4c33bc99895f3a1672eca7e80e8cda8bd1e29a80536b4ec2153fa9804 \
--hash=sha256:ef551c053692b1e39e3f7950ce2296536728871110e7d75c4e7753fb30ca87f4 \
--hash=sha256:ef6113cd31411eaf9b39fc5a8848e71c72656fd418882488598758b2c8c6dfa0 \
--hash=sha256:f685dbc1fdadb1dcd5b5e51e0a378d4685a891b2ddaf8e2bba89bd3a7144e44a \
--hash=sha256:f8ed79883b4328b7f0bd142733d99c8e6b22703e908ec63d930b06be3a0e7113 \
--hash=sha256:fe56851c3f1d6f5384b3051c536cc81b3a93a73faf931f404fef95217cf1e10d \
--hash=sha256:ff7c97eb7a29aba230389a2661edf2e9e06ce616c7e35aa764879b6894a44b25
# via pydantic
pyjwt[crypto]==2.4.0 \
--hash=sha256:72d1d253f32dbd4f5c88eaf1fdc62f3a19f676ccbadb9dbc5d07e951b2b26daf \
--hash=sha256:d42908208c699b3b973cbeb01a969ba6a96c821eefb1c5bfe4c390c01d67abba
Expand Down Expand Up @@ -841,6 +966,13 @@ six==1.16.0 \
# python-dateutil
# sacremoses
# singledispatch
sniffio==1.3.0 \
--hash=sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101 \
--hash=sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384
# via
# anyio
# httpx
# openai
sqlparse==0.4.2 \
--hash=sha256:0c00730c74263a94e5a9919ade150dfc3b19c574389985446148402998287dae \
--hash=sha256:48719e356bb8b42991bdbb1e8b83223757b93789c00910a616a071910ca4a64d
Expand All @@ -860,14 +992,21 @@ toml==0.10.2 \
tqdm==4.62.3 \
--hash=sha256:8dd278a422499cd6b727e6ae4061c40b48fce8b76d1ccbf5d34fca9b7f925b0c \
--hash=sha256:d359de7217506c9851b7869f3708d8ee53ed70a1b8edbba4dbcb47442592920d
# via sacremoses
# via
# openai
# sacremoses
translate-toolkit==3.3.2 \
--hash=sha256:0795bd3c8668213199550ae4ed8938874083139ec1f8c473dcca1524a206b108
# via -r requirements/default.in
typing-extensions==4.5.0 \
--hash=sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb \
--hash=sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4
# via fluent-syntax
typing-extensions==4.9.0 \
--hash=sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783 \
--hash=sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd
# via
# anyio
# fluent-syntax
# openai
# pydantic
# pydantic-core
tzdata==2022.7 \
--hash=sha256:2b88858b0e3120792a3c0635c23daf36a7d7eeeca657c323da299d2094402a0d \
--hash=sha256:fe5f866eddd8b96e9fcba978f8e503c909b19ea7efda11e52e39494bad3a7bfa
Expand Down
10 changes: 6 additions & 4 deletions requirements/test.txt
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,12 @@ coverage[toml]==7.2.5 \
# via
# -r requirements/test.in
# pytest-cov
exceptiongroup==1.1.1 \
--hash=sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e \
--hash=sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785
# via pytest
exceptiongroup==1.2.0 \
--hash=sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14 \
--hash=sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68
# via
# -c requirements/default.txt
# pytest
factory-boy==3.2.1 \
--hash=sha256:a98d277b0c047c75eb6e4ab8508a7f81fb03d2cb21986f627913546ef7a2a55e \
--hash=sha256:eb02a7dd1b577ef606b75a253b9818e6f9eaf996d94449c9d5ebb124f90dc795
Expand Down