4.9 KiB
AI Usage CNY Cost Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Make AI usage fees calculated and displayed as Chinese yuan.
Architecture: Keep the existing AI usage ledger API and database compatibility fields. Update AiCostCalculator to use CNY model rates while preserving cache-hit, cache-miss, and completion token calculation. Update the admin Vue page label and formatter to present CNY.
Tech Stack: Java, JUnit 4, Spring/MyBatis, Vue 2, Element UI.
File Structure
- Modify:
ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/AiCostCalculatorTest.java- Owns pricing expectations for Flash, Pro, default DeepSeek models, missing usage, and cent rounding.
- Modify:
ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/AiUsageRecorderTest.java- Verifies recorded ledger/scope costs reflect the calculator's CNY amount.
- Modify:
ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/AiCostCalculator.java- Owns token-to-money calculation and model rate selection.
- Modify:
ruoyi-ui/src/views/generator/aiUsage/index.vue- Owns AI usage fee labels and currency formatting.
Task 1: Backend Pricing Tests
- Step 1: Write failing calculator expectations
Update expected values in AiCostCalculatorTest:
assertEquals(300, calculator.estimateCostCents("deepseek", "deepseek-chat", 1_000_000, 1_000_000));
assertEquals(new BigDecimal("2.90200000"),
calculator.estimateCostUsd("deepseek", "deepseek-v4-flash", usage));
assertEquals(new BigDecimal("9.02500000"),
calculator.estimateCostUsd("deepseek", "deepseek-v4-pro", usage));
assertEquals(new BigDecimal("3.00000000"),
calculator.estimateCostUsd("deepseek", "deepseek-chat", usage));
- Step 2: Verify tests fail under old USD rates
Run:
mvn -pl ruoyi-generator -Dtest=AiCostCalculatorTest test
Expected: failures show old USD amounts such as 0.40628000 where CNY amounts are expected.
- Step 3: Update recorder expectation
In AiUsageRecorderTest, replace 0.40628000 expectations with 2.90200000.
- Step 4: Verify recorder test fails under old USD rates
Run:
mvn -pl ruoyi-generator -Dtest=AiUsageRecorderTest test
Expected: failures show old USD amount 0.40628000 instead of 2.90000000.
Task 2: Backend CNY Implementation
- Step 1: Replace calculator rate constants
In AiCostCalculator, replace USD constants with CNY constants:
private static final BigDecimal FLASH_CACHE_HIT_CNY_PER_1M = new BigDecimal("0.02");
private static final BigDecimal FLASH_CACHE_MISS_CNY_PER_1M = new BigDecimal("1");
private static final BigDecimal FLASH_OUTPUT_CNY_PER_1M = new BigDecimal("2");
private static final BigDecimal PRO_CACHE_HIT_CNY_PER_1M = new BigDecimal("0.025");
private static final BigDecimal PRO_CACHE_MISS_CNY_PER_1M = new BigDecimal("3");
private static final BigDecimal PRO_OUTPUT_CNY_PER_1M = new BigDecimal("6");
Keep public method names unchanged for compatibility.
- Step 2: Update internal variable names where local only
Rename local variables and Rate fields from Usd to neutral Amount or Cny inside AiCostCalculator. Do not rename public methods or domain fields in this task.
- Step 3: Verify backend tests pass
Run:
mvn -pl ruoyi-generator -Dtest=AiCostCalculatorTest,AiUsageRecorderTest test
Expected: both test classes pass.
Task 3: Admin UI CNY Display
- Step 1: Update label and formatter
In ruoyi-ui/src/views/generator/aiUsage/index.vue:
<div class="metric-label">费用 CNY</div>
<div class="metric-value">{{ formatCny(summary.costUsd) }}</div>
Use formatCny for row values and return a yuan-prefixed string:
formatCny(value, cents) {
let amount = Number(value || 0)
if (!amount && cents) {
amount = Number(cents || 0) / 100
}
return `¥${amount.toFixed(8).replace(/0+$/, '').replace(/\.$/, '') || '0'}`
}
- Step 2: Verify UI references
Run:
rg -n "formatUsd|费用 USD|\\$[0-9]" ruoyi-ui/src/views/generator/aiUsage/index.vue
Expected: no matches.
Task 4: Final Verification
- Step 1: Run targeted backend tests
Run:
mvn -pl ruoyi-generator -Dtest=AiCostCalculatorTest,AiUsageRecorderTest test
Expected: exit code 0.
- Step 2: Check changed file diff
Run:
git diff -- ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/AiCostCalculator.java ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/AiCostCalculatorTest.java ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/AiUsageRecorderTest.java ruoyi-ui/src/views/generator/aiUsage/index.vue
Expected: diff only changes pricing tests, CNY rates, and UI CNY formatter/labels.