Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Documentation/Validation.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# 1.6.0 validation · 2026-10-02

- 63 Swift tests pass on Xcode 27.0. New coverage: English II small/large tasks (scales 10/15, 100/150 words, own rubrics loaded from the bundle), kaoyan task order, and the grader prompt carrying the 【配图说明】 transcription rule with the 0–15 scale.
- An isolated QA copy restored a 68-question local package (2010–2026 English I/II small and large essays, 34 figures) through the existing backup restore: 17 per task, figures stored and shown in the library badge, preparation page and immersive view; English II large essay countdown is 30 minutes. The six kaoyan task tabs fit the preparation column. No user database was used.
- Past-paper text and figures are not bundled in the app or repository; they were imported only into the user's local question bank.

# 1.5.0 validation · 2026-10-02

- 62 Swift tests pass on Xcode 27.0 / macOS 27.0.1. New coverage: correction anchoring across curly quotes, full-width punctuation, whitespace and case; invented spans dropped without failing the review; DeepSeek streamed usage (including cache hits and reasoning tokens) and Codex turn-completion usage; required `expressions` in the Codex schema; single-judge quick review routing, aggregation and persistence; legacy reports decoding as full reviews; one exam time-up signal per crossing; clearing an untouched submitted draft; word/character revision diffs; parent-then-earlier revision baselines; built-in bank uniqueness and practice index; review-card sync idempotence and the 1/2/4/8/16-day schedule; backup export/restore round trip with images, cards and drafts, and a second restore that adds nothing.
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ WriteBench 把练习收敛为一条清晰的路径:选题、作答、评阅、

| 考试 | 题型 | 评分尺度 |
| :--- | :--- | :--- |
| **考研英语一** | 小作文 · 大作文 · 英译汉 | 10 分 · 20 分 · 10 分 |
| **考研英语二** | 英译汉段落翻译 | 15 分 |
| **考研英语一** | 小作文 · 大作文(图画 / 图表)· 英译汉 | 10 分 · 20 分 · 10 分 |
| **考研英语二** | 小作文 · 大作文(图表)· 英译汉段落翻译 | 10 分 · 15 分 · 15 分 |
| **CET-6 六级** | 写作 · 汉译英 | 各 15 分练习尺度 |
| **IELTS 雅思 Academic** | Task 1 · Task 2 | 单项任务 Band 9 |

Expand Down Expand Up @@ -137,7 +137,7 @@ platforms/android/ Android Studio 项目与手机界面
scripts/ 构建、图标生成与显式联调脚本
```

macOS 自动化测试覆盖 62 个案例,Android 有 5 个领域测试与 2 个实际设备服务测试;Windows 通过评分、持久化、字段校验及实际 OCR 自检。GPT-6 Astra/MAX 已通过实际 Swift 子进程完成样例评卷;DeepSeek 已验证官方模型接口连接。后台、流式输出及版本路径已用隔离测试验证;本次未执行完整付费三评,需用户填入有效 Key 后使用。
macOS 自动化测试覆盖 63 个案例,Android 有 5 个领域测试与 2 个实际设备服务测试;Windows 通过评分、持久化、字段校验及实际 OCR 自检。GPT-6 Astra/MAX 已通过实际 Swift 子进程完成样例评卷;DeepSeek 已验证官方模型接口连接。后台、流式输出及版本路径已用隔离测试验证;本次未执行完整付费三评,需用户填入有效 Key 后使用。

<details>
<summary><strong>更多文档</strong></summary>
Expand Down
7 changes: 7 additions & 0 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# 1.6.0 · 考研英语二写作与图表题

- 新增 **英二小作文**(10 分,约 100 词)和 **英二大作文**(15 分,约 150 词,以图表为主),各有独立评分标准、考试限时(15 / 30 分钟)和原创练习题。考研题型标签改为“英一小作文 / 英一大作文 / 英二小作文 / 英二大作文 / 英一翻译 / 英二翻译”。
- 图画和图表题:题目可附带“【配图说明】”,即配图的文字版(漫画内容、图表标题与全部数值)。三位评审以它为准核对作文中的描述与数据,误读或编造数据按任务完成问题处理;评审不会臆测图中没有的信息。评审提示词升级到 1.3.1。
- 准备页的题目配图默认展开;题库列表标出“配图”。
- 已有记录、草稿和题库不受影响;原“小作文 / 大作文”即英一小作文 / 英一大作文。

# 1.5.0 · 练习闭环:限时、对比、复习

- **评分更稳**:评审引用原文时出现弯引号、全角标点、多余空格或大小写差异,会自动对齐到原文;个别找不到的修改建议只丢弃该条,不再让整份评阅失败。
Expand Down
16 changes: 12 additions & 4 deletions WriteBench.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
CB760C24CAE63253B9400E19 /* WriteBenchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 679F1D25813DBB4821B089EF /* WriteBenchTests.swift */; };
CCB636BAB11DE1B7DE6C1CA2 /* ImmersiveWritingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B600C2CBBB1B477ABB65C42 /* ImmersiveWritingView.swift */; };
CF9CA154E89BD40306ABC7D2 /* EssayFolderMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F9C06884EE52989CB4491F /* EssayFolderMetadata.swift */; };
D03424B806D55BF2BB9F11DC /* kaoyan_english2_large.md in Resources */ = {isa = PBXBuildFile; fileRef = 0506352B36FD805B5E9053D8 /* kaoyan_english2_large.md */; };
D3F29CFA674B891722D5B739 /* cet6_writing.md in Resources */ = {isa = PBXBuildFile; fileRef = 650B4D62F506EDDC71D6396A /* cet6_writing.md */; };
D4A1396AF9FFF2FF6C40C24D /* kaoyan_english2_translation.md in Resources */ = {isa = PBXBuildFile; fileRef = 56792E2C1501DBCE7B80739B /* kaoyan_english2_translation.md */; };
DB3DEEA68D82D9F8BECF108E /* ReviewOutline.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B9132C06548AC9B8B44070 /* ReviewOutline.swift */; };
Expand All @@ -63,6 +64,7 @@
DCC333A3FAF19BC2ECC79BA0 /* KeychainService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17802ADDF6589CB80F4B4F01 /* KeychainService.swift */; };
DEBA962949C4AADDFCB2C5D0 /* ielts_task1.md in Resources */ = {isa = PBXBuildFile; fileRef = 405A85F2A07E72B5AD277D96 /* ielts_task1.md */; };
DEF094BE47996A62C68AB985 /* CodexJudgeService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27300883AE5AE3DD46C36924 /* CodexJudgeService.swift */; };
E041B0138CF95145600B02C6 /* kaoyan_english2_small.md in Resources */ = {isa = PBXBuildFile; fileRef = 015B10F8076FB519F8FDAACD /* kaoyan_english2_small.md */; };
E0495C7F8744F99633CD2EF5 /* UsageCost.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6B358A2E1043646F5A65FA4 /* UsageCost.swift */; };
E32387900468FFCA09760D27 /* kaoyan_english1_large.md in Resources */ = {isa = PBXBuildFile; fileRef = ACA34C8DE60D85ABFA45116F /* kaoyan_english1_large.md */; };
E7928726F27B1B2EB5341AEB /* EssaySession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A8874F23C092B83269A6E56 /* EssaySession.swift */; };
Expand All @@ -84,8 +86,10 @@
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
015B10F8076FB519F8FDAACD /* kaoyan_english2_small.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = kaoyan_english2_small.md; sourceTree = "<group>"; };
018639A9F1452A7617A5A0A2 /* AppLifecycle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLifecycle.swift; sourceTree = "<group>"; };
029A81F1C48B2FAE8914576B /* ReviewTextExporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReviewTextExporter.swift; sourceTree = "<group>"; };
0506352B36FD805B5E9053D8 /* kaoyan_english2_large.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = kaoyan_english2_large.md; sourceTree = "<group>"; };
0A8874F23C092B83269A6E56 /* EssaySession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EssaySession.swift; sourceTree = "<group>"; };
0F9DB3748FBE72E213C6EB37 /* ReviewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReviewView.swift; sourceTree = "<group>"; };
100F5B726342F502CA8C4207 /* LocalProcessRunner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalProcessRunner.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -287,6 +291,8 @@
ACA34C8DE60D85ABFA45116F /* kaoyan_english1_large.md */,
6A7B637179FC6E271F31DBF4 /* kaoyan_english1_small.md */,
AD3CEB6EC11C595CA1EA79D6 /* kaoyan_english1_translation.md */,
0506352B36FD805B5E9053D8 /* kaoyan_english2_large.md */,
015B10F8076FB519F8FDAACD /* kaoyan_english2_small.md */,
56792E2C1501DBCE7B80739B /* kaoyan_english2_translation.md */,
);
path = Rubrics;
Expand Down Expand Up @@ -508,6 +514,8 @@
E32387900468FFCA09760D27 /* kaoyan_english1_large.md in Resources */,
96EB80336D8E7D70E3839817 /* kaoyan_english1_small.md in Resources */,
4B7B1CDF7FADBE73B96E26DA /* kaoyan_english1_translation.md in Resources */,
D03424B806D55BF2BB9F11DC /* kaoyan_english2_large.md in Resources */,
E041B0138CF95145600B02C6 /* kaoyan_english2_small.md in Resources */,
D4A1396AF9FFF2FF6C40C24D /* kaoyan_english2_translation.md in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -647,7 +655,7 @@
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 8;
CURRENT_PROJECT_VERSION = 9;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_NS_ASSERTIONS = NO;
Expand All @@ -662,7 +670,7 @@
GCC_WARN_UNUSED_VARIABLE = YES;
GENERATE_INFOPLIST_FILE = YES;
MACOSX_DEPLOYMENT_TARGET = 15.0;
MARKETING_VERSION = 1.5.0;
MARKETING_VERSION = 1.6.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
Expand Down Expand Up @@ -743,7 +751,7 @@
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 8;
CURRENT_PROJECT_VERSION = 9;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_STRICT_OBJC_MSGSEND = YES;
Expand All @@ -764,7 +772,7 @@
GCC_WARN_UNUSED_VARIABLE = YES;
GENERATE_INFOPLIST_FILE = YES;
MACOSX_DEPLOYMENT_TARGET = 15.0;
MARKETING_VERSION = 1.5.0;
MARKETING_VERSION = 1.6.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
Expand Down
4 changes: 4 additions & 0 deletions WriteBench/Components/ExamTaskBadge.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ struct ExamTaskBadge: View {
switch task {
case .kaoyanSmall: "英语一 · 小作文"
case .kaoyanLarge: "英语一 · 大作文"
case .kaoyan2Small: "英语二 · 小作文"
case .kaoyan2Large: "英语二 · 大作文"
case .kaoyanTranslation: "英语一 · 翻译"
case .kaoyan2Translation: "英语二 · 翻译"
case .cet6Writing: "写作"
case .ieltsTask1: "Task 1 · 小作文"
case .ieltsTask2: "Task 2 · 大作文"
Expand Down
1 change: 1 addition & 0 deletions WriteBench/Features/Writing/QuestionLibraryView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ struct QuestionLibraryView: View {
HStack(spacing: 8) {
Text(item.title).font(.system(size: 14, weight: .semibold))
if let year = item.year { Text(String(year)).font(.system(size: 11)).foregroundStyle(WB.blue) }
if item.image != nil { Label("配图", systemImage: "photo").font(.system(size: 11)).foregroundStyle(WB.secondary) }
if !item.label.isEmpty { Text(item.label).font(.system(size: 11)).foregroundStyle(WB.secondary).padding(.horizontal, 6).padding(.vertical, 2).background(WB.tint, in: Capsule()) }
Spacer()
if let latest = attempts.last {
Expand Down
3 changes: 2 additions & 1 deletion WriteBench/Features/Writing/WritingView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ struct WritingView: View {
@State private var ocrTask: Task<Void, Never>?
@State private var editingQuestion = false
@State private var importingText = false
@State private var showQuestionImage = true
private let clock = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
var body: some View {
Group {
Expand Down Expand Up @@ -109,7 +110,7 @@ struct WritingView: View {
Text(store.question).font(.system(size: 16)).lineSpacing(7).textSelection(.enabled).frame(maxWidth: .infinity, alignment: .leading)
}
if let data = store.questionImage, let image = NSImage(data: data) {
DisclosureGroup("题目原图") { Image(nsImage: image).resizable().scaledToFit().frame(maxHeight: 230).padding(.top, 8) }.font(.system(size: 12)).foregroundStyle(WB.secondary)
DisclosureGroup("题目配图", isExpanded: $showQuestionImage) { Image(nsImage: image).resizable().scaledToFit().frame(maxHeight: 320).padding(.top, 8) }.font(.system(size: 12)).foregroundStyle(WB.secondary)
}
HStack {
Text(store.task.fullTitle).font(.system(size: 11)).foregroundStyle(WB.secondary)
Expand Down
Loading
Loading