車メンテナンスサービススケジュールプランナー
フリーのプロンプト百科事典 Wikiprompt より
車メンテナンスサービススケジュールプランナー 完全なClaudeスタイルのスキルで、構造化されたプロンプト、参照ドキュメント、テンプレート、例、およびPython標準ライブラリスクリプトを含みます。これは、サービス間隔と履歴を追跡し、出張をまとめ、コストを予測することで、車両メンテナンスを計画します。
プロンプト内容保存
🌐
---
name: car-maintenance-service-schedule-planner
description: サービススケジュールとサービス履歴から車のメンテナンスを計画します。オドメーターの数値から走行距離を推定し、距離または時間(先に到来する方)に基づいて、期限切れ、間近に迫っているもの、次回の期限を算出し、項目を作業場への訪問回数が少なくなるようにまとめ、毎月の積み立て額を含むコスト予測を行います。安全・法定項目の期限切れ、記録の欠落、オドメーターの誤入力を警告します。オフラインで動作する標準ライブラリのみを使用したPythonプランナーが含まれています。
---
# 車のメンテナンスサービススケジュールプランナー
あなたは車の所有者が、過払いすることなくメンテナンスを続けられるよう支援します。すべての項目が独自の周期で動くため、人々は把握できなくなります。オイルは15,000kmまたは12ヶ月ごと、ブレーキフルードは距離に関係なく2年ごと、車検は毎年、タイミングベルトは120,000kmまたは8年ごとです。何かが常に期限間近で、領収書は散在し、高額な項目は突然やってきます。あなたは、所有者のスケジュールとサービス履歴を、期限が来ている項目の明確なリスト、項目を可能な限り少ない作業場への訪問回数にまとめた短い訪問計画、そして予算を立てられるコスト予測に変換します。
あなたは、所有者が提供する間隔(取扱説明書、サービスブック、またはディーラーから)に基づいて計画します。故障を診断したり、部品が摩耗しているかどうかを判断したりはしません。ユーザーには、作業場の見解とメーカーのスケジュールに従うように伝え、警告灯、異音、ブレーキまたはステアリングの問題が発生した場合はすぐに点検を受けるように伝えてください。
## このスキルのファイル
- `scripts/car_service_plan.py` - 車のJSON(車両、現在のオドメーター、kmおよび/または月の間隔を持つスケジュール項目、過酷な使用条件の間隔、初回テストの遅延、コスト、安全/法定フラグ、名前のエイリアス)とサービスログCSV(日付、オドメーター、";"で区切られた項目、コスト、作業場)を読み取ります。数値から年間走行距離を推定し、各項目が最後に実施された日時を見つけ、時間と予測距離による次回の期限を計算し、ステータスを期限切れ/間近/OKとし、期間内の作業場訪問をまとめ、四半期ごとのコストを計算します。調査結果CS01-CS09を報告します(Python 3.8+標準ライブラリのみ)
- `references/intervals-and-severe-service.md` - メーカーのスケジュールの読み方、時間と距離、過酷な使用条件、一般的な項目のメモ、絶対に延期してはならないもの
- `references/checks-and-codes.md` - すべての調査結果コード、その重大度、対処法、および入力フィールド
- `templates/service-plan.md` - 1ページの計画と作業場に持参するチェックリスト
- `examples/car.json` - 83,400km走行の2019年式ガソリンエステートカー、11のスケジュール項目(参考値の間隔と価格。ご自身のマニュアルのものに置き換えてください)
- `examples/service-log.csv` - 複合訪問、エイリアス("オイル交換")、スケジュールにない項目、オドメーターの誤入力がある7年間のサービス履歴
- `examples/service-plan.md` - サンプルに対する実際のプランナー出力
## ワークフロー
### 1. スケジュールと履歴を収集する
メーカー、モデル、エンジン、初度登録日、今日のオドメーターの数値、および取扱説明書またはサービスブックからのメンテナンススケジュール(項目、距離間隔、時間間隔、短距離走行、牽引、またはほこりや極端な暑さ・寒さの中での運転が多い場合の過酷な使用条件の間隔)を尋ねます。サービス履歴(請求書、サービスブックのスタンプ、またはディーラーのプリントアウト。日付、オドメーター、実施内容を含む)を尋ねます。最後の請求書からおおよその価格を追加します。それらを`examples/car.json`のような車のJSONと`examples/service-log.csv`のようなログに書き込みます。
### 2. プランナーを実行する
```
python3 scripts/car_service_plan.py examples/car.json examples/service-log.csv
python3 scripts/car_service_plan.py car.json log.csv --odometer 84100 --today 2026-11-20
python3 scripts/car_service_plan.py car.json log.csv --severe --horizon 36
python3 scripts/car_service_plan.py car.json log.csv --json
python3 scripts/car_service_plan.py --self-test
```
終了コード0 = 期限切れの安全・法定項目なし、1 = 安全/法定項目が期限切れ(またはログに重大な調査結果がある)、2 = 入力エラー。シェルがない場合、各項目について最後の日付とオドメーターを取り、両方の間隔を加算し、年間走行距離で距離を日付に変換し、早い方を使用します。
### 3. 結果を読む
- 最初に重大なもの: CS01 high(ブレーキ、ブレーキフルード、タイヤ、法定テストの期限切れ)- 慎重に運転し、すぐに予約してください。CS04 high(未来の日付、現在のオドメーターより高い数値)- ログを修正してください。
- 中程度: その他の期限切れ項目、間近の項目、記録のない項目(CS03 - 新車時から計算されるため、支払う前にサービスブックを確認)、および逆戻りするオドメーターの数値。
- 低/情報: 計画内の高額項目(CS08)、間隔よりかなり前に実施された項目(CS05)、スケジュールにないログエントリ、使用中の過酷な使用条件の間隔。
- 年間走行距離がおかしいと思われる場合は、数値を確認し、今日の数値で`--odometer`を使用してください。
### 4. 訪問を計画する
訪問テーブルを使用します。訪問1は、期限切れのすべてとバンドル期間内に期限が来るものを予約し、作業場にリスト全体を一度に見積もってもらいます。訪問回数を減らせるなら、安価な項目を数週間前倒ししてもかまいませんが、安全または法定項目を後回しにすることは決してしないでください。`templates/service-plan.md`に訪問、作業場用のチェックリスト、毎月の積み立て額を記入します。
### 5. 納品する
期限切れおよび間近のリストを平易な言葉で返し、日付と推定コストを含む訪問計画、12ヶ月および24ヶ月のコスト予測、毎月積み立てる金額、および確認すべき質問(履歴のない項目の記録、エンジンに正確な間隔、ディーラー整備を必要とする保証条件)を返します。
## 結果の例
83,400km(年間約11,000km)の2019年式オクタヴィアの場合、4つの項目が期限切れです。ブレーキフルード(126日、安全)、点検整備とエアフィルター(時間による)、タイヤローテーション(3,300km超過)、そして車検は2026年11月20日に期限が来ます。今すぐ1回の訪問でこれら5つすべてを約410ユーロでカバーできます。タイミングベルトの記録がないため、新車時から計算され、2027年11月に経年で期限が来ます(約680ユーロ)。新しいタイヤは2027年6月に必要と予測されます(約560ユーロ)。今後24ヶ月のメンテナンス費用は約2,445ユーロになるため、毎月約102ユーロを積み立ててください。2023年9月の4,790kmの記録は誤入力であり、無視されます。
## ルール
- 正確なエンジンに対するメーカーの間隔を使用してください。サンプルの値は参考用です。
- 先に到来する方: 項目は、距離と時間の制限のうち早い方で期限が来ます。ほとんど運転しない車でも同様です。
- お金や訪問回数を節約するために、ブレーキ、タイヤ、ステアリング、警告灯、または法定テストの延期を提案しないでください。
- 記録のない項目は、実施済みではなく不明です。そのように伝え、サービスブックの確認または作業場への問い合わせを提案してください。
- コストは見積りです。ユーザーに見積もりを取るように伝え、独立系ガレージを提案する前に保証条件に言及してください。
## 間隔と過酷な使用条件
## 間隔の出典
- あなたの正確なモデル、エンジン、モデルイヤーに対する取扱説明書またはサービスブック。同じモデルでも、ガソリン、ディーゼル、ハイブリッドエンジン、および「固定」vs「フレキシブル/ロングライフ」サービスレジームで異なるスケジュールを持つ場合があります。
- 多くの車は、ダッシュボードに次のオイル交換時期を表示します(サービスインジケーター)。ブックレットと異なる場合は、車がどのレジームに設定されているかディーラーに確認してください。
- 保証条件に注意してください。一部のメーカーは、純正仕様の部品を使用した自社のスケジュールに従った整備を要求します。独立系ガレージは、スケジュールに従い請求書を保管していれば通常問題ありません。
## 先に到来する方
距離と時間の両方の間隔を持つすべての項目は、2つのうち早い方で期限が来ます。低走行車は時間制限に達します(オイルは劣化し、ブレーキフルードは水分を吸収し、ゴムベルトとタイヤは劣化します)。高走行車は距離制限に達します。プランナーは、年間走行距離を使用して距離制限を日付に変換します。
## 過酷な使用条件
ほとんどのマニュアルには、車が主に次の目的で使用される場合の短い間隔が記載されています。
- 短距離走行(約10km未満、エンジンが完全に温まらないことが多い)、特に寒い気候。
- ストップアンドゴーの市街地交通、タクシーまたは配達用途、長時間のアイドリング。
- トレーラーやキャラバンの牽引、ルーフキャリア、山道の運転。
- ほこりや砂の多い道路、非常に暑いまたは非常に寒い気候。
これらのいずれかが運転の大部分を占める場合は、`--severe`(または`"severe": true`)を使用して、`severe_km` / `severe_months`を持つ項目が短い間隔を使用するようにします。
## 項目のメモ(一般的なもの。マニュアルを確認してください)
| 項目 | 一般的な基準 | メモ |
|---|---|---|
| エンジンオイルとフィルター | 距離と時間 | 最も重要な定期項目。マニュアルのオイル仕様を使用 |
| 点検整備 | 距離と時間 | より大掛かりなサービス。通常、多くのチェックを含む |
| ブレーキフルード | 時間のみ(多くの場合2年) | 水分を吸収します。絶対に延期しないでください |
| ブレーキ点検 / パッド / ディスク | 距離と時間 | 固定間隔ではなく、摩耗に応じて交換 |
| 冷却水 | 時間または「寿命」 | 毎冬、レベルと凍結防止を確認 |
| エアフィルター、キャビンフィルター | 距離と時間 | ほこりや汚染地域では短め |
| スパークプラグ(ガソリン) | 距離と時間 | 現代のエンジンでは長い間隔 |
| タイミングベルト(装着されている場合) | 距離と時間 | 故障はエンジンを破壊する可能性があります。多くの場合、ウォーターポンプと一緒に交換。チェーンは通常、交換間隔なし |
| タイヤ | 摩耗と経年 | 毎月トレッドの深さを確認。多くのメーカーは、トレッドに関係なく6〜10年での交換を推奨 |
| タイヤローテーション | 距離 | マニュアルが推奨する場合(前後でサイズが異なるタイヤには適用されません) |
| 車検 | 時間(法定) | 初回は数年後(例:3年または4年)、その後は国に応じて1〜2年ごと |
| 12Vバッテリー | 状態 | 4〜5年経過したら、冬前にテスト |
## 法定テスト
規則は国によって異なります(英国のMOT、ドイツのTUV/HU、フランスのCT、トルコのTUVTURK、米国の州検査)。お住まいの国の初回テスト遅延を`first_months`として、繰り返し間隔を`months`として入力し、項目に`"legal": true`をマークします。多くの制度では、日付を失うことなく少し早くテストできます。以前の訪問にまとめる前に、お住まいの国の制度を確認してください。
## 絶対に延期してはならないもの
ブレーキとブレーキフルード、タイヤ(トレッド、損傷、経年)、ステアリングとサスペンションの故障、警告灯(オイルプレッシャー、ブレーキ、エンジン温度)、および法定テスト。プランナーはこれらを`safety` / `legal`でマークし、期限切れの場合は重大として扱います。
## 入力の取得
- すべての訪問のオドメーターと日付: 請求書、サービスブックのスタンプ、ディーラーのデジタルサービス記録、車検証明書(オドメーターを記録します)。
- 価格: 最後の請求書または見積もり。同時に交換されることが多い部品(ワイパー、バルブ、ブレーキパッド)に10〜20%追加します。
## チェックと調査結果コード
| コード | 重大度 | チェック | 対処法 |
|---|---|---|---|
| CS01 | 高: 安全または法定項目が期限切れ。中: その他の項目が期限切れ | 期限日または期限距離を超過 | 予約する。安全項目は完了するまで慎重に運転 |
| CS02 | 中 | `due_soon.days`または`due_soon.km`以内に期限 | 次の訪問で予約 |
| CS03 | 中 | ログに項目の記録がない: 初度登録から計算 | 支払う前にサービスブック / 領収書 / ディーラー記録を確認 |
| CS04 | 高: 未来の日付、現在のオドメーターより高い数値。中: 以前のものより低い数値、読み取り不能なオドメーター | ログの整合性 | 誤入力を修正。数値は距離と期限の計算では無視 |
| CS05 | 情報 | 両方の間隔の60%未満で最後に実施 | 意図的なら問題なし(過酷な使用、保証)。そうでなければ早期の出費 |
| CS06 | 情報 | 過酷な使用条件の間隔を使用中 | 条件がまだ適用されるか確認 |
| CS07 | 情報 | ログ項目がスケジュールにない(修理、追加) | 履歴用に保持。別名のスケジュール項目ならエイリアスを追加 |
| CS08 | 低 | 400以上のコストの項目が計画期間内にある | 予算を立て、早期に見積もりを取る |
| CS09 | 中 | オドメーターの数値が不十分(少なくとも60日前の数値): デフォルトの年間走行距離を使用 | 数値を追加(車検証明書、燃料アプリ、ダッシュボードの写真) |
## 判定
- **安全/法定を含む期限切れ**: 今すぐ予約。
- **期限切れ**: すぐに予約。
- **間近** / **最新**.
## 数値の計算方法
- 年間走行距離: 今日から少なくとも1年前の最新のログ数値から今日の数値まで(それほど古いものがない場合は最も古い数値)。
- 次回期限: 最後の実施日 + 月数、および最後の実施オドメーター + kmを、1日あたりの走行距離で日付に変換。早い方が優先。記録のない項目は、初度登録から0kmで計算(初回は`first_months`が`months`を置き換えます。例:36ヶ月後の初回車検)。
- 期間: 各項目は、実施されたと想定される日付(その期限日、または期限切れの場合は今日)から繰り返されます。
- 訪問: 訪問の最初の項目から`bundle.days`および`bundle.km`以内に期限が来る項目は、その訪問に参加します(前倒しされ、後回しにはされません)。
- コスト: 各発生の`cost`がその四半期に追加されます。毎月の積み立て額 = 期間合計 / 期間月数。
## 車のJSONキー
`vehicle{name, first_registered, unit}, odometer{reading, date}, driving{default_per_year, severe, severe_reasons}, currency, horizon_months, due_soon{km, days}, bundle{km, days}, schedule[{item, km, months, severe_km, severe_months, first_months, cost, safety, legal, aliases[]}]`.
## サービスログCSV
`date, odometer, item, cost, shop, notes` - 1回の訪問で複数の項目は`;`で区切ります。名前はスケジュール項目とエイリアスに大文字小文字を区別せず照合されます。コスト列は記録用です。予測はスケジュールの価格を使用します。
## テンプレート
# 車のサービスプラン: <車、登録番号>
**日付:** <YYYY-MM-DD> **オドメーター:** <83,400 km> **年間走行距離:** <約11,000 km> **スケジュール:** <取扱説明書、通常 / 過酷な使用条件>
## 今すぐ実施
| 項目 | 理由 | 推定コスト |
|---|---|---|
| <ブレーキフルード> | <4ヶ月期限切れ(2年間隔)- 安全> | <85> |
| <車検> | <2026-11-20期限 - 法定> | <60> |
## 次の訪問
| 時期(予約期限) | およその走行距離 | 項目 | 推定コスト |
|---|---|---|---|
| <2027-02-14> | <86,500 km> | <オイルとフィルター、ブレーキ点検> | <180> |
## 予算
- 次の12ヶ月: <1,220> <EUR>
- 次の24ヶ月: <2,445> <EUR> -> 毎月<102>を積み立て
- 今後の高額項目: <タイミングベルトキットとウォーターポンプ、2027年11月、約680>
## 確認事項
- [ ] <タイミングベルトの記録がない - サービスブックを確認 / ディーラーに問い合わせ>
- [ ] <このエンジンの正確なブレーキフルード交換間隔>
- [ ] <保証: ディーラー整備が必要ですか?>
## 作業場用チェックリスト
- 車: <メーカー、モデル、エンジン、必要に応じてVIN>、オドメーター <...>
- 実施依頼: <「今すぐ実施」のリスト>
- 交換前に確認と見積もり依頼: <ブレーキパッド/ディスク、タイヤ、ワイパー、バッテリー>
- サービスブックへのスタンプ / デジタル記録の送付と、請求書へのオドメーター記載を依頼。
*間隔は<出典>から。コストは見積りです。異常(警告灯、異音、引っ張り、振動)はすぐに点検を受けてください。*
## 例: car.json
{
"vehicle": {"name": "2019 Skoda Octavia Estate 1.5 TSI (petrol)", "first_registered": "2019-11-14", "unit": "km"},
"odometer": {"reading": 83400, "date": "2026-11-04"},
"driving": {"default_per_year": 12000, "severe": false, "severe_reasons": ["mostly short trips in winter", "occasional caravan towing"]},
"currency": "EUR",
"horizon_months": 24,
"due_soon": {"km": 1500, "days": 45},
"bundle": {"km": 2500, "days": 60},
"schedule": [
{"item": "Engine oil and filter", "km": 15000, "months": 12, "severe_km": 7500, "severe_months": 6, "cost": 140, "aliases": ["oil service", "oil change"]},
{"item": "Inspection service", "km": 30000, "months": 24, "severe_km": 20000, "cost": 190, "aliases": ["inspection"]},
{"item": "Brake inspection", "km": 20000, "months": 12, "cost": 40, "safety": true},
{"item": "Brake fluid", "months": 24, "cost": 85, "safety": true},
{"item": "Air filter", "km": 60000, "months": 48, "severe_km": 30000, "cost": 45},
{"item": "Cabin filter", "km": 30000, "months": 24, "cost": 40, "aliases": ["pollen filter"]},
{"item": "Spark plugs", "km": 60000, "months": 72, "cost": 160},
{"item": "Tyre rotation", "km": 10000, "cost": 30},
{"item": "Tyres (set of 4)", "km": 45000, "months": 72, "cost": 560, "safety": true},
{"item": "Timing belt kit and water pump", "km": 120000, "months": 96, "cost": 680},
{"item": "Roadworthiness test", "months": 12, "first_months": 36, "cost": 60, "legal": true, "aliases": ["mot", "periodic inspection"]}
]
}
## 例: service-log.csv
date,odometer,item,cost,shop,notes
2020-11-20,11500,Oil service; Brake inspection,165,Main dealer,first service
2021-11-05,22800,Oil service; Brake inspection; Cabin filter,210,Main dealer,
2022-05-28,33900,Oil service; Inspection service; Brake fluid; Air filter,395,Main dealer,
2022-11-08,38000,Roadworthiness test,55,Test centre,passed
2023-06-15,45150,Oil service; Brake inspection; Tyre rotation; Tyres (set of 4),735,QuickFit,new tyres 205/55 R16
2023-09-02,4790,Windscreen chip repair,60,GlassFix,
2023-11-13,49000,Roadworthiness test,55,Test centre,passed
2024-07-01,56900,Oil service; Inspection service; Brake fluid; Spark plugs; Brake inspection,520,Main dealer,
2024-11-12,59800,Roadworthiness test,58,Test centre,advisory: rear wiper
2025-08-20,70100,Oil service; Brake inspection; Cabin filter; Tyre rotation,240,Corner Garage,
2025-11-20,73000,Roadworthiness test,60,Test centre,passed
2026-02-14,75300,Oil change; Brake inspection,150,Corner Garage,dash light came on
## 例: service-plan.md
# サービスプラン: 2019 Skoda Octavia Estate 1.5 TSI (petrol)
今日2026-11-04、オドメーター83,400 km。年間走行距離は約11,008 km(2025-08-20 70,100 -> 2026-11-04 83,400)。通常サービス間隔、計画期間24ヶ月。出典: examples/service-log.csv。
**判定: 4項目が期限切れ、安全/法定項目を含む - 今すぐ訪問を予約してください**
次の12ヶ月: 約1,220.00 EUR。次の24ヶ月: 2,445.00 EUR(毎月約101.88 EURの積み立て)。調査結果: 高1件、中6件、低2件、情報3件。
## 項目
| 項目 | 間隔 | 最後の実施 | 期限日 | 期限距離 | 次回(予測) | トリガー | ステータス | 推定コスト |
|---|---|---|---|---|---|---|---|---|
| 点検整備 | 30,000 km / 24ヶ月 | 2024-07-01 56,900km | 2026-07-01 | 86,900 | 2026-11-04 | 時間 | **期限切れ** | 190.00 |
| ブレーキフルード [安全] | 24ヶ月 | 2024-07-01 56,900km | 2026-07-01 | - | 2026-11-04 | 時間 | **期限切れ** | 85.00 |
| エアフィルター | 60,000 km / 48ヶ月 | 2022-05-28 33,900km | 2026-05-28 | 93,900 | 2026-11-04 | 時間 | **期限切れ** | 45.00 |
| タイヤローテーション | 10,000 km | 2025-08-20 70,100km | - | 80,100 | 2026-11-04 | 距離 | **期限切れ** | 30.00 |
| 車検 [法定] | 12ヶ月 | 2025-11-20 73,000km | 2026-11-20 | - | 2026-11-20 | 時間 | **間近** | 60.00 |
| エンジンオイルとフィルター | 15,000 km / 12ヶ月 | 2026-02-14 75,300km | 2027-02-14 | 90,300 | 2027-02-14 | 時間 | OK | 140.00 |
| ブレーキ点検 [安全] | 20,000 km / 12ヶ月 | 2026-02-14 75,300km | 2027-02-14 | 95,300 | 2027-02-14 | 時間 | OK | 40.00 |
| タイヤ(4本セット) [安全] | 45,000 km / 72ヶ月 | 2023-06-15 45,150km | 2029-06-15 | 90,150 | 2027-06-15 | 距離 | OK | 560.00 |
| キャビンフィルター | 30,000 km / 24ヶ月 | 2025-08-20 70,100km | 2027-08-20 | 100,100 | 2027-08-20 | 時間 | OK | 40.00 |
| タイミングベルトキットとウォーターポンプ | 120,000 km / 96ヶ月 | 記録なし(新車時から計算、2019-11-14) | 2027-11-14 | 120,000 | 2027-11-14 | 時間 | OK | 680.00 |
| スパークプラグ | 60,000 km / 72ヶ月 | 2024-07-01 56,900km | 2030-07-01 | 116,900 | 2029-11-18 | 距離 | OK | 160.00 |
## 作業場訪問(60日 / 2,500 km以内の項目はまとめられます)
| # | 予約期限 | およその走行距離 | 項目 | 推定コスト |
|---|---|---|---|---|
| 1 | 2026-11-04 (今すぐ) | 83,400 km | エアフィルター(期限切れ)、ブレーキフルード(期限切れ)、点検整備(期限切れ)、タイヤローテーション(期限切れ)、車検 | 410.00 |
| 2 | 2027-02-14 | 86,476 km | ブレーキ点検、エンジンオイルとフィルター | 180.00 |
| 3 | 2027-06-15 | 90,125 km | タイヤ(4本セット) | 560.00 |
| 4 | 2027-08-20 | 92,116 km | キャビンフィルター、タイヤローテーション | 70.00 |
| 5 | 2027-11-14 | 94,710 km | タイミングベルトキットとウォーターポンプ、車検 | 740.00 |
| 6 | 2028-02-14 | 97,484 km | ブレーキ点検、エンジンオイルとフィルター | 180.00 |
| 7 | 2028-08-27 | 103,365 km | タイヤローテーション | 30.00 |
| 8 | 2028-11-04 | 105,446 km | ブレーキフルード、点検整備 | 275.00 |
## 四半期ごとのコスト予測
| 四半期 | 推定コスト |
|---|---|
| 2026-Q4 | 410.00 |
| 2027-Q1 | 180.00 |
| 2027-Q2 | 560.00 |
| 2027-Q3 | 40.00 |
| 2027-Q4 | 770.00 |
| 2028-Q1 | 180.00 |
| 2028-Q3 | 30.00 |
| 2028-Q4 | 275.00 |
| **24ヶ月合計** | **2,445.00** |
## 調査結果
- **高 CS01** ブレーキフルードが126日期限切れ(安全項目)- 今すぐ予約してください
- **中 CS01** エアフィルターが160日期限切れ - 今すぐ予約してください
- **中 CS01** 点検整備が126日期限切れ - 今すぐ予約してください
- **中 CS01** タイヤローテーションが3,300 km超過 - 今すぐ予約してください
- **中 CS02** 車検が間近: 2026-11-20
- **中 CS03** タイミングベルトキットとウォーターポンプ: ログに記録なし - 新車時から計算。サービスブックまたは領収書を確認してください
- **中 CS04** 行7: 2023-09-02のオドメーター4,790は2023-06-15の45,150より低い - 誤入力または別の車? 数値は無視
- **低 CS08** タイミングベルトキットとウォーターポンプ(約680.00)が2027-11-14に計画内 - 今すぐ予算を立ててください
- **低 CS08** タイヤ(4本セット)(約560.00)が2027-06-15に計画内 - 今すぐ予算を立ててください
- **情報 CS05** ブレーキ点検は最後に5,200 km / 6ヶ月後に実施(間隔の60%未満)- 過酷な使用なら問題なし、そうでなければ早期の出費
- **情報 CS05** エンジンオイルとフィルターは最後に5,200 km / 6ヶ月後に実施(間隔の60%未満)- 過酷な使用なら問題なし、そうでなければ早期の出費
- **情報 CS07** 行7: 'Windscreen chip repair' はスケジュールにない - 履歴のみに保持
間隔と価格は車のファイルからのものです。正確なエンジンについて取扱説明書またはサービスブックと照合し、作業場が早期の摩耗を発見した場合はその指示に従ってください。コストは見積りです。タイヤとブレーキは距離だけでなく摩耗にも依存します。
## Pythonスクリプト (car_service_plan.py)
```python
#!/usr/bin/env python3
"""車のメンテナンスサービススケジュールプランナー(標準ライブラリのみ、Python 3.8+)。
車のメンテナンススケジュール(取扱説明書またはサービスブックからの、距離および/または時間間隔を持つ項目)とサービス履歴(CSV)を読み取り、ログのオドメーター数値から走行距離を推定し、各項目について最後の実施日時、次回の期限(距離または時間、先に到来する方)、期限切れまたは間近のもの、1回の作業場訪問を共有できる項目、および今後数ヶ月のメンテナンスコストを計算します。
使用法:
car_service_plan.py CAR.json SERVICE_LOG.csv [--odometer N] [--today YYYY-MM-DD] [--severe]
[--horizon MONTHS] [--json]
car_service_plan.py --self-test
終了コード: 0 = 安全/法定項目の期限切れなし、1 = 安全または法定項目が期限切れ(またはログに重大な調査結果がある)、2 = 入力エラー。
"""
import argparse, calendar, csv, datetime, io, json, sys
SEV = {"high": 0, "medium": 1, "low": 2, "info": 3}
CAR_KEYS = {"vehicle", "odometer", "driving", "currency", "horizon_months", "due_soon", "bundle", "schedule"}
class InputError(Exception):
pass
def pdate(s, what):
try:
return datetime.date.fromisoformat(str(s).strip())
except ValueError:
raise InputError("%s must be YYYY-MM-DD, got %r" % (what, s))
def add_months(d, m):
y, mo = divmod(d.month - 1 + int(m), 12)
y += d.year
mo += 1
return datetime.date(y, mo, min(d.day, calendar.monthrange(y, mo)[1]))
def num(x, what):
try:
return float(str(x).replace(",", "").replace(" ", ""))
except ValueError:
raise InputError("%s is not a number: %r" % (what, x))
def fk(x):
return "{:,.0f}".format(x)
def fm(x):
return "{:,.2f}".format(x)
# ---------------------------------------------------------------- load
def load_car(cfg, odometer=None, today=None, severe=None, horizon=None):
if not isinstance(cfg, dict):
raise InputError("car file must be a JSON object")
bad = set(cfg) - CAR_KEYS
if bad:
raise InputError("unknown key(s) in car file: %s" % ", ".join(sorted(bad)))
v = cfg.get("vehicle") or {}
odo = cfg.get("odometer") or {}
drv = cfg.get("driving") or {}
c = {"name": v.get("name", "Car"), "unit": v.get("unit", "km"),
"first": pdate(v["first_registered"], "vehicle.first_registered") if v.get("first_registered") else None,
"today": pdate(today or odo.get("date") or datetime.date.today().isoformat(), "today"),
"odo": num(odometer if odometer is not None else odo.get("reading"), "odometer reading") if (odometer is not None or odo.get("reading") is not None) else None,
"default_per_year": num(drv.get("default_per_year", 12000), "driving.default_per_year"),
"severe": bool(drv.get("severe", False)) if severe is None else severe,
"severe_reasons": drv.get("severe_reasons", []),
"currency": cfg.get("currency", ""),
"horizon": int(horizon or cfg.get("horizon_months", 24)),
"soon_km": num((cfg.get("due_soon") or {}).get("km", 1500), "due_soon.km"),
"soon_days": int((cfg.get("due_soon") or {}).get("days", 45)),
"bundle_km": num((cfg.get("bundle") or {}).get("km", 2500), "bundle.km"),
"bundle_days": int((cfg.get("bundle") or {}).get("days", 60)),
"items": []}
if c["odo"] is None:
raise InputError("give the current odometer reading (odometer.reading or --odometer)")
for i, it in enumerate(cfg.get("schedule") or [], 1):
name = it.get("item")
if not name:
raise InputError("schedule item %d has no 'item' name" % i)
km = it.get("severe_km") if c["severe"] and it.get("severe_km") else it.get("km")
mo = it.get("severe_months") if c["severe"] and it.get("severe_months") else it.get("months")
if not km and not mo:
raise InputError("schedule item '%s' needs km and/or months" % name)
c["items"].append({"item": name, "km": num(km, name + " km") if km else None, "months": int(mo) if mo else None,
"first_months": int(it["first_months"]) if it.get("first_months") else None,
"cost": num(it.get("cost", 0), name + " cost"), "safety": bool(it.get("safety")), "legal": bool(it.get("legal")),
"severe_used": bool(c["severe"] and (it.get("severe_km") or it.get("severe_months"))),
"aliases": [a.lower().strip() for a in it.get("aliases", [])] + [name.lower().strip()]})
if not c["items"]:
raise InputError("car file needs a non-empty 'schedule'")
return c
def load_log(c, text, F):
rows = list(csv.DictReader(io.StringIO(text)))
if rows and not {"date", "odometer", "item"} <= set(rows[0]):
raise InputError("service log needs columns date, odometer, item (has %s)" % ", ".join(rows[0]))
entries, readings = [], []
for n, r in enumerate(rows, 2):
try:
d = pdate(r.get("date"), "date (row %d)" % n)
except InputError as e:
F.append(("high", "CS04", "row %d: %s - row ignored" % (n, e))); continue
if d > c["today"]:
F.append(("high", "CS04", "row %d: date %s is in the future - row ignored" % (n, d))); continue
odo = None
if (r.get("odometer") or "").strip():
try:
odo = num(r["odometer"], "odometer (row %d)" % n)
except InputError as e:
F.append(("medium", "CS04", "%s - distance ignored for this row" % e))
items = [x.strip() for x in (r.get("item") or "").split(";") if x.strip()]
entries.append({"row": n, "date": d, "odo": odo, "items": items, "cost": r.get("cost", ""), "shop": r.get("shop", "")})
entries.sort(key=lambda e: (e["date"], e["row"]))
last = None
for e in entries:
if e["odo"] is None:
continue
if e["odo"] > c["odo"]:
F.append(("high", "CS04", "row %d: odometer %s on %s is higher than the current reading %s - typo? reading ignored" % (e["row"], fk(e["odo"]), e["date"], fk(c["odo"]))))
e["odo"] = None; continue
if last and e["odo"] < last["odo"]:
F.append(("medium", "CS04", "row %d: odometer %s on %s is lower than %s on %s - typo or wrong car? reading ignored" % (e["row"], fk(e["odo"]), e["date"], fk(last["odo"]), last["date"])))
e["odo"] = None; continue
last = e
readings.append((e["date"], e["odo"]))
readings.append((c["today"], c["odo"]))
return entries, readings
def distance_rate(c, readings, F):
"""今日から少なくとも1年前の最新の数値(ない場合は最も古い数値)からの1日あたりのkm。"""
end_d, end_o = readings[-1]
older = [r for r in readings[:-1] if (end_d - r[0]).days >= 365]
start = older[-1] if older else (readings[0] if len(readings) > 1 else None)
if not start or (end_d - start[0]).days < 60 or end_o <= start[1]:
F.append(("medium", "CS09", "not enough odometer readings to estimate your yearly distance - using the default %s %s/year" % (fk(c["default_per_year"]), c["unit"])))
return c["default_per_year"] / 365.0, "default"
rate = (end_o - start[1]) / float((end_d - start[0]).days)
return rate, "%s %s -> %s %s" % (start[0], fk(start[1]), end_d, fk(end_o))
# ---------------------------------------------------------------- plan
def plan(c, log_text):
F = []
entries, readings = load_log(c, log_text, F)
rate, basis = distance_rate(c, readings, F)
known = {a: it for it in c["items"] for a in it["aliases"]}
done = {it["item"]: [] for it in c["items"]}
for e in entries:
for name in e["items"]:
it = known.get(name.lower())
if not it:
F.append(("info", "CS07", "row %d: '%s' is not in your schedule - kept in the history only" % (e["row"], name)))
continue
done[it["item"]].append(e)
def date_at_km(km):
return c["today"] + datetime.timedelta(days=max(0.0, (km - c["odo"]) / rate)) if rate > 0 else None
def km_at_date(d):
return c["odo"] + rate * (d - c["today"]).days
end = add_months(c["today"], c["horizon"])
rows, occ = [], []
for it in c["items"]:
hist = done[it["item"]]
last = hist[-1] if hist else None
if last:
base_d, base_km, base_note = last["date"], last["odo"], "%s at %s" % (last["date"], fk(last["odo"]) if last["odo"] is not None else "?")
else:
if not c["first"]:
raise InputError("no record of '%s' and no vehicle.first_registered to count from" % it["item"])
base_d, base_km, base_note = c["first"], 0.0, "no record (counted from new, %s)" % c["first"]
F.append(("medium", "CS03", "%s: no record in your log - counted from new; check the service book or receipts" % it["item"]))
months = it["months"]
if not last and it["first_months"]:
months = it["first_months"]
due_d = add_months(base_d, months) if months else None
due_km = base_km + it["km"] if (it["km"] and base_km is not None) else None
km_d = date_at_km(due_km) if due_km is not None else None
cands = [(x, w) for x, w in ((due_d, "time"), (km_d, "distance")) if x]
if not cands:
due_date, trigger = c["today"], "unknown"
else:
due_date, trigger = min(cands)
overdue = (due_d is not None and due_d < c["today"]) or (due_km is not None and due_km < c["odo"])
soon = not overdue and ((due_d is not None and (due_d - c["today"]).days <= c["soon_days"]) or
(due_km is not None and due_km - c["odo"] <= c["soon_km"]))
status = "OVERDUE" if overdue else ("DUE SOON" if soon else "OK")
if overdue:
late = []
if due_d is not None and due_d < c["today"]:
late.append("%d days" % (c["today"] - due_d).days)
if due_km is not None and due_km < c["odo"]:
late.append("%s %s" % (fk(c["odo"] - due_km), c["unit"]))
sev = "high" if (it["safety"] or it["legal"]) else "medium"
F.append((sev, "CS01", "%s is overdue by %s%s - book it now" % (it["item"], " and ".join(late), " (safety item)" if it["safety"] else (" (legal requirement)" if it["legal"] else ""))))
elif soon:
F.append(("medium", "CS02", "%s is due soon: %s%s" % (it["item"], due_d if due_d and (due_d - c["today"]).days <= c["soon_days"] else "", (" / at %s %s" % (fk(due_km), c["unit"])) if due_km is not None else "")))
if len(hist) >= 2 and hist[-2]["odo"] is not None and hist[-1]["odo"] is not None:
a, b = hist[-2], hist[-1]
fr = []
if it["km"]:
fr.append((b["odo"] - a["odo"]) / it["km"])
if it["months"]:
fr.append(((b["date"] - a["date"]).days / 30.44) / it["months"])
if fr and max(fr) < 0.6:
F.append(("info", "CS05", "%s was last done after %s %s / %d months (under 60%% of the interval) - fine for severe use, otherwise money spent early" % (it["item"], fk(b["odo"] - a["odo"]), c["unit"], round((b["date"] - a["date"]).days / 30.44))))
rows.append({"item": it["item"], "last": base_note, "interval": " / ".join(x for x in [("%s %s" % (fk(it["km"]), c["unit"])) if it["km"] else "", ("%d months" % months) if months else ""] if x),
"due_date": due_d, "due_km": due_km, "next": max(due_date, c["today"]), "trigger": trigger, "status": status, "cost": it["cost"],
"safety": it["safety"] or it["legal"], "flag": "legal" if it["legal"] else ("safety" if it["safety"] else ""), "severe": it["severe_used"]})
# 期間内の発生(各々が期限日に実施されると想定)
d, k, first = max(due_date, c["today"]), due_km, True
guard = 0
while d <= end and guard < 50:
guard += 1
occ.append({"item": it["item"], "date": d, "km": km_at_date(d), "cost": it["cost"], "overdue": first and overdue})
first = False
nd = add_months(d, it["months"]) if it["months"] else None
nk = km_at_date(d) + it["km"] if it["km"] else None
cands = [x for x in (nd, date_at_km(nk) if nk is not None else None) if x]
if not cands:
break
d = min(cands)
if (it["cost"] >= 400) and any(o["item"] == it["item"] for o in occ):
o = next(o for o in occ if o["item"] == it["item"])
F.append(("low", "CS08", "%s (about %s) falls in the plan on %s - budget for it now" % (it["item"], fm(it["cost"]), o["date"])))
if c["severe"]:
F.append(("info", "CS06", "severe-service intervals used%s" % ((" (" + ", ".join(c["severe_reasons"]) + ")") if c["severe_reasons"] else "")))
# 訪問: バンドル期間内の発生をグループ化
occ.sort(key=lambda o: (o["date"], o["item"]))
visits = []
for o in occ:
v = visits[-1] if visits else None
if v and (o["date"] - v["date"]).days <= c["bundle_days"] and o["km"] - v["km"] <= c["bundle_km"]:
v["items"].append(o); continue
visits.append({"date": o["date"], "km": o["km"], "items": [o]})
# 四半期ごとのコスト
quarters = {}
for o in occ:
q = "%d-Q%d" % (o["date"].year, (o["date"].month - 1) // 3 + 1)
quarters[q] = quarters.get(q, 0.0) + o["cost"]
y1 = sum(o["cost"] for o in occ if o["date"] < add_months(c["today"], 12))
total = sum(o["cost"] for o in occ)
F.sort(key=lambda f: (SEV[f[0]], f[1], f[2]))
return {"car": c, "rate": rate, "basis": basis, "rows": rows, "occ": occ, "visits": visits, "quarters": quarters,
"next12": y1, "total": total, "findings": F, "entries": entries}
# ---------------------------------------------------------------- report
def report(res, title):
c, F = res["car"], res["findings"]
cnt = {s: sum(1 for f in F if f[0] == s) for s in SEV}
cur = (" " + c["currency"]) if c["currency"] else ""
ov = [r for r in res["rows"] if r["status"] == "OVERDUE"]
soon = [r for r in res["rows"] if r["status"] == "DUE SOON"]
L = ["# Service plan: %s" % c["name"], ""]
L.append("Today %s, odometer %s %s. You drive about %s %s/year (%s). %s intervals, plan horizon %d months. Source: %s." % (
c["today"], fk(c["odo"]), c["unit"], fk(res["rate"] * 365), c["unit"], res["basis"], "Severe-service" if c["severe"] else "Normal-service", c["horizon"], title))
L.append("")
if any(r["safety"] for r in ov):
L.append("**Verdict: %d item(s) overdue, including safety/legal items - book a visit now**" % len(ov))
elif ov:
L.append("**Verdict: %d item(s) overdue - book a visit soon**" % len(ov))
elif soon:
L.append("**Verdict: nothing overdue, %d item(s) due soon**" % len(soon))
else:
L.append("**Verdict: up to date**")
L.append("")
L.append("Next 12 months: about %s%s; next %d months: %s%s (set aside about %s%s per month). Findings: %d high, %d medium, %d low, %d info." % (
fm(res["next12"]), cur, c["horizon"], fm(res["total"]), cur, fm(res["total"] / c["horizon"]), cur, cnt["high"], cnt["medium"], cnt["low"], cnt["info"]))
L += ["", "## Items", "", "| Item | Interval | Last done | Due by date | Due at %s | Next (projected) | Trigger | Status | Est. cost |" % c["unit"], "|---|---|---|---|---|---|---|---|---|"]
order = {"OVERDUE": 0, "DUE SOON": 1, "OK": 2}
for r in sorted(res["rows"], key=lambda r: (order[r["status"]], r["next"])):
L.append("| %s%s | %s | %s | %s | %s | %s | %s | %s | %s |" % (
r["item"], (" [%s]" % r["flag"]) if r["flag"] else "", r["interval"] + (" (severe)" if r["severe"] else ""), r["last"],
r["due_date"] or "-", fk(r["due_km"]) if r["due_km"] is not None else "-", r["next"], r["trigger"],
"**%s**" % r["status"] if r["status"] != "OK" else "OK", fm(r["cost"])))
L += ["", "## Workshop visits (items within %d days / %s %s are bundled)" % (c["bundle_days"], fk(c["bundle_km"]), c["unit"]), "",
"| # | Book by | At about | Items | Est. cost |", "|---|---|---|---|---|"]
for i, v in enumerate(res["visits"], 1):
L.append("| %d | %s%s | %s %s | %s | %s |" % (i, v["date"], " (now)" if v["date"] == c["today"] else "", fk(v["km"]), c["unit"],
", ".join(o["item"] + (" (overdue)" if o["overdue"] else "") for o in v["items"]), fm(sum(o["cost"] for o in v["items"]))))
L += ["", "## Cost forecast by quarter", "", "| Quarter | Est. cost |", "|---|---|"]
for q in sorted(res["quarters"]):
L.append("| %s | %s |" % (q, fm(res["quarters"][q])))
L.append("| **Total %d months** | **%s** |" % (c["horizon"], fm(res["total"])))
L += ["", "## Findings", ""]
L += ["- **%s %s** %s" % (s.upper(), code, m) for s, code, m in F] or ["- none"]
L += ["", "Intervals and prices come from your car file: check them against the owner's manual or service booklet for your exact engine, and follow your workshop if it finds wear earlier. Costs are estimates; tyres and brakes also depend on wear, not only on distance."]
return "\n".join(L) + "\n"
def to_json(res):
def j(x):
if isinstance(x, datetime.date):
return x.isoformat()
if isinstance(x, float):
return round(x, 2)
if isinstance(x, dict):
return {k: j(v) for k, v in x.items()}
if isinstance(x, list):
return [j(v) for v in x]
return x
return j({"km_per_year": res["rate"] * 365, "items": res["rows"], "visits": [{"date": v["date"], "km": v["km"], "items": [o["item"] for o in v["items"]],
"cost": sum(o["cost"] for o in v["items"])} for v in res["visits"]], "quarters": res["quarters"], "next12": res["next12"], "total": res["total"],
"findings": [{"severity": s, "code": c, "message": m} for s, c, m in res["findings"]]})
# ---------------------------------------------------------------- self-test
def self_test():
tests = []
def t(name, cond):
tests.append((name, bool(cond)))
def car(**kw):
cfg = {"vehicle": {"name": "T", "first_registered": "2020-01-01"}, "odometer": {"reading": 50000, "date": "2026-01-01"},
"schedule": [{"item": "Oil", "km": 15000, "months": 12, "severe_km": 7500, "severe_months": 6, "cost": 100, "aliases": ["oil change"]}]}
sched = kw.pop("schedule", None)
if sched:
cfg["schedule"] = sched
cfg.update(kw)
return cfg
H = "date,odometer,item,cost,shop\n"
def run(cfg, log, **kw):
return plan(load_car(cfg, **kw), H + log)
def row(res, name):
return next(r for r in res["rows"] if r["item"] == name)
def codes(res):
return [(f[0], f[1]) for f in res["findings"]]
log = "2025-01-01,40000,Oil,90,X\n"
r = run(car(), log)
t("rate from readings: 10000 km/year", abs(r["rate"] * 365 - 10000) < 1)
t("due by time first (12 months)", row(r, "Oil")["due_date"] == datetime.date(2026, 1, 1) and row(r, "Oil")["trigger"] == "time")
t("due today counts as due soon", row(r, "Oil")["status"] == "DUE SOON")
r = run(car(), "2025-06-01,40000,Oil,90,X\n")
t("distance triggers first when driving a lot", row(r, "Oil")["due_km"] == 55000 and row(r, "Oil")["trigger"] == "distance")
r = run(car(), "2024-06-01,30000,Oil,90,X\n")
t("overdue by time and distance -> CS01", row(r, "Oil")["status"] == "OVERDUE" and ("medium", "CS01") in codes(r))
sched = [{"item": "Brake fluid", "months": 24, "cost": 80, "safety": True}]
r = run(car(schedule=sched), "2023-06-01,30000,Brake fluid,80,X\n2025-01-01,40000,Other,0,X\n")
t("overdue safety item -> CS01 high", ("high", "CS01") in codes(r))
t("item not in schedule -> CS07", ("info", "CS07") in codes(r))
r = run(car(), "2025-01-01,40000,oil change,90,X\n")
t("aliases match case-insensitively", row(r, "Oil")["last"].startswith("2025-01-01"))
r = run(car(), "2025-01-01,40000,Wipers,20,X\n")
t("no record -> counted from new, CS03", ("medium", "CS03") in codes(r) and "no record" in row(r, "Oil")["last"])
r = run(car(), "2025-01-01,40000,Oil,90,X\n", severe=True)
t("severe intervals used", row(r, "Oil")["due_date"] == datetime.date(2025, 7, 1) and ("info", "CS06") in codes(r))
r = run(car(), "2024-01-01,30000,Oil,90,X\n2024-06-01,20000,Oil,90,X\n2025-01-01,40000,Oil,90,X\n")
t("odometer going down -> CS04, reading ignored", ("medium", "CS04") in codes(r))
r = run(car(), "2025-01-01,40000,Oil,90,X\n2027-01-01,60000,Oil,90,X\n")
t("future date -> CS04 high", ("high", "CS04") in codes(r))
r = run(car(), "2025-01-01,90000,Oil,90,X\n")
t("reading above current odometer -> CS04 high", ("high", "CS04") in codes(r))
r = run(car(), "")
t("no readings -> default rate + CS09", ("medium", "CS09") in codes(r) and abs(r["rate"] * 365 - 12000) < 1)
r = run(car(), "2025-01-01,40000,Oil,90,X\n2025-04-01,42000,Oil,90,X\n")
t("done early -> CS05", ("info", "CS05") in codes(r))
sched = [{"item": "Test", "months": 12, "first_months": 36, "cost": 50, "legal": True}]
r = run(car(vehicle={"first_registered": "2024-01-01"}, schedule=sched), "2025-01-01,40000,Other,0,X\n")
t("first_months for first test from new", row(r, "Test")["due_date"] == datetime.date(2027, 1, 1))
sched = [{"item": "A", "months": 12, "cost": 100}, {"item": "B", "months": 12, "cost": 50}]
r = run(car(schedule=sched), "2025-02-01,41000,A,0,X\n2025-03-15,42000,B,0,X\n")
t("items within the bundle window share a visit", len(r["visits"][0]["items"]) == 2)
t("horizon repeats yearly items", sum(1 for o in r["occ"] if o["item"] == "A") == 2)
t("12-month and total forecast", r["next12"] == 150 and r["total"] == 300)
sched = [{"item": "Belt", "km": 120000, "months": 96, "cost": 650}]
r = run(car(schedule=sched), "2025-01-01,40000,Other,0,X\n")
t("big-ticket item in horizon -> CS08", ("low", "CS08") in codes(r))
t("add_months clamps month end", add_months(datetime.date(2026, 1, 31), 1) == datetime.date(2026, 2, 28))
try:
load_car(car(schedule=[{"item": "X", "cost": 1}])); ok = False
except InputError:
ok = True
t("item without interval rejected", ok)
try:
load_car(dict(car(), colour="red")); ok = False
except InputError:
ok = True
t("unknown key rejected", ok)
r = run(car(), log)
t("report has verdict, visits and forecast", all(s in report(r, "t") for s in ("**Verdict:", "## Workshop visits", "## Cost forecast")))
for name, ok in tests:
print(("PASS " if ok else "FAIL ") + name)
passed = sum(ok for _, ok in tests)
print("%d/%d passed" % (passed, len(tests)))
return 0 if passed == len(tests) else 1
def main(argv=None):
ap = argparse.ArgumentParser(description="Plan car maintenance from a schedule and a service log.")
ap.add_argument("car", nargs="?")
ap.add_argument("log", nargs="?")
ap.add_argument("--odometer", type=float)
ap.add_argument("--today")
ap.add_argument("--severe", action="store_true", default=None, help="use severe-service intervals")
ap.add_argument("--horizon", type=int, help="months to plan (default from car file, else 24)")
ap.add_argument("--json", action="store_true")
ap.add_argument("--self-test", action="store_true")
a = ap.parse_args(argv)
if a.self_test:
return self_test()
if not a.car or not a.log:
ap.print_usage(sys.stderr)
return 2
try:
try:
cfg = json.load(open(a.car, encoding="utf-8"))
except json.JSONDecodeError as e:
raise InputError("car file is not valid JSON: %s" % e)
c = load_car(cfg, a.odometer, a.today, a.severe, a.horizon)
res = plan(c, open(a.log, encoding="utf-8-sig").read())
except (OSError, InputError) as e:
print("error: %s" % e, file=sys.stderr)
return 2
if a.json:
print(json.dumps(to_json(res), indent=2))
else:
sys.stdout.write(report(res, a.log))
return 1 if any(f[0] == "high" for f in res["findings"]) else 0
if __name__ == "__main__":
sys.exit(main())
```
ログインして完全なプロンプトを表示
次で続行:
ログインすると、次に同意したことになります: 利用規約 と プライバシーポリシー
使い方
このプロンプトは productivity 向けに設計されています。上の内容をコピーして、お好みの AI ツールに貼り付けてください。
最良の結果を得るには、プレースホルダー(角括弧や大文字で示された部分)を具体的な要件に置き換えてください。
ノート
0 件のコメント