This commit is contained in:
CakeCN
2025-01-01 01:43:28 +08:00
parent 1280a978f5
commit eb67bcfb70
115 changed files with 989 additions and 535 deletions

10
Html/app.log Normal file
View File

@@ -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 <module>
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.

View File

@@ -9,10 +9,24 @@ import sys
import json import json
parent_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) parent_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
sys.path.insert(0, parent_dir) 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__), '.')) current_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '.'))
sys.path.insert(0, current_dir) sys.path.insert(0, current_dir)
from AlgoriAgent.projects.algoriAgent.agent_manager import AgentManager 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__) app = Flask(__name__)
socketio = SocketIO(app, cors_allowed_origins="*",ping_timeout=60, ping_interval=5) socketio = SocketIO(app, cors_allowed_origins="*",ping_timeout=60, ping_interval=5)
# socketio = SocketIO(app, cors_allowed_origins="http://localhost:9888") # 设置跨域支持 # socketio = SocketIO(app, cors_allowed_origins="http://localhost:9888") # 设置跨域支持
@@ -20,7 +34,7 @@ import logging
app.secret_key = 'cakebaker' app.secret_key = 'cakebaker'
app.logger.setLevel(logging.DEBUG) app.logger.setLevel(logging.DEBUG)
# 配置 CORS # 配置 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'] userid_recorder = {} # user_id&path -> session['user_id']
@@ -31,8 +45,8 @@ Backboard
from backboardManager import BackBoardManager, Backboard from backboardManager import BackBoardManager, Backboard
backboard_manager = BackBoardManager() backboard_manager = BackBoardManager()
uuid2user_id = {} uuid2username = {}
user_id2uuid = {} username2uuid = {}
@@ -45,7 +59,7 @@ class VSCodeNamespace(Namespace):
user_id = dataconfig.get('user_id') user_id = dataconfig.get('user_id')
path = dataconfig.get('path') path = dataconfig.get('path')
print(f"User {user_id} connected with path: {path}") print(f"User {user_id} connected with path: {path}")
useruuid = user_id2uuid[user_id] useruuid = username2uuid[user_id]
join_room(useruuid, namespace='/vscode') join_room(useruuid, namespace='/vscode')
if backboard_manager.get_backboard(useruuid) == None: if backboard_manager.get_backboard(useruuid) == None:
backboard_manager.add_backboard(useruuid, path) backboard_manager.add_backboard(useruuid, path)
@@ -56,14 +70,15 @@ class VSCodeNamespace(Namespace):
dataconfig = data['config'] dataconfig = data['config']
realtime_response(dataconfig, data) realtime_response(dataconfig, data)
# emit('response', {'message': 'Config data received and connection established'}) # emit('response', {'message': 'Config data received and connection established'})
def on_disconnect(self): def on_disconnect(self, data):
print("VSCode client disconnected") print("VSCode client disconnected")
print("Disconnect reason:"+str(data))
def realtime_response(config, realtime_action): def realtime_response(config, realtime_action):
user_id = config['user_id'] user_id = config['user_id']
folder_path = config['path'] folder_path = config['path']
useruuid = user_id2uuid[user_id] useruuid = username2uuid[user_id]
bb = backboard_manager.get_backboard(useruuid) bb = backboard_manager.get_backboard(useruuid)
assert type(bb) == Backboard assert type(bb) == Backboard
@@ -75,14 +90,12 @@ def realtime_response(config, realtime_action):
if realtime_action['type'] == 'activeFile': if realtime_action['type'] == 'activeFile':
file_path = realtime_action['filePath'] file_path = realtime_action['filePath']
assert type(file_path) == str assert type(file_path) == str
file_path = "".join(file_path.split(f'/{user_id}/{folder_path}/')[1:]) with open(f"{file_path}") as f:
bb.active_file_path = file_path
with open(f"../{user_id}/{folder_path}/{file_path}") as f:
bb.active_file_content = f.read() bb.active_file_content = f.read()
if realtime_action['type'] == 'paste': if realtime_action['type'] == 'paste':
file_path = realtime_action['filePath'] file_path = realtime_action['filePath']
file_path = "".join(file_path.split(f'/{user_id}/{folder_path}/')[1:]) assert type(file_path) == str
bb.pasted_file_path = file_path bb.pasted_file_path = file_path
bb.pasted_content = realtime_action['content'] bb.pasted_content = realtime_action['content']
@@ -106,21 +119,22 @@ class AgentNamespace(Namespace):
def on_login(self, data): def on_login(self, data):
data = json.loads(data) data = json.loads(data)
user = data['username'] user = data['username']
folder_name = data['folder'] course_id = data['course_id']
user_uuid = user_id2uuid[user] chapter_id = data['chapter_id']
user_uuid = username2uuid[user]
session['user_id'] = user_uuid session['user_id'] = user_uuid
print(f'User connected with session user_id: {user_uuid}') print(f'User connected with session user_id: {user_uuid}')
# 从markdown、markdown_prompts、score_prompts中各读取数据folder.md并进行new_agent # 从markdown、markdown_prompts、score_prompts中各读取数据folder.md并进行new_agent
with open(f'books/markdown/{folder_name}.md','r',encoding='UTF-8') as fmd,\ with open(f'books/markdown/{course_id}/{chapter_id}.md','r',encoding='UTF-8') as fmd,\
open(f'books/markdown_prompts/{folder_name}.md','r',encoding='UTF-8')as fmdp,\ open(f'books/markdown_prompts/{course_id}/{chapter_id}.md','r',encoding='UTF-8')as fmdp,\
open(f'books/score_prompts/{folder_name}.md','r',encoding='UTF-8') as fsp: open(f'books/score_prompts/{course_id}/{chapter_id}.md','r',encoding='UTF-8') as fsp:
markdown = fmd.read() markdown = fmd.read()
markdown_prompts = fmdp.read() markdown_prompts = fmdp.read()
score_prompts = fsp.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) print(user_uuid)
join_room(user_uuid, namespace='/agent') # 将该用户加入以user_id为名的room 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): def on_language(self, language):
id = session.get('user_id') id = session.get('user_id')
@@ -154,8 +168,9 @@ class AgentNamespace(Namespace):
agent_manager.function_call(id, data['data']) agent_manager.function_call(id, data['data'])
def on_disconnect(self): def on_disconnect(self,data):
print("VSCode client disconnected") print("VSCode client disconnected")
print("Disconnect reason:"+str(data))
@@ -169,9 +184,9 @@ IMAGE_DIR = 'image' # 图片资源相对于 markdown 的位置
@app.route('/<filename>-markdown', methods=['GET']) @app.route('/<course_id>-<filename>-markdown', methods=['GET'])
def convert_md(filename): def convert_md(course_id, filename):
md_file_path = os.path.join(MARKDOWN_DIR, f'{filename}.md') md_file_path = os.path.join(MARKDOWN_DIR,course_id, f'{filename}.md')
if not os.path.exists(md_file_path): if not os.path.exists(md_file_path):
return jsonify({'error': 'Markdown file not found'}), 404 return jsonify({'error': 'Markdown file not found'}), 404
@@ -205,7 +220,7 @@ def convert_md(filename):
html_file.write(html_with_styles) html_file.write(html_with_styles)
# 处理图片资源,将 image/xxx 文件夹拷贝到 static/image/xxx # 处理图片资源,将 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) image_target_dir = os.path.join(STATIC_DIR, IMAGE_DIR, filename)
print(f"Copying image resources from {image_source_dir} to {image_target_dir}") print(f"Copying image resources from {image_source_dir} to {image_target_dir}")
if os.path.exists(image_source_dir): if os.path.exists(image_source_dir):
@@ -230,25 +245,35 @@ def serve_static(filename):
''' '''
Vscode Vscode
''' '''
@app.route('/desktop/<user_id>/<path>') @app.route('/desktop/<user_id>/<course_id>/<chapter_id>')
def hello_world(user_id, path): def desktop(user_id, course_id, chapter_id):
if 'user_id' not in session: if 'user_id' not in session:
# return redirect(url_for('login')) # return redirect(url_for('login'))
session['user_id'] = 'user_' + str(uuid.uuid4()) session['user_id'] = 'user_' + str(uuid.uuid4())
print("user "+ user_id + "uuid is"+ session['user_id']) print("user "+ user_id + "uuid is"+ session['user_id'])
user_id2uuid[user_id] = session['user_id'] username2uuid[user_id] = session['user_id']
uuid2user_id[session['user_id']] = user_id uuid2username[session['user_id']] = user_id
userid_recorder[user_id+'&'+path] = session['user_id'] userid_recorder[user_id+'&'+course_id] = session['user_id']
# 在上层 目录下创建一个名为 user_id_path 的文件夹 # 在学习目录下创建一个名为 user_id_path 的文件夹
path_dir = os.path.join(parent_dir, 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) os.makedirs(path_dir, exist_ok=True)
# 在此文件夹内部创建一个.config文件并写入 user_id=user_id\n path=path # 在此文件夹内部创建一个.config文件并写入 user_id=user_id\n path=path
config_path = os.path.join(path_dir, '.config') config_path = os.path.join(path_dir, '.config')
print('---------------------')
print(config_path)
with open(config_path, 'w') as f: with open(config_path, 'w') as f:
f.write(f"user_id={user_id}\npath={path}") tmpd = {'user_id': user_id, 'course_id': course_id, 'chapter_id': chapter_id, 'path': path_dir}
return render_template('desktop.html', user_id=user_id, path=path) 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/<course_id>/<chapter_id>')
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']) @app.route('/vscode_data', methods=['POST'])
def vscode_data(): def vscode_data():
@@ -269,17 +294,33 @@ def get_session():
Login 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') @app.route('/login')
def login(): def login():
return render_template('login.html')
if 'user_id' not in session: if 'user_id' not in session:
return render_template('login.html') return render_template('login.html')
else: else:
return redirect(url_for('/')) return redirect(url_for('/'))
from db.user_list import UserList
users_list = UserList()
@app.route('/login_post', methods=['POST']) @app.route('/login_post', methods=['POST'])
def login_post(): def login_post():
# 获取请求的 JSON 数据 # 获取请求的 JSON 数据
@@ -288,42 +329,79 @@ def login_post():
username = data.get('username') username = data.get('username')
password = data.get('password') password = data.get('password')
user = users_list.get_user(username) pswd = users_list.get_user_pswd(username)
if user is None:
return jsonify({'success': False, 'message': '用户名或密码错误'})
if user['password'] != password: if pswd is None:
return jsonify({'success': False, 'message': '用户名或密码错误'})
if pswd != password:
return jsonify({'success': False, 'message': '用户名或密码错误'}) return jsonify({'success': False, 'message': '用户名或密码错误'})
session['user_id'] = 'user_' + str(uuid.uuid4()) session['user_id'] = 'user_' + str(uuid.uuid4())
print("user "+ username + "uuid is"+ session['user_id']) print("user "+ username + "uuid is"+ session['user_id'])
user_id2uuid[username] = session['user_id'] username2uuid[username] = session['user_id']
uuid2user_id[session['user_id']] = username uuid2username[session['user_id']] = username
return jsonify({'success': True, 'message': '登录成功'}) return jsonify({'success': True, 'message': '登录成功'})
user_id2UserClass = {}
''' '''
DashBoard DashBoard
''' '''
@app.route('/dashboard') @app.route('/dashboard')
def 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 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/<book_name>') @app.route('/course/<course_id>')
def book(book_name): def course(course_id):
return render_template('book.html', book_name=book_name) 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('/') @app.route('/')
def home_index(): 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__': if __name__ == '__main__':
socketio.on_namespace(VSCodeNamespace('/vscode')) socketio.on_namespace(VSCodeNamespace('/vscode'))
socketio.on_namespace(AgentNamespace('/agent')) socketio.on_namespace(AgentNamespace('/agent'))

View File

@@ -30,4 +30,4 @@
本体测试点文件夹名 `twice_split。` 本体测试点文件夹名 `twice_split。`
_require_tools=judge _require_tools=judge,algorithm,binary_search,binary_search

View File

@@ -14,3 +14,10 @@ listen_port = 3001
server_address = ws://localhost:3000/myService server_address = ws://localhost:3000/myService
agent_process_provider_host = localhost agent_process_provider_host = localhost
agent_process_provider_port = 3002 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/

42
Html/db/course.py Normal file
View File

@@ -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')

View File

@@ -1,105 +1,62 @@
import os import json
from tinydb import TinyDB, Query, where import copy
import re
class CourseList: class CourseList:
def __init__(self, db_file='db/data/course/course_list.json'): def __init__(self, db_file='db/data/course/course_list.json'):
"""初始化课程列表,自动打开并加载 JSON 数据文件。"""
self.db_file = db_file self.db_file = db_file
self.db = TinyDB(self.db_file) with open(self.db_file, 'r') as f:
self.course_query = Query() self.db = json.load(f)
def add_course(self, course_data): def add_course(self, course_id, course_name, course_create_date, course_update_data, course_img_path):
"""添加新的课程到课程列表。""" """添加新的用户登录信息"""
if not self.db.search(self.course_query.course_id == course_data['course_id']): # 检查是否已经有该用户
self.db.insert(course_data) assert course_id not in self.db, f"Course {course_name} with ID {course_id} already exists."
else: self.db[course_id] = {}
print(f"Course with ID {course_data['course_id']} already exists.") 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): with open(self.db_file, 'w') as f:
"""获取指定 course_id 的课程信息。""" json.dump(self.db, f, indent=4)
result = self.db.search(self.course_query.course_id == course_id)
return result[0] if result else None
def update_course(self, course_id, updated_data):
"""更新指定 course_id 的课程信息。""" def get_course_brief_info(self, course_id, course) -> dict:
self.db.update(updated_data, self.course_query.course_id == course_id) 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): def delete_course(self, course_id):
"""删除指定 course_id 的课程。""" assert course_id in self.db, f"Course ID {course_id} does not exist."
self.db.remove(self.course_query.course_id == course_id) self.db.remove(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
def get_all_courses(self): def get_all_courses(self):
"""获取所有课程。""" return list(self.db)
return self.db.all()
def to_json(self):
return json.dumps(self.db)
# # 课程数据结构示例 def items(self):
# course_data = { assert type(self.db) is dict, "db is not a dict"
# 'course_id': 'CS101', return self.db.items()
# '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')

View File

@@ -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"
}
]
}

View File

@@ -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"
}
]
}

View File

@@ -1,21 +1,25 @@
{ {
"CS101":{
"course_id": "CS101", "course_id": "CS101",
"course_name": "Computer Science 101", "course_name": "Computer Science 101",
"course_img_path": "images/cs101.png", "course_description":"这个老师很懒,没有写介绍",
"lessons": [ "course_img_path": "/static/image/algorithm/book_cover.png",
{ "course_create_date": "2023-01-01",
"lesson_id": "L001", "course_update_data": "2023-01-01"},
"lesson_name": "Introduction to Computer Science",
"markdown": "This is the introduction lesson.", "algorithm":{
"markdown_prompt": "What is Computer Science?", "course_id": "algorithm",
"score_prompt": "Please provide an overview of CS." "course_name": "算法分析与设计",
}, "course_description":"这个老师很懒,没有写介绍",
{ "course_img_path": "/static/image/algorithm/book_cover.png",
"lesson_id": "L002", "course_create_date": "2023-01-01",
"lesson_name": "Data Structures", "course_update_data": "2023-01-01"},
"markdown": "In this lesson, we cover Data Structures.",
"markdown_prompt": "What is an array?", "data-structure":{
"score_prompt": "Explain how linked lists work." "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"}
} }

View File

@@ -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"
}
]
}

40
Html/db/data/user/a.json Normal file
View File

@@ -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
}
}
}

View File

@@ -1,57 +1,105 @@
{ {
"user_id": "user123", "user_id": "cake",
"select_course": ["algorithm", "data-structure"], "select_course": [
"CS101",
"algorithm",
"data-structure"
],
"head_icon": "/static/image/book_cover.jpg", "head_icon": "/static/image/book_cover.jpg",
"course_process_dict": { "course_process_dict": {
"algorithm": { "algorithm": {
"course_process": {
"lesson_processs": [ "lesson_processs": [
[
[
{ {
"lesson_process": [ "title": "\u5f15\u5165",
"dialog": [
{ {
"chapter_info": { "id": "0b26417b9a4a41c3a86a63e96ac279f7",
"dialog": ["This is chapter 1 dialog"], "timestamp": "2025-01-01 01:40:36",
"score": 85, "name": "system",
"is_rebuttal": true, "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",
"rebuttal_score": 90 "role": "system",
} "url": null,
"metadata": null
}, },
{ {
"chapter_info": { "id": "461938c9265547c9bd0187ece94d659d",
"dialog": ["This is chapter 2 dialog"], "timestamp": "2025-01-01 01:40:43",
"score": 75, "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, "is_rebuttal": false,
"rebuttal_score": 0 "rebuttal_score": 0
} }
}
]
}
], ],
"course_put_in_date": "2024-01-01", "binary_search"
"course_last_study_date": "2024-12-25", ],
"course_total_study_time": 120 [
} [],
"L002"
]
],
"course_put_in_date": "",
"course_last_study_date": "2025-01-01",
"course_total_study_time": 0
}, },
"data-structure": { "data-structure": {
"course_process": {
"lesson_processs": [ "lesson_processs": [
{ [
"lesson_process": [ [],
{ "L001"
"chapter_info": {
"dialog": ["This is course2 chapter 1 dialog"],
"score": 88,
"is_rebuttal": false,
"rebuttal_score": 0
}
}
]
}
], ],
"course_put_in_date": "2024-01-01", [
"course_last_study_date": "2024-12-25", [],
"course_total_study_time": 90 "L002"
} ]
],
"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
} }
} }
} }

View File

@@ -2,6 +2,6 @@
"user123": "password123", "user123": "password123",
"user456": "password456", "user456": "password456",
"user789": "password789", "user789": "password789",
"cake": "12138ckC" "cake": "123123",
"a": "123123"
} }

View File

@@ -1,116 +1,116 @@
from datetime import date import os
from tinydb import TinyDB, Query # Example usage:
import json
from datetime import datetime
LOCAL_USER_DATA_DIR = "data/user/" # only use locally, not for other .py files
class User: class User:
def __init__(self, db_file='user_data.json'): def __init__(self, user_id, select_course, head_icon, course_process_dict, save_path):
"""初始化用户管理,自动打开并加载 JSON 数据文件。""" self.user_id = user_id # User ID
self.db_file = db_file self.select_course = select_course # List of selected courses
self.db = TinyDB(self.db_file) self.head_icon = head_icon # URL of the user's head icon
self.user_query = Query() self.course_process_dict = course_process_dict # Dictionary of courses with their progress
self.save_path = save_path
def add_user(self, user_data): def save_chapter_memory(self, course_id, lesson_id, subchapter_title, mem_list, score, is_rebuttal):
"""添加新的用户""" '''
if not self.db.search(self.user_query.user_id == user_data['user_id']): Save the memory of a chapter
self.db.insert(user_data) '''
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: else:
print(f"User with ID {user_data['user_id']} already exists.") 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): def select_new_course(self, course_id, course):
"""根据 user_id 获取用户信息""" self.select_course.append(course_id)
result = self.db.search(self.user_query.user_id == user_id)
return result[0] if result else None
def update_user(self, user_id, updated_data): 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']
self.db.update(updated_data, self.user_query.user_id == user_id) for lesson in course.lessons:
self.course_process_dict[course_id]['lesson_processs'].append(([], lesson['lesson_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()
# 用户数据结构示例 with open(self.save_path, 'w') as f:
# user_data = { json.dump(self.__json__(), f, indent=4)
# '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
# }
# }
# }
# }
# updated_user_data = { def save_to_file(self):
# 'select_course': ['course1', 'course3'] 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 实例 def __json__(self):
# user_list = User() return {
'user_id': self.user_id,
'select_course': self.select_course,
'head_icon': self.head_icon,
'course_process_dict': self.course_process_dict
}
# # 添加用户 def to_json(self):
# user_list.add_user(user_data) return json.dumps(self.__json__(), indent=4)
# # 获取用户信息 def load_user_from_json(user_id, user_data_dir = None)-> User:
# user = user_list.get_user('user123') USER_DATA_DIR = user_data_dir if user_data_dir else LOCAL_USER_DATA_DIR
# print(user) 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)
# # 更新用户选择的课程 def create_user_json(user_id, user_data_dir = None):
# user_list.update_user('user123', updated_user_data) 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': {}
}))
# # 获取所有用户 if(__name__ == "__main__"):
# all_users = user_list.get_all_users()
# print(all_users)
# # 删除用户 user = load_user_from_json('cake')
# user_list.delete_user('user123')
user.get_course_progress()

View File

@@ -1,36 +1,48 @@
from tinydb import TinyDB, Query import json
class UserList: class UserList:
def __init__(self, db_file='db/data/user/user_id_list.json'): def __init__(self, db_file='db/data/user/user_id_list.json'):
"""初始化用户管理,自动打开并加载 JSON 数据文件。""" """初始化用户管理,自动打开并加载 JSON 数据文件。"""
self.db_file = db_file self.db_file = db_file
self.db = TinyDB(self.db_file) with open(self.db_file, 'r') as f:
self.user_query = Query() self.db = json.load(f)
def add_user(self, user_id, password): def add_user(self, user_id, password):
"""添加新的用户登录信息""" """添加新的用户登录信息"""
# 检查是否已经有该用户 # 检查是否已经有该用户
if not self.db.search(self.user_query.user_id == user_id): if user_id not in self.db:
self.db.insert({'user_id': user_id, 'password': password}) self.db[user_id] = password
with open(self.db_file, 'w') as f:
json.dump(self.db, f, indent=4)
else: else:
print(f"User with ID {user_id} already exists.") 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 的用户信息""" """获取指定 user_id 的用户信息"""
result = self.db.search(self.user_query.user_id == user_id) if user_id in self.db:
return result[0] if result else None result = self.db[user_id]
return result
return None
def update_password(self, user_id, new_password): 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): 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): def get_all_users(self):
"""获取所有用户的信息""" """获取所有用户的信息"""
return self.db.all() return list(self.db.keys())
# 创建 UserList 实例 # 创建 UserList 实例
# user_list = UserList() # user_list = UserList()

Some files were not shown because too many files have changed in this diff Show More