samu commited on
Commit
6c8a2d5
·
1 Parent(s): 6ee087a

application version 0

Browse files
Dockerfile ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.9
2
+
3
+ # Create a non-root user and set paths
4
+ RUN useradd -m -u 1000 user
5
+ USER user
6
+ ENV PATH="/home/user/.local/bin:$PATH"
7
+
8
+ WORKDIR /app
9
+
10
+ # Copy and install dependencies
11
+ COPY --chown=user ./requirements.txt requirements.txt
12
+ RUN pip install --no-cache-dir --upgrade -r requirements.txt
13
+
14
+ # Copy the rest of the application files
15
+ COPY --chown=user . /app
16
+
17
+ # Ensure .env file exists before copying
18
+ COPY --chown=user .env /app/.env
19
+
20
+ CMD ["uvicorn", "backend.api.app:app", "--host", "0.0.0.0", "--port", "7860"]
21
+
backend/CurriculumManager/__init__.py ADDED
File without changes
backend/CurriculumManager/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (189 Bytes). View file
 
backend/CurriculumManager/__pycache__/generate_curriculum.cpython-312.pyc ADDED
Binary file (2.4 kB). View file
 
backend/CurriculumManager/config.json ADDED
@@ -0,0 +1 @@
 
 
1
+ {}
backend/CurriculumManager/generate_curriculum.py ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+ from openai import OpenAI
4
+ from backend.config import config, CURRICULUM_INSTRUCTION
5
+ from backend.utils import write_json_file, ensure_directory
6
+
7
+ PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
8
+ output_dir = os.path.join(PROJECT_ROOT, "output")
9
+ ensure_directory(output_dir)
10
+
11
+ client = OpenAI(
12
+ api_key=config.get('api_key'),
13
+ base_url=config.get('base_url'),
14
+ )
15
+
16
+ def get_completion(prompt: str):
17
+ response = client.chat.completions.create(
18
+ model=config.get('model'),
19
+ messages=[
20
+ {"role": "system", "content": CURRICULUM_INSTRUCTION},
21
+ {"role": "user", "content": prompt},
22
+ ],
23
+ response_format={"type": "json_object"},
24
+ )
25
+
26
+ try:
27
+ data = json.loads(response.choices[0].message.content)
28
+ filename = os.path.join(output_dir, "curriculum.json")
29
+
30
+ if write_json_file(filename, data):
31
+ print(f"JSON data saved to {filename}")
32
+ # Reset the config when new curriculum is generated
33
+ config.set("current_week", 0)
34
+ config.save()
35
+ return data # Return the data instead of True
36
+ print("Failed to save data")
37
+ return None
38
+
39
+ except json.JSONDecodeError as e:
40
+ print(f"Error decoding JSON: {e}")
41
+ return None
backend/LessonManager/__init__.py ADDED
File without changes
backend/LessonManager/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (185 Bytes). View file
 
backend/LessonManager/__pycache__/generate_daily_lesson.cpython-312.pyc ADDED
Binary file (2.23 kB). View file
 
backend/LessonManager/__pycache__/generate_lesson.cpython-312.pyc ADDED
Binary file (2.21 kB). View file
 
backend/LessonManager/generate_daily_lesson.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+ from openai import OpenAI
4
+ from backend.config import config
5
+ from backend.utils import write_json_file, ensure_directory
6
+
7
+ PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
8
+ output_dir = os.path.join(PROJECT_ROOT, "output")
9
+ ensure_directory(output_dir)
10
+
11
+ client = OpenAI(
12
+ api_key=config.get('api_key'),
13
+ base_url=config.get('base_url'),
14
+ )
15
+
16
+ def get_completion(prompt: str):
17
+ response = client.chat.completions.create(
18
+ model=config.get('model'),
19
+ messages=[
20
+ {"role": "system", "content": config.get('daily_lesson_instruction')},
21
+ {"role": "user", "content": prompt},
22
+ ],
23
+ response_format={"type": "json_object"},
24
+ )
25
+
26
+ try:
27
+ data = json.loads(response.choices[0].message.content)
28
+ filename = f"{output_dir}/daily_lesson.json"
29
+
30
+ if write_json_file(filename, data):
31
+ print(f"JSON data saved to {filename}")
32
+ else:
33
+ print("Failed to save data")
34
+ return data
35
+
36
+ except json.JSONDecodeError as e:
37
+ print(f"Error decoding JSON: {e}")
38
+ return None
backend/LessonManager/generate_lesson.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+ from openai import OpenAI
4
+ from backend.config import config
5
+ from backend.utils import write_json_file, ensure_directory
6
+
7
+ PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
8
+ output_dir = os.path.join(PROJECT_ROOT, "output")
9
+ ensure_directory(output_dir)
10
+
11
+ client = OpenAI(
12
+ api_key=config.get('api_key'),
13
+ base_url=config.get('base_url'),
14
+ )
15
+
16
+ def get_completion(prompt: str):
17
+ response = client.chat.completions.create(
18
+ model=config.get('model'),
19
+ messages=[
20
+ {"role": "system", "content": config.get('lesson_instruction')},
21
+ {"role": "user", "content": prompt},
22
+ ],
23
+ response_format={"type": "json_object"},
24
+ )
25
+
26
+ try:
27
+ data = json.loads(response.choices[0].message.content)
28
+ filename = f"{output_dir}/lesson.json"
29
+
30
+ if write_json_file(filename, data):
31
+ print(f"JSON data saved to {filename}")
32
+ else:
33
+ print("Failed to save data")
34
+ return data
35
+
36
+ except json.JSONDecodeError as e:
37
+ print(f"Error decoding JSON: {e}")
38
+ return None
backend/__init__.py ADDED
File without changes
backend/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (171 Bytes). View file
 
backend/__pycache__/config.cpython-312.pyc ADDED
Binary file (3.84 kB). View file
 
backend/__pycache__/config_manager.cpython-312.pyc ADDED
Binary file (3.57 kB). View file
 
backend/__pycache__/main.cpython-312.pyc ADDED
Binary file (9.02 kB). View file
 
backend/__pycache__/utils.cpython-312.pyc ADDED
Binary file (2.68 kB). View file
 
backend/api/__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+ # Empty init file
backend/api/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (175 Bytes). View file
 
backend/api/__pycache__/app.cpython-312.pyc ADDED
Binary file (5.64 kB). View file
 
backend/api/__pycache__/models.cpython-312.pyc ADDED
Binary file (903 Bytes). View file
 
backend/api/app.py ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import socket
3
+ from fastapi import FastAPI, HTTPException
4
+ from .models import CurriculumRequest, LessonRequest, DailyLessonRequest
5
+ from backend.CurriculumManager.generate_curriculum import get_completion as generate_curriculum
6
+ from backend.LessonManager.generate_lesson import get_completion as generate_lesson
7
+ from backend.LessonManager.generate_daily_lesson import get_completion as generate_daily_lesson
8
+ from backend.config_manager import Config
9
+ from backend.utils import read_json_file, ensure_directory
10
+
11
+ # Set up paths correctly
12
+ PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
13
+ CONFIG_DIR = os.path.join(PROJECT_ROOT, "backend")
14
+ CONFIG_PATH = os.path.join(CONFIG_DIR, "config.json")
15
+
16
+ # Ensure config directory exists
17
+ ensure_directory(CONFIG_DIR)
18
+
19
+ # Import and run config setup
20
+ from backend.config import (
21
+ CURRICULUM_INSTRUCTION,
22
+ MODEL,
23
+ BASE_URL,
24
+ API_KEY,
25
+ API_PORT
26
+ )
27
+
28
+ app = FastAPI(title="AI Language Tutor API")
29
+ config = Config(CONFIG_PATH)
30
+
31
+ # Initialize config with default values if not exists
32
+ if not config.data:
33
+ config.set("curriculum_instruction", CURRICULUM_INSTRUCTION)
34
+ config.set("model", MODEL)
35
+ config.set("base_url", BASE_URL)
36
+ config.set("api_key", API_KEY)
37
+ config.save()
38
+
39
+ @app.post("/curriculum")
40
+ async def create_curriculum(request: CurriculumRequest):
41
+ try:
42
+ return generate_curriculum(request.prompt)
43
+ except Exception as e:
44
+ raise HTTPException(status_code=500, detail=str(e))
45
+
46
+ @app.post("/lesson")
47
+ async def create_lesson(request: LessonRequest):
48
+ try:
49
+ # Simulate args object for compatibility
50
+ class Args:
51
+ def __init__(self, week):
52
+ self.week = week
53
+
54
+ args = Args(request.week)
55
+ from backend.main import setup_lesson_instruction
56
+
57
+ setup_lesson_instruction(args)
58
+ return generate_lesson(config.get("lesson_prompt"))
59
+ except FileNotFoundError:
60
+ raise HTTPException(status_code=404, detail="Curriculum not found")
61
+ except ValueError as e:
62
+ raise HTTPException(status_code=400, detail=str(e))
63
+
64
+ @app.post("/daily-lesson")
65
+ async def create_daily_lesson(request: DailyLessonRequest):
66
+ try:
67
+ class Args:
68
+ def __init__(self, week, day):
69
+ self.week = week
70
+ self.day = day
71
+
72
+ args = Args(request.week, request.day)
73
+ from backend.main import setup_daily_lesson
74
+
75
+ return setup_daily_lesson(args)
76
+ except FileNotFoundError:
77
+ raise HTTPException(status_code=404, detail="Lesson plan not found")
78
+ except ValueError as e:
79
+ raise HTTPException(status_code=400, detail=str(e))
80
+
81
+ # Add Args class at module level
82
+ class Args:
83
+ def __init__(self, week=0, day=0):
84
+ self.week = week
85
+ self.day = day
backend/api/models.py ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic import BaseModel
2
+
3
+ class CurriculumRequest(BaseModel):
4
+ prompt: str
5
+
6
+ class LessonRequest(BaseModel):
7
+ week: int = 0
8
+
9
+ class DailyLessonRequest(BaseModel):
10
+ week: int = 0
11
+ day: int = 0
backend/config.json ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "curriculum_instruction": "\nYou are an expert language learning curriculum designer. Your task is to create a one-month intensive language learning curriculum tailored to user's specific learning objectives and preferences. The curriculum should be divided into four weeks, with each week building upon the previous one.\n\n**Curriculum Design Principles:**\n\n1. **Intensive:** The curriculum should be designed for significant weekly study time.\n2. **Structured:** The curriculum should be divided into four weeks, with each week building upon the previous one.\n3. **Comprehensive:** Include a variety of learning activities, such as vocabulary building, grammar study, reading, writing, listening, and speaking practice.\n4. **Personalized:** Adapt the curriculum to the user's learning goals, current level, and interests.\n5. **Measurable:** Suggest ways the user can track their progress.\n6. **Output Format:** Provide the curriculum in a valid JSON format.\n7. **Weekly Content:** Instead of daily content, focus on providing a theme and a set of activities for each week. Include the approximate time the user should invest in that week.\n\n**Output JSON Format:**\n\n```json\n{\n \"language\": \"target_language\",\n \"learning_goal\": \"user_provided_goal\",\n \"current_level\": \"user_provided_level\",\n \"weeks\": [\n {\n \"week\": 1,\n \"theme\": \"week_theme\",\n \"estimated_duration\": \"estimated_weekly_time\",\n \"activities\": [\n {\n \"type\": \"activity_type\",\n \"description\": \"activity_description\",\n \"resources\": [\"resource1\", \"resource2\", ...]\n },\n {\n \"type\": \"activity_type\",\n \"description\": \"activity_description\",\n \"resources\": [\"resource1\", \"resource2\", ...]\n },\n ...\n ]\n },\n {\n \"week\": 2,\n \"theme\": \"week_theme\",\n \"estimated_duration\": \"estimated_weekly_time\",\n \"activities\": [\n {\n \"type\": \"activity_type\",\n \"description\": \"activity_description\",\n \"resources\": [\"resource1\", \"resource2\", ...]\n },\n ...\n ]\n },\n ...\n ]\n}\n",
3
+ "model": "gemini-1.5-flash-8b",
4
+ "base_url": "https://generativelanguage.googleapis.com/v1beta/openai/",
5
+ "api_key": "AIzaSyA5V1Pp8icIuj6vd5agdk9sYsEi4sUzWlU",
6
+ "lesson_instruction": "\n You are an advanced AI language tutor specializing in personalized language instruction. Your task is to create detailed, AI-driven daily lesson plans for a full week based on the curriculum provided.\n\n Student Profile:\n - Target Language: Chinese\n - Learning Goal: Advanced fluency in technical Chinese communication for machine learning roles\n - Current Level: Intermediate\n\n Instructions:\n 1. Create engaging, AI-driven activities for each day of the week (7 days)\n 2. Focus on interactive, personalized learning experiences\n 3. Avoid suggesting external resources or tools\n 4. Ensure activities align with the week's theme and learning objectives\n 5. Include specific examples and practice scenarios for each day\n 6. Format your response as a valid JSON object\n\n Output Format:\n {\n \"week\": number,\n \"theme\": \"string\",\n \"estimated_duration\": \"string\",\n \"daily_lessons\": [\n {\n \"day\": number,\n \"focus\": \"string\",\n \"duration\": \"string\",\n \"activities\": [\n {\n \"type\": \"string\",\n \"description\": \"string\"\n }\n ]\n },\n // Repeat for all 7 days\n ]\n }\n\n Notes:\n - Create lessons for all 7 days of the week\n - Each day should have a specific focus while maintaining the week's theme\n - Weekend lessons (days 6-7) can be lighter but should maintain learning momentum\n - All activities should be completable through AI interaction\n ",
7
+ "lesson_prompt": "\n Based on the curriculum week 4:\n {'week': 4, 'theme': 'Presentations and Debates', 'estimated_duration': '20-25 hours', 'activities': [{'type': 'Presentation Practice', 'description': 'Prepare and practice presenting a machine learning project or topic in Chinese. Record your presentation and seek feedback from a language partner or AI assistant.'}, {'type': 'Debate Practice', 'description': 'Practice debating machine learning topics or concepts. Structure arguments and counter-arguments, using formal and informal Chinese communication strategies.'}, {'type': 'Application Focus', 'description': 'Review the concepts from the past weeks. Apply the skills from previous weeks in a real-world context. This could be by joining a discussion, presenting a project, or initiating a conversation with a native speaker. '}, {'type': 'Progress Reflection', 'description': 'Summarize your achievements. Set realistic next steps for continued language development and technical communication.'}]}\n\n Generate a detailed, AI-driven lesson plan following the instruction format.\n ",
8
+ "daily_lesson_instruction": "\n You are an AI assistant tasked with curating today's lesson to help the user improve their skills in the target language.\n\n Instructions:\n 1. Determine the target language based on the user's input.\n 2. Create a bilingual lesson (English and the target language) to enable the user to achieve their learning goal.\n 3. For vocabulary sections:\n - Provide terms in English, their translations in the target language, and example sentences in both languages.\n - For character-based languages (e.g., Chinese, Japanese, Korean, Arabic), include phonetic aids alongside the target language:\n - Chinese: Include Pinyin for Mandarin terms.\n - Japanese: Include Romaji for Japanese terms.\n - Korean: Include Romanized Korean (Revised Romanization).\n - Arabic: Include transliteration using the Latin alphabet.\n - Example format:\n - Term: \"prototype\"\n - Translation: \"原型\" (Chinese), Pinyin: \"yuánxíng\"\n - Example Sentence: \n - English: \"We've developed a prototype for the new app.\"\n - Target Language: \"我们为新应用开发了一个原型。\" (Chinese), Pinyin: \"Wǒmen wèi xīn yìngyòng kāifāle yígè yuánxíng.\"\n 4. For practice activities:\n - Include prompts in both English and the target language.\n - Provide example responses in both languages, including phonetic aids for character-based languages.\n 5. Provide feedback on the user's input, focusing on grammar, vocabulary, and fluency. If applicable, include corrections with phonetic aids.\n 6. Always remember to include both English and the target language for all cases, along with phonetic aids for character-based languages.\n\n The lesson should be engaging, interactive, and tailored to the user's proficiency level.\n ",
9
+ "daily_lesson_prompt": "\n Theme: Foundational Technical Vocabulary\n\n Based on today's lesson plan, create a bilingual lesson (English and Chinese) with the following structure:\n\n Lesson Plan: {'day': 5, 'focus': 'Review and Consolidation', 'duration': '2 hours', 'activities': [{'type': 'Vocabulary Recall', 'description': 'The AI will present a list of machine learning terms. You will write the definition or appropriate synonym in Chinese for each.'}, {'type': 'Grammar Application', 'description': 'The AI will give a series of technical statements about machine learning. Reformulate each statement into a question using appropriate grammar structures for questioning. The AI will check your accuracy.'}]}\n ",
10
+ "target_language": "Chinese",
11
+ "current_week": 3
12
+ }
backend/config.py ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dotenv import load_dotenv
2
+ from backend.config_manager import Config
3
+ from backend.utils import ensure_directory
4
+ import os
5
+
6
+ load_dotenv()
7
+
8
+ # Set up base paths
9
+ PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
10
+ CONFIG_DIR = os.path.join(PROJECT_ROOT, "backend")
11
+ OUTPUT_DIR = os.path.join(PROJECT_ROOT, "output")
12
+
13
+ # Ensure directories exist
14
+ ensure_directory(CONFIG_DIR)
15
+ ensure_directory(OUTPUT_DIR)
16
+
17
+ config_path = os.path.join(CONFIG_DIR, "config.json")
18
+ config = Config(config_path)
19
+
20
+ # Default values - update API key handling
21
+ API_KEY = os.getenv('OPENAI_API_KEY') or os.getenv('GEMINI_API_KEY')
22
+ if not API_KEY:
23
+ raise ValueError("No API key found. Please set OPENAI_API_KEY or GEMINI_API_KEY environment variable")
24
+
25
+ MODEL = "gemini-1.5-flash-8b"
26
+ BASE_URL = "https://generativelanguage.googleapis.com/v1beta/openai/"
27
+
28
+ # Add API port configuration
29
+ API_PORT = int(os.getenv('API_PORT', 8000))
30
+
31
+ CURRICULUM_INSTRUCTION = """
32
+ You are an expert AI language learning curriculum designer. Your task is to create a one-month intensive language learning curriculum tailored to user's specific learning objectives and preferences. The curriculum should be divided into four weeks, with each week building upon the previous one.
33
+
34
+ **Curriculum Design Principles:**
35
+
36
+ 1. **AI-Driven:** The curriculum leverages AI for personalized learning experiences.
37
+ 2. **Intensive:** The curriculum should be designed for significant weekly study time.
38
+ 3. **Structured:** The curriculum should be divided into four weeks, with each week building upon the previous one.
39
+ 4. **Comprehensive:** Include a variety of learning activities, such as vocabulary building, grammar study, reading, writing, listening, and speaking practice.
40
+ 5. **Personalized:** Adapt the curriculum to the user's learning goals, current level, and interests.
41
+ 6. **Measurable:** Suggest ways the user can track their progress.
42
+ 7. **Output Format:** Provide the curriculum in a valid JSON format.
43
+ 8. **Weekly Content:** Instead of daily content, focus on providing a theme and a set of activities for each week. Include the approximate time the user should invest in that week.
44
+
45
+ **Output JSON Format:**
46
+
47
+ ```json
48
+ {
49
+ "language": "target_language",
50
+ "learning_goal": "user_provided_goal",
51
+ "current_level": "user_provided_level",
52
+ "weeks": [
53
+ {
54
+ "week": 1,
55
+ "theme": "week_theme",
56
+ "estimated_duration": "estimated_weekly_time",
57
+ "activities": [
58
+ {
59
+ "type": "activity_type",
60
+ "description": "activity_description"
61
+ },
62
+ {
63
+ "type": "activity_type",
64
+ "description": "activity_description"
65
+ },
66
+ ...
67
+ ]
68
+ },
69
+ {
70
+ "week": 2,
71
+ "theme": "week_theme",
72
+ "estimated_duration": "estimated_weekly_time",
73
+ "activities": [
74
+ {
75
+ "type": "activity_type",
76
+ "description": "activity_description"
77
+ },
78
+ ...
79
+ ]
80
+ },
81
+ ...
82
+ ]
83
+ }
84
+ """
85
+
86
+ # Export CURRICULUM_INSTRUCTION
87
+ __all__ = ['config', 'CURRICULUM_INSTRUCTION', 'API_PORT']
88
+
89
+ # Initialize config with default values if not exists
90
+ if not config.data:
91
+ config.set("curriculum_instruction", CURRICULUM_INSTRUCTION)
92
+ config.set("model", MODEL)
93
+ config.set("base_url", BASE_URL)
94
+ config.set("api_key", API_KEY)
95
+ config.set("api_port", API_PORT)
96
+ config.save()
backend/config_manager.py ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+
4
+
5
+ class Config:
6
+ def __init__(self, file_path="config.json"):
7
+ self.file_path = file_path
8
+ self.data = {}
9
+ self.load()
10
+
11
+ def load(self):
12
+ """Loads the configuration data from the JSON file."""
13
+ try:
14
+ with open(self.file_path, "r", encoding="utf-8") as f:
15
+ self.data = json.load(f)
16
+ except FileNotFoundError:
17
+ print(f"Config file not found at {self.file_path}. Creating a new one.")
18
+ self.data = {} # Start with an empty config
19
+ self.save()
20
+ except json.JSONDecodeError:
21
+ print(
22
+ f"Error: Invalid JSON format in config file at {self.file_path}. The file will be reset."
23
+ )
24
+ self.data = {}
25
+ self.save()
26
+
27
+ def save(self):
28
+ """Saves the configuration data to the JSON file."""
29
+ with open(self.file_path, "w", encoding="utf-8") as f:
30
+ json.dump(self.data, f, indent=4, ensure_ascii=False)
31
+
32
+ def get(self, key, default=None):
33
+ """Gets a configuration value by key.
34
+
35
+ Args:
36
+ key (str): The key to look up.
37
+ default: The default value to return if the key is not found.
38
+
39
+ Returns:
40
+ The configuration value or the default.
41
+ """
42
+ return self.data.get(key, default)
43
+
44
+ def set(self, key, value):
45
+ """Sets a configuration value.
46
+
47
+ Args:
48
+ key (str): The key to set.
49
+ value: The value to set.
50
+ """
51
+ self.data[key] = value
52
+ self.save()
53
+
54
+ def update(self, new_data):
55
+ """Updates the config data with a new dict
56
+
57
+ Args:
58
+ new_data: The data to update
59
+ """
60
+ self.data.update(new_data)
61
+ self.save()
62
+
63
+ def delete(self, key):
64
+ """Deletes a key from the config
65
+
66
+ Args:
67
+ key (str): the key to delete
68
+ """
69
+ if key in self.data:
70
+ del self.data[key]
71
+ self.save()
backend/main.py ADDED
@@ -0,0 +1,248 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import argparse
3
+ import sys
4
+ from backend.CurriculumManager.generate_curriculum import get_completion as generate_curriculum
5
+ from backend.LessonManager.generate_lesson import get_completion as generate_lesson
6
+ from backend.LessonManager.generate_daily_lesson import get_completion as generate_daily_lesson
7
+ from backend.config_manager import Config
8
+ from backend.utils import read_json_file, ensure_directory
9
+
10
+ # Set up paths
11
+ PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
12
+ CONFIG_PATH = os.path.join(PROJECT_ROOT, "backend", "config.json")
13
+ OUTPUT_DIR = os.path.join(PROJECT_ROOT, "output")
14
+ CURRICULUM_PATH = os.path.join(OUTPUT_DIR, "curriculum.json")
15
+ LESSON_PATH = os.path.join(OUTPUT_DIR, "lesson.json")
16
+
17
+ # Ensure output directory exists
18
+ ensure_directory(OUTPUT_DIR)
19
+
20
+ config = Config(CONFIG_PATH)
21
+
22
+ def parse_args():
23
+ parser = argparse.ArgumentParser(description='AI Language Tutor')
24
+ parser.add_argument('--mode', choices=['curriculum', 'lesson', 'daily'], required=True,
25
+ help='Mode of operation: curriculum, weekly lesson, or daily micro-lessons')
26
+ parser.add_argument('--prompt', type=str, required='curriculum' in sys.argv,
27
+ help='User prompt for curriculum generation (required for curriculum mode)')
28
+ parser.add_argument('--week', type=int, default=0, help='Week number (0-based index)')
29
+ parser.add_argument('--day', type=int, default=0, help='Day number (0-based index)')
30
+ return parser.parse_args()
31
+
32
+ def setup_lesson_instruction(args):
33
+ """Setup lesson instruction from curriculum data using specified week."""
34
+ curriculum_data = read_json_file(CURRICULUM_PATH)
35
+ if curriculum_data is None:
36
+ raise FileNotFoundError("Curriculum not found. Please generate curriculum first.")
37
+
38
+ if args.week >= len(curriculum_data["weeks"]):
39
+ raise ValueError(f"Week {args.week} not found. Available weeks: 0-{len(curriculum_data['weeks'])-1}")
40
+
41
+ language = curriculum_data["language"]
42
+ learning_goal = curriculum_data["learning_goal"]
43
+ current_level = curriculum_data["current_level"]
44
+ week = curriculum_data["weeks"][args.week]
45
+
46
+ lesson_instruction = """
47
+ You are an advanced AI language tutor specializing in personalized language instruction. Your task is to create detailed, AI-driven daily lesson plans for a full week based on the curriculum provided.
48
+
49
+ Student Profile:
50
+ - Target Language: {language}
51
+ - Learning Goal: {learning_goal}
52
+ - Current Level: {current_level}
53
+
54
+ Instructions:
55
+ 1. Create engaging, AI-driven activities for each day of the week (7 days)
56
+ 2. Focus on interactive, personalized learning experiences
57
+ 3. Avoid suggesting external resources or tools
58
+ 4. Ensure activities align with the week's theme and learning objectives
59
+ 5. Include specific examples and practice scenarios for each day
60
+ 6. Format your response as a valid JSON object
61
+
62
+ Output Format:
63
+ {{
64
+ "week": number,
65
+ "theme": "string",
66
+ "estimated_duration": "string",
67
+ "daily_lessons": [
68
+ {{
69
+ "day": number,
70
+ "focus": "string",
71
+ "duration": "string",
72
+ "activities": [
73
+ {{
74
+ "type": "string",
75
+ "description": "string"
76
+ }}
77
+ ]
78
+ }},
79
+ // Repeat for all 7 days
80
+ ]
81
+ }}
82
+
83
+ Notes:
84
+ - Create lessons for all 7 days of the week
85
+ - Each day should have a specific focus while maintaining the week's theme
86
+ - Weekend lessons (days 6-7) can be lighter but should maintain learning momentum
87
+ - All activities should be completable through AI interaction
88
+ """.format(
89
+ language=language,
90
+ learning_goal=learning_goal,
91
+ current_level=current_level
92
+ )
93
+
94
+ lesson_prompt = """
95
+ Based on the curriculum week {week_num}:
96
+ {curriculum}
97
+
98
+ Generate a detailed, AI-driven lesson plan following the instruction format.
99
+ """.format(week_num=args.week + 1, curriculum=week)
100
+
101
+ config.set("target_language", language)
102
+ config.set("lesson_instruction", lesson_instruction)
103
+ config.set("lesson_prompt", lesson_prompt)
104
+
105
+ # Return the generated lesson directly instead of True
106
+ return generate_lesson(lesson_prompt)
107
+
108
+ def setup_daily_lesson(args):
109
+ """Setup and generate daily lesson using specified day"""
110
+ lesson_data = read_json_file(LESSON_PATH)
111
+ theme = lesson_data["theme"]
112
+ lessons = lesson_data["daily_lessons"]
113
+
114
+ if args.day >= len(lessons):
115
+ raise ValueError(f"Day {args.day} not found in lesson plan. Available days: 0-{len(lessons)-1}")
116
+
117
+ daily_lesson_instruction = """
118
+ You are an AI assistant tasked with curating today's lesson to help the user improve their skills in the target language.
119
+
120
+ Instructions:
121
+ 1. Determine the target language based on the user's input.
122
+ 2. Create a bilingual lesson (English and the target language) to enable the user to achieve their learning goal.
123
+ 3. For vocabulary sections:
124
+ - Provide terms in English, their translations in the target language, and example sentences in both languages.
125
+ - For character-based languages (e.g., Chinese, Japanese, Korean, Arabic), include phonetic aids alongside the target language:
126
+ - Chinese: Include Pinyin for Mandarin terms.
127
+ - Japanese: Include Romaji for Japanese terms.
128
+ - Korean: Include Romanized Korean (Revised Romanization).
129
+ - Arabic: Include transliteration using the Latin alphabet.
130
+ - Example format:
131
+ - Term: "prototype"
132
+ - Translation: "原型" (Chinese), Pinyin: "yuánxíng"
133
+ - Example Sentence:
134
+ - English: "We've developed a prototype for the new app."
135
+ - Target Language: "我们为新应用开发了一个原型。" (Chinese), Pinyin: "Wǒmen wèi xīn yìngyòng kāifāle yígè yuánxíng."
136
+ 4. For practice activities:
137
+ - Include prompts in both English and the target language.
138
+ - Provide example responses in both languages, including phonetic aids for character-based languages.
139
+ 5. Provide feedback on the user's input, focusing on grammar, vocabulary, and fluency. If applicable, include corrections with phonetic aids.
140
+ 6. Always remember to include both English and the target language for all cases, along with phonetic aids for character-based languages.
141
+
142
+ The lesson should be engaging, interactive, and tailored to the user's proficiency level.
143
+ """
144
+
145
+ lesson_prompt = """
146
+ Theme: {theme}
147
+
148
+ Based on today's lesson plan, create a bilingual lesson (English and {target_language}) with the following structure:
149
+
150
+ Lesson Plan: {lesson_plan}
151
+ """.format(
152
+ theme=theme,
153
+ target_language=config.get("target_language"),
154
+ lesson_plan=lessons[args.day]
155
+ )
156
+
157
+ config.set("daily_lesson_instruction", daily_lesson_instruction)
158
+ config.set("daily_lesson_prompt", lesson_prompt)
159
+ return generate_daily_lesson(lesson_prompt)
160
+
161
+ def main():
162
+ args = parse_args()
163
+
164
+ if args.mode == 'curriculum':
165
+ if not args.prompt:
166
+ raise ValueError("--prompt is required for curriculum mode")
167
+ generate_curriculum(args.prompt)
168
+ elif args.mode == 'lesson':
169
+ setup_lesson_instruction(args) # Remove separate generate_lesson call
170
+ elif args.mode == 'daily':
171
+ setup_daily_lesson(args) # Already generates lesson using internal prompt
172
+
173
+ if __name__ == "__main__":
174
+ main()
175
+
176
+ # curriculum_data = read_json_file(CURRICULUM_PATH)
177
+ # if curriculum_data is None:
178
+ # raise FileNotFoundError("Curriculum not found. Please generate curriculum first.")
179
+
180
+ # if args.week >= len(curriculum_data["weeks"]):
181
+ # raise ValueError(f"Week {args.week} not found. Available weeks: 0-{len(curriculum_data['weeks'])-1}")
182
+
183
+ # language = curriculum_data["language"]
184
+ # learning_goal = curriculum_data["learning_goal"]
185
+ # current_level = curriculum_data["current_level"]
186
+ # week = curriculum_data["weeks"][args.week]
187
+
188
+ # lesson_instruction = """
189
+ # You are an advanced AI language tutor specializing in personalized language instruction. Your task is to create detailed, AI-driven daily lesson plans for a full week based on the curriculum provided.
190
+
191
+ # Student Profile:
192
+ # - Target Language: {language}
193
+ # - Learning Goal: {learning_goal}
194
+ # - Current Level: {current_level}
195
+
196
+ # Instructions:
197
+ # 1. Create engaging, AI-driven activities for each day of the week (7 days)
198
+ # 2. Focus on interactive, personalized learning experiences
199
+ # 3. Avoid suggesting external resources or tools
200
+ # 4. Ensure activities align with the week's theme and learning objectives
201
+ # 5. Include specific examples and practice scenarios for each day
202
+ # 6. Format your response as a valid JSON object
203
+
204
+ # Output Format:
205
+ # {{
206
+ # "week": number,
207
+ # "theme": "string",
208
+ # "estimated_duration": "string",
209
+ # "daily_lessons": [
210
+ # {{
211
+ # "day": number,
212
+ # "focus": "string",
213
+ # "duration": "string",
214
+ # "activities": [
215
+ # {{
216
+ # "type": "string",
217
+ # "description": "string"
218
+ # }}
219
+ # ]
220
+ # }},
221
+ # // Repeat for all 7 days
222
+ # ]
223
+ # }}
224
+
225
+ # Notes:
226
+ # - Create lessons for all 7 days of the week
227
+ # - Each day should have a specific focus while maintaining the week's theme
228
+ # - Weekend lessons (days 6-7) can be lighter but should maintain learning momentum
229
+ # - All activities should be completable through AI interaction
230
+ # """.format(
231
+ # language=language,
232
+ # learning_goal=learning_goal,
233
+ # current_level=current_level
234
+ # )
235
+
236
+ # lesson_prompt = """
237
+ # Based on the curriculum week {week_num}:
238
+ # {curriculum}
239
+
240
+ # Generate a detailed, AI-driven lesson plan following the instruction format.
241
+ # """.format(week_num=args.week + 1, curriculum=week)
242
+
243
+ # config.set("target_language", language)
244
+ # config.set("lesson_instruction", lesson_instruction)
245
+ # config.set("lesson_prompt", lesson_prompt)
246
+
247
+ # # Return the generated lesson directly instead of True
248
+ # generate_lesson(lesson_prompt)
backend/requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ fastapi==0.68.0
2
+ uvicorn==0.15.0
3
+ python-dotenv==0.19.0
4
+ pydantic==1.8.2
5
+ openai==0.27.0
6
+ python-multipart==0.0.5
backend/utils.py ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+
4
+ def read_json_file(file_path: str) -> dict:
5
+ """Reads and parses a JSON file.
6
+
7
+ Args:
8
+ file_path (str): Path to the JSON file
9
+
10
+ Returns:
11
+ dict: Parsed JSON data or None if there was an error
12
+ """
13
+ try:
14
+ with open(file_path, "r", encoding="utf-8") as f:
15
+ return json.load(f)
16
+ except FileNotFoundError:
17
+ print(f"Error: File not found at {file_path}")
18
+ return None
19
+ except json.JSONDecodeError:
20
+ print(f"Error: Invalid JSON format in file at {file_path}")
21
+ return None
22
+
23
+ def write_json_file(file_path: str, data: dict, indent: int = 4) -> bool:
24
+ """Writes data to a JSON file.
25
+
26
+ Args:
27
+ file_path (str): Path to save the JSON file
28
+ data (dict): Data to write
29
+ indent (int): Indentation level for pretty printing
30
+
31
+ Returns:
32
+ bool: True if successful, False otherwise
33
+ """
34
+ try:
35
+ with open(file_path, "w", encoding="utf-8") as f:
36
+ json.dump(data, f, indent=indent, ensure_ascii=False)
37
+ return True
38
+ except Exception as e:
39
+ print(f"Error writing to file {file_path}: {str(e)}")
40
+ return False
41
+
42
+ def ensure_directory(directory_path: str) -> bool:
43
+ """Ensures a directory exists, creates it if it doesn't.
44
+
45
+ Args:
46
+ directory_path (str): Path to the directory
47
+
48
+ Returns:
49
+ bool: True if directory exists or was created successfully
50
+ """
51
+ try:
52
+ os.makedirs(directory_path, exist_ok=True)
53
+ return True
54
+ except Exception as e:
55
+ print(f"Error creating directory {directory_path}: {str(e)}")
56
+ return False
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ openai
2
+ fastapi
3
+ uvicorn[standard]
4
+ pydantic
5
+ ollama
6
+ python-dotenv