diff --git a/Html/__pycache__/backboardManager.cpython-310.pyc b/Html/__pycache__/backboardManager.cpython-310.pyc index 1b96bd0..b26aeca 100644 Binary files a/Html/__pycache__/backboardManager.cpython-310.pyc and b/Html/__pycache__/backboardManager.cpython-310.pyc differ diff --git a/Html/app.log b/Html/app.log new file mode 100644 index 0000000..5df5216 --- /dev/null +++ b/Html/app.log @@ -0,0 +1,10 @@ +/home/caikecheng/anaconda3/envs/algoAgent/lib/python3.10/site-packages/pydantic/_internal/_config.py:345: UserWarning: Valid config keys have changed in V2: +* 'fields' has been removed + warnings.warn(message, UserWarning) +2024-12-28 22:52:57.446 | INFO | agentscope.models:read_model_configs:186 - Load configs for model wrapper: openai_cfg +Traceback (most recent call last): + File "/home/caikecheng/algoAgent/code-agent/Html/app.py", line 343, in + socketio.run(app, host='0.0.0.0', port=5000, debug=True) + File "/home/caikecheng/anaconda3/envs/algoAgent/lib/python3.10/site-packages/flask_socketio/__init__.py", line 640, in run + raise RuntimeError('The Werkzeug web server is not ' +RuntimeError: The Werkzeug web server is not designed to run in production. Pass allow_unsafe_werkzeug=True to the run() method to disable this error. diff --git a/Html/app.py b/Html/app.py index d0c7ba3..4cb1ab0 100644 --- a/Html/app.py +++ b/Html/app.py @@ -9,10 +9,24 @@ import sys import json parent_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) sys.path.insert(0, parent_dir) +student_workspace_root_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../study')) current_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '.')) sys.path.insert(0, current_dir) from AlgoriAgent.projects.algoriAgent.agent_manager import AgentManager + +import configparser + +from db.user_list import UserList +from db.user import User, load_user_from_json, create_user_json +from db.course_list import CourseList +from db.course import Course, load_course_from_json +GLOBAL_CONFIG = configparser.ConfigParser() +GLOBAL_CONFIG.read('config.ini') +VSCODE_WEB_URL = GLOBAL_CONFIG['VSCODE_WEB']['url'] +USER_DATA_DIR = GLOBAL_CONFIG['USER_DATA']['dir'] +COURSE_DATA_DIR = GLOBAL_CONFIG['COURSE_DATA']['dir'] + app = Flask(__name__) socketio = SocketIO(app, cors_allowed_origins="*",ping_timeout=60, ping_interval=5) # socketio = SocketIO(app, cors_allowed_origins="http://localhost:9888") # 设置跨域支持 @@ -20,7 +34,7 @@ import logging app.secret_key = 'cakebaker' app.logger.setLevel(logging.DEBUG) # 配置 CORS -CORS(app, resources={r"/*": {"origins": "http://127.0.0.1:9090"},}, supports_credentials=True) +CORS(app, resources={r"/*": {"origins": VSCODE_WEB_URL},}, supports_credentials=True) userid_recorder = {} # user_id&path -> session['user_id'] @@ -31,8 +45,8 @@ Backboard from backboardManager import BackBoardManager, Backboard backboard_manager = BackBoardManager() -uuid2user_id = {} -user_id2uuid = {} +uuid2username = {} +username2uuid = {} @@ -45,7 +59,7 @@ class VSCodeNamespace(Namespace): user_id = dataconfig.get('user_id') path = dataconfig.get('path') print(f"User {user_id} connected with path: {path}") - useruuid = user_id2uuid[user_id] + useruuid = username2uuid[user_id] join_room(useruuid, namespace='/vscode') if backboard_manager.get_backboard(useruuid) == None: backboard_manager.add_backboard(useruuid, path) @@ -56,14 +70,15 @@ class VSCodeNamespace(Namespace): dataconfig = data['config'] realtime_response(dataconfig, data) # emit('response', {'message': 'Config data received and connection established'}) - def on_disconnect(self): + def on_disconnect(self, data): print("VSCode client disconnected") + print("Disconnect reason:"+str(data)) def realtime_response(config, realtime_action): user_id = config['user_id'] folder_path = config['path'] - useruuid = user_id2uuid[user_id] + useruuid = username2uuid[user_id] bb = backboard_manager.get_backboard(useruuid) assert type(bb) == Backboard @@ -75,14 +90,12 @@ def realtime_response(config, realtime_action): if realtime_action['type'] == 'activeFile': file_path = realtime_action['filePath'] assert type(file_path) == str - file_path = "".join(file_path.split(f'/{user_id}/{folder_path}/')[1:]) - bb.active_file_path = file_path - with open(f"../{user_id}/{folder_path}/{file_path}") as f: + with open(f"{file_path}") as f: bb.active_file_content = f.read() if realtime_action['type'] == 'paste': - file_path = realtime_action['filePath'] - file_path = "".join(file_path.split(f'/{user_id}/{folder_path}/')[1:]) + file_path = realtime_action['filePath'] + assert type(file_path) == str bb.pasted_file_path = file_path bb.pasted_content = realtime_action['content'] @@ -106,21 +119,22 @@ class AgentNamespace(Namespace): def on_login(self, data): data = json.loads(data) user = data['username'] - folder_name = data['folder'] - user_uuid = user_id2uuid[user] + course_id = data['course_id'] + chapter_id = data['chapter_id'] + user_uuid = username2uuid[user] session['user_id'] = user_uuid print(f'User connected with session user_id: {user_uuid}') # 从markdown、markdown_prompts、score_prompts中各读取数据folder.md并进行new_agent - with open(f'books/markdown/{folder_name}.md','r',encoding='UTF-8') as fmd,\ - open(f'books/markdown_prompts/{folder_name}.md','r',encoding='UTF-8')as fmdp,\ - open(f'books/score_prompts/{folder_name}.md','r',encoding='UTF-8') as fsp: + with open(f'books/markdown/{course_id}/{chapter_id}.md','r',encoding='UTF-8') as fmd,\ + open(f'books/markdown_prompts/{course_id}/{chapter_id}.md','r',encoding='UTF-8')as fmdp,\ + open(f'books/score_prompts/{course_id}/{chapter_id}.md','r',encoding='UTF-8') as fsp: markdown = fmd.read() markdown_prompts = fmdp.read() score_prompts = fsp.read() - user_uuid, agent = agent_manager.new_agent(markdown, markdown_prompts, score_prompts, id=user_uuid, root_path=f'{user}/{folder_name}') + user_uuid, agent = agent_manager.new_agent(course_id, chapter_id, markdown, markdown_prompts, score_prompts, id=user_uuid, root_path=f'{user}/{course_id}/{chapter_id}') print(user_uuid) join_room(user_uuid, namespace='/agent') # 将该用户加入以user_id为名的room - backboard_manager.add_backboard(user_uuid, folder_name) + backboard_manager.add_backboard(user_uuid, chapter_id) def on_language(self, language): id = session.get('user_id') @@ -154,8 +168,9 @@ class AgentNamespace(Namespace): agent_manager.function_call(id, data['data']) - def on_disconnect(self): + def on_disconnect(self,data): print("VSCode client disconnected") + print("Disconnect reason:"+str(data)) @@ -169,9 +184,9 @@ IMAGE_DIR = 'image' # 图片资源相对于 markdown 的位置 -@app.route('/-markdown', methods=['GET']) -def convert_md(filename): - md_file_path = os.path.join(MARKDOWN_DIR, f'{filename}.md') +@app.route('/--markdown', methods=['GET']) +def convert_md(course_id, filename): + md_file_path = os.path.join(MARKDOWN_DIR,course_id, f'{filename}.md') if not os.path.exists(md_file_path): return jsonify({'error': 'Markdown file not found'}), 404 @@ -205,7 +220,7 @@ def convert_md(filename): html_file.write(html_with_styles) # 处理图片资源,将 image/xxx 文件夹拷贝到 static/image/xxx - image_source_dir = os.path.join(MARKDOWN_DIR, IMAGE_DIR, filename) + image_source_dir = os.path.join(MARKDOWN_DIR,course_id, IMAGE_DIR, filename) image_target_dir = os.path.join(STATIC_DIR, IMAGE_DIR, filename) print(f"Copying image resources from {image_source_dir} to {image_target_dir}") if os.path.exists(image_source_dir): @@ -230,25 +245,35 @@ def serve_static(filename): ''' Vscode ''' -@app.route('/desktop//') -def hello_world(user_id, path): +@app.route('/desktop///') +def desktop(user_id, course_id, chapter_id): if 'user_id' not in session: # return redirect(url_for('login')) session['user_id'] = 'user_' + str(uuid.uuid4()) print("user "+ user_id + "uuid is"+ session['user_id']) - user_id2uuid[user_id] = session['user_id'] - uuid2user_id[session['user_id']] = user_id - userid_recorder[user_id+'&'+path] = session['user_id'] + username2uuid[user_id] = session['user_id'] + uuid2username[session['user_id']] = user_id + userid_recorder[user_id+'&'+course_id] = session['user_id'] - # 在上层 目录下创建一个名为 user_id_path 的文件夹 - path_dir = os.path.join(parent_dir, user_id, path) + # 在学习目录下创建一个名为 user_id_path 的文件夹 + path_dir = os.path.join(student_workspace_root_path, user_id, course_id,chapter_id) os.makedirs(path_dir, exist_ok=True) # 在此文件夹内部创建一个.config文件,并写入 user_id=user_id\n path=path config_path = os.path.join(path_dir, '.config') + print('---------------------') + print(config_path) with open(config_path, 'w') as f: - f.write(f"user_id={user_id}\npath={path}") - return render_template('desktop.html', user_id=user_id, path=path) + tmpd = {'user_id': user_id, 'course_id': course_id, 'chapter_id': chapter_id, 'path': path_dir} + json.dump(tmpd, f) + return render_template('desktop.html', vscode_web_url=VSCODE_WEB_URL, user_id=user_id, course_id=course_id, chapter_id=chapter_id, workspace_path=path_dir) +@app.route('/desktop_nouser//') +def desktop_nouser(course_id, chapter_id): + if 'user_id' not in session: + return redirect(url_for('login')) + user_id = session['user_id'] + username = uuid2username[user_id] + return redirect(url_for('desktop', user_id=username, course_id=course_id, chapter_id=chapter_id)) @app.route('/vscode_data', methods=['POST']) def vscode_data(): @@ -269,17 +294,33 @@ def get_session(): Login ''' +users_list = UserList() +course_list = CourseList() + +@app.route('/register') +def register(): + return render_template('register.html') + +@app.route('/register_post', methods=['POST']) +def register_post(): + data = request.get_json() + username = data.get('username') + password = data.get('password') + if users_list.has_user(username) is not None: + users_list.add_user(username, password) + create_user_json(username, USER_DATA_DIR) + return jsonify({'success': True, 'message': '注册成功'}) + else: return jsonify({'success': False, 'message': '用户已存在,请更换用户名'}) + @app.route('/login') def login(): + return render_template('login.html') if 'user_id' not in session: return render_template('login.html') else: return redirect(url_for('/')) -from db.user_list import UserList -users_list = UserList() - @app.route('/login_post', methods=['POST']) def login_post(): # 获取请求的 JSON 数据 @@ -288,44 +329,81 @@ def login_post(): username = data.get('username') password = data.get('password') - user = users_list.get_user(username) - if user is None: - return jsonify({'success': False, 'message': '用户名或密码错误'}) + pswd = users_list.get_user_pswd(username) - if user['password'] != password: + if pswd is None: + return jsonify({'success': False, 'message': '用户名或密码错误'}) + if pswd != password: return jsonify({'success': False, 'message': '用户名或密码错误'}) session['user_id'] = 'user_' + str(uuid.uuid4()) print("user "+ username + "uuid is"+ session['user_id']) - user_id2uuid[username] = session['user_id'] - uuid2user_id[session['user_id']] = username + username2uuid[username] = session['user_id'] + uuid2username[session['user_id']] = username return jsonify({'success': True, 'message': '登录成功'}) - +user_id2UserClass = {} ''' DashBoard ''' @app.route('/dashboard') def dashboard(): - if 'user_id' not in session: + if 'user_id' not in session or session['user_id'] not in uuid2username: return redirect(url_for('login')) - return render_template('dashboard.html') + user_id = session['user_id'] + username = uuid2username[user_id] + if (user_id not in user_id2UserClass): + user_id2UserClass[user_id] = load_user_from_json(username, user_data_dir = USER_DATA_DIR) + user_course_data = [] + for course_id in user_id2UserClass[user_id].select_course: + course_brief_info = course_list.get_course_brief_info(course_id, load_course_from_json(course_id, course_data_dir = COURSE_DATA_DIR)) + user_course_data.append(course_brief_info) + return render_template('dashboard.html',user_data = json.dumps(user_id2UserClass[user_id].__json__()), user_course_data = json.dumps(user_course_data)) ''' -Book +Course ''' -@app.route('/book/') -def book(book_name): - return render_template('book.html', book_name=book_name) +@app.route('/course/') +def course(course_id): + c = load_course_from_json(course_id, course_data_dir = COURSE_DATA_DIR) + return render_template('course.html', course_id=course_id, course_data=c) + +@app.route('/select_course', methods=['POST']) +def select_course(): + if ('user_id' not in session or session['user_id'] not in user_id2UserClass):return redirect(url_for('login')) + user = user_id2UserClass[session['user_id']] + data = request.get_json() + course_id = data.get('course_id') + if course_id: + user.select_new_course(course_id, load_course_from_json(course_id, COURSE_DATA_DIR)) + return jsonify({'success': True, 'message': '课程选择成功'}) @app.route('/') def home_index(): - return render_template('index.html') + selected_courses=[] + if ('user_id' in session): + if (session['user_id'] not in user_id2UserClass): return redirect(url_for('login')) + user = user_id2UserClass[session['user_id']] + for course_id in user.select_course: + selected_courses.append(course_id) + + return render_template('index.html', courses_data = course_list, selected_courses =selected_courses) +# 一些app辅助函数,主要提供给Agent与数据库的交互能力 + +class MyFunction: + def save_chapter_memory(self, id, course_id, lesson_id, subchapter_title, mem_list, score, is_rebuttal): + print("-=-=-=-=-=-=-=-") + print(id, course_id, lesson_id, subchapter_title, mem_list, score, is_rebuttal) + username = uuid2username[id] + u = load_user_from_json(username, user_data_dir = USER_DATA_DIR) + u.save_chapter_memory(course_id, lesson_id, subchapter_title, mem_list, score, is_rebuttal) + +app.my_function = MyFunction() if __name__ == '__main__': socketio.on_namespace(VSCodeNamespace('/vscode')) socketio.on_namespace(AgentNamespace('/agent')) socketio.run(app, host='0.0.0.0', port=5000, debug=True) - + diff --git a/Html/books/code_tests/binary_search/agent-twice_split_0.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_0.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_0.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_0.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_0.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_0.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_0.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_0.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_1.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_1.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_1.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_1.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_1.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_1.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_1.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_1.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_10.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_10.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_10.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_10.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_10.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_10.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_10.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_10.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_11.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_11.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_11.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_11.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_11.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_11.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_11.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_11.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_12.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_12.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_12.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_12.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_12.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_12.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_12.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_12.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_13.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_13.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_13.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_13.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_13.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_13.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_13.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_13.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_14.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_14.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_14.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_14.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_14.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_14.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_14.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_14.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_15.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_15.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_15.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_15.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_15.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_15.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_15.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_15.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_16.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_16.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_16.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_16.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_16.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_16.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_16.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_16.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_17.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_17.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_17.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_17.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_17.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_17.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_17.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_17.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_18.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_18.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_18.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_18.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_18.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_18.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_18.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_18.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_19.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_19.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_19.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_19.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_19.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_19.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_19.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_19.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_2.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_2.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_2.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_2.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_2.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_2.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_2.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_2.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_20.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_20.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_20.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_20.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_20.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_20.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_20.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_20.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_21.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_21.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_21.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_21.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_21.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_21.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_21.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_21.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_22.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_22.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_22.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_22.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_22.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_22.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_22.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_22.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_23.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_23.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_23.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_23.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_23.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_23.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_23.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_23.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_24.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_24.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_24.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_24.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_24.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_24.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_24.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_24.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_25.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_25.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_25.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_25.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_25.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_25.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_25.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_25.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_26.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_26.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_26.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_26.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_26.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_26.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_26.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_26.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_27.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_27.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_27.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_27.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_27.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_27.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_27.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_27.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_28.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_28.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_28.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_28.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_28.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_28.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_28.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_28.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_29.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_29.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_29.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_29.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_29.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_29.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_29.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_29.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_3.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_3.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_3.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_3.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_3.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_3.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_3.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_3.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_30.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_30.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_30.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_30.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_30.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_30.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_30.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_30.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_31.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_31.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_31.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_31.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_31.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_31.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_31.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_31.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_32.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_32.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_32.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_32.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_32.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_32.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_32.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_32.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_33.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_33.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_33.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_33.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_33.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_33.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_33.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_33.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_34.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_34.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_34.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_34.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_34.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_34.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_34.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_34.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_35.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_35.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_35.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_35.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_35.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_35.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_35.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_35.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_36.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_36.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_36.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_36.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_36.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_36.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_36.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_36.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_37.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_37.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_37.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_37.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_37.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_37.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_37.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_37.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_38.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_38.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_38.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_38.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_38.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_38.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_38.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_38.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_39.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_39.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_39.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_39.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_39.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_39.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_39.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_39.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_4.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_4.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_4.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_4.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_4.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_4.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_4.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_4.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_5.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_5.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_5.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_5.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_5.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_5.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_5.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_5.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_6.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_6.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_6.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_6.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_6.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_6.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_6.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_6.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_7.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_7.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_7.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_7.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_7.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_7.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_7.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_7.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_8.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_8.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_8.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_8.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_8.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_8.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_8.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_8.out diff --git a/Html/books/code_tests/binary_search/agent-twice_split_9.in b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_9.in similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_9.in rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_9.in diff --git a/Html/books/code_tests/binary_search/agent-twice_split_9.out b/Html/books/code_tests/algorithm/binary_search/agent-twice_split_9.out similarity index 100% rename from Html/books/code_tests/binary_search/agent-twice_split_9.out rename to Html/books/code_tests/algorithm/binary_search/agent-twice_split_9.out diff --git a/Html/books/markdown/binary_search.md b/Html/books/markdown/algorithm/binary_search.md similarity index 100% rename from Html/books/markdown/binary_search.md rename to Html/books/markdown/algorithm/binary_search.md diff --git a/Html/books/markdown/example.md b/Html/books/markdown/algorithm/example.md similarity index 100% rename from Html/books/markdown/example.md rename to Html/books/markdown/algorithm/example.md diff --git a/Html/books/markdown_prompts/binary_search.md b/Html/books/markdown_prompts/algorithm/binary_search.md similarity index 95% rename from Html/books/markdown_prompts/binary_search.md rename to Html/books/markdown_prompts/algorithm/binary_search.md index 76c320d..eb62437 100644 --- a/Html/books/markdown_prompts/binary_search.md +++ b/Html/books/markdown_prompts/algorithm/binary_search.md @@ -30,4 +30,4 @@ 本体测试点文件夹名 `twice_split。` -_require_tools=judge +_require_tools=judge,algorithm,binary_search,binary_search diff --git a/Html/books/markdown_prompts/example.md b/Html/books/markdown_prompts/algorithm/example.md similarity index 100% rename from Html/books/markdown_prompts/example.md rename to Html/books/markdown_prompts/algorithm/example.md diff --git a/Html/books/score_prompts/binary_search.md b/Html/books/score_prompts/algorithm/binary_search.md similarity index 100% rename from Html/books/score_prompts/binary_search.md rename to Html/books/score_prompts/algorithm/binary_search.md diff --git a/Html/config.ini b/Html/config.ini index 705109f..3985d7d 100644 --- a/Html/config.ini +++ b/Html/config.ini @@ -13,4 +13,11 @@ terminal_name = Windows PowerShell listen_port = 3001 server_address = ws://localhost:3000/myService agent_process_provider_host = localhost -agent_process_provider_port = 3002 \ No newline at end of file +agent_process_provider_port = 3002 + +[VSCODE_WEB] +url = http://59.78.194.131:9090 +[USER_DATA] +dir = db/data/user/ +[COURSE_DATA] +dir = db/data/course/ \ No newline at end of file diff --git a/Html/db/course.py b/Html/db/course.py new file mode 100644 index 0000000..0010b41 --- /dev/null +++ b/Html/db/course.py @@ -0,0 +1,42 @@ +import os +# Example usage: +import json +LOCAL_COURSE_DATA_DIR = "data/course/" # only use locally, not for other .py files + +class Course: + def __init__(self, course_name, course_id, course_auther, course_img_path, lessons, description): + self.course_name = course_name + self.course_id = course_id + self.course_auther = course_auther + self.course_img_path = course_img_path + self.lessons = lessons + self.description = description + + + def __json__(self): + return { + 'course_id': self.course_id, + 'course_name': self.course_name, + 'course_auther': self.course_auther, + 'course_img_path': self.course_img_path, + 'lessons': self.lessons, + 'description': self.description + } + def to_json(self): + return json.dumps(self, default=lambda o: o.__json__(), indent=4) + +def load_course_from_json(course_id, course_data_dir = None)-> Course: + try: + COURSE_DATA_DIR = course_data_dir if course_data_dir else LOCAL_COURSE_DATA_DIR + with open(os.path.join(COURSE_DATA_DIR, f'{course_id}.json'), "r") as f: + raw_json = f.read() + user_data = json.loads(raw_json) + return Course(**user_data) + except Exception as e: + print(e) + return None + +if(__name__ == "__main__"): + + user = load_course_from_json('CS101') + diff --git a/Html/db/course_list.py b/Html/db/course_list.py index 6c444bf..db23004 100644 --- a/Html/db/course_list.py +++ b/Html/db/course_list.py @@ -1,105 +1,62 @@ -import os -from tinydb import TinyDB, Query, where - +import json +import copy +import re class CourseList: def __init__(self, db_file='db/data/course/course_list.json'): - """初始化课程列表,自动打开并加载 JSON 数据文件。""" self.db_file = db_file - self.db = TinyDB(self.db_file) - self.course_query = Query() + with open(self.db_file, 'r') as f: + self.db = json.load(f) - def add_course(self, course_data): - """添加新的课程到课程列表。""" - if not self.db.search(self.course_query.course_id == course_data['course_id']): - self.db.insert(course_data) - else: - print(f"Course with ID {course_data['course_id']} already exists.") + def add_course(self, course_id, course_name, course_create_date, course_update_data, course_img_path): + """添加新的用户登录信息""" + # 检查是否已经有该用户 + assert course_id not in self.db, f"Course {course_name} with ID {course_id} already exists." + self.db[course_id] = {} + self.db[course_id]['course_name'] = course_name + self.db[course_id]['course_create_date'] = course_create_date + self.db[course_id]['course_update_data'] = course_update_data + self.db[course_id]['course_img_path'] = course_img_path - def get_course(self, course_id): - """获取指定 course_id 的课程信息。""" - result = self.db.search(self.course_query.course_id == course_id) - return result[0] if result else None + with open(self.db_file, 'w') as f: + json.dump(self.db, f, indent=4) - def update_course(self, course_id, updated_data): - """更新指定 course_id 的课程信息。""" - self.db.update(updated_data, self.course_query.course_id == course_id) + + def get_course_brief_info(self, course_id, course) -> dict: + assert course_id in self.db, f"Course ID {course_id} does not exist." + result = copy.deepcopy(self.db[course_id]) + result["lessons"]=[] + for lesson in course.lessons: + d={} + d['lesson_id'] = lesson['lesson_id'] + d["lesson_name"]=lesson['lesson_name'] + print(lesson["markdown"]) + h3_titles = re.findall(r'[\s]###\s+(.*)', lesson["markdown"]) + print(h3_titles) + d["subChapters"]=h3_titles + result["lessons"].append(d) + return result + + def update_course_brief_info(self, course_id, course_name, course_create_date, course_update_data, course_img_path): + assert course_id in self.db, f"Course ID {course_id} does not exist." + + self.db[course_id]['course_name'] = course_name + self.db[course_id]['course_create_date'] = course_create_date + self.db[course_id]['course_update_data'] = course_update_data + self.db[course_id]['course_img_path'] = course_img_path + + with open(self.db_file, 'w') as f: + json.dump(self.db, f, indent=4) def delete_course(self, course_id): - """删除指定 course_id 的课程。""" - self.db.remove(self.course_query.course_id == course_id) - - def add_lesson_to_course(self, course_id, lesson_data): - """为指定课程添加课时。""" - course = self.get_course(course_id) - if course: - if 'lessons' not in course: - course['lessons'] = [] - course['lessons'].append(lesson_data) - self.update_course(course_id, {'lessons': course['lessons']}) - else: - print(f"Course with ID {course_id} not found.") - - def get_lessons_of_course(self, course_id): - """获取指定课程的所有课时信息。""" - course = self.get_course(course_id) - return course['lessons'] if course else None - + assert course_id in self.db, f"Course ID {course_id} does not exist." + self.db.remove(course_id) + def get_all_courses(self): - """获取所有课程。""" - return self.db.all() + return list(self.db) - -# # 课程数据结构示例 -# course_data = { -# 'course_id': 'CS101', -# 'course_name': 'Computer Science 101', -# 'course_img_path': 'images/cs101.png', -# 'lessons': [ -# { -# 'lesson_id': 'L001', -# 'lesson_name': 'Introduction to Computer Science', -# 'markdown': 'This is the introduction lesson.', -# 'markdown_prompt': 'What is Computer Science?', -# 'score_prompt': 'Please provide an overview of CS.' -# }, -# { -# 'lesson_id': 'L002', -# 'lesson_name': 'Data Structures', -# 'markdown': 'In this lesson, we cover Data Structures.', -# 'markdown_prompt': 'What is an array?', -# 'score_prompt': 'Explain how linked lists work.' -# } -# ] -# } - -# lesson_data = { -# 'lesson_id': 'L003', -# 'lesson_name': 'Algorithms', -# 'markdown': 'In this lesson, we will discuss algorithms.', -# 'markdown_prompt': 'What is a sorting algorithm?', -# 'score_prompt': 'Explain the difference between merge sort and quicksort.' -# } - -# # 创建 CourseList 实例 -# course_list = CourseList() - -# # 添加课程 -# course_list.add_course(course_data) - -# # 添加课时到现有课程 -# course_list.add_lesson_to_course('CS101', lesson_data) - -# # 获取并显示所有课程 -# courses = course_list.get_all_courses() -# print(courses) - -# # 获取某个课程的课时 -# lessons = course_list.get_lessons_of_course('CS101') -# print(lessons) - -# # 更新课程信息 -# updated_data = {'course_name': 'Computer Science 101 - Updated'} -# course_list.update_course('CS101', updated_data) - -# # 删除课程 -# course_list.delete_course('CS101') + def to_json(self): + return json.dumps(self.db) + + def items(self): + assert type(self.db) is dict, "db is not a dict" + return self.db.items() \ No newline at end of file diff --git a/Html/db/data/course/CS101.json b/Html/db/data/course/CS101.json new file mode 100644 index 0000000..8135c4a --- /dev/null +++ b/Html/db/data/course/CS101.json @@ -0,0 +1,25 @@ +{ + "course_id": "CS101", + "course_name": "Computer Science 101", + "course_auther": "John Doe", + "course_img_path": "/static/image/algorithm/book_cover.png", + "description":"这个老师很懒,没有写介绍", + "lessons": [ + { + "lesson_id": "L001", + "lesson_name": "Introduction to Computer Science", + "markdown": "This is the introduction lesson.", + "markdown_prompt": "What is Computer Science?", + "score_prompt": "Please provide an overview of CS.", + "lesson_img_path": "/static/image/algorithm/book_cover.png" + }, + { + "lesson_id": "L002", + "lesson_name": "Data Structures", + "markdown": "In this lesson, we cover Data Structures.", + "markdown_prompt": "What is an array?", + "score_prompt": "Explain how linked lists work.", + "lesson_img_path": "/static/image/algorithm/book_cover.png" + } + ] +} diff --git a/Html/db/data/course/algorithm.json b/Html/db/data/course/algorithm.json new file mode 100644 index 0000000..44de87d --- /dev/null +++ b/Html/db/data/course/algorithm.json @@ -0,0 +1,25 @@ +{ + "course_id": "algorithm", + "course_name": "algorithm", + "course_auther": "Chao Peng", + "course_img_path": "/static/image/algorithm/book_cover.png", + "description":"这个老师很懒,没有写介绍", + "lessons": [ + { + "lesson_id": "binary_search", + "lesson_name": "Introduction to Algorithm", + "markdown": "# 二分查找与二分答案\n\n## 二分查找\n\n### 引入\n\n二分是一个很简单基础,但很重要的知识点,为以后许多高级的数据结构与算法铺垫。\n\n下面是一个用二分的简单场景:\n\n假设小明从0到1000之间选择了一个数字但不告诉你,你可以不断猜测这个数,每次猜测小明会告知你的猜测得过大还是过小,问最多几次就一定能猜中?\n\n答案是利用二分查找的原理,猜测11次即可。\n\n1. 对于0到1000的答案备选区,猜测中位数500,假设过小,\n2. 则对于501到1000的答案备选区,猜测750,假设过大\n3. 则对于501到749的答案备选区,猜测625,假设过小,\n4. 则对于626到749区间......\n5. (688-749)\n6. (718-749)\n7. (734-749)\n8. (742-749)\n9. (746-749)\n10. (748-749)\n11. (749-749)\n\n在最差的情况下,第11次的答案备选区就一定长度为1了,也就是必然是答案。\n\n因此如果序列是有序的,就可以通过二分查找快速定位所需要的数据。\n\n#### 思考题(询问Agent以学习计算方法,或验证你的答案)\n\n对于上面那个题目,如果问题区间是1到4000,最差情况下需要猜测几次?\n\n### 练习:二分查找\n\n试试对于下面的题目,用代码实现一下二分查找。\n\n#### 题目:有序数组寻址\n\n给出一个长度为n的有序数组(从小到大),有q次询问,对于每次询问,输出指定数在数组中的下标。如果不存在则输出-1。\n\n##### 输入\n\n第一行一个整数n。(1<=n<=10^5)\n\n第二行n个用空格分开的整数ai。(0<=ai<=10^8)\n\n第三行一个整数q,表示询问的次数。(1<=q<=10^4)\n\n后q行,每行一个整数b,表示询问的数。(0<=b<=10^8)\n\n##### 输出\n\nq行,每行一个整数,对应每次询问的返回结果。\n\n##### 提示:\n\n完成代码后,通知Agent进行评测。\n\n如果你还不完全会这个算法,询问Agent获取提示并进行学习。\n", + "markdown_prompt": "What is Algorithm?", + "score_prompt": "Please provide an overview of CS.", + "lesson_img_path": "/static/image/algorithm/book_cover.png" + }, + { + "lesson_id": "L002", + "lesson_name": "Data Structures", + "markdown": "### This is the introduction lesson.\n ### This is the introduction lesson.\n", + "markdown_prompt": "What is an array?", + "score_prompt": "Explain how linked lists work.", + "lesson_img_path": "/static/image/algorithm/book_cover.png" + } + ] +} diff --git a/Html/db/data/course/course_list.json b/Html/db/data/course/course_list.json index a1643a2..9f695a2 100644 --- a/Html/db/data/course/course_list.json +++ b/Html/db/data/course/course_list.json @@ -1,21 +1,25 @@ { - "course_id": "CS101", - "course_name": "Computer Science 101", - "course_img_path": "images/cs101.png", - "lessons": [ - { - "lesson_id": "L001", - "lesson_name": "Introduction to Computer Science", - "markdown": "This is the introduction lesson.", - "markdown_prompt": "What is Computer Science?", - "score_prompt": "Please provide an overview of CS." - }, - { - "lesson_id": "L002", - "lesson_name": "Data Structures", - "markdown": "In this lesson, we cover Data Structures.", - "markdown_prompt": "What is an array?", - "score_prompt": "Explain how linked lists work." - } - ] -} + "CS101":{ + "course_id": "CS101", + "course_name": "Computer Science 101", + "course_description":"这个老师很懒,没有写介绍", + "course_img_path": "/static/image/algorithm/book_cover.png", + "course_create_date": "2023-01-01", + "course_update_data": "2023-01-01"}, + + "algorithm":{ + "course_id": "algorithm", + "course_name": "算法分析与设计", + "course_description":"这个老师很懒,没有写介绍", + "course_img_path": "/static/image/algorithm/book_cover.png", + "course_create_date": "2023-01-01", + "course_update_data": "2023-01-01"}, + + "data-structure":{ + "course_id": "data-structure", + "course_name": "数据结构", + "course_description":"这个老师很懒,没有写介绍", + "course_img_path": "/static/image/algorithm/book_cover.png", + "course_create_date": "2023-01-01", + "course_update_data": "2023-01-01"} +} \ No newline at end of file diff --git a/Html/db/data/course/data-structure.json b/Html/db/data/course/data-structure.json new file mode 100644 index 0000000..ce96ac9 --- /dev/null +++ b/Html/db/data/course/data-structure.json @@ -0,0 +1,25 @@ +{ + "course_id": "data-structure", + "course_name": "data-structure", + "course_auther": "Chao Peng", + "course_img_path": "/static/image/algorithm/book_cover.png", + "description":"这个老师很懒,没有写介绍", + "lessons": [ + { + "lesson_id": "L001", + "lesson_name": "Introduction to Data structure", + "markdown": "This is the introduction lesson.", + "markdown_prompt": "What is Data structure?", + "score_prompt": "Please provide an overview of CS.", + "lesson_img_path": "/static/image/algorithm/book_cover.png" + }, + { + "lesson_id": "L002", + "lesson_name": "Data Structures", + "markdown": "In this lesson, we cover Data Structures.", + "markdown_prompt": "What is an array?", + "score_prompt": "Explain how linked lists work.", + "lesson_img_path": "/static/image/algorithm/book_cover.png" + } + ] +} diff --git a/Html/db/data/user/a.json b/Html/db/data/user/a.json new file mode 100644 index 0000000..12314a7 --- /dev/null +++ b/Html/db/data/user/a.json @@ -0,0 +1,40 @@ +{ + "user_id": "a", + "select_course": [ + "algorithm", + "data-structure" + ], + "head_icon": "", + "course_process_dict": { + "algorithm": { + "lesson_processs": [ + [ + [], + "L001" + ], + [ + [], + "L002" + ] + ], + "course_put_in_date": "", + "course_last_study_date": "", + "course_total_study_time": 0 + }, + "data-structure": { + "lesson_processs": [ + [ + [], + "L001" + ], + [ + [], + "L002" + ] + ], + "course_put_in_date": "", + "course_last_study_date": "", + "course_total_study_time": 0 + } + } +} \ No newline at end of file diff --git a/Html/db/data/user/cake.json b/Html/db/data/user/cake.json index 166b262..67e05bf 100644 --- a/Html/db/data/user/cake.json +++ b/Html/db/data/user/cake.json @@ -1,57 +1,105 @@ { -"user_id": "user123", -"select_course": ["algorithm", "data-structure"], -"head_icon": "/static/image/book_cover.jpg", -"course_process_dict": { - "algorithm": { - "course_process": { + "user_id": "cake", + "select_course": [ + "CS101", + "algorithm", + "data-structure" + ], + "head_icon": "/static/image/book_cover.jpg", + "course_process_dict": { + "algorithm": { "lesson_processs": [ - { - "lesson_process": [ + [ + [ { - "chapter_info": { - "dialog": ["This is chapter 1 dialog"], - "score": 85, - "is_rebuttal": true, - "rebuttal_score": 90 - } - }, - { - "chapter_info": { - "dialog": ["This is chapter 2 dialog"], - "score": 75, - "is_rebuttal": false, - "rebuttal_score": 0 - } + "title": "\u5f15\u5165", + "dialog": [ + { + "id": "0b26417b9a4a41c3a86a63e96ac279f7", + "timestamp": "2025-01-01 01:40:36", + "name": "system", + "content": "You're a helpful assistant.\n\n## \u4f60\u7684\u89d2\u8272\uff1a\n\u4f60\u9700\u8981\u5e2e\u52a9\u5b66\u751f\u5b66\u4e60\u7b97\u6cd5\uff0c\u5b8c\u6210\u7279\u5b9a\u7684\u7f16\u7a0b\u4efb\u52a1\u3002\n\n## \u4f60\u9700\u8981\u505a\u7684\uff1a\n0. \u4f60\u5fc5\u987b\u6839\u636e\u8001\u5e08\u63d0\u4f9b\u7684\u6559\u5b66\u5927\u7eb2\uff0c\u6309\u7167\u7ae0\u8282\u987a\u5e8f\uff0c\u4f9d\u6b21\u5b66\u4e60\u3002\n1. \u5b66\u751f\u53ef\u80fd\u4f1a\u63d0\u51fa\u4e00\u4e9b\u95ee\u9898\uff0c\u4f60\u65e0\u9700\u56de\u7b54\u95ee\u9898\uff0c\u800c\u662f\u6839\u636e\u4e0a\u4e0b\u6587\uff08\u6bd4\u5982\u5b66\u751f\u81ea\u5df1\u7684\u4ee3\u7801\uff09\u6765\u5206\u6790\uff0c\u5e76\u7ed9\u51fa\u4e00\u6b65\u7684\u89e3\u51b3\u65b9\u6848\u3002\n2. \u6559\u5b66\u5927\u7eb2\u4e2d\u4f1a\u6307\u660e\u6bcf\u4e2a\u7ae0\u8282\u7684\u5b66\u4e60\u76ee\u6807\uff0c\u4f60\u6309\u7167\u76ee\u6807\u5b66\u4e60\u3002\n3. \u7cfb\u7edf\u4f1aoccasionally gather\u5b66\u751f\u4fe1\u606f\uff0c\u4f60\u9700\u8981\u5206\u6790\u5b66\u751f\u5b66\u4e60\u8bb0\u5f55\uff0c\u8c03\u7528\u5fc5\u8981\u7684\u51fd\u6570\u3002\n\n## \u6ce8\u610f\u4e8b\u9879\uff1a\n1. \u786e\u4fdd\u4f7f\u7528\u5de5\u5177\u51fd\u6570\u65f6\uff0c\u63d0\u4f9b\u7684\u53c2\u6570\u7c7b\u578b\u548c\u503c\u662f\u6b63\u786e\u7684\u3002\n2. \u4e0d\u8981\u592a\u76f8\u4fe1\u81ea\u5df1\uff0c\u4f8b\u5982\uff0c\u5f53\u524d\u4f4d\u7f6e\uff0c\u5f53\u524d\u65f6\u95f4\u7b49\uff0c\u4f60\u53ef\u4ee5\u5c1d\u8bd5\u4f7f\u7528\u5de5\u5177\u51fd\u6570\u83b7\u53d6\u4fe1\u606f\u3002\n3. \u5982\u679c\u51fd\u6570\u6267\u884c\u5931\u8d25\uff0c\u4f60\u9700\u8981\u5206\u6790\u9519\u8bef\u5e76\u5c1d\u8bd5\u89e3\u51b3\u3002\n4. \u786e\u4fdd\u5b66\u751f\u63d0\u51fa\u7684\u95ee\u9898\u6216\u60f3\u6cd5\u662f\u5426\u4e0e\u5f53\u524d\u7ae0\u8282\u76f8\u5173\uff0c\u5982\u679c\u4e0d\u76f8\u5173\uff0c\u4f60\u5e94\u7b54\u5e76\u63d0\u9192\u5b66\u751f\u5173\u6ce8\u5f53\u524d\u7ae0\u8282\u3002\n\n## \u8d44\u6e90\uff1a\n1. \u4f60\u53ef\u4ee5\u4f7f\u7528\u7684\u5de5\u5177\u51fd\u6570\u3002\n2. \u4e0a\u4e0b\u6587\uff0c\u5305\u62ec\u5b66\u751f\u7684\u4ee3\u7801\uff0c\u548c\u6559\u5b66\u5927\u7eb2\u3002\n", + "role": "system", + "url": null, + "metadata": null + }, + { + "id": "461938c9265547c9bd0187ece94d659d", + "timestamp": "2025-01-01 01:40:43", + "name": "system", + "content": "##The Chapter Chain##\n(Your Now Chapter) Chapter 1: \n\u4e8c\u5206\u662f\u4e00\u4e2a\u5f88\u7b80\u5355\u57fa\u7840\uff0c\u4f46\u5f88\u91cd\u8981\u7684\u77e5\u8bc6\u70b9\uff0c\u4e3a\u4ee5\u540e\u8bb8\u591a\u9ad8\u7ea7\u7684\u6570\u636e\u7ed3\u6784\u4e0e\u7b97\u6cd5\u94fa\u57ab\u3002\n\n\u4e0b\u9762\u662f\u4e00\u4e2a\u7528\u4e8c\u5206\u7684\u7b80\u5355\u573a\u666f\uff1a\n\n\u5047\u8bbe\u5c0f\u660e\u4ece0\u52301000\u4e4b\u95f4\u9009\u62e9\u4e86\u4e00\u4e2a\u6570\u5b57\u4f46\u4e0d\u544a\u8bc9\u4f60\uff0c\u4f60\u53ef\u4ee5\u4e0d\u65ad\u731c\u6d4b\u8fd9\u4e2a\u6570\uff0c\u6bcf\u6b21\u731c\u6d4b\u5c0f\u660e\u4f1a\u544a\u77e5\u4f60\u7684\u731c\u6d4b\u5f97\u8fc7\u5927\u8fd8\u662f\u8fc7\u5c0f\uff0c\u95ee\u6700\u591a\u51e0\u6b21\u5c31\u4e00\u5b9a\u80fd\u731c\u4e2d\uff1f\n\n\u7b54\u6848\u662f\u5229\u7528\u4e8c\u5206\u67e5\u627e\u7684\u539f\u7406\uff0c\u731c\u6d4b11\u6b21\u5373\u53ef\u3002\n\n1. \u5bf9\u4e8e0\u52301000\u7684\u7b54\u6848\u5907\u9009\u533a\uff0c\u731c\u6d4b\u4e2d\u4f4d\u6570500\uff0c\u5047\u8bbe\u8fc7\u5c0f\uff0c\n2. \u5219\u5bf9\u4e8e501\u52301000\u7684\u7b54\u6848\u5907\u9009\u533a\uff0c\u731c\u6d4b750\uff0c\u5047\u8bbe\u8fc7\u5927\n3. \u5219\u5bf9\u4e8e501\u5230749\u7684\u7b54\u6848\u5907\u9009\u533a\uff0c\u731c\u6d4b625\uff0c\u5047\u8bbe\u8fc7\u5c0f\uff0c\n4. \u5219\u5bf9\u4e8e626\u5230749\u533a\u95f4......\n5. \uff08688-749\uff09\n6. \uff08718-749\uff09\n7. \uff08734-749\uff09\n8. \uff08742-749\uff09\n9. \uff08746-749\uff09\n10. \uff08748-749\uff09\n11. \uff08749-749\uff09\n\n\u5728\u6700\u5dee\u7684\u60c5\u51b5\u4e0b\uff0c\u7b2c11\u6b21\u7684\u7b54\u6848\u5907\u9009\u533a\u5c31\u4e00\u5b9a\u957f\u5ea6\u4e3a1\u4e86\uff0c\u4e5f\u5c31\u662f\u5fc5\u7136\u662f\u7b54\u6848\u3002\n\n\u56e0\u6b64\u5982\u679c\u5e8f\u5217\u662f\u6709\u5e8f\u7684\uff0c\u5c31\u53ef\u4ee5\u901a\u8fc7\u4e8c\u5206\u67e5\u627e\u5feb\u901f\u5b9a\u4f4d\u6240\u9700\u8981\u7684\u6570\u636e\u3002\n\n#### \u601d\u8003\u9898\uff08\u8be2\u95eeAgent\u4ee5\u5b66\u4e60\u8ba1\u7b97\u65b9\u6cd5\uff0c\u6216\u9a8c\u8bc1\u4f60\u7684\u7b54\u6848\uff09\n\n\u5bf9\u4e8e\u4e0a\u9762\u90a3\u4e2a\u9898\u76ee\uff0c\u5982\u679c\u95ee\u9898\u533a\u95f4\u662f1\u52304000\uff0c\u6700\u5dee\u60c5\u51b5\u4e0b\u9700\u8981\u731c\u6d4b\u51e0\u6b21\uff1f\n\n\nHere are some concrete instructions:\n\n\u672c\u5c0f\u8282\u8fdb\u884c\u4e8c\u5206\u67e5\u627e\u7684\u5f15\u5165\uff0c\u9996\u5148\u5e2e\u52a9\u5b66\u751f\u7406\u89e3\u6559\u6848\u5f15\u5165\u7ae0\u8282\u7684\u6545\u4e8b\u3002\n\n\u786e\u4fdd\u5b66\u751f\u7406\u89e3\u4e86\u5f15\u5165\u540e\uff0c\u5728\u8fdb\u884c\u601d\u8003\u9898\u3002\n\n\u5982\u679c\u4e0d\u8fdb\u884c\u601d\u8003\u9898\uff0c\u5219\u8be2\u95ee\u4e00\u4e0b\u662f\u5426\u4e0d\u8fdb\u884c\u601d\u8003\u9898\uff0c\u786e\u8ba4\u540e\u8fdb\u5165\u4e0b\u4e00\u8282\u3002\n\n\u5982\u679c\u8fdb\u884c\u601d\u8003\u9898\uff0c\u544a\u77e5\u5b66\u751f\u8ba1\u7b97\u65b9\u6cd5\u5e76\u9a8c\u8bc1\u7b54\u6848\uff08\u7b54\u6848\u662f13\u6b21\uff09\n\n\u8ba1\u7b97\u65b9\u6cd5\uff1a\n\n4000\u662f\u521d\u59cb\u7b54\u6848\u533a\u95f4\u957f\u5ea6\uff0c\u6bcf\u6b21\u8be2\u95ee\u80fd\u591f\u6392\u9664\u4e00\u534a\u7684\u533a\u95f4\uff0c\u5f53\u533a\u95f4\u957f\u5ea6\u5c0f\u4e8e\u7b49\u4e8e1\u65f6\uff0c\u518d\u8fdb\u884c\u4e00\u6b21\u731c\u6d4b\u5c31\u4e00\u5b9a\u662f\u7b54\u6848\u3002\n\n4000\u4e0d\u65ad\u9664\u4ee52\uff0c\u966412\u6b21\u5c31\u5c0f\u4e8e\u7b49\u4e8e1\u4e86\uff0c\u518d\u52a0\u4e00\u6b21\u5c31\u4e00\u5b9a\u662f\u7b54\u6848\u3002\u6700\u540e\u662f12+1=13\u6b21\u3002\n\n\uff08\u6bd44000\u5927\u7684\u6700\u5c0f2\u7684\u6b21\u65b9\u6570\uff0c4096\u5c31\u662f2\u768412\u6b21\u65b9\uff0c\u8fd9\u91cc\u768412\u5c31\u662f\u7b54\u6848\u4e2d\u768412\uff0c\u6216\u8005\u5199\u4f5c\"\u4e0a\u53d6\u6574(log2(4000))\")\n\n\u8be2\u95ee\u5b66\u751f\uff0c\u5f53\u5b66\u751f\u544a\u77e5\u7406\u89e3\u540e\uff0c\u8fdb\u5165\u4e0b\u4e00\u8282\u3002\n\n\n\n\n", + "role": "system", + "url": null, + "metadata": null + }, + { + "id": "4d63161cb43344d79a2a27abde4a4439", + "timestamp": "2025-01-01 01:40:43", + "name": "user", + "content": "\u7b54\u6848\u662f13\uff0clog2 4000+1", + "role": "user", + "url": null, + "metadata": null + }, + { + "id": "af2e4a0d68f34e61b977ee54f72acf63", + "timestamp": "2025-01-01 01:40:46", + "name": "user_342ee332-16c3-4722-a7aa-fd020088aba1", + "content": { + "thought": "\u5b66\u751f\u7406\u89e3\u4e86\u601d\u8003\u9898\u7684\u7b54\u6848\uff0c\u4e0b\u4e00\u6b65\u8fdb\u5165\u4e0b\u4e00\u8282\u3002", + "speak": "\u597d\u7684\uff0c\u4f60\u7684\u8ba1\u7b97\u65b9\u6cd5\u662f\u6b63\u786e\u7684\uff0c\u6700\u5dee\u60c5\u51b5\u4e0b\u9700\u8981\u731c\u6d4b13\u6b21\u3002\u6211\u4eec\u73b0\u5728\u53ef\u4ee5\u8fdb\u5165\u4e0b\u4e00\u8282\u3002", + "function": "[{\"name\": \"next_chapter\", \"arguments\": {}}]" + }, + "role": "assistant", + "url": null, + "metadata": null + } + ], + "score": 10, + "is_rebuttal": false, + "rebuttal_score": 0 } - ] - } + ], + "binary_search" + ], + [ + [], + "L002" + ] ], - "course_put_in_date": "2024-01-01", - "course_last_study_date": "2024-12-25", - "course_total_study_time": 120 - } - }, - "data-structure": { - "course_process": { + "course_put_in_date": "", + "course_last_study_date": "2025-01-01", + "course_total_study_time": 0 + }, + "data-structure": { "lesson_processs": [ - { - "lesson_process": [ - { - "chapter_info": { - "dialog": ["This is course2 chapter 1 dialog"], - "score": 88, - "is_rebuttal": false, - "rebuttal_score": 0 - } - } - ] - } + [ + [], + "L001" + ], + [ + [], + "L002" + ] ], - "course_put_in_date": "2024-01-01", - "course_last_study_date": "2024-12-25", - "course_total_study_time": 90 + "course_put_in_date": "", + "course_last_study_date": "", + "course_total_study_time": 0 + }, + "CS101": { + "lesson_processs": [ + [ + [], + "L001" + ], + [ + [], + "L002" + ] + ], + "course_put_in_date": "", + "course_last_study_date": "", + "course_total_study_time": 0 } } -} } \ No newline at end of file diff --git a/Html/db/data/user/user_id_list.json b/Html/db/data/user/user_id_list.json index 8e4d91c..c57d13c 100644 --- a/Html/db/data/user/user_id_list.json +++ b/Html/db/data/user/user_id_list.json @@ -2,6 +2,6 @@ "user123": "password123", "user456": "password456", "user789": "password789", - "cake": "12138ckC" -} - \ No newline at end of file + "cake": "123123", + "a": "123123" +} \ No newline at end of file diff --git a/Html/db/user.py b/Html/db/user.py index 516c009..c389fc8 100644 --- a/Html/db/user.py +++ b/Html/db/user.py @@ -1,116 +1,116 @@ -from datetime import date -from tinydb import TinyDB, Query +import os +# Example usage: +import json +from datetime import datetime + +LOCAL_USER_DATA_DIR = "data/user/" # only use locally, not for other .py files class User: - def __init__(self, db_file='user_data.json'): - """初始化用户管理,自动打开并加载 JSON 数据文件。""" - self.db_file = db_file - self.db = TinyDB(self.db_file) - self.user_query = Query() + def __init__(self, user_id, select_course, head_icon, course_process_dict, save_path): + self.user_id = user_id # User ID + self.select_course = select_course # List of selected courses + self.head_icon = head_icon # URL of the user's head icon + self.course_process_dict = course_process_dict # Dictionary of courses with their progress + self.save_path = save_path - def add_user(self, user_data): - """添加新的用户""" - if not self.db.search(self.user_query.user_id == user_data['user_id']): - self.db.insert(user_data) - else: - print(f"User with ID {user_data['user_id']} already exists.") + def save_chapter_memory(self, course_id, lesson_id, subchapter_title, mem_list, score, is_rebuttal): + ''' + Save the memory of a chapter + ''' + try: + if(course_id not in self.course_process_dict): + self.course_process_dict[course_id] = {'lesson_processs':[], 'course_put_in_date':'', 'course_last_study_date':'', 'course_total_study_time':0} + self.course_process_dict[course_id]['course_last_study_date'] = datetime.now().strftime('%Y-%m-%d') + for _ in range(len(self.course_process_dict[course_id]['lesson_processs'])): + lesson_process, lid = self.course_process_dict[course_id]['lesson_processs'][_] + if lid == lesson_id: + saveed = False + for i in range(len(lesson_process)): + chapter_info = lesson_process[i] + if chapter_info['title'] == subchapter_title: + chapter_info['dialog'] = mem_list + if is_rebuttal: + chapter_info['rebuttal_score'] = score + else: + chapter_info['score'] = score + chapter_info['is_rebuttal'] = is_rebuttal + saveed = True + break + if not saveed: + lesson_process.append({ + 'title': subchapter_title, + 'dialog': mem_list, + 'score': score, + 'is_rebuttal': is_rebuttal, + 'rebuttal_score': score if is_rebuttal else 0, + }) + break + self.save_to_file() + except Exception as e: + print("=-=-=-=-=-=") + print(e) + def get_course_progress(self): + for course_name, course_data in self.course_process_dict.items(): + print(f"Course: {course_name}") + for lessons,lesson_id in course_data["lesson_processs"]: + print(f" Lesson ID: {lesson_id}") + for chapter in lessons: + chapter_info = chapter + print(f" Chapter Dialog: {chapter_info['dialog']}") + print(f" Chapter Score: {chapter_info['score']}") + print(f" Rebuttal: {'Yes' if chapter_info['is_rebuttal'] else 'No'}") + if chapter_info['is_rebuttal']: + print(f" Rebuttal Score: {chapter_info['rebuttal_score']}") - def get_user(self, user_id): - """根据 user_id 获取用户信息""" - result = self.db.search(self.user_query.user_id == user_id) - return result[0] if result else None + def select_new_course(self, course_id, course): + self.select_course.append(course_id) - def update_user(self, user_id, updated_data): - """更新用户信息""" - self.db.update(updated_data, self.user_query.user_id == user_id) - - def delete_user(self, user_id): - """删除用户""" - self.db.remove(self.user_query.user_id == user_id) - - def get_all_users(self): - """获取所有用户""" - return self.db.all() + self.course_process_dict[course_id] = {'lesson_processs':[], 'course_put_in_date':'', 'course_last_study_date':'','course_total_study_time':0} + self.course_process_dict[course_id]['lesson_processs'] + for lesson in course.lessons: + self.course_process_dict[course_id]['lesson_processs'].append(([], lesson['lesson_id'])) -# 用户数据结构示例 -# user_data = { -# 'user_id': 'user123', -# 'select_course': ['course1', 'course2'], -# 'course_process_dict': { -# 'course1': { -# 'course_process': { -# 'lesson_processs': [ -# { -# 'lesson_process': [ -# { -# 'chapter_info': { -# 'dialog': ['This is chapter 1 dialog'], -# 'score': 85, -# 'is_rebuttal': True, -# 'rebuttal_score': 90 -# } -# }, -# { -# 'chapter_info': { -# 'dialog': ['This is chapter 2 dialog'], -# 'score': 75, -# 'is_rebuttal': False, -# 'rebuttal_score': 0 -# } -# } -# ] -# } -# ], -# 'course_put_in_date': date(2024, 1, 1), -# 'course_last_study_date': date(2024, 12, 25), -# 'course_total_study_time': 120 # 总学习时间:分钟 -# } -# }, -# 'course2': { -# 'course_process': { -# 'lesson_processs': [ -# { -# 'lesson_process': [ -# { -# 'chapter_info': { -# 'dialog': ['This is course2 chapter 1 dialog'], -# 'score': 88, -# 'is_rebuttal': False, -# 'rebuttal_score': 0 -# } -# } -# ] -# } -# ], -# 'course_put_in_date': date(2024, 2, 1), -# 'course_last_study_date': date(2024, 12, 24), -# 'course_total_study_time': 90 -# } -# } -# } -# } + with open(self.save_path, 'w') as f: + json.dump(self.__json__(), f, indent=4) -# updated_user_data = { -# 'select_course': ['course1', 'course3'] -# } + def save_to_file(self): + print(f"saved at {self.save_path}") + self.get_course_progress() + with open(self.save_path, 'w') as f: + json.dump(self.__json__(), f, indent=4) -# # 创建 User 实例 -# user_list = User() + def __json__(self): + return { + 'user_id': self.user_id, + 'select_course': self.select_course, + 'head_icon': self.head_icon, + 'course_process_dict': self.course_process_dict + } -# # 添加用户 -# user_list.add_user(user_data) + def to_json(self): + return json.dumps(self.__json__(), indent=4) -# # 获取用户信息 -# user = user_list.get_user('user123') -# print(user) +def load_user_from_json(user_id, user_data_dir = None)-> User: + USER_DATA_DIR = user_data_dir if user_data_dir else LOCAL_USER_DATA_DIR + with open(os.path.join(USER_DATA_DIR, f'{user_id}.json'), "r") as f: + raw_json = f.read() + user_data = json.loads(raw_json) + return User(save_path = os.path.join(USER_DATA_DIR, f'{user_id}.json'), **user_data) -# # 更新用户选择的课程 -# user_list.update_user('user123', updated_user_data) +def create_user_json(user_id, user_data_dir = None): + USER_DATA_DIR = user_data_dir if user_data_dir else LOCAL_USER_DATA_DIR + with open(os.path.join(USER_DATA_DIR, f'{user_id}.json'), "w") as f: + f.write(json.dumps({ + 'user_id': user_id, + 'select_course': [], + 'head_icon': '', + 'course_process_dict': {} + })) -# # 获取所有用户 -# all_users = user_list.get_all_users() -# print(all_users) +if(__name__ == "__main__"): -# # 删除用户 -# user_list.delete_user('user123') + user = load_user_from_json('cake') + + + user.get_course_progress() diff --git a/Html/db/user_list.py b/Html/db/user_list.py index 2b0e915..b6f0c25 100644 --- a/Html/db/user_list.py +++ b/Html/db/user_list.py @@ -1,36 +1,48 @@ -from tinydb import TinyDB, Query +import json class UserList: def __init__(self, db_file='db/data/user/user_id_list.json'): """初始化用户管理,自动打开并加载 JSON 数据文件。""" self.db_file = db_file - self.db = TinyDB(self.db_file) - self.user_query = Query() + with open(self.db_file, 'r') as f: + self.db = json.load(f) def add_user(self, user_id, password): """添加新的用户登录信息""" # 检查是否已经有该用户 - if not self.db.search(self.user_query.user_id == user_id): - self.db.insert({'user_id': user_id, 'password': password}) + if user_id not in self.db: + self.db[user_id] = password + with open(self.db_file, 'w') as f: + json.dump(self.db, f, indent=4) else: print(f"User with ID {user_id} already exists.") - def get_user(self, user_id): + def has_user(self, user_id): + """检查用户是否存在""" + return user_id in self.db + + def get_user_pswd(self, user_id): """获取指定 user_id 的用户信息""" - result = self.db.search(self.user_query.user_id == user_id) - return result[0] if result else None - + if user_id in self.db: + result = self.db[user_id] + return result + return None + def update_password(self, user_id, new_password): """更新用户的密码""" - self.db.update({'password': new_password}, self.user_query.user_id == user_id) + assert self.db.get(user_id) is not None, f"User with ID {user_id} does not exist." + self.db[user_id] = new_password + with open(self.db_file, 'w') as f: + json.dump(self.db, f, indent=4) def delete_user(self, user_id): """删除用户""" - self.db.remove(self.user_query.user_id == user_id) - + assert self.db.get(user_id) is not None, f"User with ID {user_id} does not exist." + self.db.remove(user_id) + def get_all_users(self): """获取所有用户的信息""" - return self.db.all() + return list(self.db.keys()) # 创建 UserList 实例 # user_list = UserList() diff --git a/Html/static/css/book.css b/Html/static/css/course.css similarity index 100% rename from Html/static/css/book.css rename to Html/static/css/course.css diff --git a/Html/static/css/dashboard.css b/Html/static/css/dashboard.css index 979b688..becc690 100644 --- a/Html/static/css/dashboard.css +++ b/Html/static/css/dashboard.css @@ -9,7 +9,6 @@ body { font-family: 'Arial', sans-serif; background-color: #f5f5f5; - padding: 20px; } /* 页眉导航栏 */ @@ -18,7 +17,6 @@ body { justify-content: space-between; align-items: center; background-color: #2575fc; - padding: 10px 30px; color: white; border-radius: 10px; margin-bottom: 30px; @@ -74,14 +72,27 @@ body { .course-card { width: 300px; height: 500px; + display: flex; + flex-direction: column; background-color: white; border-radius: 15px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); overflow: hidden; - position: relative; transition: transform 0.3s; } +.select-button { + display: block; + width: 100%; + padding: 10px; + background-color: #2575fc; + color: white; + border: none; + cursor: pointer; + font-size: 16px; + margin-top: auto; /* 将按钮推到父元素的底部 */ +} + .course-card:hover { transform: translateY(-10px); /* 提升效果 */ } diff --git a/Html/static/css/index.css b/Html/static/css/index.css index 929f93a..44ead8d 100644 --- a/Html/static/css/index.css +++ b/Html/static/css/index.css @@ -1,38 +1,4 @@ -/* 页眉导航栏 */ -.navbar { - display: flex; - justify-content: space-between; - align-items: center; - background-color: #2575fc; - padding: 10px 30px; - color: white; - border-radius: 10px; - margin-bottom: 30px; -} -.navbar .logo h1 { - font-size: 24px; - font-weight: bold; -} - -.navbar-links a { - color: white; - text-decoration: none; - margin: 0 15px; - font-size: 16px; - transition: color 0.3s; -} - -.navbar-links a:hover { - color: #f1c40f; -} - -.navbar .avatar img { - width: 40px; - height: 40px; - border-radius: 50%; - border: 2px solid white; -} /* General reset */ * { margin: 0; @@ -42,12 +8,23 @@ /* Body & Page Background */ + body { + display: flex; font-family: 'Arial', sans-serif; background-color: #f5f5f5; - padding: 20px; + flex-direction: column; + min-height: 100vh; + margin: 0; +} +main { + flex: 1; +} +footer { + background-color: #f8f9fa; + text-align: center; + padding: 10px 0; } - /* Header styles */ header { background-color: #2575fc; @@ -105,14 +82,31 @@ main { .course-card { background-color: white; + display: flex; + flex-direction: column; border-radius: 8px; width: 300px; height: 400px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); overflow: hidden; transition: transform 0.3s ease; + margin: 0px; } +.select-button { + display: block; + width: 100%; + padding: 10px; + background-color: #2575fc; + color: white; + border: none; + cursor: pointer; + font-size: 16px; + margin-top: auto; /* 将按钮推到父元素的底部 */ +} +.course-card:hover { + transform: translateY(-10px); /* 提升效果 */ +} .course-card img { width: 100%; height: 261px; @@ -131,19 +125,22 @@ main { color: #555; } -.select-button { + +.select-button:hover { + background-color: #113c86; +} + +.selected-button { display: block; width: 100%; padding: 10px; - background-color: #2575fc; + background-color: #8a8b8c; color: white; border: none; cursor: pointer; font-size: 16px; -} - -.select-button:hover { - background-color: #113c86; + cursor: not-allowed; + margin-top: auto; /* 将按钮推到父元素的底部 */ } /* Footer styles */ diff --git a/Html/static/js/chatbox.js b/Html/static/js/chatbox.js index f7a59bb..b6b492b 100644 --- a/Html/static/js/chatbox.js +++ b/Html/static/js/chatbox.js @@ -31,10 +31,15 @@ document.addEventListener('DOMContentLoaded', function() { const approveButton = document.createElement('button'); approveButton.innerText = '批准'; approveButton.data = element; + approveButton.style.width = '100%'; + approveButton.style.maxHeight = '30px'; approveButton.onclick = function(event) { console.log(element) socket.emit('message', JSON.stringify({type:'function', data:element})); event.currentTarget.disabled = true; + event.currentTarget.style.backgroundColor = 'gray'; + event.currentTarget.style.color = 'white'; // 可选:设置文字颜色为白色,以便更清晰地显示 + event.currentTarget.style.border = 'none'; // 可选:去掉边框 }; // 将按钮添加到消息气泡中 requestMessage.innerHTML = `Function: ${element.name}(${JSON.stringify(element.arguments)})
`; @@ -56,7 +61,7 @@ document.addEventListener('DOMContentLoaded', function() { console.log(data) const scoreMessage = document.createElement('div'); scoreMessage.className = 'chat-message server-message'; - scoreMessage.innerHTML = `Chapter ${data.chapter_id} Score: ${data.data}`; + scoreMessage.innerHTML = `Chapter ${data.chapter_id} Score: ${JSON.stringify(data.data.content.speak)}`; document.getElementById('chatbox').appendChild(scoreMessage); document.getElementById('chatbox').scrollTop = document.getElementById('chatbox').scrollHeight; }) diff --git a/Html/static/js/dashboard.js b/Html/static/js/dashboard.js index 7830edf..e1a059a 100644 --- a/Html/static/js/dashboard.js +++ b/Html/static/js/dashboard.js @@ -1,70 +1,54 @@ // dashboard.js +let courseData; +function show_user_data(user_data, course_brief_data_list){ + courseData = user_data.course_process_dict + for (let i=0;i +
+

${course.title}

+

${course.course_description}

+
+ + `; + courseCardsContainer.appendChild(courseCard); + courseCard.data = course_id + courseCard.addEventListener('click',() => { + openCourseProgress(courseCard.data); + }); + } +} function openCourseProgress(courseId) { - const courseData = { - 'algorithm': { - title: '算法分析与设计', - progress: '50%', - chapters: [ - { - title: '第一章: 算法基础', - subChapters: [ - { title: '子章节1: 算法介绍', path: 'introduction' }, - { title: '子章节2: 时间复杂度分析', path: 'time-complexity' } - ] - }, - { - title: '第二章: 排序与查找', - subChapters: [ - { title: '子章节1: 排序算法', path: 'sorting-algorithms' }, - { title: '子章节2: 查找算法', path: 'searching-algorithms' } - ] - }, - { - title: '第三章: 图算法', - subChapters: [ - { title: '子章节1: 图的表示', path: 'graph-representation' }, - { title: '子章节2: DFS 与 BFS', path: 'dfs-bfs' } - ] - } - ] - }, - 'data-structures': { - title: '数据结构与算法', - progress: '30%', - chapters: [ - { - title: '第一章: 数组与链表', - subChapters: [ - { title: '子章节1: 数组基础', path: 'array-basics' }, - { title: '子章节2: 链表实现', path: 'linked-list' } - ] - }, - { - title: '第二章: 栈与队列', - subChapters: [ - { title: '子章节1: 栈的实现', path: 'stack-implementation' }, - { title: '子章节2: 队列的应用', path: 'queue-application' } - ] - }, - { - title: '第三章: 二叉树', - subChapters: [ - { title: '子章节1: 二叉树的遍历', path: 'binary-tree-traversal' }, - { title: '子章节2: 二叉查找树', path: 'binary-search-tree' } - ] - } - ] - } - // 可以继续添加其他课程的数据 - }; - - // 获取对应课程的数据 + console.log(courseId) const course = courseData[courseId]; if (!course) return; // 更新右侧滑出卡片的内容 document.getElementById('course-title').textContent = course.title; + ///////////////////////// course.progress;还没有计算 document.getElementById('progress').textContent = course.progress; // 更新章节列表 @@ -77,25 +61,43 @@ function openCourseProgress(courseId) { const chapterTitle = document.createElement('div'); chapterTitle.classList.add('chapter-title'); - chapterTitle.textContent = chapter.title; + chapterTitle.textContent = chapter.lesson_id; chapterItem.appendChild(chapterTitle); // 创建子章节 if (chapter.subChapters && chapter.subChapters.length > 0) { const subChapterList = document.createElement('ul'); subChapterList.classList.add('sub-chapter-list'); - + chapter.subChapters.forEach(subChapter => { const subChapterItem = document.createElement('li'); subChapterItem.classList.add('sub-chapter-item'); - subChapterItem.textContent = subChapter.title; - + subChapterItem.textContent = subChapter; + console.log('-------------------') + console.log(course) + // 查找学生进度 + for(let i = 0; i < course.lesson_processs.length; i++) { + if (course.lesson_processs[i][1] == chapter.lesson_id) {//确定lesson_id对应正确 + console.log('-------------------') + console.log(course.lesson_processs[i][0]) + lesson_chapters_progress = course.lesson_processs[i][0];//寻找对应的每一个章节的进度 + for (let j=0; j { - const userId = 'userid'; // 这里可以动态传入当前用户ID - const courseName = encodeURIComponent(course.title); // 对课程名称进行编码 - const subChapterPath = subChapter.path; // 子章节路径 - const url = `/desktop/${userId}/${courseName}/${subChapterPath}`; + const courseId = encodeURIComponent(course.course_id); // 对课程名称进行编码 + const url = `/desktop_nouser/${courseId}/${chapter.lesson_id}`; window.location.href = url; // 跳转到该学习页面 }); diff --git a/Html/static/js/index.js b/Html/static/js/index.js new file mode 100644 index 0000000..39baf62 --- /dev/null +++ b/Html/static/js/index.js @@ -0,0 +1,42 @@ +function show_books(courses_data, user_selected_courses){ + console.log(courses_data) + console.log(user_selected_courses) +} +function show_course_details(course_id){ + window.location.href = '/course/' + course_id +} + +document.addEventListener('DOMContentLoaded', function() { + const selectButtons = document.querySelectorAll('.select-button'); + + selectButtons.forEach(button => { + button.addEventListener('click', function(event) { + event.stopPropagation(); // 阻止事件冒泡 + const courseId = this.getAttribute('data-course-id'); + fetch(`/select_course`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-CSRFToken': '{{ csrf_token() }}' // 如果使用 CSRF 保护 + }, + body: JSON.stringify({ course_id: courseId }) + }) + .then(response => response.json()) + .then(data => { + if (data.success) { + // 更新按钮样式或显示消息 + this.classList.remove('select-button'); + this.classList.add('selected-button'); + this.textContent = '已选择'; + alert('选择课程成功'); + } else { + alert('选择课程失败'); + } + }) + .catch(error => { + console.error('Error:', error); + alert('选择课程失败'); + }); + }); + }); +}); \ No newline at end of file diff --git a/Html/static/js/register.js b/Html/static/js/register.js new file mode 100644 index 0000000..1e19dcf --- /dev/null +++ b/Html/static/js/register.js @@ -0,0 +1,39 @@ +document.addEventListener('DOMContentLoaded', function() { + const registerForm = document.getElementById('register-form'); + + registerForm.addEventListener('submit', function(event) { + event.preventDefault(); // 阻止表单默认提交行为 + + const username = document.getElementById('username').value; + const email = document.getElementById('email').value; + const password = document.getElementById('password').value; + const confirmPassword = document.getElementById('confirm-password').value; + + if (password !== confirmPassword) { + alert('密码和确认密码不一致'); + return; + } + + fetch('/register_post', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-CSRFToken': '{{ csrf_token() }}' // 如果使用 CSRF 保护 + }, + body: JSON.stringify({ username, email, password }) + }) + .then(response => response.json()) + .then(data => { + if (data.success) { + alert('注册成功'); + window.location.href = '/login'; // 注册成功后跳转到登录页面 + } else { + alert('注册失败: ' + data.message); + } + }) + .catch(error => { + console.error('Error:', error); + alert('注册失败'); + }); + }); +}); \ No newline at end of file diff --git a/Html/templates/book.html b/Html/templates/book.html deleted file mode 100644 index 7a65033..0000000 --- a/Html/templates/book.html +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - 课程详情 - - - - - {% include 'navbar.html' %} - - -
- -
-
- 课程封面 -
-
-

计算机科学导论

-

作者:张教授

-

- 本课程将介绍计算机科学的基本概念,包括计算机的硬件结构、操作系统、编程语言等基础知识,适合初学者。 -

-
-
-
-
- -
- -
- -
- 教案封面 -
-

第一章:计算机概述

-

介绍计算机的基础概念和发展历程。

-
-
- -
- 教案封面 -
-

第二章:操作系统基础

-

学习操作系统的基本原理与结构。

-
-
- - -
-
-
- - - diff --git a/Html/templates/course.html b/Html/templates/course.html new file mode 100644 index 0000000..1052d08 --- /dev/null +++ b/Html/templates/course.html @@ -0,0 +1,54 @@ + + + + + + 课程详情 + + + + + {% include 'navbar.html' %} + + +
+ +
+
+ 课程封面 +
+
+

{{course_data.course_name}}

+

作者:{{course_data.course_auther}}

+

+ {{course_data.description}} +

+ +
+
+
+
+ +
+ +
+ + {% for lesson in course_data.lessons %} +
+ 教案封面 +
+

{{lesson.lesson_name}}

+

{{lesson.markdown}}

+
+
+ + {% endfor %} +
+
+
+ + + diff --git a/Html/templates/dashboard.html b/Html/templates/dashboard.html index 8591251..b5bee8a 100644 --- a/Html/templates/dashboard.html +++ b/Html/templates/dashboard.html @@ -13,7 +13,7 @@

—— 我的选课 ——

-
+
课程封面 @@ -51,5 +51,14 @@
+ diff --git a/Html/templates/desktop.html b/Html/templates/desktop.html index fab5478..3a115df 100644 --- a/Html/templates/desktop.html +++ b/Html/templates/desktop.html @@ -10,7 +10,7 @@ - + @@ -33,8 +33,7 @@
- -
+
@@ -65,7 +64,8 @@ @@ -126,7 +126,7 @@ // 在成功获取 session 后创建并插入 iframe const iframe = document.createElement('iframe'); const sessionInfo = data - iframe.src = 'http://127.0.0.1:9090/?workspace=/mnt/c/CAKE/vscode/{{user_id}}/{{path}}&folder=/mnt/c/CAKE/vscode/{{user_id}}/{{path}}'; + iframe.src = '{{vscode_web_url}}/?workspace={{workspace_path}}&folder={{workspace_path}}'; iframe.style.width = '100%'; iframe.style.height = '100%'; @@ -146,8 +146,8 @@ // 动态加载 Markdown 文件 - function loadMarkdown(filename) { - fetch(`/${filename}-markdown`) + function loadMarkdown(course_id, filename) { + fetch(`/${course_id}-${filename}-markdown`) .then(response => response.json()) .then(data => { if (data.html_url) { @@ -166,7 +166,7 @@ }); } document.addEventListener('DOMContentLoaded', function() { - loadMarkdown('{{path}}'); + loadMarkdown('{{course_id}}','{{chapter_id}}'); }); diff --git a/Html/templates/index.html b/Html/templates/index.html index 6b92330..865194a 100644 --- a/Html/templates/index.html +++ b/Html/templates/index.html @@ -6,37 +6,39 @@ 课程选择主页 - + {% include 'navbar.html' %}

课程列表

-
- 课程1 -

课程名称 1

-

课程描述信息,简要介绍课程内容和学习目标。

- + {% for course_id, course in courses_data.items() %} +
+ {{ course.course_name }} +

{{ course.course_name }}

+

{{ course.course_description }}

+ {% if course_id in selected_courses %} + + {% else %} + + {% endif %}
-
- 课程2 -

课程名称 2

-

课程描述信息,简要介绍课程内容和学习目标。

- -
-
- 课程3 -

课程名称 3

-

课程描述信息,简要介绍课程内容和学习目标。

- -
- + {% endfor %} +
-

© 2024 学生管理系统 | 所有权利保留

+

版权所有 © 2024 “华实伴学君”——教学练评一体的虚拟编码助教

+ + + diff --git a/Html/templates/login.html b/Html/templates/login.html index 7e7e388..7126d29 100644 --- a/Html/templates/login.html +++ b/Html/templates/login.html @@ -21,6 +21,9 @@
+ diff --git a/Html/templates/navbar.html b/Html/templates/navbar.html index 0e529b2..b204050 100644 --- a/Html/templates/navbar.html +++ b/Html/templates/navbar.html @@ -1,7 +1,48 @@