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
34 changes: 32 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,43 @@ jobs:
dotnet-version: '10.0.x'
- name: Publish WPF app
run: dotnet publish platforms/windows/WriteBench/WriteBench.csproj -c Release -r win-x64 --self-contained true -o publish
- name: Validate domain and real OCR
- name: Validate domain, credentials, native WPF interactions and real OCR
shell: pwsh
run: |
Copy-Item Documentation/TestImages/ocr-sample-1.png publish/ocr-fixture.png
$result = Start-Process "$pwd/publish/WriteBench.exe" -ArgumentList '--self-test' -Wait -PassThru
$result = Start-Process "$pwd/publish/WriteBench.exe" -ArgumentList '--self-test' -PassThru
if (-not $result.WaitForExit(180000)) { Stop-Process -Id $result.Id -Force; throw 'Self-test timed out' }
if ($result.ExitCode -ne 0) { Get-Content publish/self-test-error.txt; exit 1 }
Get-Content publish/self-test-passed.txt
- name: Render actual WPF screens
shell: pwsh
run: |
$result = Start-Process "$pwd/publish/WriteBench.exe" -ArgumentList '--render-preview' -PassThru
if (-not $result.WaitForExit(60000)) { Stop-Process -Id $result.Id -Force; throw 'Preview timed out' }
if ($result.ExitCode -ne 0) { Get-Content publish/preview-error.txt; exit 1 }
- name: Upload Windows verification evidence
if: always()
uses: actions/upload-artifact@v4
with:
name: windows-verification
path: |
publish/*test*.txt
publish/*error*.txt
publish/windows-preview-*.png
- name: Package self-contained Windows x64 app
shell: pwsh
run: |
Remove-Item publish/ocr-fixture.png, publish/*test*.txt, publish/windows-preview-*.png -ErrorAction SilentlyContinue
Copy-Item platforms/windows/README.md publish/README.md
Copy-Item THIRD_PARTY_NOTICES.md publish/THIRD_PARTY_NOTICES.md
Compress-Archive -Path publish/* -DestinationPath WriteBench-Windows-x64.zip
(Get-FileHash WriteBench-Windows-x64.zip -Algorithm SHA256).Hash.ToLower() + ' WriteBench-Windows-x64.zip' | Set-Content WriteBench-Windows-x64.zip.sha256
- uses: actions/upload-artifact@v4
with:
name: WriteBench-Windows-x64
path: |
WriteBench-Windows-x64.zip
WriteBench-Windows-x64.zip.sha256
android:
runs-on: ubuntu-latest
steps:
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,5 @@ Documentation/codex-live-check.json
# Per-machine IDE settings
.idea/
*.iml

.codex-build/
5 changes: 3 additions & 2 deletions Documentation/Providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ History groups records at display time by task, normalized exact prompt and ques

## Direct key entry

A user pastes a DeepSeek key and clicks **使用此 Key**. It works immediately from process memory, without accessing an old Keychain item. **在这台 Mac 上记住 Key** is optional and defaults off. No key is stored in UserDefaults, SwiftData, source, logs or a release package. Submission reads memory only. Explicit persistence and opt-in startup restoration run off the UI thread using a new data-protection Keychain item, with authentication UI disallowed. Legacy development items are never queried. An inaccessible item leaves the user able to enter the API key again. A failed optional save leaves the in-memory key usable and reports that it could not be remembered.
A user pastes a DeepSeek key and clicks **使用此 Key**. **在这台 Mac 上记住 Key** defaults on. The key is stored in `~/Library/Application Support/WriteBench/Credentials/deepseek.key`, a plain-text file restricted to the current macOS user (directory 0700, file 0600). This avoids changing ad-hoc signing identities preventing restoration. The UI explicitly describes storage as unencrypted. No key is stored in UserDefaults, SwiftData, logs, source, backups, or release packages. Startup and submission restore the local file in the background. Previously opted-in v2 Keychain keys are imported when accessible, with authentication UI disallowed; failure is shown in Settings. A failed save keeps the session key available and explains the failure.

Missing keys block typed and OCR-confirmed submissions before any provider receives the essay. Drafts remain saved. Turning off remembering and saving a key removes the persisted copy; clearing a key removes both the local file and the old opted-in Keychain item where accessible.

Missing keys block both typed and OCR-confirmed submissions before any provider receives the essay. The draft is saved; the user can continue answering or open Settings. Clearing a key or quitting clears the session key. Remembered keys follow macOS Keychain storage rules.

## Official Codex subprocess

Expand Down
7 changes: 7 additions & 0 deletions Documentation/Validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,10 @@ GPT-6 Astra/MAX completed a sample through the actual macOS Swift subprocess ser
The ruled surface is a screen practice area, not an exact official answer-card reproduction. It never truncates a longer stored essay. The user can leave macOS full screen through system controls, but this never exposes another answer editor: the app remains in its minimal answering layout until hand-in or save-and-leave.

No API key was supplied; paid DeepSeek grading and live Keychain storage remain untested. HTTP behavior is covered with injected fixtures. Vision's automated fixture uses printed text and does not establish handwriting accuracy. Local ad-hoc signing is used; App Store signing and notarization are not included.

## 1.9.0 translation teaching and hand-in timing

- 79 hosted macOS tests pass, including old report decoding, teaching persistence/export, source and vocabulary anchoring, synthesis score preservation, and pausing before missing-key checks with explicit resume.
- Rendered the native SwiftUI teaching card with synthetic source/answer data and inspected its expanded vocabulary, techniques, translations, assembly notes and student advice. No user's report was modified for this check.
- Recovered the original `com.chen.WriteBench.deepseek` Keychain item into the private local credential file without printing the credential. A read-only DeepSeek models request returned HTTP 401; the recovered credential therefore still needs replacement with a valid key. No paid grading call was made.
- New teaching fields apply to newly generated English I/II reports; old saved reports remain readable and are not retroactively regenerated.
10 changes: 7 additions & 3 deletions Documentation/macOS-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ Vision recognition runs on a worker task, on the Mac. Automatic language correct

Open **Settings**. Each of the three roles has its own provider selector; defaults are DeepSeek / DeepSeek / ChatGPT via Codex.

For DeepSeek, paste your own API key and click **使用此 Key**. It works immediately, with no Mac password required. By default it remains only in process memory until quitting. **在这台 Mac 上记住 Key** optionally saves it to Keychain. The current default model is `deepseek-v4-pro`, with `thinking: enabled`, `reasoning_effort: max`, and a 128K output ceiling that includes thinking. The app validates the entire JSON response before saving a grade.
For DeepSeek, paste your own API key and click **使用此 Key**. It works immediately, with no Mac password required. **在这台 Mac 上记住 Key** defaults on and saves a private local file (directory 0700, file 0600, not encrypted), automatically restored after relaunch or updates. Turn it off for session-only use; saving in that mode removes the remembered copy. The current default model is `deepseek-v4-pro`, with `thinking: enabled`, `reasoning_effort: max`, and a 128K output ceiling that includes thinking. The app validates the entire JSON response before saving a grade.

For **ChatGPT · via Codex**, install the official CLI and run `codex login` once in Terminal if needed. **Check Connection** checks the executable and official ChatGPT login status; an existing login is reused without another browser flow. Default model: `gpt-6-astra`; reasoning: **MAX**. WriteBench never reads Codex authentication files, cookies or tokens. Codex manages authentication and allowance. Each judge uses a fresh ephemeral CLI request with a JSON Schema.

Expand Down Expand Up @@ -68,11 +68,11 @@ WriteBench/
History/ Saved reviews and search
Statistics/ Swift Charts and normalized statistics
Mistakes/ Recurring categories with examples
Settings/ Judge providers, Codex status, model and optional Keychain UI
Settings/ Judge providers, Codex status, model and local credential UI
Persistence/ EssaySession, WritingDraft, SavedQuestion (SwiftData)
Services/
OCR/ Vision and native file import
DeepSeek/ URLSession, in-memory credentials, optional Keychain
DeepSeek/ URLSession, in-memory credentials, private local credential file
Codex/ Official CLI discovery, subprocess, JSON Schema
Grading/ Provider protocol, orchestration, validation, median
Rubrics/ Eight bundled, versioned Markdown resources
Expand Down Expand Up @@ -105,3 +105,7 @@ Build and copy the Release app into this folder:
```

`project.yml` is the optional XcodeGen source. Regenerate only after changing target/file structure: `xcodegen generate`. The original W app icon is generated by `scripts/make-icon.swift` using AppKit drawing. Editable vector source, PNG/ICNS exports and size previews are in [Design/Icon](Design/Icon/README.md).

English I/II translation reports now include **意群精讲**: source meaning groups, vocabulary (part of speech, common and contextual meanings), specific translation techniques, each group translation, an assembled reference translation, and advice on the student's rendering. The first sentence expands initially; other sentences can be opened separately. English I lessons stay within the numbered underlined segments. English II retains whole-passage scoring, without a fixed two marks per sentence. Report copying and backups preserve teaching fields; older reports remain readable without them.

Hand In and Quick Review immediately pause the timer, including while credentials are restored or a submission is blocked. **继续作答** resumes it without counting the paused interval. Stored-key availability is distinct from server authentication; Settings shows whether the key is merely loaded or has passed its connection test.
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,14 @@ WriteBench 把练习收敛为一条清晰的路径:选题、作答、评阅、
| 平台 | 安装方式 | 当前状态 |
| :--- | :--- | :--- |
| **macOS 15+** | 下载 ZIP / DMG,将 WriteBench.app 放入 Applications | 原生 SwiftUI,Apple silicon + Intel |
| **Windows 11 x64** | [下载便携 ZIP](https://github.com/Functionhx/WriteBench/releases/download/v1.3.0/WriteBench-0.1.0-Windows-x64.zip),完整解压后运行 WriteBench.exe | 原生 WPF / .NET 10 · 0.1 预览版 |
| **Windows 11 x64** | [下载便携 ZIP](https://github.com/Functionhx/WriteBench/releases/download/v1.9.1/WriteBench-1.9.1-Windows-x64.zip),完整解压后运行 WriteBench.exe | 原生 WPF / .NET 10 · 1.9.1 |
| **Android 13+** | [下载签名 APK](https://github.com/Functionhx/WriteBench/releases/download/v1.3.0/WriteBench-0.1.0-Android.apk),在手机安装 | 原生 Android Views · 0.1 预览版 |

macOS 当前是本地 ad-hoc 签名版本,尚未经过 Apple Developer ID 公证;Windows 预览版尚未进行 Authenticode 签名。Windows OCR 需要 Microsoft Visual C++ x64 运行库,详见[平台说明](platforms/windows/README.md)。公开仓库与安装包不包含 API Key、Codex 登录信息或用户作文。

## 开始使用

1. 打开 **Settings**,填写自己的 DeepSeek API Key,点击 **使用此 Key**。默认仅在本次运行内存中保留;macOS 可勾选 **在这台 Mac 上记住 Key**。提交时只读已启用的内存 Key,记住与恢复在后台完成。
1. 打开 **Settings**,填写自己的 DeepSeek API Key,点击 **使用此 Key**。macOS 默认勾选 **在这台 Mac 上记住 Key**,重启和更新后自动读取。保存为仅当前用户可读写的本机文件(非加密、不随作文备份导出);取消勾选并保存则仅本次运行使用。
2. 使用 Codex 评审时,先安装[官方 Codex CLI](https://learn.chatgpt.com/docs/codex-cli),在终端运行 `codex login`。已登录的用户直接点击 **Check Connection**,无需再走浏览器。
3. 选择考试与题型。macOS 点击题目卡片的 **导入文字**,粘贴完整题目,或选择 `.txt` / `.md` 文件(UTF-8 / UTF-16),编辑确认后自动保存;也可以导入题目图片。
4. 点击 **开始答题**,在沉浸式界面完成作文,然后 **交卷**。
Expand Down Expand Up @@ -137,7 +137,7 @@ platforms/android/ Android Studio 项目与手机界面
scripts/ 构建、图标生成与显式联调脚本
```

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

<details>
<summary><strong>更多文档</strong></summary>
Expand All @@ -156,3 +156,5 @@ macOS 自动化测试覆盖 72 个案例,Android 有 5 个领域测试与 2
---

<p align="center">WriteBench · 一次练习,一份原稿,一次认真重写。</p>

考研翻译报告支持“意群精讲”:词汇、结构与翻译要点、分组译文及完整译文组合;英一只讲解作答划线句,英二按全文句子展开。点击交卷即暂停计时,提交受阻时可点击继续作答恢复。
27 changes: 27 additions & 0 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,30 @@
# 1.9.1 · Windows 核心功能补齐与评分兼容

- Windows 便携 x64 版升级至 1.9.1,Key 使用当前 Windows 账户加密保存,支持忘记 Key 与连接检查。
- Windows 交卷立即暂停计时,缺 Key、取消或失败后继续保持暂停;手动继续作答恢复。
- Windows 答题区支持当前行/选中行独立对齐、四空格 Tab 与撤销;DeepSeek 分评审流式进度、一次格式重试、考研翻译意群精讲。
- Windows 发布流程增加真实 Windows runner 上启动 EXE、自测原生编辑器和 OCR、渲染三个 WPF 页面及 ZIP 打包。界面覆盖及实机交互限制见 Windows 使用说明。

- 接受评分数字字符串(例如 "18.5"),无错误时允许错误列表为空或 null。
- 完整返回的评分格式无效时,自动重新请求一次完整评分;仍须通过所有评分范围与必填内容校验。预览评语不会作为总分。
- 重试仍失败时,提示具体缺失或类型错误的字段,便于定位。两次请求的 token 用量合并记录。
- 新增三项回归测试;82 项测试通过。

# 1.9.0 · 翻译意群精讲与交卷暂停

- 英一、英二翻译报告新增意群精讲:重点词汇的词性、常见义与本句义,具体翻译要点,意群译文,完整译文及组合说明,对照学生译文的建议。
- 精讲来自原题,不使用未划线上下文充当英一作答句;短句可少于 3 个意群。评分保持原有规则,英二不套用英一每句 2 分。
- 精讲包含在复制报告与备份中,旧报告继续可读,新字段缺失时不影响原报告。
- 点击交卷或快速单评立即暂停计时;缺 Key 或其他提交阻塞时保持暂停,继续作答才恢复。
- 自动恢复原始旧版 Keychain 项目,修复已配置 Key 却提示缺失的问题。

# 1.8.1 · 本机记住 Key 与答题卡排版

- DeepSeek Key 默认保存到当前用户私有的本机文件,重启和更新后自动读取;设置明确注明文件未加密。取消记住并保存可改为仅本次运行使用。
- 答题卡增加当前行/选中行左对齐、居中、右对齐;缩进作为空格写入草稿,支持撤销。
- 修复行尾连续空格的光标位置,Tab 插入四个空格。
- 保留上轮未完成的评阅 JSON 容错修改。

# 1.8.0 · 三评汇总成一份报告

- 三位评审独立评完后,由一位“主考官”把三份意见汇总成一份报告:一个结论,一份优点、不足和下一稿建议,一份逐句修改,一篇参考改写;英一翻译每句一个分数、一条评语和一组采分点。重复的意见合并,有分歧的地方由主考官核对原文后取舍。
Expand Down
Loading
Loading