Async release
This commit is contained in:
5
app/configs/__init__.py
Normal file
5
app/configs/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from .dependency_injection import config_di
|
||||
|
||||
__all__ = [
|
||||
"config_di"
|
||||
]
|
||||
706
app/configs/constants.py
Normal file
706
app/configs/constants.py
Normal file
@@ -0,0 +1,706 @@
|
||||
from enum import Enum
|
||||
|
||||
BLACKLISTED_WORDS = ["jesus", "sex", "gay", "lesbian", "homosexual", "god", "angel", "pornography", "beer", "wine",
|
||||
"cocaine", "alcohol", "nudity", "lgbt", "casino", "gambling", "catholicism",
|
||||
"discrimination", "politics", "politic", "christianity", "islam", "christian", "christians",
|
||||
"jews", "jew", "discrimination", "discriminatory"]
|
||||
|
||||
|
||||
class ExamVariant(Enum):
|
||||
FULL = "full"
|
||||
PARTIAL = "partial"
|
||||
|
||||
|
||||
class QuestionType(Enum):
|
||||
LISTENING_SECTION_1 = "Listening Section 1"
|
||||
LISTENING_SECTION_2 = "Listening Section 2"
|
||||
LISTENING_SECTION_3 = "Listening Section 3"
|
||||
LISTENING_SECTION_4 = "Listening Section 4"
|
||||
WRITING_TASK_1 = "Writing Task 1"
|
||||
WRITING_TASK_2 = "Writing Task 2"
|
||||
SPEAKING_1 = "Speaking Task Part 1"
|
||||
SPEAKING_2 = "Speaking Task Part 2"
|
||||
READING_PASSAGE_1 = "Reading Passage 1"
|
||||
READING_PASSAGE_2 = "Reading Passage 2"
|
||||
READING_PASSAGE_3 = "Reading Passage 3"
|
||||
|
||||
|
||||
class AvatarEnum(Enum):
|
||||
MATTHEW_NOAH = "5912afa7c77c47d3883af3d874047aaf"
|
||||
VERA_CERISE = "9e58d96a383e4568a7f1e49df549e0e4"
|
||||
EDWARD_TONY = "d2cdd9c0379a4d06ae2afb6e5039bd0c"
|
||||
TANYA_MOLLY = "045cb5dcd00042b3a1e4f3bc1c12176b"
|
||||
KAYLA_ABBI = "1ae1e5396cc444bfad332155fdb7a934"
|
||||
JEROME_RYAN = "0ee6aa7cc1084063a630ae514fccaa31"
|
||||
TYLER_CHRISTOPHER = "5772cff935844516ad7eeff21f839e43"
|
||||
|
||||
|
||||
class FilePaths:
|
||||
AUDIO_FILES_PATH = 'download-audio/'
|
||||
FIREBASE_LISTENING_AUDIO_FILES_PATH = 'listening_recordings/'
|
||||
VIDEO_FILES_PATH = 'download-video/'
|
||||
FIREBASE_SPEAKING_VIDEO_FILES_PATH = 'speaking_videos/'
|
||||
|
||||
|
||||
class TemperatureSettings:
|
||||
GRADING_TEMPERATURE = 0.1
|
||||
TIPS_TEMPERATURE = 0.2
|
||||
GEN_QUESTION_TEMPERATURE = 0.7
|
||||
|
||||
|
||||
class GPTModels:
|
||||
GPT_3_5_TURBO = "gpt-3.5-turbo"
|
||||
GPT_4_TURBO = "gpt-4-turbo"
|
||||
GPT_4_O = "gpt-4o"
|
||||
GPT_3_5_TURBO_16K = "gpt-3.5-turbo-16k"
|
||||
GPT_3_5_TURBO_INSTRUCT = "gpt-3.5-turbo-instruct"
|
||||
GPT_4_PREVIEW = "gpt-4-turbo-preview"
|
||||
|
||||
|
||||
class FieldsAndExercises:
|
||||
GRADING_FIELDS = ['comment', 'overall', 'task_response']
|
||||
GEN_FIELDS = ['topic']
|
||||
GEN_TEXT_FIELDS = ['title']
|
||||
LISTENING_GEN_FIELDS = ['transcript', 'exercise']
|
||||
READING_EXERCISE_TYPES = ['fillBlanks', 'writeBlanks', 'trueFalse', 'paragraphMatch']
|
||||
LISTENING_EXERCISE_TYPES = ['multipleChoice', 'writeBlanksQuestions', 'writeBlanksFill', 'writeBlanksForm']
|
||||
|
||||
TOTAL_READING_PASSAGE_1_EXERCISES = 13
|
||||
TOTAL_READING_PASSAGE_2_EXERCISES = 13
|
||||
TOTAL_READING_PASSAGE_3_EXERCISES = 14
|
||||
|
||||
TOTAL_LISTENING_SECTION_1_EXERCISES = 10
|
||||
TOTAL_LISTENING_SECTION_2_EXERCISES = 10
|
||||
TOTAL_LISTENING_SECTION_3_EXERCISES = 10
|
||||
TOTAL_LISTENING_SECTION_4_EXERCISES = 10
|
||||
|
||||
|
||||
class MinTimers:
|
||||
LISTENING_MIN_TIMER_DEFAULT = 30
|
||||
WRITING_MIN_TIMER_DEFAULT = 60
|
||||
SPEAKING_MIN_TIMER_DEFAULT = 14
|
||||
|
||||
|
||||
class Voices:
|
||||
EN_US_VOICES = [
|
||||
{'Gender': 'Female', 'Id': 'Salli', 'LanguageCode': 'en-US', 'LanguageName': 'US English', 'Name': 'Salli',
|
||||
'SupportedEngines': ['neural', 'standard']},
|
||||
{'Gender': 'Male', 'Id': 'Matthew', 'LanguageCode': 'en-US', 'LanguageName': 'US English', 'Name': 'Matthew',
|
||||
'SupportedEngines': ['neural', 'standard']},
|
||||
{'Gender': 'Female', 'Id': 'Kimberly', 'LanguageCode': 'en-US', 'LanguageName': 'US English', 'Name': 'Kimberly',
|
||||
'SupportedEngines': ['neural', 'standard']},
|
||||
{'Gender': 'Female', 'Id': 'Kendra', 'LanguageCode': 'en-US', 'LanguageName': 'US English', 'Name': 'Kendra',
|
||||
'SupportedEngines': ['neural', 'standard']},
|
||||
{'Gender': 'Male', 'Id': 'Justin', 'LanguageCode': 'en-US', 'LanguageName': 'US English', 'Name': 'Justin',
|
||||
'SupportedEngines': ['neural', 'standard']},
|
||||
{'Gender': 'Male', 'Id': 'Joey', 'LanguageCode': 'en-US', 'LanguageName': 'US English', 'Name': 'Joey',
|
||||
'SupportedEngines': ['neural', 'standard']},
|
||||
{'Gender': 'Female', 'Id': 'Joanna', 'LanguageCode': 'en-US', 'LanguageName': 'US English', 'Name': 'Joanna',
|
||||
'SupportedEngines': ['neural', 'standard']},
|
||||
{'Gender': 'Female', 'Id': 'Ivy', 'LanguageCode': 'en-US', 'LanguageName': 'US English', 'Name': 'Ivy',
|
||||
'SupportedEngines': ['neural', 'standard']}]
|
||||
EN_GB_VOICES = [
|
||||
{'Gender': 'Female', 'Id': 'Emma', 'LanguageCode': 'en-GB', 'LanguageName': 'British English', 'Name': 'Emma',
|
||||
'SupportedEngines': ['neural', 'standard']},
|
||||
{'Gender': 'Male', 'Id': 'Brian', 'LanguageCode': 'en-GB', 'LanguageName': 'British English', 'Name': 'Brian',
|
||||
'SupportedEngines': ['neural', 'standard']},
|
||||
{'Gender': 'Female', 'Id': 'Amy', 'LanguageCode': 'en-GB', 'LanguageName': 'British English', 'Name': 'Amy',
|
||||
'SupportedEngines': ['neural', 'standard']}]
|
||||
EN_GB_WLS_VOICES = [
|
||||
{'Gender': 'Male', 'Id': 'Geraint', 'LanguageCode': 'en-GB-WLS', 'LanguageName': 'Welsh English', 'Name': 'Geraint',
|
||||
'SupportedEngines': ['standard']}]
|
||||
EN_AU_VOICES = [{'Gender': 'Male', 'Id': 'Russell', 'LanguageCode': 'en-AU', 'LanguageName': 'Australian English',
|
||||
'Name': 'Russell', 'SupportedEngines': ['standard']},
|
||||
{'Gender': 'Female', 'Id': 'Nicole', 'LanguageCode': 'en-AU', 'LanguageName': 'Australian English',
|
||||
'Name': 'Nicole', 'SupportedEngines': ['standard']}]
|
||||
|
||||
ALL_VOICES = EN_US_VOICES + EN_GB_VOICES + EN_GB_WLS_VOICES + EN_AU_VOICES
|
||||
|
||||
MALE_VOICES = [item for item in ALL_VOICES if item.get('Gender') == 'Male']
|
||||
FEMALE_VOICES = [item for item in ALL_VOICES if item.get('Gender') == 'Female']
|
||||
|
||||
|
||||
class NeuralVoices:
|
||||
NEURAL_EN_US_VOICES = [
|
||||
{'Gender': 'Female', 'Id': 'Danielle', 'LanguageCode': 'en-US', 'LanguageName': 'US English', 'Name': 'Danielle',
|
||||
'SupportedEngines': ['neural']},
|
||||
{'Gender': 'Male', 'Id': 'Gregory', 'LanguageCode': 'en-US', 'LanguageName': 'US English', 'Name': 'Gregory',
|
||||
'SupportedEngines': ['neural']},
|
||||
{'Gender': 'Male', 'Id': 'Kevin', 'LanguageCode': 'en-US', 'LanguageName': 'US English', 'Name': 'Kevin',
|
||||
'SupportedEngines': ['neural']},
|
||||
{'Gender': 'Female', 'Id': 'Ruth', 'LanguageCode': 'en-US', 'LanguageName': 'US English', 'Name': 'Ruth',
|
||||
'SupportedEngines': ['neural']},
|
||||
{'Gender': 'Male', 'Id': 'Stephen', 'LanguageCode': 'en-US', 'LanguageName': 'US English', 'Name': 'Stephen',
|
||||
'SupportedEngines': ['neural']}]
|
||||
NEURAL_EN_GB_VOICES = [
|
||||
{'Gender': 'Male', 'Id': 'Arthur', 'LanguageCode': 'en-GB', 'LanguageName': 'British English', 'Name': 'Arthur',
|
||||
'SupportedEngines': ['neural']}]
|
||||
NEURAL_EN_AU_VOICES = [
|
||||
{'Gender': 'Female', 'Id': 'Olivia', 'LanguageCode': 'en-AU', 'LanguageName': 'Australian English',
|
||||
'Name': 'Olivia', 'SupportedEngines': ['neural']}]
|
||||
NEURAL_EN_ZA_VOICES = [
|
||||
{'Gender': 'Female', 'Id': 'Ayanda', 'LanguageCode': 'en-ZA', 'LanguageName': 'South African English',
|
||||
'Name': 'Ayanda', 'SupportedEngines': ['neural']}]
|
||||
NEURAL_EN_NZ_VOICES = [
|
||||
{'Gender': 'Female', 'Id': 'Aria', 'LanguageCode': 'en-NZ', 'LanguageName': 'New Zealand English', 'Name': 'Aria',
|
||||
'SupportedEngines': ['neural']}]
|
||||
NEURAL_EN_IN_VOICES = [
|
||||
{'Gender': 'Female', 'Id': 'Kajal', 'LanguageCode': 'en-IN', 'LanguageName': 'Indian English', 'Name': 'Kajal',
|
||||
'SupportedEngines': ['neural']}]
|
||||
NEURAL_EN_IE_VOICES = [
|
||||
{'Gender': 'Female', 'Id': 'Niamh', 'LanguageCode': 'en-IE', 'LanguageName': 'Irish English', 'Name': 'Niamh',
|
||||
'SupportedEngines': ['neural']}]
|
||||
|
||||
ALL_NEURAL_VOICES = NEURAL_EN_US_VOICES + NEURAL_EN_GB_VOICES + NEURAL_EN_AU_VOICES + NEURAL_EN_ZA_VOICES + NEURAL_EN_NZ_VOICES + NEURAL_EN_IE_VOICES
|
||||
|
||||
MALE_NEURAL_VOICES = [item for item in ALL_NEURAL_VOICES if item.get('Gender') == 'Male']
|
||||
FEMALE_NEURAL_VOICES = [item for item in ALL_NEURAL_VOICES if item.get('Gender') == 'Female']
|
||||
|
||||
|
||||
class EducationalContent:
|
||||
DIFFICULTIES = ["easy", "medium", "hard"]
|
||||
|
||||
MTI_TOPICS = [
|
||||
"Education",
|
||||
"Technology",
|
||||
"Environment",
|
||||
"Health and Fitness",
|
||||
"Engineering",
|
||||
"Work and Careers",
|
||||
"Travel and Tourism",
|
||||
"Culture and Traditions",
|
||||
"Social Issues",
|
||||
"Arts and Entertainment",
|
||||
"Climate Change",
|
||||
"Social Media",
|
||||
"Sustainable Development",
|
||||
"Health Care",
|
||||
"Immigration",
|
||||
"Artificial Intelligence",
|
||||
"Consumerism",
|
||||
"Online Shopping",
|
||||
"Energy",
|
||||
"Oil and Gas",
|
||||
"Poverty and Inequality",
|
||||
"Cultural Diversity",
|
||||
"Democracy and Governance",
|
||||
"Mental Health",
|
||||
"Ethics and Morality",
|
||||
"Population Growth",
|
||||
"Science and Innovation",
|
||||
"Poverty Alleviation",
|
||||
"Cybersecurity and Privacy",
|
||||
"Human Rights",
|
||||
"Food and Agriculture",
|
||||
"Cyberbullying and Online Safety",
|
||||
"Linguistic Diversity",
|
||||
"Urbanization",
|
||||
"Artificial Intelligence in Education",
|
||||
"Youth Empowerment",
|
||||
"Disaster Management",
|
||||
"Mental Health Stigma",
|
||||
"Internet Censorship",
|
||||
"Sustainable Fashion",
|
||||
"Indigenous Rights",
|
||||
"Water Scarcity",
|
||||
"Social Entrepreneurship",
|
||||
"Privacy in the Digital Age",
|
||||
"Sustainable Transportation",
|
||||
"Gender Equality",
|
||||
"Automation and Job Displacement",
|
||||
"Digital Divide",
|
||||
"Education Inequality"
|
||||
]
|
||||
TOPICS = [
|
||||
"Art and Creativity",
|
||||
"History of Ancient Civilizations",
|
||||
"Environmental Conservation",
|
||||
"Space Exploration",
|
||||
"Artificial Intelligence",
|
||||
"Climate Change",
|
||||
"World Religions",
|
||||
"The Human Brain",
|
||||
"Renewable Energy",
|
||||
"Cultural Diversity",
|
||||
"Modern Technology Trends",
|
||||
"Sustainable Agriculture",
|
||||
"Natural Disasters",
|
||||
"Cybersecurity",
|
||||
"Philosophy of Ethics",
|
||||
"Robotics",
|
||||
"Health and Wellness",
|
||||
"Literature and Classics",
|
||||
"World Geography",
|
||||
"Social Media Impact",
|
||||
"Food Sustainability",
|
||||
"Economics and Markets",
|
||||
"Human Evolution",
|
||||
"Political Systems",
|
||||
"Mental Health Awareness",
|
||||
"Quantum Physics",
|
||||
"Biodiversity",
|
||||
"Education Reform",
|
||||
"Animal Rights",
|
||||
"The Industrial Revolution",
|
||||
"Future of Work",
|
||||
"Film and Cinema",
|
||||
"Genetic Engineering",
|
||||
"Climate Policy",
|
||||
"Space Travel",
|
||||
"Renewable Energy Sources",
|
||||
"Cultural Heritage Preservation",
|
||||
"Modern Art Movements",
|
||||
"Sustainable Transportation",
|
||||
"The History of Medicine",
|
||||
"Artificial Neural Networks",
|
||||
"Climate Adaptation",
|
||||
"Philosophy of Existence",
|
||||
"Augmented Reality",
|
||||
"Yoga and Meditation",
|
||||
"Literary Genres",
|
||||
"World Oceans",
|
||||
"Social Networking",
|
||||
"Sustainable Fashion",
|
||||
"Prehistoric Era",
|
||||
"Democracy and Governance",
|
||||
"Postcolonial Literature",
|
||||
"Geopolitics",
|
||||
"Psychology and Behavior",
|
||||
"Nanotechnology",
|
||||
"Endangered Species",
|
||||
"Education Technology",
|
||||
"Renaissance Art",
|
||||
"Renewable Energy Policy",
|
||||
"Modern Architecture",
|
||||
"Climate Resilience",
|
||||
"Artificial Life",
|
||||
"Fitness and Nutrition",
|
||||
"Classic Literature Adaptations",
|
||||
"Ethical Dilemmas",
|
||||
"Internet of Things (IoT)",
|
||||
"Meditation Practices",
|
||||
"Literary Symbolism",
|
||||
"Marine Conservation",
|
||||
"Sustainable Tourism",
|
||||
"Ancient Philosophy",
|
||||
"Cold War Era",
|
||||
"Behavioral Economics",
|
||||
"Space Colonization",
|
||||
"Clean Energy Initiatives",
|
||||
"Cultural Exchange",
|
||||
"Modern Sculpture",
|
||||
"Climate Mitigation",
|
||||
"Mindfulness",
|
||||
"Literary Criticism",
|
||||
"Wildlife Conservation",
|
||||
"Renewable Energy Innovations",
|
||||
"History of Mathematics",
|
||||
"Human-Computer Interaction",
|
||||
"Global Health",
|
||||
"Cultural Appropriation",
|
||||
"Traditional cuisine and culinary arts",
|
||||
"Local music and dance traditions",
|
||||
"History of the region and historical landmarks",
|
||||
"Traditional crafts and artisanal skills",
|
||||
"Wildlife and conservation efforts",
|
||||
"Local sports and athletic competitions",
|
||||
"Fashion trends and clothing styles",
|
||||
"Education systems and advancements",
|
||||
"Healthcare services and medical innovations",
|
||||
"Family values and social dynamics",
|
||||
"Travel destinations and tourist attractions",
|
||||
"Environmental sustainability projects",
|
||||
"Technological developments and innovations",
|
||||
"Entrepreneurship and business ventures",
|
||||
"Youth empowerment initiatives",
|
||||
"Art exhibitions and cultural events",
|
||||
"Philanthropy and community development projects"
|
||||
]
|
||||
|
||||
TWO_PEOPLE_SCENARIOS = [
|
||||
"Booking a table at a restaurant",
|
||||
"Making a doctor's appointment",
|
||||
"Asking for directions to a tourist attraction",
|
||||
"Inquiring about public transportation options",
|
||||
"Discussing weekend plans with a friend",
|
||||
"Ordering food at a café",
|
||||
"Renting a bicycle for a day",
|
||||
"Arranging a meeting with a colleague",
|
||||
"Talking to a real estate agent about renting an apartment",
|
||||
"Discussing travel plans for an upcoming vacation",
|
||||
"Checking the availability of a hotel room",
|
||||
"Talking to a car rental service",
|
||||
"Asking for recommendations at a library",
|
||||
"Inquiring about opening hours at a museum",
|
||||
"Discussing the weather forecast",
|
||||
"Shopping for groceries",
|
||||
"Renting a movie from a video store",
|
||||
"Booking a flight ticket",
|
||||
"Discussing a school assignment with a classmate",
|
||||
"Making a reservation for a spa appointment",
|
||||
"Talking to a customer service representative about a product issue",
|
||||
"Discussing household chores with a family member",
|
||||
"Planning a surprise party for a friend",
|
||||
"Talking to a coworker about a project deadline",
|
||||
"Inquiring about a gym membership",
|
||||
"Discussing the menu options at a fast-food restaurant",
|
||||
"Talking to a neighbor about a community event",
|
||||
"Asking for help with computer problems",
|
||||
"Discussing a recent sports game with a sports enthusiast",
|
||||
"Talking to a pet store employee about buying a pet",
|
||||
"Asking for information about a local farmer's market",
|
||||
"Discussing the details of a home renovation project",
|
||||
"Talking to a coworker about office supplies",
|
||||
"Making plans for a family picnic",
|
||||
"Inquiring about admission requirements at a university",
|
||||
"Discussing the features of a new smartphone with a salesperson",
|
||||
"Talking to a mechanic about car repairs",
|
||||
"Making arrangements for a child's birthday party",
|
||||
"Discussing a new diet plan with a nutritionist",
|
||||
"Asking for information about a music concert",
|
||||
"Talking to a hairdresser about getting a haircut",
|
||||
"Inquiring about a language course at a language school",
|
||||
"Discussing plans for a weekend camping trip",
|
||||
"Talking to a bank teller about opening a new account",
|
||||
"Ordering a drink at a coffee shop",
|
||||
"Discussing a new book with a book club member",
|
||||
"Talking to a librarian about library services",
|
||||
"Asking for advice on finding a job",
|
||||
"Discussing plans for a garden makeover with a landscaper",
|
||||
"Talking to a travel agent about a cruise vacation",
|
||||
"Inquiring about a fitness class at a gym",
|
||||
"Ordering flowers for a special occasion",
|
||||
"Discussing a new exercise routine with a personal trainer",
|
||||
"Talking to a teacher about a child's progress in school",
|
||||
"Asking for information about a local art exhibition",
|
||||
"Discussing a home improvement project with a contractor",
|
||||
"Talking to a babysitter about childcare arrangements",
|
||||
"Making arrangements for a car service appointment",
|
||||
"Inquiring about a photography workshop at a studio",
|
||||
"Discussing plans for a family reunion with a relative",
|
||||
"Talking to a tech support representative about computer issues",
|
||||
"Asking for recommendations on pet grooming services",
|
||||
"Discussing weekend plans with a significant other",
|
||||
"Talking to a counselor about personal issues",
|
||||
"Inquiring about a music lesson with a music teacher",
|
||||
"Ordering a pizza for delivery",
|
||||
"Making a reservation for a taxi",
|
||||
"Discussing a new recipe with a chef",
|
||||
"Talking to a fitness trainer about weight loss goals",
|
||||
"Inquiring about a dance class at a dance studio",
|
||||
"Ordering a meal at a food truck",
|
||||
"Discussing plans for a weekend getaway with a partner",
|
||||
"Talking to a florist about wedding flower arrangements",
|
||||
"Asking for advice on home decorating",
|
||||
"Discussing plans for a charity fundraiser event",
|
||||
"Talking to a pet sitter about taking care of pets",
|
||||
"Making arrangements for a spa day with a friend",
|
||||
"Asking for recommendations on home improvement stores",
|
||||
"Discussing weekend plans with a travel enthusiast",
|
||||
"Talking to a car mechanic about car maintenance",
|
||||
"Inquiring about a cooking class at a culinary school",
|
||||
"Ordering a sandwich at a deli",
|
||||
"Discussing plans for a family holiday party",
|
||||
"Talking to a personal assistant about organizing tasks",
|
||||
"Asking for information about a local theater production",
|
||||
"Discussing a new DIY project with a home improvement expert",
|
||||
"Talking to a wine expert about wine pairing",
|
||||
"Making arrangements for a pet adoption",
|
||||
"Asking for advice on planning a wedding"
|
||||
]
|
||||
|
||||
SOCIAL_MONOLOGUE_CONTEXTS = [
|
||||
"A guided tour of a historical museum",
|
||||
"An introduction to a new city for tourists",
|
||||
"An orientation session for new university students",
|
||||
"A safety briefing for airline passengers",
|
||||
"An explanation of the process of recycling",
|
||||
"A lecture on the benefits of a healthy diet",
|
||||
"A talk on the importance of time management",
|
||||
"A monologue about wildlife conservation",
|
||||
"An overview of local public transportation options",
|
||||
"A presentation on the history of cinema",
|
||||
"An introduction to the art of photography",
|
||||
"A discussion about the effects of climate change",
|
||||
"An overview of different types of cuisine",
|
||||
"A lecture on the principles of financial planning",
|
||||
"A monologue about sustainable energy sources",
|
||||
"An explanation of the process of online shopping",
|
||||
"A guided tour of a botanical garden",
|
||||
"An introduction to a local wildlife sanctuary",
|
||||
"A safety briefing for hikers in a national park",
|
||||
"A talk on the benefits of physical exercise",
|
||||
"A lecture on the principles of effective communication",
|
||||
"A monologue about the impact of social media",
|
||||
"An overview of the history of a famous landmark",
|
||||
"An introduction to the world of fashion design",
|
||||
"A discussion about the challenges of global poverty",
|
||||
"An explanation of the process of organic farming",
|
||||
"A presentation on the history of space exploration",
|
||||
"An overview of traditional music from different cultures",
|
||||
"A lecture on the principles of effective leadership",
|
||||
"A monologue about the influence of technology",
|
||||
"A guided tour of a famous archaeological site",
|
||||
"An introduction to a local wildlife rehabilitation center",
|
||||
"A safety briefing for visitors to a science museum",
|
||||
"A talk on the benefits of learning a new language",
|
||||
"A lecture on the principles of architectural design",
|
||||
"A monologue about the impact of renewable energy",
|
||||
"An explanation of the process of online banking",
|
||||
"A presentation on the history of a famous art movement",
|
||||
"An overview of traditional clothing from various regions",
|
||||
"A lecture on the principles of sustainable agriculture",
|
||||
"A discussion about the challenges of urban development",
|
||||
"A monologue about the influence of social norms",
|
||||
"A guided tour of a historical battlefield",
|
||||
"An introduction to a local animal shelter",
|
||||
"A safety briefing for participants in a charity run",
|
||||
"A talk on the benefits of community involvement",
|
||||
"A lecture on the principles of sustainable tourism",
|
||||
"A monologue about the impact of alternative medicine",
|
||||
"An explanation of the process of wildlife tracking",
|
||||
"A presentation on the history of a famous inventor",
|
||||
"An overview of traditional dance forms from different cultures",
|
||||
"A lecture on the principles of ethical business practices",
|
||||
"A discussion about the challenges of healthcare access",
|
||||
"A monologue about the influence of cultural traditions",
|
||||
"A guided tour of a famous lighthouse",
|
||||
"An introduction to a local astronomy observatory",
|
||||
"A safety briefing for participants in a team-building event",
|
||||
"A talk on the benefits of volunteering",
|
||||
"A lecture on the principles of wildlife protection",
|
||||
"A monologue about the impact of space exploration",
|
||||
"An explanation of the process of wildlife photography",
|
||||
"A presentation on the history of a famous musician",
|
||||
"An overview of traditional art forms from different cultures",
|
||||
"A lecture on the principles of effective education",
|
||||
"A discussion about the challenges of sustainable development",
|
||||
"A monologue about the influence of cultural diversity",
|
||||
"A guided tour of a famous national park",
|
||||
"An introduction to a local marine conservation project",
|
||||
"A safety briefing for participants in a hot air balloon ride",
|
||||
"A talk on the benefits of cultural exchange programs",
|
||||
"A lecture on the principles of wildlife conservation",
|
||||
"A monologue about the impact of technological advancements",
|
||||
"An explanation of the process of wildlife rehabilitation",
|
||||
"A presentation on the history of a famous explorer",
|
||||
"A lecture on the principles of effective marketing",
|
||||
"A discussion about the challenges of environmental sustainability",
|
||||
"A monologue about the influence of social entrepreneurship",
|
||||
"A guided tour of a famous historical estate",
|
||||
"An introduction to a local marine life research center",
|
||||
"A safety briefing for participants in a zip-lining adventure",
|
||||
"A talk on the benefits of cultural preservation",
|
||||
"A lecture on the principles of wildlife ecology",
|
||||
"A monologue about the impact of space technology",
|
||||
"An explanation of the process of wildlife conservation",
|
||||
"A presentation on the history of a famous scientist",
|
||||
"An overview of traditional crafts and artisans from different cultures",
|
||||
"A lecture on the principles of effective intercultural communication"
|
||||
]
|
||||
|
||||
FOUR_PEOPLE_SCENARIOS = [
|
||||
"A university lecture on history",
|
||||
"A physics class discussing Newton's laws",
|
||||
"A medical school seminar on anatomy",
|
||||
"A training session on computer programming",
|
||||
"A business school lecture on marketing strategies",
|
||||
"A chemistry lab experiment and discussion",
|
||||
"A language class practicing conversational skills",
|
||||
"A workshop on creative writing techniques",
|
||||
"A high school math lesson on calculus",
|
||||
"A training program for customer service representatives",
|
||||
"A lecture on environmental science and sustainability",
|
||||
"A psychology class exploring human behavior",
|
||||
"A music theory class analyzing compositions",
|
||||
"A nursing school simulation for patient care",
|
||||
"A computer science class on algorithms",
|
||||
"A workshop on graphic design principles",
|
||||
"A law school lecture on constitutional law",
|
||||
"A geology class studying rock formations",
|
||||
"A vocational training program for electricians",
|
||||
"A history seminar focusing on ancient civilizations",
|
||||
"A biology class dissecting specimens",
|
||||
"A financial literacy course for adults",
|
||||
"A literature class discussing classic novels",
|
||||
"A training session for emergency response teams",
|
||||
"A sociology lecture on social inequality",
|
||||
"An art class exploring different painting techniques",
|
||||
"A medical school seminar on diagnosis",
|
||||
"A programming bootcamp teaching web development",
|
||||
"An economics class analyzing market trends",
|
||||
"A chemistry lab experiment on chemical reactions",
|
||||
"A language class practicing pronunciation",
|
||||
"A workshop on public speaking skills",
|
||||
"A high school physics lesson on electromagnetism",
|
||||
"A training program for IT professionals",
|
||||
"A lecture on climate change and its effects",
|
||||
"A psychology class studying cognitive psychology",
|
||||
"A music class composing original songs",
|
||||
"A nursing school simulation for patient assessment",
|
||||
"A computer science class on data structures",
|
||||
"A workshop on 3D modeling and animation",
|
||||
"A law school lecture on contract law",
|
||||
"A geography class examining world maps",
|
||||
"A vocational training program for plumbers",
|
||||
"A history seminar discussing revolutions",
|
||||
"A biology class exploring genetics",
|
||||
"A financial literacy course for teens",
|
||||
"A literature class analyzing poetry",
|
||||
"A training session for public speaking coaches",
|
||||
"A sociology lecture on cultural diversity",
|
||||
"An art class creating sculptures",
|
||||
"A medical school seminar on surgical techniques",
|
||||
"A programming bootcamp teaching app development",
|
||||
"An economics class on global trade policies",
|
||||
"A chemistry lab experiment on chemical bonding",
|
||||
"A language class discussing idiomatic expressions",
|
||||
"A workshop on conflict resolution",
|
||||
"A high school biology lesson on evolution",
|
||||
"A training program for project managers",
|
||||
"A lecture on renewable energy sources",
|
||||
"A psychology class on abnormal psychology",
|
||||
"A music class rehearsing for a performance",
|
||||
"A nursing school simulation for emergency response",
|
||||
"A computer science class on cybersecurity",
|
||||
"A workshop on digital marketing strategies",
|
||||
"A law school lecture on intellectual property",
|
||||
"A geology class analyzing seismic activity",
|
||||
"A vocational training program for carpenters",
|
||||
"A history seminar on the Renaissance",
|
||||
"A chemistry class synthesizing compounds",
|
||||
"A financial literacy course for seniors",
|
||||
"A literature class interpreting Shakespearean plays",
|
||||
"A training session for negotiation skills",
|
||||
"A sociology lecture on urbanization",
|
||||
"An art class creating digital art",
|
||||
"A medical school seminar on patient communication",
|
||||
"A programming bootcamp teaching mobile app development",
|
||||
"An economics class on fiscal policy",
|
||||
"A physics lab experiment on electromagnetism",
|
||||
"A language class on cultural immersion",
|
||||
"A workshop on time management",
|
||||
"A high school chemistry lesson on stoichiometry",
|
||||
"A training program for HR professionals",
|
||||
"A lecture on space exploration and astronomy",
|
||||
"A psychology class on human development",
|
||||
"A music class practicing for a recital",
|
||||
"A nursing school simulation for triage",
|
||||
"A computer science class on web development frameworks",
|
||||
"A workshop on team-building exercises",
|
||||
"A law school lecture on criminal law",
|
||||
"A geography class studying world cultures",
|
||||
"A vocational training program for HVAC technicians",
|
||||
"A history seminar on ancient civilizations",
|
||||
"A biology class examining ecosystems",
|
||||
"A financial literacy course for entrepreneurs",
|
||||
"A literature class analyzing modern literature",
|
||||
"A training session for leadership skills",
|
||||
"A sociology lecture on gender studies",
|
||||
"An art class exploring multimedia art",
|
||||
"A medical school seminar on patient diagnosis",
|
||||
"A programming bootcamp teaching software architecture"
|
||||
]
|
||||
|
||||
ACADEMIC_SUBJECTS = [
|
||||
"Astrophysics",
|
||||
"Microbiology",
|
||||
"Political Science",
|
||||
"Environmental Science",
|
||||
"Literature",
|
||||
"Biochemistry",
|
||||
"Sociology",
|
||||
"Art History",
|
||||
"Geology",
|
||||
"Economics",
|
||||
"Psychology",
|
||||
"History of Architecture",
|
||||
"Linguistics",
|
||||
"Neurobiology",
|
||||
"Anthropology",
|
||||
"Quantum Mechanics",
|
||||
"Urban Planning",
|
||||
"Philosophy",
|
||||
"Marine Biology",
|
||||
"International Relations",
|
||||
"Medieval History",
|
||||
"Geophysics",
|
||||
"Finance",
|
||||
"Educational Psychology",
|
||||
"Graphic Design",
|
||||
"Paleontology",
|
||||
"Macroeconomics",
|
||||
"Cognitive Psychology",
|
||||
"Renaissance Art",
|
||||
"Archaeology",
|
||||
"Microeconomics",
|
||||
"Social Psychology",
|
||||
"Contemporary Art",
|
||||
"Meteorology",
|
||||
"Political Philosophy",
|
||||
"Space Exploration",
|
||||
"Cognitive Science",
|
||||
"Classical Music",
|
||||
"Oceanography",
|
||||
"Public Health",
|
||||
"Gender Studies",
|
||||
"Baroque Art",
|
||||
"Volcanology",
|
||||
"Business Ethics",
|
||||
"Music Composition",
|
||||
"Environmental Policy",
|
||||
"Media Studies",
|
||||
"Ancient History",
|
||||
"Seismology",
|
||||
"Marketing",
|
||||
"Human Development",
|
||||
"Modern Art",
|
||||
"Astronomy",
|
||||
"International Law",
|
||||
"Developmental Psychology",
|
||||
"Film Studies",
|
||||
"American History",
|
||||
"Soil Science",
|
||||
"Entrepreneurship",
|
||||
"Clinical Psychology",
|
||||
"Contemporary Dance",
|
||||
"Space Physics",
|
||||
"Political Economy",
|
||||
"Cognitive Neuroscience",
|
||||
"20th Century Literature",
|
||||
"Public Administration",
|
||||
"European History",
|
||||
"Atmospheric Science",
|
||||
"Supply Chain Management",
|
||||
"Social Work",
|
||||
"Japanese Literature",
|
||||
"Planetary Science",
|
||||
"Labor Economics",
|
||||
"Industrial-Organizational Psychology",
|
||||
"French Philosophy",
|
||||
"Biogeochemistry",
|
||||
"Strategic Management",
|
||||
"Educational Sociology",
|
||||
"Postmodern Literature",
|
||||
"Public Relations",
|
||||
"Middle Eastern History",
|
||||
"Oceanography",
|
||||
"International Development",
|
||||
"Human Resources Management",
|
||||
"Educational Leadership",
|
||||
"Russian Literature",
|
||||
"Quantum Chemistry",
|
||||
"Environmental Economics",
|
||||
"Environmental Psychology",
|
||||
"Ancient Philosophy",
|
||||
"Immunology",
|
||||
"Comparative Politics",
|
||||
"Child Development",
|
||||
"Fashion Design",
|
||||
"Geological Engineering",
|
||||
"Macroeconomic Policy",
|
||||
"Media Psychology",
|
||||
"Byzantine Art",
|
||||
"Ecology",
|
||||
"International Business"
|
||||
]
|
||||
108
app/configs/dependency_injection.py
Normal file
108
app/configs/dependency_injection.py
Normal file
@@ -0,0 +1,108 @@
|
||||
import os
|
||||
|
||||
from dependency_injector import providers, containers
|
||||
from firebase_admin import credentials
|
||||
from openai import AsyncOpenAI
|
||||
from httpx import AsyncClient as HTTPClient
|
||||
from google.cloud.firestore_v1 import AsyncClient as FirestoreClient
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from app.repositories.impl import *
|
||||
from app.services.impl import *
|
||||
from app.controllers.impl import *
|
||||
|
||||
load_dotenv()
|
||||
|
||||
|
||||
def config_di(
|
||||
*, polly_client: any, http_client: HTTPClient, whisper_model: any
|
||||
) -> None:
|
||||
"""
|
||||
Loads up all the common configs of all the environments
|
||||
and then calls the specific env configs
|
||||
"""
|
||||
# Firebase token
|
||||
cred = credentials.Certificate(os.getenv("GOOGLE_APPLICATION_CREDENTIALS"))
|
||||
firebase_token = cred.get_access_token().access_token
|
||||
|
||||
container = containers.DynamicContainer()
|
||||
|
||||
openai_client = providers.Singleton(AsyncOpenAI)
|
||||
polly_client = providers.Object(polly_client)
|
||||
http_client = providers.Object(http_client)
|
||||
firestore_client = providers.Singleton(FirestoreClient)
|
||||
whisper_model = providers.Object(whisper_model)
|
||||
|
||||
llm = providers.Factory(OpenAI, client=openai_client)
|
||||
stt = providers.Factory(OpenAIWhisper, model=whisper_model)
|
||||
tts = providers.Factory(AWSPolly, client=polly_client)
|
||||
vid_gen = providers.Factory(Heygen, client=http_client, heygen_token=os.getenv("HEY_GEN_TOKEN"))
|
||||
ai_detector = providers.Factory(GPTZero, client=http_client, gpt_zero_key=os.getenv("GPT_ZERO_API_KEY"))
|
||||
|
||||
firebase_instance = providers.Factory(
|
||||
FirebaseStorage, client=http_client, token=firebase_token, bucket=os.getenv("FIREBASE_BUCKET")
|
||||
)
|
||||
|
||||
firestore = providers.Factory(Firestore, client=firestore_client)
|
||||
|
||||
# Services
|
||||
|
||||
listening_service = providers.Factory(
|
||||
ListeningService, llm=llm, tts=tts, file_storage=firebase_instance, document_store=firestore
|
||||
)
|
||||
reading_service = providers.Factory(ReadingService, llm=llm)
|
||||
|
||||
speaking_service = providers.Factory(
|
||||
SpeakingService, llm=llm, vid_gen=vid_gen,
|
||||
file_storage=firebase_instance, document_store=firestore,
|
||||
stt=stt
|
||||
)
|
||||
|
||||
writing_service = providers.Factory(WritingService, llm=llm, ai_detector=ai_detector)
|
||||
|
||||
level_service = providers.Factory(
|
||||
LevelService, llm=llm, document_store=firestore, reading_service=reading_service
|
||||
)
|
||||
|
||||
grade_service = providers.Factory(
|
||||
GradeService, llm=llm
|
||||
)
|
||||
|
||||
training_service = providers.Factory(
|
||||
TrainingService, llm=llm
|
||||
)
|
||||
|
||||
# Controllers
|
||||
|
||||
container.grade_controller = providers.Factory(
|
||||
GradeController, grade_service=grade_service, speaking_service=speaking_service, writing_service=writing_service
|
||||
)
|
||||
|
||||
container.training_controller = providers.Factory(
|
||||
TrainingController, training_service=training_service
|
||||
)
|
||||
|
||||
container.level_controller = providers.Factory(
|
||||
LevelController, level_service=level_service
|
||||
)
|
||||
container.listening_controller = providers.Factory(
|
||||
ListeningController, listening_service=listening_service
|
||||
)
|
||||
|
||||
container.reading_controller = providers.Factory(
|
||||
ReadingController, reading_service=reading_service
|
||||
)
|
||||
|
||||
container.speaking_controller = providers.Factory(
|
||||
SpeakingController, speaking_service=speaking_service
|
||||
)
|
||||
|
||||
container.writing_controller = providers.Factory(
|
||||
WritingController, writing_service=writing_service
|
||||
)
|
||||
|
||||
container.llm = llm
|
||||
|
||||
container.wire(
|
||||
packages=["app"]
|
||||
)
|
||||
7
app/configs/logging/__init__.py
Normal file
7
app/configs/logging/__init__.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from .filters import ErrorAndAboveFilter
|
||||
from .queue_handler import QueueListenerHandler
|
||||
|
||||
__all__ = [
|
||||
"ErrorAndAboveFilter",
|
||||
"QueueListenerHandler"
|
||||
]
|
||||
6
app/configs/logging/filters.py
Normal file
6
app/configs/logging/filters.py
Normal file
@@ -0,0 +1,6 @@
|
||||
import logging
|
||||
|
||||
|
||||
class ErrorAndAboveFilter(logging.Filter):
|
||||
def filter(self, record: logging.LogRecord) -> bool | logging.LogRecord:
|
||||
return record.levelno < logging.ERROR
|
||||
105
app/configs/logging/formatters.py
Normal file
105
app/configs/logging/formatters.py
Normal file
@@ -0,0 +1,105 @@
|
||||
import datetime as dt
|
||||
import json
|
||||
import logging
|
||||
|
||||
LOG_RECORD_BUILTIN_ATTRS = {
|
||||
"args",
|
||||
"asctime",
|
||||
"created",
|
||||
"exc_info",
|
||||
"exc_text",
|
||||
"filename",
|
||||
"funcName",
|
||||
"levelname",
|
||||
"levelno",
|
||||
"lineno",
|
||||
"module",
|
||||
"msecs",
|
||||
"message",
|
||||
"msg",
|
||||
"name",
|
||||
"pathname",
|
||||
"process",
|
||||
"processName",
|
||||
"relativeCreated",
|
||||
"stack_info",
|
||||
"thread",
|
||||
"threadName",
|
||||
"taskName",
|
||||
}
|
||||
|
||||
"""
|
||||
This isn't being used since the app will be run on gcloud run but this can be used for future apps.
|
||||
If you want to test it:
|
||||
|
||||
formatters:
|
||||
|
||||
"json": {
|
||||
"()": "json_formatter.JSONFormatter",
|
||||
"fmt_keys": {
|
||||
"level": "levelname",
|
||||
"message": "message",
|
||||
"timestamp": "timestamp",
|
||||
"logger": "name",
|
||||
"module": "module",
|
||||
"function": "funcName",
|
||||
"line": "lineno",
|
||||
"thread_name": "threadName"
|
||||
}
|
||||
}
|
||||
|
||||
handlers:
|
||||
|
||||
"file_json": {
|
||||
"class": "logging.handlers.RotatingFileHandler",
|
||||
"level": "DEBUG",
|
||||
"formatter": "json",
|
||||
"filename": "logs/log",
|
||||
"maxBytes": 1000000,
|
||||
"backupCount": 3
|
||||
}
|
||||
|
||||
and add "cfg://handlers.file_json" to queue handler
|
||||
"""
|
||||
|
||||
# From this video https://www.youtube.com/watch?v=9L77QExPmI0
|
||||
# Src here: https://github.com/mCodingLLC/VideosSampleCode/blob/master/videos/135_modern_logging/mylogger.py
|
||||
class JSONFormatter(logging.Formatter):
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
fmt_keys: dict[str, str] | None = None,
|
||||
):
|
||||
super().__init__()
|
||||
self.fmt_keys = fmt_keys if fmt_keys is not None else {}
|
||||
|
||||
def format(self, record: logging.LogRecord) -> str:
|
||||
message = self._prepare_log_dict(record)
|
||||
return json.dumps(message, default=str)
|
||||
|
||||
def _prepare_log_dict(self, record: logging.LogRecord):
|
||||
always_fields = {
|
||||
"message": record.getMessage(),
|
||||
"timestamp": dt.datetime.fromtimestamp(
|
||||
record.created, tz=dt.timezone.utc
|
||||
).isoformat(),
|
||||
}
|
||||
if record.exc_info is not None:
|
||||
always_fields["exc_info"] = self.formatException(record.exc_info)
|
||||
|
||||
if record.stack_info is not None:
|
||||
always_fields["stack_info"] = self.formatStack(record.stack_info)
|
||||
|
||||
message = {
|
||||
key: msg_val
|
||||
if (msg_val := always_fields.pop(val, None)) is not None
|
||||
else getattr(record, val)
|
||||
for key, val in self.fmt_keys.items()
|
||||
}
|
||||
message.update(always_fields)
|
||||
|
||||
for key, val in record.__dict__.items():
|
||||
if key not in LOG_RECORD_BUILTIN_ATTRS:
|
||||
message[key] = val
|
||||
|
||||
return message
|
||||
53
app/configs/logging/logging_config.json
Normal file
53
app/configs/logging/logging_config.json
Normal file
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"version": 1,
|
||||
"objects": {
|
||||
"queue": {
|
||||
"class": "queue.Queue",
|
||||
"maxsize": 1000
|
||||
}
|
||||
},
|
||||
"disable_existing_loggers": false,
|
||||
"formatters": {
|
||||
"simple": {
|
||||
"format": "[%(levelname)s] (%(module)s|L: %(lineno)d) %(asctime)s: %(message)s",
|
||||
"datefmt": "%Y-%m-%dT%H:%M:%S%z"
|
||||
}
|
||||
},
|
||||
"filters": {
|
||||
"error_and_above": {
|
||||
"()": "app.configs.logging.ErrorAndAboveFilter"
|
||||
}
|
||||
},
|
||||
"handlers": {
|
||||
"console": {
|
||||
"class": "logging.StreamHandler",
|
||||
"level": "INFO",
|
||||
"formatter": "simple",
|
||||
"stream": "ext://sys.stdout",
|
||||
"filters": ["error_and_above"]
|
||||
},
|
||||
"error": {
|
||||
"class": "logging.StreamHandler",
|
||||
"level": "ERROR",
|
||||
"formatter": "simple",
|
||||
"stream": "ext://sys.stderr"
|
||||
},
|
||||
"queue_handler": {
|
||||
"class": "app.configs.logging.QueueListenerHandler",
|
||||
"handlers": [
|
||||
"cfg://handlers.console",
|
||||
"cfg://handlers.error"
|
||||
],
|
||||
"queue": "cfg://objects.queue",
|
||||
"respect_handler_level": true
|
||||
}
|
||||
},
|
||||
"loggers": {
|
||||
"root": {
|
||||
"level": "DEBUG",
|
||||
"handlers": [
|
||||
"queue_handler"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
61
app/configs/logging/queue_handler.py
Normal file
61
app/configs/logging/queue_handler.py
Normal file
@@ -0,0 +1,61 @@
|
||||
from logging.config import ConvertingList, ConvertingDict, valid_ident
|
||||
from logging.handlers import QueueHandler, QueueListener
|
||||
from queue import Queue
|
||||
import atexit
|
||||
|
||||
|
||||
class QueueHnadlerHelper:
|
||||
|
||||
@staticmethod
|
||||
def resolve_handlers(l):
|
||||
if not isinstance(l, ConvertingList):
|
||||
return l
|
||||
|
||||
# Indexing the list performs the evaluation.
|
||||
return [l[i] for i in range(len(l))]
|
||||
|
||||
@staticmethod
|
||||
def resolve_queue(q):
|
||||
if not isinstance(q, ConvertingDict):
|
||||
return q
|
||||
if '__resolved_value__' in q:
|
||||
return q['__resolved_value__']
|
||||
|
||||
cname = q.pop('class')
|
||||
klass = q.configurator.resolve(cname)
|
||||
props = q.pop('.', None)
|
||||
kwargs = {k: q[k] for k in q if valid_ident(k)}
|
||||
result = klass(**kwargs)
|
||||
if props:
|
||||
for name, value in props.items():
|
||||
setattr(result, name, value)
|
||||
|
||||
q['__resolved_value__'] = result
|
||||
return result
|
||||
|
||||
|
||||
# The guy from this video https://www.youtube.com/watch?v=9L77QExPmI0 is using logging features only available in 3.12
|
||||
# This article had the class required to build the queue handler in 3.11
|
||||
# https://rob-blackbourn.medium.com/how-to-use-python-logging-queuehandler-with-dictconfig-1e8b1284e27a
|
||||
class QueueListenerHandler(QueueHandler):
|
||||
|
||||
def __init__(self, handlers, respect_handler_level=False, auto_run=True, queue=Queue(-1)):
|
||||
queue = QueueHnadlerHelper.resolve_queue(queue)
|
||||
super().__init__(queue)
|
||||
handlers = QueueHnadlerHelper.resolve_handlers(handlers)
|
||||
self._listener = QueueListener(
|
||||
self.queue,
|
||||
*handlers,
|
||||
respect_handler_level=respect_handler_level)
|
||||
if auto_run:
|
||||
self.start()
|
||||
atexit.register(self.stop)
|
||||
|
||||
def start(self):
|
||||
self._listener.start()
|
||||
|
||||
def stop(self):
|
||||
self._listener.stop()
|
||||
|
||||
def emit(self, record):
|
||||
return super().emit(record)
|
||||
1275
app/configs/question_templates.py
Normal file
1275
app/configs/question_templates.py
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user