From 6629e60862e03c5f3f6a67fae149665ec940c4ca Mon Sep 17 00:00:00 2001 From: Pathompum Jirakarnpaisan <107536914+Saannddy@users.noreply.github.com> Date: Wed, 8 Apr 2026 22:28:26 +0700 Subject: [PATCH 1/3] refactor: improve code formatting and indentation in 404 error page --- src/html/404.html | 251 ++++++++++++++++++++++++---------------------- 1 file changed, 132 insertions(+), 119 deletions(-) diff --git a/src/html/404.html b/src/html/404.html index d0ee5f1..16f89d2 100644 --- a/src/html/404.html +++ b/src/html/404.html @@ -1,126 +1,139 @@ - - - 404 - DevScape API - - - - -
-
-

404

-

Oops! The page you are looking for does not exist.

- Back to Home -
- - + } + + + + +
+
+

404

+

Oops! The page you are looking for does not exist.

+ Back to Home +
+ + + \ No newline at end of file From e87cf981cd2ac383e7c8ac9d1d2d5adfd04d8fec Mon Sep 17 00:00:00 2001 From: Pathompum Jirakarnpaisan <107536914+Saannddy@users.noreply.github.com> Date: Wed, 8 Apr 2026 22:35:50 +0700 Subject: [PATCH 2/3] chore: remove unused verification script and temporary Java data files --- src/scripts/process_elevatorhall.py | 114 ---------------------------- src/verify_fix.py | 50 ------------ 2 files changed, 164 deletions(-) delete mode 100644 src/scripts/process_elevatorhall.py delete mode 100644 src/verify_fix.py diff --git a/src/scripts/process_elevatorhall.py b/src/scripts/process_elevatorhall.py deleted file mode 100644 index 42dd51f..0000000 --- a/src/scripts/process_elevatorhall.py +++ /dev/null @@ -1,114 +0,0 @@ -import pandas as pd -import json -import os -import re - -def process_excel(): - xl = pd.ExcelFile('Level 4 Puzzles.xlsx') - chunks = [] - problems = [] - - for name in xl.sheet_names: - df = xl.parse(name) - # Extract Px from L4_Px - match_p = re.search(r'L4_(P\d+)', name) - category_id = f"ELV-{match_p.group(1)}" if match_p else "Elevator Hall" - - if '(Chunk)' in name: - for i, row in df.iterrows(): - template_code = str(row.get('Problem', row.get('Template', ''))) - snippet_block = str(row.get('Expected Input', row.get('Expected Snippet', ''))) - - placeholders = re.findall(r'\{TASK\s*(\d+):[^\}]+\}', template_code) - s_dict = {} - - new_template = template_code - for p_num in placeholders: - placeholder_search = re.search(rf'\{{TASK\s*{p_num}:[^\}}]+\}}', new_template) - if placeholder_search: - placeholder_str = placeholder_search.group(0) - new_template = new_template.replace(placeholder_str, f'{{{{{{snippet_{p_num}}}}}}}') - - pattern = rf'TASK\s*{p_num}\s*\([^\)]+\):\s*(.*?)(?=TASK\s*\d+\s*\(|$)' - match = re.search(pattern, snippet_block, re.DOTALL) - if match: - s_dict[f"snippet_{p_num}"] = match.group(1).strip() - else: - s_dict[f"snippet_{p_num}"] = f"// Missing snippet for Task {p_num}" - - chunk_data = { - "title": f"{category_id}-CHUNK-{i+1:03d}", - "difficulty": str(row.get('Difficulty', "Medium")), - "category": category_id, - "templates": { - "java": { - "name": "Java Implementation", - "template_code": new_template, - "snippets": s_dict - } - }, - "expectation": { - "input": str(row.get('Input', '')), - "output": str(row.get('Expected Output', '')) - } - } - chunks.append(chunk_data) - elif '(Problem)' in name: - for i, row in df.iterrows(): - template_code = str(row.get('Problem', row.get('Template', ''))) - expected_output = str(row.get('Expected Output', '')) - - outputs = [o.strip() for o in expected_output.split('\n') if o.strip()] - - method_match = re.search(r'public\s+static\s+(?:\w+(?:\[\])?)\s+(\w+)\(', template_code) - method_name = method_match.group(1) if method_match else "" - - inputs = [] - if method_name: - # Look only inside the main method - main_match = re.search(r'public\s+static\s+void\s+main\s*\(.*?\)\s*\{(.*?)\}', template_code, re.DOTALL) - if main_match: - main_content = main_match.group(1) - # Look for calls: method_name(...) - # We want the arguments between the first "(" and last ")" for this call - matches = re.finditer(rf'{method_name}\((.*?)\)', main_content) - for m in matches: - inputs.append(m.group(1)) - - test_cases = [] - # Use whichever count is larger, but match them up - count = max(len(inputs), len(outputs)) - for j in range(count): - inp = inputs[j] if j < len(inputs) else "" - out = outputs[j] if j < len(outputs) else "" - test_cases.append({ - "input": inp, - "output": out, - "is_hidden": j > 0 - }) - - problem_data = { - "title": f"{category_id}-PROB-{i+1:03d}", - "description": template_code, - "difficulty": str(row.get('Difficulty', "Hard")), - "category": category_id, - "templates": { - "java": template_code - }, - "test_cases": test_cases - } - problems.append(problem_data) - - out_dir = 'src/scripts/data/java/elevatorhall' - os.makedirs(out_dir, exist_ok=True) - - with open(os.path.join(out_dir, 'chunks.json'), 'w') as f: - json.dump(chunks, f, indent=4) - - with open(os.path.join(out_dir, 'problems.json'), 'w') as f: - json.dump(problems, f, indent=4) - - print(f"Processed {len(chunks)} chunks and {len(problems)} problems with category mapping.") - -if __name__ == "__main__": - process_excel() diff --git a/src/verify_fix.py b/src/verify_fix.py deleted file mode 100644 index abb7eed..0000000 --- a/src/verify_fix.py +++ /dev/null @@ -1,50 +0,0 @@ - -import sys -import os -from uuid import UUID - -# Add src to path -sys.path.append(os.path.dirname(os.path.abspath(__file__))) - -from services.question_service import QuestionService -from repositories.question_repository import QuestionRepository -from models.base import Question, Tag, Choice -from infrastructure import SessionLocal - -def verify(): - service = QuestionService() - - # Try to find a tag to test with - with SessionLocal() as session: - tag = session.query(Tag).first() - if not tag: - print("No tags found in database. Cannot run verification. Please seed the database first.") - return - tag_name = tag.name - print(f"Testing with tag: {tag_name}") - - try: - results = service.get_random_questions(tag_name, amount=1) - print("Success! get_random_questions executed without DetachedInstanceError.") - print(f"Results: {results}") - - # Verify structure - if results: - q = results[0] - if 'choices' in q and isinstance(q['choices'], list): - print(f"Verified: 'choices' is a list with {len(q['choices'])} items.") - else: - print("Error: 'choices' is missing or not a list in the response.") - - if 'tags' in q and isinstance(q['tags'], list): - print(f"Verified: 'tags' is a list with {len(q['tags'])} items.") - - if 'categories' in q and isinstance(q['categories'], list): - print(f"Verified: 'categories' is a list with {len(q['categories'])} items.") - except Exception as e: - print(f"Failed: {type(e).__name__}: {e}") - import traceback - traceback.print_exc() - -if __name__ == "__main__": - verify() From 660d5fd39d5eaff5f5887204d769b209301ce116 Mon Sep 17 00:00:00 2001 From: Pathompum Jirakarnpaisan <107536914+Saannddy@users.noreply.github.com> Date: Wed, 8 Apr 2026 23:23:49 +0700 Subject: [PATCH 3/3] feat: add progress bars to seeding scripts and remove automatic seeding from docker-compose startup --- docker-compose.yml | 1 - src/scripts/seed.py | 7 ++++--- src/scripts/seeders/seed_elevatorhall_java.py | 7 +++---- src/scripts/seeders/seed_hallway_java.py | 13 +++++-------- src/scripts/seeders/seed_lockerroom_java.py | 13 +++++-------- src/scripts/seeders/seed_restroom_java.py | 12 ++++-------- 6 files changed, 21 insertions(+), 32 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 7fc0d74..c6117dd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -30,7 +30,6 @@ services: condition: service_healthy command: > sh -c "python3 -m alembic upgrade head && - python3 -m scripts.seed && gunicorn --bind 0.0.0.0:3000 app:app" code-api: diff --git a/src/scripts/seed.py b/src/scripts/seed.py index 8e646b8..4e0c8cf 100644 --- a/src/scripts/seed.py +++ b/src/scripts/seed.py @@ -1,4 +1,5 @@ import logging +from tqdm import tqdm import uuid import random import string @@ -230,7 +231,7 @@ def add_problem(title, description, difficulty, category_list, tag_list, config= session.commit() logging.info("Seeding 30 riddles...") - for i in range(1, 31): + for i in tqdm(range(1, 31), desc="Seeding Riddles"): riddle = Riddle( riddle_text=f"This is riddle number {i}. What is it?", refer_char=random.choice(string.ascii_uppercase), @@ -254,7 +255,7 @@ def add_problem(title, description, difficulty, category_list, tag_list, config= session.commit() logging.info("Seeding 10 questions with 4 choices each...") - for i in range(1, 11): + for i in tqdm(range(1, 11), desc="Seeding Questions"): question = Question( title=f"Sample Question {i}", question_text=f"This is the content for question {i}. Which choice is correct?", @@ -375,7 +376,7 @@ def add_problem(title, description, difficulty, category_list, tag_list, config= } ] - for c_data in chunks_to_seed: + for c_data in tqdm(chunks_to_seed, desc="Seeding Chunks"): existing = session.exec(select(Chunk).where(Chunk.title == c_data["title"])).first() if existing: continue diff --git a/src/scripts/seeders/seed_elevatorhall_java.py b/src/scripts/seeders/seed_elevatorhall_java.py index ce9a72d..5fdc057 100644 --- a/src/scripts/seeders/seed_elevatorhall_java.py +++ b/src/scripts/seeders/seed_elevatorhall_java.py @@ -1,4 +1,5 @@ import logging +from tqdm import tqdm import uuid import json import os @@ -61,9 +62,8 @@ def get_or_create_tag(name): elv_hall_tag = get_or_create_tag("JAV_ELVHALL") java_cat = get_or_create_category("Java") - # 1. Seed Chunks logging.info(f"Seeding {len(CHUNKS)} Java chunks...") - for c_data in CHUNKS: + for c_data in tqdm(CHUNKS, desc="Seeding Chunks"): c_id = get_uuid(f"jav_elvhall_chunk_{c_data['title']}") chunk = session.exec(select(Chunk).where(Chunk.id == c_id)).first() if not chunk: @@ -109,9 +109,8 @@ def get_or_create_tag(name): ) session.add(ex) - # 2. Seed Problems logging.info(f"Seeding {len(PROBLEMS)} Java problems...") - for p_data in PROBLEMS: + for p_data in tqdm(PROBLEMS, desc="Seeding Problems"): p_id = get_uuid(f"jav_elvhall_prob_{p_data['title']}") problem = session.exec(select(Problem).where(Problem.id == p_id)).first() if not problem: diff --git a/src/scripts/seeders/seed_hallway_java.py b/src/scripts/seeders/seed_hallway_java.py index c5fb9e0..2a05b7a 100644 --- a/src/scripts/seeders/seed_hallway_java.py +++ b/src/scripts/seeders/seed_hallway_java.py @@ -1,4 +1,5 @@ import logging +from tqdm import tqdm import uuid import random import json @@ -71,9 +72,8 @@ def get_or_create_tag(name): jav_hallway_tag = get_or_create_tag("JAV_HALLWAY") java_cat = get_or_create_category("Java") - # 1. Seed Questions logging.info(f"Seeding {len(QUESTIONS)} Java questions...") - for q_data in QUESTIONS: + for q_data in tqdm(QUESTIONS, desc="Seeding Questions"): q_id = get_uuid(f"jav_hallway_q_{q_data['title']}") if session.exec(select(Question).where(Question.id == q_id)).first(): continue @@ -99,9 +99,8 @@ def get_or_create_tag(name): ) session.add(choice) - # 2. Seed Riddles logging.info(f"Seeding {len(RIDDLES)} Java riddles...") - for i, r_data in enumerate(RIDDLES): + for i, r_data in enumerate(tqdm(RIDDLES, desc="Seeding Riddles")): r_id = get_uuid(f"jav_hallway_r_{i}") if session.exec(select(Riddle).where(Riddle.id == r_id)).first(): continue @@ -117,9 +116,8 @@ def get_or_create_tag(name): riddle.tags = [jav_hallway_tag] session.add(riddle) - # 3. Seed Chunks logging.info(f"Seeding {len(CHUNKS)} Java chunks...") - for c_data in CHUNKS: + for c_data in tqdm(CHUNKS, desc="Seeding Chunks"): c_id = get_uuid(f"jav_hallway_chunk_{c_data['title']}") chunk = session.exec(select(Chunk).where(Chunk.id == c_id)).first() if not chunk: @@ -169,9 +167,8 @@ def get_or_create_tag(name): ) session.add(ex) - # 4. Seed Problems logging.info(f"Seeding {len(PROBLEMS)} Java problems...") - for p_data in PROBLEMS: + for p_data in tqdm(PROBLEMS, desc="Seeding Problems"): p_id = get_uuid(f"jav_rst_prob_{p_data['title']}") problem = session.exec(select(Problem).where(Problem.id == p_id)).first() diff --git a/src/scripts/seeders/seed_lockerroom_java.py b/src/scripts/seeders/seed_lockerroom_java.py index 73999dc..6dc5545 100644 --- a/src/scripts/seeders/seed_lockerroom_java.py +++ b/src/scripts/seeders/seed_lockerroom_java.py @@ -1,4 +1,5 @@ import logging +from tqdm import tqdm import uuid import random import json @@ -71,9 +72,8 @@ def get_or_create_tag(name): jav_lockerroom_tag = get_or_create_tag("JAV_LOCKERROOM") java_cat = get_or_create_category("Java") - # 1. Seed Questions logging.info(f"Seeding {len(QUESTIONS)} Java questions...") - for q_data in QUESTIONS: + for q_data in tqdm(QUESTIONS, desc="Seeding Questions"): q_id = get_uuid(f"jav_lockerroom_q_{q_data['title']}") if session.exec(select(Question).where(Question.id == q_id)).first(): continue @@ -99,9 +99,8 @@ def get_or_create_tag(name): ) session.add(choice) - # 2. Seed Riddles logging.info(f"Seeding {len(RIDDLES)} Java riddles...") - for i, r_data in enumerate(RIDDLES): + for i, r_data in enumerate(tqdm(RIDDLES, desc="Seeding Riddles")): r_id = get_uuid(f"jav_lockerroom_r_{i}") if session.exec(select(Riddle).where(Riddle.id == r_id)).first(): continue @@ -117,9 +116,8 @@ def get_or_create_tag(name): riddle.tags = [jav_lockerroom_tag] session.add(riddle) - # 3. Seed Chunks logging.info(f"Seeding {len(CHUNKS)} Java chunks...") - for c_data in CHUNKS: + for c_data in tqdm(CHUNKS, desc="Seeding Chunks"): c_id = get_uuid(f"jav_lockerroom_chunk_{c_data['title']}") chunk = session.exec(select(Chunk).where(Chunk.id == c_id)).first() if not chunk: @@ -169,9 +167,8 @@ def get_or_create_tag(name): ) session.add(ex) - # 4. Seed Problems logging.info(f"Seeding {len(PROBLEMS)} Java problems...") - for p_data in PROBLEMS: + for p_data in tqdm(PROBLEMS, desc="Seeding Problems"): p_id = get_uuid(f"jav_rst_prob_{p_data['title']}") problem = session.exec(select(Problem).where(Problem.id == p_id)).first() diff --git a/src/scripts/seeders/seed_restroom_java.py b/src/scripts/seeders/seed_restroom_java.py index 38d993a..5cb30a7 100644 --- a/src/scripts/seeders/seed_restroom_java.py +++ b/src/scripts/seeders/seed_restroom_java.py @@ -72,9 +72,8 @@ def get_or_create_tag(name): jav_restroom_tag = get_or_create_tag("JAV_RESTROOM") java_cat = get_or_create_category("Java") - # 1. Seed Questions logging.info(f"Seeding {len(QUESTIONS)} Java questions...") - for q_data in QUESTIONS: + for q_data in tqdm(QUESTIONS, desc="Seeding Questions"): q_id = get_uuid(f"jav_rst_q_{q_data['title']}") if session.exec(select(Question).where(Question.id == q_id)).first(): continue @@ -100,9 +99,8 @@ def get_or_create_tag(name): ) session.add(choice) - # 2. Seed Riddles logging.info(f"Seeding {len(RIDDLES)} Java riddles...") - for i, r_data in enumerate(RIDDLES): + for i, r_data in enumerate(tqdm(RIDDLES, desc="Seeding Riddles")): r_id = get_uuid(f"jav_rst_r_{i}") if session.exec(select(Riddle).where(Riddle.id == r_id)).first(): continue @@ -118,9 +116,8 @@ def get_or_create_tag(name): riddle.tags = [jav_restroom_tag] session.add(riddle) - # 3. Seed Chunks logging.info(f"Seeding {len(CHUNKS)} Java chunks...") - for c_data in CHUNKS: + for c_data in tqdm(CHUNKS, desc="Seeding Chunks"): c_id = get_uuid(f"jav_rst_chunk_{c_data['title']}") chunk = session.exec(select(Chunk).where(Chunk.id == c_id)).first() if not chunk: @@ -170,9 +167,8 @@ def get_or_create_tag(name): ) session.add(ex) - # 4. Seed Problems logging.info(f"Seeding {len(PROBLEMS)} Java problems...") - for p_data in PROBLEMS: + for p_data in tqdm(PROBLEMS, desc="Seeding Problems"): p_id = get_uuid(f"jav_rst_prob_{p_data['title']}") problem = session.exec(select(Problem).where(Problem.id == p_id)).first()