fix:优化配置存储
This commit is contained in:
33
.idea/workspace.xml
generated
33
.idea/workspace.xml
generated
@@ -4,11 +4,23 @@
|
|||||||
<option name="autoReloadType" value="SELECTIVE" />
|
<option name="autoReloadType" value="SELECTIVE" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ChangeListManager">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="41690157-d51b-4dae-98de-6b96990d681a" name="更改" comment="fix:优化一些命名规范">
|
<list default="true" id="41690157-d51b-4dae-98de-6b96990d681a" name="更改" comment="fix:优化PDF转换逻辑">
|
||||||
<change afterPath="$PROJECT_DIR$/ui/views/convert_pdf_page.py" afterDir="false" />
|
<change afterPath="$PROJECT_DIR$/ui/views/templates/back_home.py" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/config.toml" beforeDir="false" afterPath="$PROJECT_DIR$/config.toml" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/config/config.py" beforeDir="false" afterPath="$PROJECT_DIR$/config/config.py" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/data/names.xlsx" beforeDir="false" afterPath="$PROJECT_DIR$/data/names.xlsx" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/main.py" beforeDir="false" afterPath="$PROJECT_DIR$/main.py" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/main.py" beforeDir="false" afterPath="$PROJECT_DIR$/main.py" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/pyproject.toml" beforeDir="false" afterPath="$PROJECT_DIR$/pyproject.toml" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/ui/views/config_page.py" beforeDir="false" afterPath="$PROJECT_DIR$/ui/views/config_page.py" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/ui/views/convert_pdf_page.py" beforeDir="false" afterPath="$PROJECT_DIR$/ui/views/convert_pdf_page.py" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/ui/views/data_page.py" beforeDir="false" afterPath="$PROJECT_DIR$/ui/views/data_page.py" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/ui/views/home_page.py" beforeDir="false" afterPath="$PROJECT_DIR$/ui/views/home_page.py" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/ui/views/home_page.py" beforeDir="false" afterPath="$PROJECT_DIR$/ui/views/home_page.py" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/ui/views/signature_page.py" beforeDir="false" afterPath="$PROJECT_DIR$/ui/views/signature_page.py" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/utils/font_utils.py" beforeDir="false" afterPath="$PROJECT_DIR$/utils/font_utils.py" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/utils/generate_utils.py" beforeDir="false" afterPath="$PROJECT_DIR$/utils/generate_utils.py" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/utils/growt_utils.py" beforeDir="false" afterPath="$PROJECT_DIR$/utils/growt_utils.py" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/uv.lock" beforeDir="false" afterPath="$PROJECT_DIR$/uv.lock" afterDir="false" />
|
||||||
</list>
|
</list>
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
@@ -137,7 +149,7 @@
|
|||||||
<workItem from="1768312972093" duration="486000" />
|
<workItem from="1768312972093" duration="486000" />
|
||||||
<workItem from="1768314152581" duration="7000" />
|
<workItem from="1768314152581" duration="7000" />
|
||||||
<workItem from="1769696481591" duration="57000" />
|
<workItem from="1769696481591" duration="57000" />
|
||||||
<workItem from="1769696548056" duration="2806000" />
|
<workItem from="1769696548056" duration="6079000" />
|
||||||
</task>
|
</task>
|
||||||
<task id="LOCAL-00001" summary="fix:修复一些BUG">
|
<task id="LOCAL-00001" summary="fix:修复一些BUG">
|
||||||
<option name="closed" value="true" />
|
<option name="closed" value="true" />
|
||||||
@@ -171,7 +183,15 @@
|
|||||||
<option name="project" value="LOCAL" />
|
<option name="project" value="LOCAL" />
|
||||||
<updated>1766330259490</updated>
|
<updated>1766330259490</updated>
|
||||||
</task>
|
</task>
|
||||||
<option name="localTasksCounter" value="5" />
|
<task id="LOCAL-00005" summary="fix:优化PDF转换逻辑">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1769699406868</created>
|
||||||
|
<option name="number" value="00005" />
|
||||||
|
<option name="presentableId" value="LOCAL-00005" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1769699406868</updated>
|
||||||
|
</task>
|
||||||
|
<option name="localTasksCounter" value="6" />
|
||||||
<servers />
|
<servers />
|
||||||
</component>
|
</component>
|
||||||
<component name="TypeScriptGeneratedFilesManager">
|
<component name="TypeScriptGeneratedFilesManager">
|
||||||
@@ -191,13 +211,14 @@
|
|||||||
<component name="VcsManagerConfiguration">
|
<component name="VcsManagerConfiguration">
|
||||||
<MESSAGE value="fix:修复一些BUG" />
|
<MESSAGE value="fix:修复一些BUG" />
|
||||||
<MESSAGE value="fix:优化一些命名规范" />
|
<MESSAGE value="fix:优化一些命名规范" />
|
||||||
<option name="LAST_COMMIT_MESSAGE" value="fix:优化一些命名规范" />
|
<MESSAGE value="fix:优化PDF转换逻辑" />
|
||||||
|
<option name="LAST_COMMIT_MESSAGE" value="fix:优化PDF转换逻辑" />
|
||||||
<option name="OPTIMIZE_IMPORTS_BEFORE_PROJECT_COMMIT" value="true" />
|
<option name="OPTIMIZE_IMPORTS_BEFORE_PROJECT_COMMIT" value="true" />
|
||||||
<option name="REFORMAT_BEFORE_PROJECT_COMMIT" value="true" />
|
<option name="REFORMAT_BEFORE_PROJECT_COMMIT" value="true" />
|
||||||
<option name="REARRANGE_BEFORE_PROJECT_COMMIT" value="true" />
|
<option name="REARRANGE_BEFORE_PROJECT_COMMIT" value="true" />
|
||||||
</component>
|
</component>
|
||||||
<component name="com.intellij.coverage.CoverageDataManagerImpl">
|
<component name="com.intellij.coverage.CoverageDataManagerImpl">
|
||||||
<SUITE FILE_PATH="coverage/growth_report$main.coverage" NAME="main 覆盖结果" MODIFIED="1769699312262" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
<SUITE FILE_PATH="coverage/growth_report$main.coverage" NAME="main 覆盖结果" MODIFIED="1769703398756" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
||||||
<SUITE FILE_PATH="coverage/growth_report$main_nicegui.coverage" NAME="main_nicegui 覆盖结果" MODIFIED="1766329725535" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
<SUITE FILE_PATH="coverage/growth_report$main_nicegui.coverage" NAME="main_nicegui 覆盖结果" MODIFIED="1766329725535" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
25
.nicegui/storage-general.json
Normal file
25
.nicegui/storage-general.json
Normal file
@@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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=适应能力强, 爱笑, 挑食)
|
|
||||||
图图宝贝,你好!
|
|
||||||
你是一个爱笑的小天使,每天早上都能看到你甜甜的笑脸,老师的心都要被你融化了。这个学期你进步真大呀,从一开始的哭鼻子到现在能开心地参与游戏,你的适应能力让老师感到惊喜。在集体活动中,你总是那么投入。
|
|
||||||
不过,老师发现你在吃饭时偶尔会把不喜欢的青菜挑出来哦。如果你能和青菜宝宝做好朋友,把身体练得棒棒的,那就更完美啦!
|
|
||||||
祝可爱的图图宝贝新年快乐,健康成长!
|
|
||||||
"""
|
|
||||||
26
config.toml
26
config.toml
@@ -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"
|
|
||||||
122
config/config.py
122
config/config.py
@@ -1,6 +1,9 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
from loguru import logger
|
||||||
|
from nicegui import app
|
||||||
|
|
||||||
# 1. 处理读取库
|
# 1. 处理读取库
|
||||||
try:
|
try:
|
||||||
import tomllib as toml_read # Python 3.11+
|
import tomllib as toml_read # Python 3.11+
|
||||||
@@ -39,53 +42,69 @@ def get_resource_path(relative_path):
|
|||||||
return external_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)
|
# 1. 配置加载 (Config Loader)
|
||||||
# ==========================================
|
# ==========================================
|
||||||
def load_config(config_filename="config.toml"):
|
def load_config():
|
||||||
config_path = get_resource_path(config_filename)
|
|
||||||
|
|
||||||
if not os.path.exists(config_path):
|
|
||||||
# 如果彻底找不到,返回一个最小化的默认值,防止程序奔溃
|
|
||||||
return {"source_file": "", "ai": {"api_key": ""}, "teachers": []}
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(config_path, "rb") as f:
|
config_data = app.storage.general
|
||||||
data = toml_read.load(f)
|
|
||||||
|
|
||||||
base_dir = get_base_dir()
|
base_dir = get_base_dir()
|
||||||
|
|
||||||
# 使用 .get() 安全获取,防止 KeyError: 'paths'
|
|
||||||
paths = data.get("paths", {})
|
|
||||||
class_info = data.get("class_info", {})
|
|
||||||
defaults = data.get("defaults", {})
|
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
"root_path": base_dir,
|
"root_path": base_dir,
|
||||||
"data_folder": os.path.join(os.path.join("data")),
|
"data_folder": os.path.join(os.path.join("data")),
|
||||||
# 扁平化映射
|
# 扁平化映射
|
||||||
"source_file": get_resource_path(
|
"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(
|
"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(
|
"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(
|
"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(
|
"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", "未命名班级"),
|
"class_name": config_data.get("class_name", "未命名班级"),
|
||||||
"teachers": class_info.get("teachers", []),
|
"teachers": config_data.get("teachers", []),
|
||||||
"class_type": class_info.get("class_type", 0),
|
"class_type": config_data.get("class_type", 0),
|
||||||
"default_comment": defaults.get("default_comment", "暂无评语"),
|
"default_comment": config_data.get("default_comment", "暂无评语"),
|
||||||
"age_group": defaults.get("age_group", "大班上学期"),
|
"age_group": config_data.get("age_group", "大班上学期"),
|
||||||
"ai": data.get(
|
"ai": config_data.get(
|
||||||
"ai", {"api_key": "", "api_url": "", "model": "", "prompt": ""}
|
"ai", {"api_key": "", "api_url": "", "model": "", "prompt": ""}
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
@@ -94,52 +113,3 @@ def load_config(config_filename="config.toml"):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"解析配置文件失败: {e}")
|
print(f"解析配置文件失败: {e}")
|
||||||
return {}
|
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)}"
|
|
||||||
|
|||||||
BIN
data/names.xlsx
BIN
data/names.xlsx
Binary file not shown.
14
main.py
14
main.py
@@ -6,7 +6,7 @@ from loguru import logger
|
|||||||
from nicegui import ui, app, run, native
|
from nicegui import ui, app, run, native
|
||||||
from screeninfo import get_monitors
|
from screeninfo import get_monitors
|
||||||
|
|
||||||
from config.config import load_config
|
from config.config import init_storage
|
||||||
# 导入我们的模块
|
# 导入我们的模块
|
||||||
from ui.core.logger import setup_logger
|
from ui.core.logger import setup_logger
|
||||||
from ui.views.config_page import create_config_page
|
from ui.views.config_page import create_config_page
|
||||||
@@ -18,9 +18,6 @@ from utils.font_utils import install_fonts_from_directory
|
|||||||
|
|
||||||
sys.stdout.reconfigure(encoding="utf-8")
|
sys.stdout.reconfigure(encoding="utf-8")
|
||||||
sys.stderr.reconfigure(encoding="utf-8")
|
sys.stderr.reconfigure(encoding="utf-8")
|
||||||
# 1. 初始化配置
|
|
||||||
config = load_config("config.toml")
|
|
||||||
|
|
||||||
setup_logger()
|
setup_logger()
|
||||||
|
|
||||||
|
|
||||||
@@ -105,12 +102,17 @@ def signature_page(folder: str = ""):
|
|||||||
def convert_pdf_page(folder: str = ""):
|
def convert_pdf_page(folder: str = ""):
|
||||||
create_convert_pdf_page(folder)
|
create_convert_pdf_page(folder)
|
||||||
|
|
||||||
|
|
||||||
# 4. 启动时钩子
|
# 4. 启动时钩子
|
||||||
async def startup_check():
|
async def startup_check():
|
||||||
try:
|
try:
|
||||||
logger.info("系统启动: 初始化资源...")
|
logger.info("系统启动: 初始化资源...")
|
||||||
await run.io_bound(install_fonts_from_directory, config["fonts_dir"])
|
# 初始化存储
|
||||||
os.makedirs(config["output_folder"], exist_ok=True)
|
init_storage()
|
||||||
|
cfg = app.storage.general
|
||||||
|
await run.io_bound(install_fonts_from_directory, cfg["fonts_dir"])
|
||||||
|
os.makedirs(cfg["output_folder"], exist_ok=True)
|
||||||
|
|
||||||
logger.success("资源初始化完成")
|
logger.success("资源初始化完成")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"初始化失败: {e}")
|
logger.error(f"初始化失败: {e}")
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ dependencies = [
|
|||||||
"comtypes>=1.4.13",
|
"comtypes>=1.4.13",
|
||||||
"langchain>=1.1.3",
|
"langchain>=1.1.3",
|
||||||
"langchain-openai>=1.1.1",
|
"langchain-openai>=1.1.1",
|
||||||
|
"logger",
|
||||||
"loguru>=0.7.3",
|
"loguru>=0.7.3",
|
||||||
"nicegui>=3.4.0",
|
"nicegui>=3.4.0",
|
||||||
"openpyxl>=3.1.5",
|
"openpyxl>=3.1.5",
|
||||||
|
|||||||
@@ -1,189 +1,98 @@
|
|||||||
from nicegui import ui
|
|
||||||
import os
|
import os
|
||||||
from utils.template_utils import get_template_files
|
|
||||||
|
|
||||||
# 修改点 1:统一导入,避免与变量名 config 冲突
|
from nicegui import ui, app
|
||||||
from config.config import load_config, save_config
|
|
||||||
|
from ui.views.templates.back_home import backHome
|
||||||
|
from utils.template_utils import get_template_files
|
||||||
|
|
||||||
|
|
||||||
def create_config_page():
|
def create_config_page():
|
||||||
# 修改点 2:将加载逻辑放入页面生成函数内,确保每次刷新页面获取最新值
|
# 获取当前持久化存储中的数据
|
||||||
conf_data = load_config("config.toml")
|
cfg = app.storage.general
|
||||||
template_options = get_template_files()
|
|
||||||
current_filename = os.path.basename(conf_data.get("source_file", ""))
|
|
||||||
|
|
||||||
|
template_options = get_template_files()
|
||||||
|
current_filename = os.path.basename(cfg.get("source_file", ""))
|
||||||
if current_filename and current_filename not in template_options:
|
if current_filename and current_filename not in template_options:
|
||||||
template_options.append(current_filename)
|
template_options.append(current_filename)
|
||||||
|
|
||||||
ui.add_head_html('<link href="/assets/style.css" rel="stylesheet" />')
|
ui.add_head_html('<link href="/assets/style.css" rel="stylesheet" />')
|
||||||
|
ui.add_head_html("""
|
||||||
# 样式修正:添加全屏且不滚动条的 CSS
|
|
||||||
ui.add_head_html(
|
|
||||||
"""
|
|
||||||
<style>
|
<style>
|
||||||
body { overflow: hidden; }
|
body { overflow: hidden; }
|
||||||
.main-card { height: calc(100vh - 100px); display: flex; flex-direction: column; }
|
.main-card { height: calc(100vh - 100px); display: flex; flex-direction: column; }
|
||||||
.q-tab-panels { flex-grow: 1; overflow-y: auto !important; }
|
.q-tab-panels { flex-grow: 1; overflow-y: auto !important; }
|
||||||
</style>
|
</style>
|
||||||
"""
|
""")
|
||||||
)
|
|
||||||
|
|
||||||
with ui.header().classes("app-header items-center justify-between shadow-md"):
|
with ui.header().classes("app-header items-center justify-between shadow-md"):
|
||||||
# 左侧:图标和标题
|
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"
|
|
||||||
)
|
|
||||||
|
|
||||||
# 修改点 3:使用 flex 布局撑满
|
|
||||||
with ui.card().classes("w-full max-w-5xl mx-auto shadow-lg main-card p-0"):
|
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:
|
with ui.tabs().classes("w-full") as tabs:
|
||||||
tab_path = ui.tab("路径设置", icon="folder")
|
tab_path = ui.tab("路径设置", icon="folder")
|
||||||
tab_class = ui.tab("班级与教师", icon="school")
|
tab_class = ui.tab("班级与教师", icon="school")
|
||||||
tab_ai = ui.tab("AI 接口配置", icon="psychology")
|
tab_ai = ui.tab("AI 接口配置", icon="psychology")
|
||||||
|
|
||||||
with ui.tab_panels(tabs, value=tab_path).classes(
|
with ui.tab_panels(tabs, value=tab_path).classes("w-full flex-grow bg-transparent"):
|
||||||
"w-full flex-grow bg-transparent"
|
# --- 1. 路径设置 ---
|
||||||
):
|
with ui.tab_panel(tab_path).classes("w-full p-4 gap-4"):
|
||||||
# --- 路径设置 ---
|
# 注意:这里改用普通的 value= 参数,不使用 bind_value
|
||||||
with ui.tab_panel(tab_path).classes("w-full p-0"):
|
source_file = ui.select(options=template_options, label="PPT 模板", value=cfg.get('source_file')).props(
|
||||||
with ui.column().classes("w-full p-4 gap-4"):
|
"outlined").classes("w-full")
|
||||||
source_file = (
|
excel_file = ui.input("Excel 文件名", value=cfg.get('excel_file')).props("outlined").classes("w-full")
|
||||||
ui.select(
|
image_folder = ui.input("图片目录名", value=cfg.get('image_folder')).props("outlined").classes("w-full")
|
||||||
options=template_options,
|
output_folder = ui.input("输出目录名", value=cfg.get('output_folder', 'output')).props(
|
||||||
label="PPT 模板",
|
"outlined").classes("w-full")
|
||||||
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")
|
|
||||||
)
|
|
||||||
|
|
||||||
# --- 班级信息 ---
|
# --- 2. 班级信息 ---
|
||||||
with ui.tab_panel(tab_class).classes("w-full p-0"):
|
with ui.tab_panel(tab_class).classes("w-full p-4 gap-4"):
|
||||||
with ui.column().classes("w-full p-4 gap-4"):
|
class_name = ui.input("班级名称", value=cfg.get('class_name')).props("outlined").classes("w-full")
|
||||||
class_name = (
|
age_group = ui.select(
|
||||||
ui.input("班级名称", value=conf_data.get("class_name", ""))
|
options=["小班上学期", "小班下学期", "中班上学期", "中班下学期", "大班上学期", "大班下学期"],
|
||||||
.props("outlined")
|
|
||||||
.classes("w-full")
|
|
||||||
)
|
|
||||||
age_group = (
|
|
||||||
ui.select(
|
|
||||||
options=[
|
|
||||||
"小班上学期",
|
|
||||||
"小班下学期",
|
|
||||||
"中班上学期",
|
|
||||||
"中班下学期",
|
|
||||||
"大班上学期",
|
|
||||||
"大班下学期",
|
|
||||||
],
|
|
||||||
label="年龄段",
|
label="年龄段",
|
||||||
value=conf_data.get("age_group", "中班上学期"),
|
value=cfg.get('age_group')
|
||||||
)
|
).props("outlined").classes("w-full")
|
||||||
.props("outlined")
|
|
||||||
.classes("w-full")
|
teachers_text = ui.textarea("教师名单(每行一个)", value="\n".join(cfg.get("teachers", []))).props(
|
||||||
)
|
"outlined").classes("w-full h-40")
|
||||||
teachers_text = (
|
|
||||||
ui.textarea(
|
class_type = ui.select(
|
||||||
"教师名单", value="\n".join(conf_data.get("teachers", []))
|
|
||||||
)
|
|
||||||
.props("outlined")
|
|
||||||
.classes("w-full h-40")
|
|
||||||
)
|
|
||||||
class_type = (
|
|
||||||
ui.select(
|
|
||||||
options={0: "便宜班", 1: "昂贵班", 2: "昂贵的双木桥班"},
|
options={0: "便宜班", 1: "昂贵班", 2: "昂贵的双木桥班"},
|
||||||
label="班级类型",
|
label="班级类型",
|
||||||
value=conf_data.get("class_type", 0),
|
value=cfg.get('class_type', 0)
|
||||||
)
|
).props("outlined").classes("w-full")
|
||||||
.props("outlined")
|
|
||||||
.classes("w-full")
|
|
||||||
)
|
|
||||||
|
|
||||||
# --- AI 配置 ---
|
# --- 3. AI 配置 ---
|
||||||
with ui.tab_panel(tab_ai).classes("w-full p-0"):
|
with ui.tab_panel(tab_ai).classes("w-full p-4 gap-4"):
|
||||||
with ui.column().classes("w-full p-4 gap-4"):
|
ai_data = cfg.get('ai', {}) # 获取子字典
|
||||||
ai_key = (
|
ai_key = ui.input("API Key", value=ai_data.get("api_key")).props("outlined password").classes("w-full")
|
||||||
ui.input("API Key", value=conf_data["ai"].get("api_key", ""))
|
ai_url = ui.input("API URL", value=ai_data.get("api_url")).props("outlined").classes("w-full")
|
||||||
.props("outlined password")
|
ai_model = ui.input("Model Name", value=ai_data.get("model")).props("outlined").classes("w-full")
|
||||||
.classes("w-full")
|
ai_prompt = ui.textarea("System Prompt", value=ai_data.get("prompt")).props("outlined").classes(
|
||||||
)
|
"w-full h-64")
|
||||||
ai_url = (
|
|
||||||
ui.input("API URL", value=conf_data["ai"].get("api_url", ""))
|
# --- 底部按钮:点击后统一更新到 Storage ---
|
||||||
.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")
|
|
||||||
)
|
|
||||||
# 底部固定按钮
|
|
||||||
with ui.row().classes("w-full p-4"):
|
with ui.row().classes("w-full p-4"):
|
||||||
|
def handle_manual_save():
|
||||||
async def handle_save():
|
# 统一更新到 app.storage.general
|
||||||
new_data = {
|
# NiceGUI 会在此时感知到字典变化并触发自动保存到 JSON 文件
|
||||||
|
cfg.update({
|
||||||
"source_file": source_file.value,
|
"source_file": source_file.value,
|
||||||
"excel_file": excel_file.value,
|
"excel_file": excel_file.value,
|
||||||
"image_folder": image_folder.value,
|
"image_folder": image_folder.value,
|
||||||
"output_folder": output_folder.value,
|
"output_folder": output_folder.value,
|
||||||
"class_name": class_name.value,
|
"class_name": class_name.value,
|
||||||
"age_group": age_group.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,
|
"class_type": class_type.value,
|
||||||
"ai": {
|
"ai": {
|
||||||
"api_key": ai_key.value,
|
"api_key": ai_key.value,
|
||||||
"api_url": ai_url.value,
|
"api_url": ai_url.value,
|
||||||
"model": ai_model.value,
|
"model": ai_model.value,
|
||||||
"prompt": ai_prompt.value,
|
"prompt": ai_prompt.value,
|
||||||
},
|
|
||||||
}
|
}
|
||||||
# 修改点 4:直接调用导入的 save_config 函数名
|
})
|
||||||
success, message = save_config(new_data)
|
ui.notify("配置已成功更新至系统存储", type="positive", icon="save")
|
||||||
ui.notify("配置已保存重启生效", type="positive")
|
|
||||||
|
|
||||||
ui.button("保存配置", on_click=handle_save).classes("w-full py-4").props(
|
ui.button("保存配置", icon="save", on_click=handle_manual_save).classes("w-full py-4 shadow-md").props(
|
||||||
"outline color=primary"
|
"color=primary")
|
||||||
)
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import pythoncom
|
|||||||
from loguru import logger
|
from loguru import logger
|
||||||
from nicegui import ui
|
from nicegui import ui
|
||||||
|
|
||||||
|
from ui.views.templates.back_home import backHome
|
||||||
from utils.file_utils import open_folder
|
from utils.file_utils import open_folder
|
||||||
|
|
||||||
progress_bar = None
|
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.header().classes("app-header items-center justify-between shadow-md"):
|
||||||
# 左侧:图标和标题
|
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"
|
|
||||||
)
|
|
||||||
|
|
||||||
with ui.card().classes("w-full"):
|
with ui.card().classes("w-full"):
|
||||||
with ui.row().classes("w-full justify-between"):
|
with ui.row().classes("w-full justify-between"):
|
||||||
|
|||||||
@@ -1,28 +1,17 @@
|
|||||||
import pandas as pd
|
|
||||||
from nicegui import ui
|
|
||||||
from config.config import load_config
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
from nicegui import ui
|
||||||
|
|
||||||
def create_header():
|
from config.config import load_config
|
||||||
with ui.header().classes("app-header items-center justify-between shadow-md"):
|
from ui.views.templates.back_home import 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("回到首页")
|
|
||||||
|
|
||||||
|
|
||||||
def create_data_page():
|
def create_data_page():
|
||||||
ui.add_head_html('<link href="/assets/style.css" rel="stylesheet" />')
|
ui.add_head_html('<link href="/assets/style.css" rel="stylesheet" />')
|
||||||
|
|
||||||
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.column().classes("w-full max-w-6xl mx-auto p-4 gap-4 thin-scrollbar"):
|
||||||
with ui.card().classes("func-card"):
|
with ui.card().classes("func-card"):
|
||||||
@@ -37,7 +26,7 @@ def create_data_page():
|
|||||||
|
|
||||||
|
|
||||||
def load_data():
|
def load_data():
|
||||||
conf_data = load_config("config.toml")
|
conf_data = load_config()
|
||||||
excel_path = conf_data.get("excel_file")
|
excel_path = conf_data.get("excel_file")
|
||||||
|
|
||||||
with (
|
with (
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ from utils.generate_utils import (
|
|||||||
generate_zodiac,
|
generate_zodiac,
|
||||||
)
|
)
|
||||||
|
|
||||||
config = load_config("config.toml")
|
config = load_config()
|
||||||
|
|
||||||
|
|
||||||
def create_header():
|
def create_header():
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
from nicegui import ui
|
|
||||||
import os
|
import os
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from loguru import logger
|
||||||
|
from nicegui import ui
|
||||||
|
from pptx import Presentation
|
||||||
|
|
||||||
from config.config import load_config
|
from config.config import load_config
|
||||||
from utils.file_utils import open_folder
|
from utils.file_utils import open_folder
|
||||||
from loguru import logger
|
|
||||||
import traceback
|
|
||||||
from pptx import Presentation
|
|
||||||
|
|
||||||
|
|
||||||
def create_signature_page(folder: str = ""):
|
def create_signature_page(folder: str = ""):
|
||||||
@@ -142,7 +144,7 @@ def sign_file(folder, file_name: str):
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# 1. 加载配置文件
|
# 1. 加载配置文件
|
||||||
config = load_config("config.toml")
|
config = load_config()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"配置文件获取失败: {str(e)}")
|
logger.error(f"配置文件获取失败: {str(e)}")
|
||||||
# 打印详细报错位置,方便调试
|
# 打印详细报错位置,方便调试
|
||||||
|
|||||||
16
ui/views/templates/back_home.py
Normal file
16
ui/views/templates/back_home.py
Normal file
@@ -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("回到首页")
|
||||||
@@ -4,14 +4,13 @@
|
|||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
import shutil
|
import shutil
|
||||||
import time
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
||||||
from config.config import load_config
|
from config.config import load_config
|
||||||
|
|
||||||
config = load_config("config.toml")
|
config = load_config()
|
||||||
|
|
||||||
|
|
||||||
def get_system_fonts():
|
def get_system_fonts():
|
||||||
|
|||||||
@@ -1,20 +1,17 @@
|
|||||||
import os
|
import os
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
import pythoncom
|
|
||||||
|
|
||||||
import pandas as pd
|
|
||||||
from loguru import logger
|
|
||||||
from pptx import Presentation
|
|
||||||
from rich.console import Console
|
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
import comtypes.client
|
import comtypes.client
|
||||||
|
import pandas as pd
|
||||||
|
import pythoncom
|
||||||
|
from loguru import logger
|
||||||
|
from pptx import Presentation
|
||||||
|
|
||||||
from config.config import load_config
|
from config.config import load_config
|
||||||
from utils.agent_utils import generate_comment
|
from utils.agent_utils import generate_comment
|
||||||
from utils.file_utils import check_file_exists, get_output_pptx_files
|
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 (
|
from utils.growt_utils import (
|
||||||
replace_one_page,
|
replace_one_page,
|
||||||
replace_two_page,
|
replace_two_page,
|
||||||
@@ -22,6 +19,8 @@ from utils.growt_utils import (
|
|||||||
replace_four_page,
|
replace_four_page,
|
||||||
replace_five_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. 加载配置文件
|
# 1. 加载配置文件
|
||||||
try:
|
try:
|
||||||
config = load_config("config.toml")
|
config = load_config()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"配置文件获取失败: {str(e)}")
|
logger.error(f"配置文件获取失败: {str(e)}")
|
||||||
# 打印详细报错位置,方便调试
|
# 打印详细报错位置,方便调试
|
||||||
@@ -89,7 +88,7 @@ def generate_comment_all(stop_event: threading.Event = None, progress_callback=N
|
|||||||
"""
|
"""
|
||||||
# 1. 加载配置文件
|
# 1. 加载配置文件
|
||||||
try:
|
try:
|
||||||
config = load_config("config.toml")
|
config = load_config()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"配置文件获取失败: {str(e)}")
|
logger.error(f"配置文件获取失败: {str(e)}")
|
||||||
# 打印详细报错位置,方便调试
|
# 打印详细报错位置,方便调试
|
||||||
@@ -184,7 +183,7 @@ def generate_report(stop_event: threading.Event = None, progress_callback=None):
|
|||||||
:params progress_callback 进度回调函数
|
:params progress_callback 进度回调函数
|
||||||
""" # 1. 加载配置文件
|
""" # 1. 加载配置文件
|
||||||
try:
|
try:
|
||||||
config = load_config("config.toml")
|
config = load_config()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"配置文件获取失败: {str(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(
|
class_image_path = find_image_path(
|
||||||
config["image_folder"], config["class_name"]
|
config["image_folder"], config["class_name"]
|
||||||
)
|
)
|
||||||
|
print(config["image_folder"], config["class_name"])
|
||||||
|
|
||||||
# 添加检查班级图片是否存在,若不存在则跳过
|
# 添加检查班级图片是否存在,若不存在则跳过
|
||||||
if check_file_exists(class_image_path):
|
if check_file_exists(class_image_path):
|
||||||
@@ -378,7 +378,7 @@ def generate_convert_pdf(stop_event: threading.Event = None, progress_callback=N
|
|||||||
"""
|
"""
|
||||||
# 1. 加载配置文件
|
# 1. 加载配置文件
|
||||||
try:
|
try:
|
||||||
config = load_config("config.toml")
|
config = load_config()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"配置文件获取失败: {str(e)}")
|
logger.error(f"配置文件获取失败: {str(e)}")
|
||||||
# 打印详细报错位置,方便调试
|
# 打印详细报错位置,方便调试
|
||||||
@@ -470,7 +470,7 @@ def generate_zodiac(stop_event: threading.Event = None, progress_callback=None):
|
|||||||
"""
|
"""
|
||||||
# 1. 加载配置文件
|
# 1. 加载配置文件
|
||||||
try:
|
try:
|
||||||
config = load_config("config.toml")
|
config = load_config()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"配置文件获取失败: {str(e)}")
|
logger.error(f"配置文件获取失败: {str(e)}")
|
||||||
# 打印详细报错位置,方便调试
|
# 打印详细报错位置,方便调试
|
||||||
@@ -559,7 +559,7 @@ def generate_signature(progress_callback=None) -> str:
|
|||||||
"""
|
"""
|
||||||
# 1. 加载配置文件
|
# 1. 加载配置文件
|
||||||
try:
|
try:
|
||||||
config = load_config("config.toml")
|
config = load_config()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"配置文件获取失败: {str(e)}")
|
logger.error(f"配置文件获取失败: {str(e)}")
|
||||||
# 打印详细报错位置,方便调试
|
# 打印详细报错位置,方便调试
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from rich.console import Console
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
from rich.console import Console
|
||||||
|
|
||||||
from config.config import load_config
|
from config.config import load_config
|
||||||
from utils.pptx_utils import replace_text_in_slide, replace_picture
|
from utils.pptx_utils import replace_text_in_slide, replace_picture
|
||||||
@@ -10,7 +10,7 @@ console = Console()
|
|||||||
# ==========================================
|
# ==========================================
|
||||||
# 1. 配置区域 (Configuration)
|
# 1. 配置区域 (Configuration)
|
||||||
# ==========================================
|
# ==========================================
|
||||||
config = load_config("config.toml")
|
config = load_config()
|
||||||
|
|
||||||
|
|
||||||
def replace_one_page(prs, name, class_name):
|
def replace_one_page(prs, name, class_name):
|
||||||
|
|||||||
10
uv.lock
generated
10
uv.lock
generated
@@ -1,5 +1,5 @@
|
|||||||
version = 1
|
version = 1
|
||||||
revision = 2
|
revision = 3
|
||||||
requires-python = ">=3.13"
|
requires-python = ">=3.13"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -413,6 +413,7 @@ dependencies = [
|
|||||||
{ name = "comtypes" },
|
{ name = "comtypes" },
|
||||||
{ name = "langchain" },
|
{ name = "langchain" },
|
||||||
{ name = "langchain-openai" },
|
{ name = "langchain-openai" },
|
||||||
|
{ name = "logger" },
|
||||||
{ name = "loguru" },
|
{ name = "loguru" },
|
||||||
{ name = "nicegui" },
|
{ name = "nicegui" },
|
||||||
{ name = "openpyxl" },
|
{ name = "openpyxl" },
|
||||||
@@ -434,6 +435,7 @@ requires-dist = [
|
|||||||
{ name = "comtypes", specifier = ">=1.4.13" },
|
{ name = "comtypes", specifier = ">=1.4.13" },
|
||||||
{ name = "langchain", specifier = ">=1.1.3" },
|
{ name = "langchain", specifier = ">=1.1.3" },
|
||||||
{ name = "langchain-openai", specifier = ">=1.1.1" },
|
{ name = "langchain-openai", specifier = ">=1.1.1" },
|
||||||
|
{ name = "logger" },
|
||||||
{ name = "loguru", specifier = ">=0.7.3" },
|
{ name = "loguru", specifier = ">=0.7.3" },
|
||||||
{ name = "nicegui", specifier = ">=3.4.0" },
|
{ name = "nicegui", specifier = ">=3.4.0" },
|
||||||
{ name = "openpyxl", specifier = ">=3.1.5" },
|
{ 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" },
|
{ 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]]
|
[[package]]
|
||||||
name = "loguru"
|
name = "loguru"
|
||||||
version = "0.7.3"
|
version = "0.7.3"
|
||||||
|
|||||||
Reference in New Issue
Block a user