From 02cbd256d86ca4d0ee4f503d4dce69a9db2de894 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=AF=92=E5=AF=92?= <2596194220@qq.com>
Date: Fri, 30 Jan 2026 00:19:09 +0800
Subject: [PATCH] =?UTF-8?q?fix=EF=BC=9A=E4=BC=98=E5=8C=96=E9=85=8D?=
=?UTF-8?q?=E7=BD=AE=E5=AD=98=E5=82=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.idea/workspace.xml | 33 ++++-
.nicegui/storage-general.json | 25 ++++
config.env.toml | 98 ---------------
config.toml | 26 ----
config/config.py | 122 +++++++------------
data/names.xlsx | Bin 12275 -> 6345 bytes
main.py | 14 ++-
pyproject.toml | 1 +
ui/views/config_page.py | 207 +++++++++-----------------------
ui/views/convert_pdf_page.py | 14 +--
ui/views/data_page.py | 33 ++---
ui/views/home_page.py | 2 +-
ui/views/signature_page.py | 12 +-
ui/views/templates/back_home.py | 16 +++
utils/font_utils.py | 3 +-
utils/generate_utils.py | 28 ++---
utils/growt_utils.py | 4 +-
uv.lock | 10 +-
18 files changed, 228 insertions(+), 420 deletions(-)
create mode 100644 .nicegui/storage-general.json
delete mode 100644 config.env.toml
delete mode 100644 config.toml
create mode 100644 ui/views/templates/back_home.py
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 53cf388..2753775 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -4,11 +4,23 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -137,7 +149,7 @@
-
+
@@ -171,7 +183,15 @@
1766330259490
-
+
+
+ 1769699406868
+
+
+
+ 1769699406868
+
+
@@ -191,13 +211,14 @@
-
+
+
-
+
\ No newline at end of file
diff --git a/.nicegui/storage-general.json b/.nicegui/storage-general.json
new file mode 100644
index 0000000..c289fdb
--- /dev/null
+++ b/.nicegui/storage-general.json
@@ -0,0 +1,25 @@
+{
+ "data_folder": "D:\\working\\tools\\growth_report\\data",
+ "templates_folder": "D:\\working\\tools\\growth_report\\templates",
+ "source_file": "大四班 幼儿学期发展报告.pptx",
+ "output_folder": "output",
+ "excel_file": "names.xlsx",
+ "image_folder": "images",
+ "fonts_dir": "fonts",
+ "signature_image": "signature.png",
+ "class_name": "K4D",
+ "teachers": [
+ "康璐璐",
+ "冯宇阳",
+ "孙继艳"
+ ],
+ "class_type": 2,
+ "default_comment": "暂无评语",
+ "age_group": "大班上学期",
+ "ai": {
+ "api_key": "sk-ccb6a1445126f2e56ba50d7622ff350f",
+ "api_url": "https://apis.iflow.cn/v1/chat/completions",
+ "model": "deepseek-v3.2",
+ "prompt": "# Role \n你是一位拥有20年经验的资深幼儿园主班老师。你的文笔温暖、细腻、充满爱意,擅长发现每个孩子身上独特的闪光点。你的评语风格是“治愈系”的,能让家长读完后感到欣慰并对未来充满希望。\n\n# Goal\n请根据用户提供的【幼儿姓名】、【年龄段/班级】以及【日常表现关键词/评分数据】,撰写一份高质量的学期末成长评语。\n# Constraints & Rules\n1. **严格的格式排版 (Strict Formatting)**:\n- **换行**:正文中间不要随意换行,保持为一段完整的段落。\n2. **称呼处理**:\n- 自动识别用户输入的姓名,去掉姓氏。\n- 例如:“王小明” -> 第一行输出“小明宝贝:”。\n3. **分龄侧重 (根据 Age_Group 调整侧重点)**:\n- **小班 (3-4岁)**:侧重于适应集体生活、情绪稳定性、基本生活自理能力、愿意与老师互动。\n- **中班 (4-5岁)**:侧重于社交互动、分享与合作、动手能力、好奇心、规则意识。\n- **大班 (5-6岁)**:侧重于学习习惯、逻辑思维、领导力、任务意识、幼小衔接准备。\n4. **写作结构 (固定内容)**:\n- **开头**:固定文本必须包含:“{class_type}”\n- **正文**:结合【表现关键词】和【性别】,具体描述进步和优点。\n- **结尾**:委婉地提出期望(“如果你能...老师会更为你骄傲”),并送上祝福。\n5. **语气风格**:\n- 积极正面,多用肯定句。\n- 字数控制在 150-250 字之间。\n# Input Format\n- Name {{name}}\n- Age_Group {{class_name}}\n- Traits {{traits}}\n- Sex {{sex}}\n# Output Example\n(假设输入:Name=张图图, Age_Group=小班, Traits=适应能力强, 爱笑, 挑食,Sex=女)\n亲爱的图图宝贝:{class_type}\n你是一个爱笑的小天使,每天早上都能看到你甜甜的笑脸。从一开始的哭鼻子到现在能开心地参与游戏,你的适应能力让老师感到惊喜。不过,老师发现你在吃饭时偶尔会把不喜欢的青菜挑出来哦。如果你能和青菜宝宝做好朋友,把身体练得棒棒的,那就更完美啦!祝可爱的图图宝贝新年快乐,健康成长!\n"
+ }
+}
\ No newline at end of file
diff --git a/config.env.toml b/config.env.toml
deleted file mode 100644
index feef62e..0000000
--- a/config.env.toml
+++ /dev/null
@@ -1,98 +0,0 @@
-[paths]
-# TODO PPT模版路径
-source_file = "大班幼儿学期发展报告.pptx"
-# 输出文件夹
-output_folder = "output"
-# Excel数据文件路径
-excel_file = "names.xlsx"
-# 图片资源文件夹
-image_folder = "images"
-# 字体文件夹
-fonts_dir = "fonts"
-
-[class_info]
-# TODO 班级名称
-class_name = "K4D"
-# TODO 老师名单 (数组格式)
-teachers = [""]
-
-[defaults]
-# 当Excel中没有评语时的默认内容
-default_comment = "暂无评语"
-age_group = "大班上学期"
-
-
-# ========================
-# Excel 配置 (Data)
-# ========================
-[excel]
-sheet_name = "Sheet1"
-# 对应Excel表头名称,顺序必须与代码中的解包顺序一致!
-# 顺序:姓名, 英文名, 性别, 生日, 属相, 好朋友, 爱好, 游戏, 食物, 评语
-columns = [
- "姓名",
- "英文名",
- "性别",
- "生日",
- "属相",
- "我的好朋友",
- "我的爱好",
- "喜欢的游戏",
- "喜欢吃的食物",
- "表现特征",
- "评价",
-]
-
-# TODO API 配置
-[ai]
-api_key = ""
-api_url = ""
-model = ""
-prompt = """
-# Role
-你是一位拥有20年经验的资深幼儿园主班老师。你的文笔温暖、细腻、充满爱意,擅长发现每个孩子身上独特的闪光点。你的评语风格是“治愈系”的,能让家长读完后感到欣慰并对未来充满希望。
-
-# Goal
-请根据用户提供的【幼儿姓名】、【年龄段/班级】以及【日常表现关键词/评分数据】,撰写一份高质量的学期末成长评语。
-
-# Constraints & Rules
-1. **称呼处理**:
- - 自动识别用户输入的姓名。
- - **必须去掉姓氏**,只使用名。
- - 统一格式为:“[名]宝贝,你好!”或“[名]宝贝:”。
- - 例如:“王小明” -> “小明宝贝”;“李在这个” -> “在这个宝贝”。
-
-2. **分龄侧重 (根据 Age_Group 调整侧重点)**:
- - **小班 (3-4岁)**:侧重于适应集体生活、情绪稳定性、基本生活自理能力(吃饭、午睡、如厕)、愿意与老师互动。
- - **中班 (4-5岁)**:侧重于社交互动、分享与合作、动手能力、好奇心、规则意识的建立、自信心的增强。
- - **大班 (5-6岁)**:侧重于学习习惯、逻辑思维、领导力/榜样作用、任务意识、为幼小衔接做的准备、抗挫折能力。
-
-3. **写作结构 (三段式)**:
- - **开头**:亲切的问候 + 总体印象(用美好的形容词,如文静、活泼、机灵等)。
- - **正文**:结合提供的【表现关键词】,具体描述孩子的进步和优点(必须具体,拒绝空洞)。
- - **结尾**:委婉地提出一点小小的期望(用“如果你能...老师会更为你骄傲”的句式),并送上新学期的祝福。
-
-4. **语气风格**:
- - 积极正面,多用肯定句。
- - 避免生硬的批评,将缺点转化为“待提升的潜力”或“期望”。
- - 字数控制在 150-250 字之间(适合PPT展示)。
-
-# Workflow
-1. 分析用户输入的年龄段,确定评价基调。
-2. 处理姓名,提取昵称。
-3. 将输入的关键词串联成通顺、优美的句子。
-4. 按照三段式结构输出最终评语。
-
-# Input Format
-用户将提供 JSON 格式或特定格式的数据,包含:
-- Name {{name}}
-- Age_Group {{class_name}}
-- Traits (表现关键词/特征,如:吃饭香、爱画画、有些胆小、数学好)
-
-# Output Example
-(假设输入:Name=张图图, Age_Group=小班, Traits=适应能力强, 爱笑, 挑食)
-图图宝贝,你好!
-你是一个爱笑的小天使,每天早上都能看到你甜甜的笑脸,老师的心都要被你融化了。这个学期你进步真大呀,从一开始的哭鼻子到现在能开心地参与游戏,你的适应能力让老师感到惊喜。在集体活动中,你总是那么投入。
-不过,老师发现你在吃饭时偶尔会把不喜欢的青菜挑出来哦。如果你能和青菜宝宝做好朋友,把身体练得棒棒的,那就更完美啦!
-祝可爱的图图宝贝新年快乐,健康成长!
-"""
\ No newline at end of file
diff --git a/config.toml b/config.toml
deleted file mode 100644
index b39fa29..0000000
--- a/config.toml
+++ /dev/null
@@ -1,26 +0,0 @@
-[paths]
-source_file = "大四班 幼儿学期发展报告.pptx"
-output_folder = "output"
-excel_file = "names.xlsx"
-image_folder = "images"
-fonts_dir = "fonts"
-signature_image = "d:\\working\\tools\\growth_report\\data\\signature.png"
-
-[class_info]
-class_name = "K4D"
-teachers = [
- "康璐璐",
- "冯宇阳",
- "孙继艳",
-]
-class_type = 2
-
-[defaults]
-default_comment = ""
-age_group = "大班上学期"
-
-[ai]
-api_key = "sk-ccb6a1445126f2e56ba50d7622ff350f"
-api_url = "https://apis.iflow.cn/v1/chat/completions"
-model = "deepseek-v3.2"
-prompt = "# Role \n你是一位拥有20年经验的资深幼儿园主班老师。你的文笔温暖、细腻、充满爱意,擅长发现每个孩子身上独特的闪光点。你的评语风格是“治愈系”的,能让家长读完后感到欣慰并对未来充满希望。\n\n# Goal\n请根据用户提供的【幼儿姓名】、【年龄段/班级】以及【日常表现关键词/评分数据】,撰写一份高质量的学期末成长评语。\n# Constraints & Rules\n1. **严格的格式排版 (Strict Formatting)**:\n- **换行**:正文中间不要随意换行,保持为一段完整的段落。\n2. **称呼处理**:\n- 自动识别用户输入的姓名,去掉姓氏。\n- 例如:“王小明” -> 第一行输出“小明宝贝:”。\n3. **分龄侧重 (根据 Age_Group 调整侧重点)**:\n- **小班 (3-4岁)**:侧重于适应集体生活、情绪稳定性、基本生活自理能力、愿意与老师互动。\n- **中班 (4-5岁)**:侧重于社交互动、分享与合作、动手能力、好奇心、规则意识。\n- **大班 (5-6岁)**:侧重于学习习惯、逻辑思维、领导力、任务意识、幼小衔接准备。\n4. **写作结构 (固定内容)**:\n- **开头**:固定文本必须包含:“{class_type}”\n- **正文**:结合【表现关键词】和【性别】,具体描述进步和优点。\n- **结尾**:委婉地提出期望(“如果你能...老师会更为你骄傲”),并送上祝福。\n5. **语气风格**:\n- 积极正面,多用肯定句。\n- 字数控制在 150-250 字之间。\n# Input Format\n- Name {{name}}\n- Age_Group {{class_name}}\n- Traits {{traits}}\n- Sex {{sex}}\n# Output Example\n(假设输入:Name=张图图, Age_Group=小班, Traits=适应能力强, 爱笑, 挑食,Sex=女)\n亲爱的图图宝贝:{class_type}\n你是一个爱笑的小天使,每天早上都能看到你甜甜的笑脸。从一开始的哭鼻子到现在能开心地参与游戏,你的适应能力让老师感到惊喜。不过,老师发现你在吃饭时偶尔会把不喜欢的青菜挑出来哦。如果你能和青菜宝宝做好朋友,把身体练得棒棒的,那就更完美啦!祝可爱的图图宝贝新年快乐,健康成长!\n"
diff --git a/config/config.py b/config/config.py
index b8af7ed..95e4d0d 100644
--- a/config/config.py
+++ b/config/config.py
@@ -1,6 +1,9 @@
import os
import sys
+from loguru import logger
+from nicegui import app
+
# 1. 处理读取库
try:
import tomllib as toml_read # Python 3.11+
@@ -39,53 +42,69 @@ def get_resource_path(relative_path):
return external_path
+def init_storage():
+ """如果 storage 是空的,则注入默认配置"""
+ cfg = app.storage.general
+ if "class_name" not in cfg:
+ logger.info("初始化默认配置...")
+ default_config = {
+ "data_folder": os.path.join(get_base_dir(), "data"),
+ "templates_folder": os.path.join(get_base_dir(), "templates"),
+ "source_file": "大四班 幼儿学期发展报告.pptx",
+ "output_folder": "output",
+ "excel_file": "names.xlsx",
+ "image_folder": "images",
+ "fonts_dir": "fonts",
+ "signature_image": "signature.png",
+ "class_name": "K4D",
+ "teachers": ["康璐璐", "冯宇阳", "孙继艳"],
+ "class_type": 2,
+ "default_comment": "暂无评语",
+ "age_group": "大班上学期",
+ "ai": {
+ "api_key": "sk-ccb6a1445126f2e56ba50d7622ff350f",
+ "api_url": "https://apis.iflow.cn/v1/chat/completions",
+ "model": "deepseek-v3.2",
+ "prompt": "# Role \n你是一位拥有20年经验的资深幼儿园主班老师。你的文笔温暖、细腻、充满爱意,擅长发现每个孩子身上独特的闪光点。你的评语风格是“治愈系”的,能让家长读完后感到欣慰并对未来充满希望。\n\n# Goal\n请根据用户提供的【幼儿姓名】、【年龄段/班级】以及【日常表现关键词/评分数据】,撰写一份高质量的学期末成长评语。\n# Constraints & Rules\n1. **严格的格式排版 (Strict Formatting)**:\n- **换行**:正文中间不要随意换行,保持为一段完整的段落。\n2. **称呼处理**:\n- 自动识别用户输入的姓名,去掉姓氏。\n- 例如:“王小明” -> 第一行输出“小明宝贝:”。\n3. **分龄侧重 (根据 Age_Group 调整侧重点)**:\n- **小班 (3-4岁)**:侧重于适应集体生活、情绪稳定性、基本生活自理能力、愿意与老师互动。\n- **中班 (4-5岁)**:侧重于社交互动、分享与合作、动手能力、好奇心、规则意识。\n- **大班 (5-6岁)**:侧重于学习习惯、逻辑思维、领导力、任务意识、幼小衔接准备。\n4. **写作结构 (固定内容)**:\n- **开头**:固定文本必须包含:“{class_type}”\n- **正文**:结合【表现关键词】和【性别】,具体描述进步和优点。\n- **结尾**:委婉地提出期望(“如果你能...老师会更为你骄傲”),并送上祝福。\n5. **语气风格**:\n- 积极正面,多用肯定句。\n- 字数控制在 150-250 字之间。\n# Input Format\n- Name {{name}}\n- Age_Group {{class_name}}\n- Traits {{traits}}\n- Sex {{sex}}\n# Output Example\n(假设输入:Name=张图图, Age_Group=小班, Traits=适应能力强, 爱笑, 挑食,Sex=女)\n亲爱的图图宝贝:{class_type}\n你是一个爱笑的小天使,每天早上都能看到你甜甜的笑脸。从一开始的哭鼻子到现在能开心地参与游戏,你的适应能力让老师感到惊喜。不过,老师发现你在吃饭时偶尔会把不喜欢的青菜挑出来哦。如果你能和青菜宝宝做好朋友,把身体练得棒棒的,那就更完美啦!祝可爱的图图宝贝新年快乐,健康成长!\n",
+ },
+ }
+ cfg.update(default_config)
+
+
# ==========================================
# 1. 配置加载 (Config Loader)
# ==========================================
-def load_config(config_filename="config.toml"):
- config_path = get_resource_path(config_filename)
-
- if not os.path.exists(config_path):
- # 如果彻底找不到,返回一个最小化的默认值,防止程序奔溃
- return {"source_file": "", "ai": {"api_key": ""}, "teachers": []}
-
+def load_config():
try:
- with open(config_path, "rb") as f:
- data = toml_read.load(f)
+ config_data = app.storage.general
base_dir = get_base_dir()
-
- # 使用 .get() 安全获取,防止 KeyError: 'paths'
- paths = data.get("paths", {})
- class_info = data.get("class_info", {})
- defaults = data.get("defaults", {})
-
config = {
"root_path": base_dir,
"data_folder": os.path.join(os.path.join("data")),
# 扁平化映射
"source_file": get_resource_path(
- os.path.join("templates", paths.get("source_file", ""))
+ os.path.join("templates", config_data.get("source_file", ""))
),
"excel_file": get_resource_path(
- os.path.join("data", paths.get("excel_file", ""))
+ os.path.join("data", config_data.get("excel_file", "names"))
),
"image_folder": get_resource_path(
- os.path.join("data", paths.get("image_folder", ""))
+ os.path.join("data", config_data.get("image_folder", ""))
),
- "fonts_dir": get_resource_path(paths.get("fonts_dir", "fonts")),
+ "fonts_dir": get_resource_path(config_data.get("fonts_dir", "fonts")),
"output_folder": os.path.join(
- base_dir, paths.get("output_folder", "output")
+ base_dir, config_data.get("output_folder", "output")
),
"signature_image": get_resource_path(
- os.path.join("data", paths.get("signature_image", "signature.png"))
+ os.path.join("data", config_data.get("signature_image", "signature.png"))
),
- "class_name": class_info.get("class_name", "未命名班级"),
- "teachers": class_info.get("teachers", []),
- "class_type": class_info.get("class_type", 0),
- "default_comment": defaults.get("default_comment", "暂无评语"),
- "age_group": defaults.get("age_group", "大班上学期"),
- "ai": data.get(
+ "class_name": config_data.get("class_name", "未命名班级"),
+ "teachers": config_data.get("teachers", []),
+ "class_type": config_data.get("class_type", 0),
+ "default_comment": config_data.get("default_comment", "暂无评语"),
+ "age_group": config_data.get("age_group", "大班上学期"),
+ "ai": config_data.get(
"ai", {"api_key": "", "api_url": "", "model": "", "prompt": ""}
),
}
@@ -94,52 +113,3 @@ def load_config(config_filename="config.toml"):
except Exception as e:
print(f"解析配置文件失败: {e}")
return {}
-
-
-# ==========================================
-# 2. 配置保存 (Config Saver)
-# ==========================================
-def save_config(config_data, config_filename="config.toml"):
- if not toml_write:
- return False, "未安装 tomli-w 库,无法保存。请运行 pip install tomli-w"
-
- base_path = get_base_dir()
- save_path = os.path.join(base_path, config_filename)
-
- try:
- # 将扁平化的数据重新打包成嵌套结构,以适配 load_config 的读取逻辑
- new_data = {
- "paths": {
- "source_file": os.path.basename(config_data.get("source_file", "")),
- "output_folder": os.path.basename(
- config_data.get("output_folder", "output")
- ),
- "excel_file": os.path.basename(config_data.get("excel_file", "")),
- "image_folder": os.path.basename(config_data.get("image_folder", "")),
- "fonts_dir": os.path.basename(config_data.get("fonts_dir", "fonts")),
- "signature_image": get_resource_path(
- os.path.join(
- "data", config_data.get("signature_image", "signature.png")
- )
- ),
- },
- "class_info": {
- "class_name": config_data.get("class_name", ""),
- "teachers": config_data.get("teachers", []),
- "class_type": config_data.get("class_type", 0),
- },
- "defaults": {
- "default_comment": config_data.get("default_comment", ""),
- "age_group": config_data.get("age_group", ""),
- },
- "ai": config_data.get("ai", {}),
- }
-
- # 写入文件
- with open(save_path, "wb") as f:
- f.write(toml_write.dumps(new_data).encode("utf-8"))
-
- return True, f"成功保存到: {save_path}"
-
- except Exception as e:
- return False, f"写入失败: {str(e)}"
diff --git a/data/names.xlsx b/data/names.xlsx
index 2c900bc9c8c9765f2c30f3693a0bcf66f3ee2aac..35fe7f1e1bf39eb7d691ac729af241fd4181708f 100644
GIT binary patch
delta 1880
zcmV-e2dDV+U&%4B#RCd0F5L;d0RRBX1e4DLAAgixZ`&XghVLisKOpWGY^Q13$ad8>
z&DvFyrhVNL``AXcITp}l`}YNBO#}2|cO2g5eDEU3ul@`@*@4mmWkJ(fLJ7zUYa!c$
z{`$H3bU}$WT-Llt2?hNNnqHM3KjeEFP0~tjwp*zXj~|$(k6x{Q*5x25M^nCGKEb#3v^{*sa8+vM6^m4fRct8XErG
zoA0>42hn!M7Fis-t-0Z4u5eG(R9uhTd4H9z($o%Gx!r5GJ&88ejlV0Cob7DS>K}0v
z6RA(!#zf{5>zJ7P#9d6B`NSqB7C!MgCeD50J|>nv@emUiKJg_cE`8$h9mn2GW%fRf
zmy*4IDcNai;P#Ct21eg{V&L&Qo94<6?#`EI!Q6LVa%jINhR%CpXu2ncetTkQwLT|?
zE}x27=r22Y03&bVD_5=DCv^F?Ss|6)nGzN#)sIz|tC>PBsX%Nk8
z;GX627b;%>vw;bQ0SbDo%Rrt3008R+lMxFVe|1z%Zz4w!y+_J_K-{x<_Yg%9W)G2a
z+gtJjkWJP|1{@ELHa9R}1`l|!3lr@yI61qyf22zL6l2M-V&PQJSlee?ntB3WIy9=sOJJHNA^NV@^~FWa;fR6$gme
zA-q*dw}xq=>qL~_PD3_^2)kaPsi&Q`9$NIOPg7G^M0avp+%hKHQQL?!tzavO?ZhX)
zcc*@1v|~)Vz0;sNAhjlmK7EZuiIJzh0U2a>#7ss^yhjAh8F+R$GAXv4u!4*Te>NM^
zbO+B4hg@Z{$`R6(-1CdwFkw3UAKUseBy!NpBJOXW*QL1z9L7zLUxr0%HhTpyyy)UK
zorQYD0ghnf8$6fUxV$p&h}wl-lc*IiBQVHYvkQ>ZL~W6WhNT;Jt;nAg;38ryz_N+;6H4-UPV~n4cenUnrxK!A4j~cO+
znOd0&ZZp$*AYbC-S!(!N$eQ1<*ql2g-m|I5J6v4Bq`_%>IV7QJ&dFXzG#leelsUG5
zoL?j7*1SrJnx(gi{zNJ{YFw~{!515Se7uHMab>3YqKTb<+-z|}yE!7uf7B>~tZiI+
z^&Ro{dEJ^RL{nH=$HTMh6sRpM$Dc(vXXz4&7+9Kvry{;QxNH$Mg%)j8fi~R?2JzOS
zOrjEde!^E}8C?>ufLs8vkLJ^vM%4<(EFUbx!0N0tr|}o0B83--lq~ZOl&YoAEIq@-
z42z`6Rf?)68MP5?%`e!pe?)q9Zo<53Co@Qnqv3O3KQg$kp&n?SS23$TMIreKulc*DvzJ0ggdZZ-DN&OB}M
zgHLfX0<{mzjy27qU^~A=@_+ZCjkHeQ33z}5dZ)HWN%|o
za&K^RFJo_VWiEJaY@L$LYQr!PgztsEgVEiV<$#+C+kv*^)Igyr4ZR6zlZaYBNNSzD
zePt(c63D5?)y#f7yQrG&RGa*Q^U~-Vkt|0EXl{hmn;LyA=jjwBJ}@m1&{13)r&x%k+hEK1H`@R%^1Q?f
z0uwAS+yhfP644PU_=vPWt{nh^V`xEv4jz+?;IlV?Q~qYdpjatAC*7}r$zvWSOknGcJ2;4m1(T63Asl+F%Rrt3008R+000yK0000000000006du
zAqSJrE2oIRa4)lS?lp9J)bs+b01408s(}01*HH00000000000JecN6O)WD
SJpzgplglq61~V1_0000fcx%c4
delta 7861
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.4.13",
"langchain>=1.1.3",
"langchain-openai>=1.1.1",
+ "logger",
"loguru>=0.7.3",
"nicegui>=3.4.0",
"openpyxl>=3.1.5",
diff --git a/ui/views/config_page.py b/ui/views/config_page.py
index b73538f..3525d77 100644
--- a/ui/views/config_page.py
+++ b/ui/views/config_page.py
@@ -1,189 +1,98 @@
-from nicegui import ui
import os
-from utils.template_utils import get_template_files
-# 修改点 1:统一导入,避免与变量名 config 冲突
-from config.config import load_config, save_config
+from nicegui import ui, app
+
+from ui.views.templates.back_home import backHome
+from utils.template_utils import get_template_files
def create_config_page():
- # 修改点 2:将加载逻辑放入页面生成函数内,确保每次刷新页面获取最新值
- conf_data = load_config("config.toml")
- template_options = get_template_files()
- current_filename = os.path.basename(conf_data.get("source_file", ""))
+ # 获取当前持久化存储中的数据
+ cfg = app.storage.general
+ template_options = get_template_files()
+ current_filename = os.path.basename(cfg.get("source_file", ""))
if current_filename and current_filename not in template_options:
template_options.append(current_filename)
ui.add_head_html('')
-
- # 样式修正:添加全屏且不滚动条的 CSS
- ui.add_head_html(
- """
+ ui.add_head_html("""
- """
- )
+ """)
with ui.header().classes("app-header items-center justify-between shadow-md"):
- # 左侧:图标和标题
- with ui.row().classes("items-center gap-2"):
- ui.image("/assets/icon.ico").classes("w-8 h-8").props("fit=contain")
- ui.label("尚城幼儿园成长报告助手").classes("text-xl font-bold")
- # 右侧:署名 + 配置按钮
- with ui.row().classes("items-center gap-4"):
- ui.label("By 寒寒 | 这里的每一份评语都充满爱意").classes(
- "text-xs opacity-90"
- )
- ui.button(icon="home", on_click=lambda: ui.navigate.to("/")).props(
- "flat round color=white"
- )
+ backHome()
- # 修改点 3:使用 flex 布局撑满
with ui.card().classes("w-full max-w-5xl mx-auto shadow-lg main-card p-0"):
with ui.tabs().classes("w-full") as tabs:
tab_path = ui.tab("路径设置", icon="folder")
tab_class = ui.tab("班级与教师", icon="school")
tab_ai = ui.tab("AI 接口配置", icon="psychology")
- with ui.tab_panels(tabs, value=tab_path).classes(
- "w-full flex-grow bg-transparent"
- ):
- # --- 路径设置 ---
- with ui.tab_panel(tab_path).classes("w-full p-0"):
- with ui.column().classes("w-full p-4 gap-4"):
- source_file = (
- ui.select(
- options=template_options,
- label="PPT 模板",
- value=current_filename,
- )
- .props("outlined fill-input")
- .classes("w-full")
- )
- excel_file = (
- ui.input(
- "Excel 文件",
- value=os.path.basename(conf_data.get("excel_file", "")),
- )
- .props("outlined")
- .classes("w-full")
- )
- image_folder = (
- ui.input(
- "图片目录",
- value=os.path.basename(conf_data.get("image_folder", "")),
- )
- .props("outlined")
- .classes("w-full")
- )
- output_folder = (
- ui.input(
- "输出目录",
- value=os.path.basename(
- conf_data.get("output_folder", "output")
- ),
- )
- .props("outlined")
- .classes("w-full")
- )
+ with ui.tab_panels(tabs, value=tab_path).classes("w-full flex-grow bg-transparent"):
+ # --- 1. 路径设置 ---
+ with ui.tab_panel(tab_path).classes("w-full p-4 gap-4"):
+ # 注意:这里改用普通的 value= 参数,不使用 bind_value
+ source_file = ui.select(options=template_options, label="PPT 模板", value=cfg.get('source_file')).props(
+ "outlined").classes("w-full")
+ excel_file = ui.input("Excel 文件名", value=cfg.get('excel_file')).props("outlined").classes("w-full")
+ image_folder = ui.input("图片目录名", value=cfg.get('image_folder')).props("outlined").classes("w-full")
+ output_folder = ui.input("输出目录名", value=cfg.get('output_folder', 'output')).props(
+ "outlined").classes("w-full")
- # --- 班级信息 ---
- with ui.tab_panel(tab_class).classes("w-full p-0"):
- with ui.column().classes("w-full p-4 gap-4"):
- class_name = (
- ui.input("班级名称", value=conf_data.get("class_name", ""))
- .props("outlined")
- .classes("w-full")
- )
- age_group = (
- ui.select(
- options=[
- "小班上学期",
- "小班下学期",
- "中班上学期",
- "中班下学期",
- "大班上学期",
- "大班下学期",
- ],
- label="年龄段",
- value=conf_data.get("age_group", "中班上学期"),
- )
- .props("outlined")
- .classes("w-full")
- )
- teachers_text = (
- ui.textarea(
- "教师名单", value="\n".join(conf_data.get("teachers", []))
- )
- .props("outlined")
- .classes("w-full h-40")
- )
- class_type = (
- ui.select(
- options={0: "便宜班", 1: "昂贵班", 2: "昂贵的双木桥班"},
- label="班级类型",
- value=conf_data.get("class_type", 0),
- )
- .props("outlined")
- .classes("w-full")
- )
+ # --- 2. 班级信息 ---
+ with ui.tab_panel(tab_class).classes("w-full p-4 gap-4"):
+ class_name = ui.input("班级名称", value=cfg.get('class_name')).props("outlined").classes("w-full")
+ age_group = ui.select(
+ options=["小班上学期", "小班下学期", "中班上学期", "中班下学期", "大班上学期", "大班下学期"],
+ label="年龄段",
+ value=cfg.get('age_group')
+ ).props("outlined").classes("w-full")
- # --- AI 配置 ---
- with ui.tab_panel(tab_ai).classes("w-full p-0"):
- with ui.column().classes("w-full p-4 gap-4"):
- ai_key = (
- ui.input("API Key", value=conf_data["ai"].get("api_key", ""))
- .props("outlined password")
- .classes("w-full")
- )
- ai_url = (
- ui.input("API URL", value=conf_data["ai"].get("api_url", ""))
- .props("outlined")
- .classes("w-full")
- )
- ai_model = (
- ui.input("Model Name", value=conf_data["ai"].get("model", ""))
- .props("outlined")
- .classes("w-full")
- )
- ai_prompt = (
- ui.textarea(
- "System Prompt", value=conf_data["ai"].get("prompt", "")
- )
- .props("outlined")
- .classes("w-full h-full")
- )
- # 底部固定按钮
+ teachers_text = ui.textarea("教师名单(每行一个)", value="\n".join(cfg.get("teachers", []))).props(
+ "outlined").classes("w-full h-40")
+
+ class_type = ui.select(
+ options={0: "便宜班", 1: "昂贵班", 2: "昂贵的双木桥班"},
+ label="班级类型",
+ value=cfg.get('class_type', 0)
+ ).props("outlined").classes("w-full")
+
+ # --- 3. AI 配置 ---
+ with ui.tab_panel(tab_ai).classes("w-full p-4 gap-4"):
+ ai_data = cfg.get('ai', {}) # 获取子字典
+ ai_key = ui.input("API Key", value=ai_data.get("api_key")).props("outlined password").classes("w-full")
+ ai_url = ui.input("API URL", value=ai_data.get("api_url")).props("outlined").classes("w-full")
+ ai_model = ui.input("Model Name", value=ai_data.get("model")).props("outlined").classes("w-full")
+ ai_prompt = ui.textarea("System Prompt", value=ai_data.get("prompt")).props("outlined").classes(
+ "w-full h-64")
+
+ # --- 底部按钮:点击后统一更新到 Storage ---
with ui.row().classes("w-full p-4"):
-
- async def handle_save():
- new_data = {
+ def handle_manual_save():
+ # 统一更新到 app.storage.general
+ # NiceGUI 会在此时感知到字典变化并触发自动保存到 JSON 文件
+ cfg.update({
"source_file": source_file.value,
"excel_file": excel_file.value,
"image_folder": image_folder.value,
"output_folder": output_folder.value,
"class_name": class_name.value,
"age_group": age_group.value,
- "signature_image": conf_data.get("signature_image", ""),
- "teachers": [
- t.strip() for t in teachers_text.value.split("\n") if t.strip()
- ],
+ "teachers": [t.strip() for t in teachers_text.value.split('\n') if t.strip()],
"class_type": class_type.value,
"ai": {
"api_key": ai_key.value,
"api_url": ai_url.value,
"model": ai_model.value,
"prompt": ai_prompt.value,
- },
- }
- # 修改点 4:直接调用导入的 save_config 函数名
- success, message = save_config(new_data)
- ui.notify("配置已保存重启生效", type="positive")
+ }
+ })
+ ui.notify("配置已成功更新至系统存储", type="positive", icon="save")
- ui.button("保存配置", on_click=handle_save).classes("w-full py-4").props(
- "outline color=primary"
- )
+ ui.button("保存配置", icon="save", on_click=handle_manual_save).classes("w-full py-4 shadow-md").props(
+ "color=primary")
diff --git a/ui/views/convert_pdf_page.py b/ui/views/convert_pdf_page.py
index ee4fb24..e69b8d1 100644
--- a/ui/views/convert_pdf_page.py
+++ b/ui/views/convert_pdf_page.py
@@ -5,6 +5,7 @@ import pythoncom
from loguru import logger
from nicegui import ui
+from ui.views.templates.back_home import backHome
from utils.file_utils import open_folder
progress_bar = None
@@ -85,18 +86,7 @@ def create_convert_pdf_page(folder: str = ""):
)
with ui.header().classes("app-header items-center justify-between shadow-md"):
- # 左侧:图标和标题
- with ui.row().classes("items-center gap-2"):
- ui.image("/assets/icon.ico").classes("w-8 h-8").props("fit=contain")
- ui.label("尚城幼儿园成长报告助手").classes("text-xl font-bold")
- # 右侧:署名 + 配置按钮
- with ui.row().classes("items-center gap-4"):
- ui.label("By 寒寒 | 这里的每一份评语都充满爱意").classes(
- "text-xs opacity-90"
- )
- ui.button(icon="home", on_click=lambda: ui.navigate.to("/")).props(
- "flat round color=white"
- )
+ backHome()
with ui.card().classes("w-full"):
with ui.row().classes("w-full justify-between"):
diff --git a/ui/views/data_page.py b/ui/views/data_page.py
index dd80053..dae91c3 100644
--- a/ui/views/data_page.py
+++ b/ui/views/data_page.py
@@ -1,28 +1,17 @@
-import pandas as pd
-from nicegui import ui
-from config.config import load_config
import os
+import pandas as pd
+from nicegui import ui
-def create_header():
- with ui.header().classes("app-header items-center justify-between shadow-md"):
- with ui.row().classes("items-center gap-2"):
- ui.image("/assets/icon.ico").classes("w-8 h-8").props("fit=contain")
- ui.label("尚城幼儿园成长报告助手").classes("text-xl font-bold")
-
- with ui.row().classes("items-center gap-4"):
- ui.label("By 寒寒 | 这里的每一份评语都充满爱意").classes(
- "text-xs opacity-90"
- )
- ui.button(icon="home", on_click=lambda: ui.navigate.to("/")).props(
- "flat round color=white"
- ).tooltip("回到首页")
+from config.config import load_config
+from ui.views.templates.back_home import backHome
def create_data_page():
ui.add_head_html('')
- create_header()
+ with ui.header().classes("app-header items-center justify-between shadow-md"):
+ backHome()
with ui.column().classes("w-full max-w-6xl mx-auto p-4 gap-4 thin-scrollbar"):
with ui.card().classes("func-card"):
@@ -37,7 +26,7 @@ def create_data_page():
def load_data():
- conf_data = load_config("config.toml")
+ conf_data = load_config()
excel_path = conf_data.get("excel_file")
with (
@@ -47,7 +36,7 @@ def load_data():
),
):
with ui.row().classes(
- "w-full bg-gradient-to-r from-blue-50 to-indigo-50 items-center justify-between"
+ "w-full bg-gradient-to-r from-blue-50 to-indigo-50 items-center justify-between"
):
with ui.column().classes("gap-0"):
ui.label("幼儿成长档案").classes(
@@ -61,7 +50,7 @@ def load_data():
content_container = ui.column().classes("w-full")
with ui.row().classes(
- "w-full p-5 bg-slate-50/80 backdrop-blur-md border-t justify-end gap-3"
+ "w-full p-5 bg-slate-50/80 backdrop-blur-md border-t justify-end gap-3"
):
ui.button("确认", on_click=detail_dialog.close).props(
"unelevated color=blue-6"
@@ -75,7 +64,7 @@ def load_data():
with content_container:
with ui.row().classes(
- "w-full items-center p-4 bg-blue-600 rounded-2xl shadow-md shadow-blue-100"
+ "w-full items-center p-4 bg-blue-600 rounded-2xl shadow-md shadow-blue-100"
):
ui.avatar("person", color="white", text_color="blue-6").props(
"size=48px"
@@ -105,7 +94,7 @@ def load_data():
df = df.fillna("-")
with ui.row().classes(
- "bg-blue-50 w-full p-3 px-6 items-center rounded-t-xl border-b border-blue-100"
+ "bg-blue-50 w-full p-3 px-6 items-center rounded-t-xl border-b border-blue-100"
):
ui.icon("fact_check", color="primary", size="20px")
ui.label(f"班级:{conf_data.get('class_name', '未设定')}").classes(
diff --git a/ui/views/home_page.py b/ui/views/home_page.py
index 595e1f6..37ef6d8 100644
--- a/ui/views/home_page.py
+++ b/ui/views/home_page.py
@@ -12,7 +12,7 @@ from utils.generate_utils import (
generate_zodiac,
)
-config = load_config("config.toml")
+config = load_config()
def create_header():
diff --git a/ui/views/signature_page.py b/ui/views/signature_page.py
index 6d9c81e..31beb5b 100644
--- a/ui/views/signature_page.py
+++ b/ui/views/signature_page.py
@@ -1,10 +1,12 @@
-from nicegui import ui
import os
+import traceback
+
+from loguru import logger
+from nicegui import ui
+from pptx import Presentation
+
from config.config import load_config
from utils.file_utils import open_folder
-from loguru import logger
-import traceback
-from pptx import Presentation
def create_signature_page(folder: str = ""):
@@ -142,7 +144,7 @@ def sign_file(folder, file_name: str):
"""
try:
# 1. 加载配置文件
- config = load_config("config.toml")
+ config = load_config()
except Exception as e:
logger.error(f"配置文件获取失败: {str(e)}")
# 打印详细报错位置,方便调试
diff --git a/ui/views/templates/back_home.py b/ui/views/templates/back_home.py
new file mode 100644
index 0000000..4e7f65d
--- /dev/null
+++ b/ui/views/templates/back_home.py
@@ -0,0 +1,16 @@
+from nicegui import ui
+
+
+def backHome():
+ """返回首页"""
+ with ui.row().classes("items-center gap-2"):
+ ui.image("/assets/icon.ico").classes("w-8 h-8").props("fit=contain")
+ ui.label("尚城幼儿园成长报告助手").classes("text-xl font-bold")
+
+ with ui.row().classes("items-center gap-4"):
+ ui.label("By 寒寒 | 这里的每一份评语都充满爱意").classes(
+ "text-xs opacity-90"
+ )
+ ui.button(icon="home", on_click=lambda: ui.navigate.to("/")).props(
+ "flat round color=white"
+ ).tooltip("回到首页")
diff --git a/utils/font_utils.py b/utils/font_utils.py
index 2f647da..f86b5ed 100644
--- a/utils/font_utils.py
+++ b/utils/font_utils.py
@@ -4,14 +4,13 @@
import os
import platform
import shutil
-import time
from pathlib import Path
from loguru import logger
from config.config import load_config
-config = load_config("config.toml")
+config = load_config()
def get_system_fonts():
diff --git a/utils/generate_utils.py b/utils/generate_utils.py
index 26f6fe5..a82558b 100644
--- a/utils/generate_utils.py
+++ b/utils/generate_utils.py
@@ -1,20 +1,17 @@
import os
import threading
import time
-import pythoncom
-
-import pandas as pd
-from loguru import logger
-from pptx import Presentation
-from rich.console import Console
import traceback
import comtypes.client
+import pandas as pd
+import pythoncom
+from loguru import logger
+from pptx import Presentation
+
from config.config import load_config
from utils.agent_utils import generate_comment
from utils.file_utils import check_file_exists, get_output_pptx_files
-from utils.image_utils import find_image_path
-from utils.zodiac_utils import calculate_zodiac
from utils.growt_utils import (
replace_one_page,
replace_two_page,
@@ -22,6 +19,8 @@ from utils.growt_utils import (
replace_four_page,
replace_five_page,
)
+from utils.image_utils import find_image_path
+from utils.zodiac_utils import calculate_zodiac
# ==========================================
@@ -35,7 +34,7 @@ def generate_template(stop_event: threading.Event = None, progress_callback=None
"""
# 1. 加载配置文件
try:
- config = load_config("config.toml")
+ config = load_config()
except Exception as e:
logger.error(f"配置文件获取失败: {str(e)}")
# 打印详细报错位置,方便调试
@@ -89,7 +88,7 @@ def generate_comment_all(stop_event: threading.Event = None, progress_callback=N
"""
# 1. 加载配置文件
try:
- config = load_config("config.toml")
+ config = load_config()
except Exception as e:
logger.error(f"配置文件获取失败: {str(e)}")
# 打印详细报错位置,方便调试
@@ -184,7 +183,7 @@ def generate_report(stop_event: threading.Event = None, progress_callback=None):
:params progress_callback 进度回调函数
""" # 1. 加载配置文件
try:
- config = load_config("config.toml")
+ config = load_config()
except Exception as e:
logger.error(f"配置文件获取失败: {str(e)}")
# 打印详细报错位置,方便调试
@@ -316,6 +315,7 @@ def generate_report(stop_event: threading.Event = None, progress_callback=None):
class_image_path = find_image_path(
config["image_folder"], config["class_name"]
)
+ print(config["image_folder"], config["class_name"])
# 添加检查班级图片是否存在,若不存在则跳过
if check_file_exists(class_image_path):
@@ -378,7 +378,7 @@ def generate_convert_pdf(stop_event: threading.Event = None, progress_callback=N
"""
# 1. 加载配置文件
try:
- config = load_config("config.toml")
+ config = load_config()
except Exception as e:
logger.error(f"配置文件获取失败: {str(e)}")
# 打印详细报错位置,方便调试
@@ -470,7 +470,7 @@ def generate_zodiac(stop_event: threading.Event = None, progress_callback=None):
"""
# 1. 加载配置文件
try:
- config = load_config("config.toml")
+ config = load_config()
except Exception as e:
logger.error(f"配置文件获取失败: {str(e)}")
# 打印详细报错位置,方便调试
@@ -559,7 +559,7 @@ def generate_signature(progress_callback=None) -> str:
"""
# 1. 加载配置文件
try:
- config = load_config("config.toml")
+ config = load_config()
except Exception as e:
logger.error(f"配置文件获取失败: {str(e)}")
# 打印详细报错位置,方便调试
diff --git a/utils/growt_utils.py b/utils/growt_utils.py
index 59b6e5f..632b288 100644
--- a/utils/growt_utils.py
+++ b/utils/growt_utils.py
@@ -1,5 +1,5 @@
-from rich.console import Console
from loguru import logger
+from rich.console import Console
from config.config import load_config
from utils.pptx_utils import replace_text_in_slide, replace_picture
@@ -10,7 +10,7 @@ console = Console()
# ==========================================
# 1. 配置区域 (Configuration)
# ==========================================
-config = load_config("config.toml")
+config = load_config()
def replace_one_page(prs, name, class_name):
diff --git a/uv.lock b/uv.lock
index 11b41c5..32a6703 100644
--- a/uv.lock
+++ b/uv.lock
@@ -1,5 +1,5 @@
version = 1
-revision = 2
+revision = 3
requires-python = ">=3.13"
[[package]]
@@ -413,6 +413,7 @@ dependencies = [
{ name = "comtypes" },
{ name = "langchain" },
{ name = "langchain-openai" },
+ { name = "logger" },
{ name = "loguru" },
{ name = "nicegui" },
{ name = "openpyxl" },
@@ -434,6 +435,7 @@ requires-dist = [
{ name = "comtypes", specifier = ">=1.4.13" },
{ name = "langchain", specifier = ">=1.1.3" },
{ name = "langchain-openai", specifier = ">=1.1.1" },
+ { name = "logger" },
{ name = "loguru", specifier = ">=0.7.3" },
{ name = "nicegui", specifier = ">=3.4.0" },
{ name = "openpyxl", specifier = ">=3.1.5" },
@@ -742,6 +744,12 @@ wheels = [
{ url = "https://mirrors.aliyun.com/pypi/packages/63/54/4577ef9424debea2fa08af338489d593276520d2e2f8950575d292be612c/langsmith-0.4.59-py3-none-any.whl", hash = "sha256:97c26399286441a7b7b06b912e2801420fbbf3a049787e609d49dc975ab10bc5" },
]
+[[package]]
+name = "logger"
+version = "1.4"
+source = { registry = "https://mirrors.aliyun.com/pypi/simple/" }
+sdist = { url = "https://mirrors.aliyun.com/pypi/packages/73/2f/b0d28eaa1e2c1cf64129f8da3fe701888d152677fec708cd0f13e8309e1e/logger-1.4.tar.gz", hash = "sha256:4ecac57133c6376fa215f0fe6b4dc4d60e4d1ad8be005cab4e8a702df682f8b3" }
+
[[package]]
name = "loguru"
version = "0.7.3"