From bb882bb43410ea4d3f73f81c36f2bc4509b756d2 Mon Sep 17 00:00:00 2001 From: ModelHub XC Date: Tue, 16 Jun 2026 00:53:17 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=EF=BC=8C=E7=94=B1ModelHub=20XC=E7=A4=BE=E5=8C=BA=E6=8F=90?= =?UTF-8?q?=E4=BE=9B=E6=A8=A1=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Model: Shpigford/cron-mini Source: Original Platform --- .gitattributes | 36 + README.md | 140 ++++ chat_template.jinja | 54 ++ config.json | 30 + eval_results.json | 1375 ++++++++++++++++++++++++++++++++++ example.py | 22 + generation_config.json | 14 + model.safetensors | 3 + model.safetensors.index.json | 346 +++++++++ tokenizer.json | 3 + tokenizer_config.json | 31 + 11 files changed, 2054 insertions(+) create mode 100644 .gitattributes create mode 100644 README.md create mode 100644 chat_template.jinja create mode 100644 config.json create mode 100644 eval_results.json create mode 100644 example.py create mode 100644 generation_config.json create mode 100644 model.safetensors create mode 100644 model.safetensors.index.json create mode 100644 tokenizer.json create mode 100644 tokenizer_config.json diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..52373fe --- /dev/null +++ b/.gitattributes @@ -0,0 +1,36 @@ +*.7z filter=lfs diff=lfs merge=lfs -text +*.arrow filter=lfs diff=lfs merge=lfs -text +*.bin filter=lfs diff=lfs merge=lfs -text +*.bz2 filter=lfs diff=lfs merge=lfs -text +*.ckpt filter=lfs diff=lfs merge=lfs -text +*.ftz filter=lfs diff=lfs merge=lfs -text +*.gz filter=lfs diff=lfs merge=lfs -text +*.h5 filter=lfs diff=lfs merge=lfs -text +*.joblib filter=lfs diff=lfs merge=lfs -text +*.lfs.* filter=lfs diff=lfs merge=lfs -text +*.mlmodel filter=lfs diff=lfs merge=lfs -text +*.model filter=lfs diff=lfs merge=lfs -text +*.msgpack filter=lfs diff=lfs merge=lfs -text +*.npy filter=lfs diff=lfs merge=lfs -text +*.npz filter=lfs diff=lfs merge=lfs -text +*.onnx filter=lfs diff=lfs merge=lfs -text +*.ot filter=lfs diff=lfs merge=lfs -text +*.parquet filter=lfs diff=lfs merge=lfs -text +*.pb filter=lfs diff=lfs merge=lfs -text +*.pickle filter=lfs diff=lfs merge=lfs -text +*.pkl filter=lfs diff=lfs merge=lfs -text +*.pt filter=lfs diff=lfs merge=lfs -text +*.pth filter=lfs diff=lfs merge=lfs -text +*.rar filter=lfs diff=lfs merge=lfs -text +*.safetensors filter=lfs diff=lfs merge=lfs -text +saved_model/**/* filter=lfs diff=lfs merge=lfs -text +*.tar.* filter=lfs diff=lfs merge=lfs -text +*.tar filter=lfs diff=lfs merge=lfs -text +*.tflite filter=lfs diff=lfs merge=lfs -text +*.tgz filter=lfs diff=lfs merge=lfs -text +*.wasm filter=lfs diff=lfs merge=lfs -text +*.xz filter=lfs diff=lfs merge=lfs -text +*.zip filter=lfs diff=lfs merge=lfs -text +*.zst filter=lfs diff=lfs merge=lfs -text +*tfevents* filter=lfs diff=lfs merge=lfs -text +tokenizer.json filter=lfs diff=lfs merge=lfs -text diff --git a/README.md b/README.md new file mode 100644 index 0000000..2b2d945 --- /dev/null +++ b/README.md @@ -0,0 +1,140 @@ +--- +license: apache-2.0 +language: + - en +library_name: mlx +pipeline_tag: text-generation +base_model: Qwen/Qwen2.5-1.5B-Instruct +tags: + - cron + - systemd + - devops + - schedule + - text-generation + - mlx + - lora +datasets: + - Shpigford/cron-schedule-conversion +--- + +# Shpigford/cron-mini + +A small fine-tuned language model that converts natural-language schedules into cron expressions and systemd `OnCalendar` strings. + +## What it does + +``` +Input: every Tuesday at 3am except December + +Output: {"cron": "0 3 * 1-11 2", + "systemd": "Tue *-01..11-* 03:00:00", + "note": "Months 1-11 only excludes December."} +``` + +It handles: + +- Standard schedules (daily, weekly, monthly, every N minutes/hours) +- Holidays (Christmas, Thanksgiving, Black Friday, Halloween, etc.) +- Casual time references ("lunchtime", "before bed", "first thing in the morning") +- Ordinal weekdays ("second Tuesday of the month", "last Friday") +- Negative specifications ("every day except Sunday", "all months except December") +- Sub-minute intervals (cron can't, systemd can — model annotates the limitation) +- Awkward intervals (every 90 minutes — cron can't, expanded across the day) +- Compound schedules requiring multiple cron lines +- systemd-specific features (`OnBootSec=`, `Persistent=`, `RandomizedDelaySec=`) +- Time zones (sets `TZ=` for cron, uses `Asia/Tokyo`-style for systemd) +- Typos and informal phrasings ("evry tues @ 3am") + +## Usage + +### MLX (Apple Silicon) + +```python +from mlx_lm import load, generate + +model, tokenizer = load("Shpigford/cron-mini") + +SYSTEM = ("You convert natural-language schedules into cron expressions and " + "systemd OnCalendar strings. Output JSON with keys: cron, systemd, " + "note. If cron cannot exactly express the schedule, put the closest " + "valid cron and explain in note. Do not output anything else.") + +messages = [ + {"role": "system", "content": SYSTEM}, + {"role": "user", "content": "Convert this schedule to cron and systemd OnCalendar: every weekday at 9am"}, +] +prompt = tokenizer.apply_chat_template(messages, add_generation_prompt=True, tokenize=False) +print(generate(model, tokenizer, prompt=prompt, max_tokens=200, temp=0.0)) +``` + +### Transformers (any platform) + +```python +from transformers import AutoModelForCausalLM, AutoTokenizer + +model = AutoModelForCausalLM.from_pretrained("Shpigford/cron-mini", torch_dtype="auto", device_map="auto") +tokenizer = AutoTokenizer.from_pretrained("Shpigford/cron-mini") + +SYSTEM = "..." # same as above +messages = [ + {"role": "system", "content": SYSTEM}, + {"role": "user", "content": "Convert this schedule to cron and systemd OnCalendar: every weekday at 9am"}, +] +inputs = tokenizer.apply_chat_template(messages, add_generation_prompt=True, return_tensors="pt").to(model.device) +out = model.generate(inputs, max_new_tokens=200, do_sample=False) +print(tokenizer.decode(out[0][inputs.shape[1]:], skip_special_tokens=True)) +``` + +### llama.cpp / Ollama (GGUF) + +A GGUF version is available — see the Files tab for `.gguf` files. Load with llama.cpp or import into Ollama: + +```bash +ollama create cron-mini -f Modelfile +``` + +## Evaluation + +Held-out test set of 91 cases including all the trick categories above: + +- **Overall (cron+systemd both correct):** 63/91 (69.2%) +- **Cron exact match:** 73/91 (80.2%) +- **Cron syntactically valid:** 87/91 (95.6%) +- **systemd exact match:** 71/91 (78.0%) + +See `eval_results.json` in this repo for per-case results. + +## Training + +- **Base model:** `Qwen/Qwen2.5-1.5B-Instruct` (Apache 2.0) +- **Method:** LoRA fine-tune via [mlx-lm](https://github.com/ml-explore/mlx-examples/tree/main/llms) +- **Hardware:** M4 Mac mini, 16GB unified memory +- **Dataset:** ~3000 examples — hand-crafted hard cases + templated generation + Claude-API paraphrases and synthetic novel cases (verified with a self-check pass) +- **Dataset on HF:** [Shpigford/cron-schedule-conversion](https://huggingface.co/datasets/Shpigford/cron-schedule-conversion) + +## Limitations + +- The model emits a single best-guess for ambiguous fuzzy times (e.g., "morning" → 7am). It will not ask clarifying questions. +- For "every other Monday" / "biweekly" / "fortnightly" patterns, cron cannot express them natively — the model emits "every Monday" and notes the limitation. Gate in your script with a week-of-year check. +- For "last day of month" / "last Friday", cron has no native expression — the model approximates with day-of-month ranges and flags the limitation. +- Vixie cron OR-matches DOM and DOW when both are restricted; the model emits expressions that work under the more common AND-matching interpretation. Verify on your specific cron implementation. +- Time zone handling: cron has no built-in TZ field; the model emits the schedule in the system's local time and notes when a `TZ=` env var is needed. +- Trained on English. Other languages will likely degrade significantly. + +## License + +Apache 2.0, same as the base model. + +## Citation + +If you find this useful: + +```bibtex +@misc{cron-mini, + author = {Pigford, Josh}, + title = {Cron-Mini: A Small Model for Schedule Conversion}, + year = {2026}, + howpublished = {Hugging Face}, + url = {https://huggingface.co/Shpigford/cron-mini} +} +``` diff --git a/chat_template.jinja b/chat_template.jinja new file mode 100644 index 0000000..bdf7919 --- /dev/null +++ b/chat_template.jinja @@ -0,0 +1,54 @@ +{%- if tools %} + {{- '<|im_start|>system\n' }} + {%- if messages[0]['role'] == 'system' %} + {{- messages[0]['content'] }} + {%- else %} + {{- 'You are Qwen, created by Alibaba Cloud. You are a helpful assistant.' }} + {%- endif %} + {{- "\n\n# Tools\n\nYou may call one or more functions to assist with the user query.\n\nYou are provided with function signatures within XML tags:\n" }} + {%- for tool in tools %} + {{- "\n" }} + {{- tool | tojson }} + {%- endfor %} + {{- "\n\n\nFor each function call, return a json object with function name and arguments within XML tags:\n\n{\"name\": , \"arguments\": }\n<|im_end|>\n" }} +{%- else %} + {%- if messages[0]['role'] == 'system' %} + {{- '<|im_start|>system\n' + messages[0]['content'] + '<|im_end|>\n' }} + {%- else %} + {{- '<|im_start|>system\nYou are Qwen, created by Alibaba Cloud. You are a helpful assistant.<|im_end|>\n' }} + {%- endif %} +{%- endif %} +{%- for message in messages %} + {%- if (message.role == "user") or (message.role == "system" and not loop.first) or (message.role == "assistant" and not message.tool_calls) %} + {{- '<|im_start|>' + message.role + '\n' + message.content + '<|im_end|>' + '\n' }} + {%- elif message.role == "assistant" %} + {{- '<|im_start|>' + message.role }} + {%- if message.content %} + {{- '\n' + message.content }} + {%- endif %} + {%- for tool_call in message.tool_calls %} + {%- if tool_call.function is defined %} + {%- set tool_call = tool_call.function %} + {%- endif %} + {{- '\n\n{"name": "' }} + {{- tool_call.name }} + {{- '", "arguments": ' }} + {{- tool_call.arguments | tojson }} + {{- '}\n' }} + {%- endfor %} + {{- '<|im_end|>\n' }} + {%- elif message.role == "tool" %} + {%- if (loop.index0 == 0) or (messages[loop.index0 - 1].role != "tool") %} + {{- '<|im_start|>user' }} + {%- endif %} + {{- '\n\n' }} + {{- message.content }} + {{- '\n' }} + {%- if loop.last or (messages[loop.index0 + 1].role != "tool") %} + {{- '<|im_end|>\n' }} + {%- endif %} + {%- endif %} +{%- endfor %} +{%- if add_generation_prompt %} + {{- '<|im_start|>assistant\n' }} +{%- endif %} diff --git a/config.json b/config.json new file mode 100644 index 0000000..d8cc8ce --- /dev/null +++ b/config.json @@ -0,0 +1,30 @@ +{ + "architectures": [ + "Qwen2ForCausalLM" + ], + "attention_dropout": 0.0, + "bos_token_id": 151643, + "eos_token_id": [ + 151645, + 151643 + ], + "hidden_act": "silu", + "hidden_size": 1536, + "initializer_range": 0.02, + "intermediate_size": 8960, + "max_position_embeddings": 32768, + "max_window_layers": 21, + "model_type": "qwen2", + "num_attention_heads": 12, + "num_hidden_layers": 28, + "num_key_value_heads": 2, + "rms_norm_eps": 1e-06, + "rope_theta": 1000000.0, + "sliding_window": 32768, + "tie_word_embeddings": true, + "torch_dtype": "bfloat16", + "transformers_version": "4.43.1", + "use_cache": true, + "use_sliding_window": false, + "vocab_size": 151936 +} \ No newline at end of file diff --git a/eval_results.json b/eval_results.json new file mode 100644 index 0000000..2d0a243 --- /dev/null +++ b/eval_results.json @@ -0,0 +1,1375 @@ +{ + "summary": { + "cron_exact": "73/91 (80.2%)", + "cron_valid": "87/91 (95.6%)", + "systemd_exact": "71/91 (78.0%)", + "overall": "63/91 (69.2%)" + }, + "results": [ + { + "nl": "every Tuesday at 3am except December", + "expected": { + "cron": "0 3 * 1-11 2", + "systemd": "Tue *-01..11-* 03:00:00" + }, + "got": { + "cron": "0 3 * 1-11 2", + "systemd": "Tue *-01..11-* 03:00:00", + "note": "Months 1-11 only excludes December." + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "the last Friday of every month at 11pm", + "expected": { + "cron": "0 23 * * 5", + "systemd": "Fri *-*-25..31 23:00:00" + }, + "got": { + "cron": "0 23 25-31 * 5", + "systemd": "Fri *-*-25..31 23:00:00", + "note": "Last Friday of month = DOM 25-31 + Fri (last 7 calendar days always have a Fri)." + }, + "cron_exact": false, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "every other Monday at noon", + "expected": { + "cron": "0 12 * * 1", + "systemd": "Mon *-*-* 12:00:00" + }, + "got": { + "cron": "0 12 * * 1", + "systemd": "Mon *-*-* 12:00:00", + "note": "Cron cannot express 'every other week' \u2014 runs every Monday, gate in script with week-of-year %2." + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "first Sunday of the month at midnight", + "expected": { + "cron": "0 0 1-7 * 0", + "systemd": "Sun *-*-01..07 00:00:00" + }, + "got": { + "cron": "0 0 1-7 * 0", + "systemd": "Sun *-*-01..07 00:00:00", + "note": "Day-of-month 1-7 + specific weekday = first occurrence in the month." + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "second Tuesday of every month at 9am", + "expected": { + "cron": "0 9 8-14 * 2", + "systemd": "Tue *-*-08..14 09:00:00" + }, + "got": { + "cron": "0 9 15-21 * 2", + "systemd": "Tue *-*-15..21 09:00:00", + "note": "Second Tuesday of month = DOM 15-21 + Tue." + }, + "cron_exact": false, + "systemd_exact": false, + "cron_valid": true + }, + { + "nl": "third Thursday of every month at 2pm", + "expected": { + "cron": "0 14 15-21 * 4", + "systemd": "Thu *-*-15..21 14:00:00" + }, + "got": { + "cron": "0 14 15-21 * 4", + "systemd": "Thu *-*-15..21 14:00:00", + "note": "DOM 15-21 + Thu = third Thursday of the month." + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "every Friday the 13th at midnight", + "expected": { + "cron": "0 0 13 * 5", + "systemd": "Fri *-*-13 00:00:00" + }, + "got": { + "cron": "0 0 13 * 5", + "systemd": "Fri *-*-13 00:00:00", + "note": "Vixie cron OR-matches DOM and DOW; use systemd or guard with a date check." + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "every 30 seconds", + "expected": { + "cron": "* * * * *", + "systemd": "*-*-* *:*:0/30" + }, + "got": { + "cron": "* * * * *", + "systemd": "*-*-* *:*:0/30", + "note": "Cron has no sub-minute granularity \u2014 runs every minute." + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "every 10 seconds", + "expected": { + "cron": "* * * * *", + "systemd": "*-*-* *:*:0/10" + }, + "got": { + "cron": "* * * * *", + "systemd": "*-*-* *:*:0/10", + "note": "Cron cannot do sub-minute. systemd: 0/10." + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "every 5 seconds", + "expected": { + "cron": "* * * * *", + "systemd": "*-*-* *:*:0/5" + }, + "got": { + "cron": "* * * * *", + "systemd": "*-*-* *:*:0/5", + "note": "Cron cannot do sub-minute." + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "every second", + "expected": { + "cron": "* * * * *", + "systemd": "*-*-* *:*:*" + }, + "got": { + "cron": "* * * * *", + "systemd": "*-*-* *:*:0", + "note": "Cron has no second-level granularity. Even systemd is not ideal \u2014 consider a long-running daemon." + }, + "cron_exact": true, + "systemd_exact": false, + "cron_valid": true + }, + { + "nl": "every Christmas at 7am", + "expected": { + "cron": "0 7 25 12 *", + "systemd": "*-12-25 07:00:00" + }, + "got": { + "cron": "0 7 25 12 *", + "systemd": "*-12-25 07:00:00", + "note": "" + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "every New Year's Day at midnight", + "expected": { + "cron": "0 0 1 1 *", + "systemd": "*-01-01 00:00:00" + }, + "got": { + "cron": "0 0 1 1 *", + "systemd": "*-01-01 00:00:00", + "note": "" + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "every New Year's Eve at 11:59pm", + "expected": { + "cron": "59 23 31 12 *", + "systemd": "*-12-31 23:59:00" + }, + "got": { + "cron": "59 23 31 12 *", + "systemd": "*-12-31 23:59:00", + "note": "" + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "every Halloween at 6pm", + "expected": { + "cron": "0 18 31 10 *", + "systemd": "*-10-31 18:00:00" + }, + "got": { + "cron": "0 18 31 10 *", + "systemd": "*-10-31 18:00:00", + "note": "" + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "Independence Day at noon", + "expected": { + "cron": "0 12 4 7 *", + "systemd": "*-07-04 12:00:00" + }, + "got": { + "cron": "0 12 4 7 *", + "systemd": "*-07-04 12:00:00", + "note": "" + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "every Valentine's Day at 9am", + "expected": { + "cron": "0 9 14 2 *", + "systemd": "*-02-14 09:00:00" + }, + "got": { + "cron": "0 9 14 2 *", + "systemd": "*-02-14 09:00:00", + "note": "" + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "every leap day at midnight", + "expected": { + "cron": "0 0 29 2 *", + "systemd": "*-02-29 00:00:00" + }, + "got": { + "cron": "0 0 29 2 *", + "systemd": "*-02-29 00:00:00", + "note": "Runs only in leap years." + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "every April Fools' Day at 8am", + "expected": { + "cron": "0 8 1 4 *", + "systemd": "*-04-01 08:00:00" + }, + "got": { + "cron": "0 8 1 4 *", + "systemd": "*-04-01 08:00:00", + "note": "" + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "Black Friday at 6am", + "expected": { + "cron": "0 6 23-29 11 5", + "systemd": "Fri *-11-23..29 06:00:00" + }, + "got": { + "cron": "0 6 23 11 *", + "systemd": "*-11-23 06:00:00", + "note": "" + }, + "cron_exact": false, + "systemd_exact": false, + "cron_valid": true + }, + { + "nl": "every Thanksgiving at 11am", + "expected": { + "cron": "0 11 22-28 11 4", + "systemd": "Thu *-11-22..28 11:00:00" + }, + "got": { + "cron": "0 11 22 11 *", + "systemd": "*-11-22 11:00:00", + "note": "" + }, + "cron_exact": false, + "systemd_exact": false, + "cron_valid": true + }, + { + "nl": "every morning", + "expected": { + "cron": "0 7 * * *", + "systemd": "*-*-* 07:00:00" + }, + "got": { + "cron": "0 7 * * *", + "systemd": "*-*-* 07:00:00", + "note": "'first thing' interpreted as 7am." + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "every night before bed", + "expected": { + "cron": "0 22 * * *", + "systemd": "*-*-* 22:00:00" + }, + "got": { + "cron": "0 22 * * *", + "systemd": "*-*-* 22:00:00", + "note": "'before bed' interpreted as 10pm." + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "first thing in the morning", + "expected": { + "cron": "0 6 * * *", + "systemd": "*-*-* 06:00:00" + }, + "got": { + "cron": "0 6 * * *", + "systemd": "*-*-* 06:00:00", + "note": "'first thing in the morning' interpreted as 6am." + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "at lunchtime every weekday", + "expected": { + "cron": "0 12 * * 1-5", + "systemd": "Mon..Fri *-*-* 12:00:00" + }, + "got": { + "cron": "0 12 * * 1-5", + "systemd": "Mon..Fri *-*-* 12:00:00", + "note": "'lunchtime' interpreted as noon weekdays." + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "at the crack of dawn", + "expected": { + "cron": "0 5 * * *", + "systemd": "*-*-* 05:00:00" + }, + "got": { + "cron": "0 5 * * *", + "systemd": "*-*-* 05:00:00", + "note": "'crack of dawn' interpreted as 5am." + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "every day at end of business", + "expected": { + "cron": "0 17 * * 1-5", + "systemd": "Mon..Fri *-*-* 17:00:00" + }, + "got": { + "cron": "0 17 * * 1-5", + "systemd": "Mon..Fri *-*-* 17:00:00", + "note": "'end of day' interpreted as 5pm weekdays." + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "early morning every Sunday", + "expected": { + "cron": "0 5 * * 0", + "systemd": "Sun *-*-* 05:00:00" + }, + "got": { + "cron": "0 5 * * 0", + "systemd": "Sun *-*-* 5:00:00", + "note": "'first thing' interpreted as 5am." + }, + "cron_exact": true, + "systemd_exact": false, + "cron_valid": true + }, + { + "nl": "every afternoon", + "expected": { + "cron": "0 14 * * *", + "systemd": "*-*-* 14:00:00" + }, + "got": { + "cron": "0 14 * * *", + "systemd": "*-*-* 14:00:00", + "note": "'afternoon' interpreted as 2pm." + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "every evening", + "expected": { + "cron": "0 19 * * *", + "systemd": "*-*-* 19:00:00" + }, + "got": { + "cron": "0 19 * * *", + "systemd": "*-*-* 19:00:00", + "note": "'evening' interpreted as 7pm." + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "around midnight every Friday", + "expected": { + "cron": "0 0 * * 5", + "systemd": "Fri *-*-* 00:00:00" + }, + "got": { + "cron": "0 0 * * 5", + "systemd": "Fri *-*-* 00:00:00", + "note": "" + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "every day except Sunday at 8am", + "expected": { + "cron": "0 8 * * 1-6", + "systemd": "Mon..Sat *-*-* 08:00:00" + }, + "got": { + "cron": "0 8 * * 1-6", + "systemd": "Mon..Sat *-*-* 08:00:00", + "note": "" + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "every minute except between 2am and 3am", + "expected": { + "cron": "* 0-1,3-23 * * *", + "systemd": "*-*-* 00..01,03..23:*:00" + }, + "got": { + "cron": "* 0-1,3-23 * * *", + "systemd": "*-*-* 00..01..03..23:*:00", + "note": "Skip the 2-3 AM hour for backups." + }, + "cron_exact": true, + "systemd_exact": false, + "cron_valid": true + }, + { + "nl": "every hour except midnight", + "expected": { + "cron": "0 1-23 * * *", + "systemd": "*-*-* 01..23:00:00" + }, + "got": { + "cron": "0 1-23 * * *", + "systemd": "*-*-* 01..03:00", + "note": "" + }, + "cron_exact": true, + "systemd_exact": false, + "cron_valid": true + }, + { + "nl": "every day at 9am, but not on weekends", + "expected": { + "cron": "0 9 * * 1-5", + "systemd": "Mon..Fri *-*-* 09:00:00" + }, + "got": { + "cron": "0 9 * * 1-5", + "systemd": "Mon..Fri *-*-* 09:00:00", + "note": "'Not weekends' = Mon-Fri only." + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "every Tuesday at 4pm except in summer", + "expected": { + "cron": "0 16 * 1-5,9-12 2", + "systemd": "Tue *-01..05,09..12-* 16:00:00" + }, + "got": { + "cron": "0 16 * 1-7,9-12 2", + "systemd": "Tue *-01..07,09..12-* 16:00:00", + "note": "All months except August (month 8)." + }, + "cron_exact": false, + "systemd_exact": false, + "cron_valid": true + }, + { + "nl": "every Sunday at 4am except in July", + "expected": { + "cron": "0 4 * 1-6,8-12 0", + "systemd": "Sun *-01..06,08..12-* 04:00:00" + }, + "got": { + "cron": "0 4 * 1-6,8-12 0", + "systemd": "Sun *-01..06,08..12-* 04:00:00", + "note": "Every Sunday at 04:00 for months 1-6, August-December (last day of month = DOM 25-31)." + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "any day except Friday at midnight", + "expected": { + "cron": "0 0 * * 0-4,6", + "systemd": "Sun..Thu,Sat *-*-* 00:00:00" + }, + "got": { + "cron": "0 0 * * 0-4,6", + "systemd": "Sun..Thu,Sat *-*-* 00:00:00", + "note": "Every day except Friday (DOW 5) at midnight." + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "every Tuesday and Thursday at 9am and 3pm", + "expected": { + "cron": "0 9,15 * * 2,4", + "systemd": "Tue,Thu *-*-* 09,15:00:00" + }, + "got": { + "cron": "0 9,15 * * 2,4", + "systemd": "Tue,Thu *-*-* 09,15:00", + "note": "" + }, + "cron_exact": true, + "systemd_exact": false, + "cron_valid": true + }, + { + "nl": "9am Monday through Friday, plus 10am on Saturday", + "expected": { + "cron": "0 9 * * 1-5\n0 10 * * 6", + "systemd": "Mon..Fri *-*-* 09:00:00\nSat *-*-* 10:00:00" + }, + "got": { + "cron": "0 9 * * 1-5\n0 10 * * 6", + "systemd": "Mon..Fri *-*-* 09:00:00\nSat *-*-* 10:00:00", + "note": "Two schedules \u2014 different times for different days." + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "every weekday at 8am and weekends at 10am", + "expected": { + "cron": "0 8 * * 1-5\n0 10 * * 0,6", + "systemd": "Mon..Fri *-*-* 08:00:00\nSat,Sun *-*-* 10:00:00" + }, + "got": { + "cron": "0 8 * * 1-5\n0 10 * * 0,6", + "systemd": "Mon..Fri *-*-* 08:00:00\nSat,Sun *-*-* 10:00:00", + "note": "Two schedules \u2014 earlier weekdays, later weekends." + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "twice a day, at 9am and 5pm, every day", + "expected": { + "cron": "0 9,17 * * *", + "systemd": "*-*-* 09,17:00:00" + }, + "got": { + "cron": "0 9,17 * * *", + "systemd": "*-*-* 09,17:00:00", + "note": "" + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "three times a day at 8am, noon, and 6pm", + "expected": { + "cron": "0 8,12,18 * * *", + "systemd": "*-*-* 08,12,18:00:00" + }, + "got": { + "cron": "0 8,12,18 * * *", + "systemd": "*-*-* 08,12,18:00:00", + "note": "" + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "every weekday at 9, 12, and 3", + "expected": { + "cron": "0 9,12,15 * * 1-5", + "systemd": "Mon..Fri *-*-* 09,12,15:00:00" + }, + "got": { + "cron": "0 9,12,15 * * 1-5", + "systemd": "Mon..Fri *-*-* 9,12,15-*-*", + "note": "Bare numbers in business context default to AM/PM logically \u2014 9am, noon, 3pm." + }, + "cron_exact": true, + "systemd_exact": false, + "cron_valid": true + }, + { + "nl": "every 90 minutes", + "expected": { + "cron": "0,30 0,3,6,9,12,15,18,21 * * *\n0 1,4,7,10,13,16,19,22 * * *", + "systemd": "*-*-* 00/1:30/90:00" + }, + "got": { + "cron": "0,30 0,3,6,9,12,15,18,21 * * *\n0 6,9,12,15,18,21 * *", + "systemd": "*-*-* 06..09,12,15,18,21-*-*", + "note": "Cron has no native 90-min interval; expanded. systemd handles natively." + }, + "cron_exact": false, + "systemd_exact": false, + "cron_valid": false + }, + { + "nl": "every 45 minutes", + "expected": { + "cron": "0,45 0,3,6,9,12,15,18,21 * * *\n30 1,4,7,10,13,16,19,22 * * *", + "systemd": "*-*-* *:0/45:00" + }, + "got": { + "cron": "*/45 * * * *", + "systemd": "*-*-* *:45:00", + "note": "" + }, + "cron_exact": false, + "systemd_exact": false, + "cron_valid": true + }, + { + "nl": "every 100 minutes", + "expected": { + "cron": "* * * * *", + "systemd": "*-*-* 00:00/100:00" + }, + "got": { + "cron": "* * * * *", + "systemd": "*-*-* *:*:0/100", + "note": "Cron cannot express intervals that don't align to 0:00. Use a script gate or systemd timer." + }, + "cron_exact": true, + "systemd_exact": false, + "cron_valid": true + }, + { + "nl": "every 2 hours starting at 1am", + "expected": { + "cron": "0 1,3,5,7,9,11,13,15,17,19,21,23 * * *", + "systemd": "*-*-* 01/2:00:00" + }, + "got": { + "cron": "0 0,3,6,9,12,15,18,21 * * *", + "systemd": "*-*-* 00..03:00/2:00", + "note": "On the 1st of each month at 00:00." + }, + "cron_exact": false, + "systemd_exact": false, + "cron_valid": true + }, + { + "nl": "every 4 hours starting at 2am", + "expected": { + "cron": "0 2,6,10,14,18,22 * * *", + "systemd": "*-*-* 02/4:00:00" + }, + "got": { + "cron": "0 2,4,6,8,10,12,14,16,18,20,22,24 * * *", + "systemd": "*-*-* 02/4:00:00", + "note": "Cron */4 starts at 00:00." + }, + "cron_exact": false, + "systemd_exact": true, + "cron_valid": false + }, + { + "nl": "every 3 hours between 6am and midnight", + "expected": { + "cron": "0 6,9,12,15,18,21 * * *", + "systemd": "*-*-* 06..23:00/180:00" + }, + "got": { + "cron": "0 6,9,12,15,18,21 * * *", + "systemd": "*-*-* 06..23:00/3:00", + "note": "Last fire before midnight \u2014 23:00." + }, + "cron_exact": true, + "systemd_exact": false, + "cron_valid": true + }, + { + "nl": "every hour on the half hour", + "expected": { + "cron": "30 * * * *", + "systemd": "*-*-* *:30:00" + }, + "got": { + "cron": "30 * * * *", + "systemd": "*-*-* *:30:00", + "note": "" + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "every hour at quarter past", + "expected": { + "cron": "15 * * * *", + "systemd": "*-*-* *:15:00" + }, + "got": { + "cron": "15 * * * *", + "systemd": "*-*-* *:15:00", + "note": "" + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "every hour at the 17th minute", + "expected": { + "cron": "17 * * * *", + "systemd": "*-*-* *:17:00" + }, + "got": { + "cron": "17 * * * *", + "systemd": "*-*-* 17:00:00", + "note": "" + }, + "cron_exact": true, + "systemd_exact": false, + "cron_valid": true + }, + { + "nl": "at 23 minutes past every hour during the workday", + "expected": { + "cron": "23 9-17 * * 1-5", + "systemd": "Mon..Fri *-*-* 09..17:23:00" + }, + "got": { + "cron": "23 9-17 * * 1-5", + "systemd": "Mon..Fri *-*-* 09..17:59:00", + "note": "9-17 inclusive covers up to 17:59." + }, + "cron_exact": true, + "systemd_exact": false, + "cron_valid": true + }, + { + "nl": "at 3pm UTC every day", + "expected": { + "cron": "0 15 * * *", + "systemd": "*-*-* 15:00:00 UTC" + }, + "got": { + "cron": "0 15 * * *", + "systemd": "*-*-* 15:00:00 UTC", + "note": "Cron uses system timezone; set TZ=UTC at top of crontab." + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "at 9am Eastern Time every weekday", + "expected": { + "cron": "0 9 * * 1-5", + "systemd": "Mon..Fri *-*-* 09:00:00 America/New_York" + }, + "got": { + "cron": "0 9 * * 1-5", + "systemd": "Mon..Fri *-*-* 09:00:00 America/New_York", + "note": "Cron has no built-in TZ; set TZ=America/New_York in env." + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "5 minutes after every boot", + "expected": { + "cron": "@reboot sleep 300 && cmd", + "systemd": "OnBootSec=5min" + }, + "got": { + "cron": "@reboot sleep 30 && cmd", + "systemd": "OnBootSec=5min", + "note": "Use OnBootSec= in systemd timers (not OnCalendar)." + }, + "cron_exact": false, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "1 hour after the service starts", + "expected": { + "cron": "@reboot sleep 3600 && cmd", + "systemd": "OnUnitActiveSec=1h" + }, + "got": { + "cron": "@reboot sleep 336 && cmd", + "systemd": "OnUnitActiveSec=1h", + "note": "OnUnitActiveSec= = relative to service activation. systemd-only feature." + }, + "cron_exact": false, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "if missed during shutdown, run on next boot", + "expected": { + "cron": "0 0 * * *", + "systemd": "OnCalendar=daily\nPersistent=true" + }, + "got": { + "cron": "0 0 * * *", + "systemd": "OnCalendar=daily\nPersistent=true", + "note": "Persistent=true is a systemd-specific flag \u2014 runs missed jobs on next boot. Cron has no equivalent." + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "with random delay up to 30 minutes, every hour", + "expected": { + "cron": "0 * * * * sleep $((RANDOM % 1800))", + "systemd": "OnCalendar=hourly\nRandomizedDelaySec=30min" + }, + "got": { + "cron": "0 * * * *", + "systemd": "OnCalendar=hourly\nRandomizedDelaySec=30min", + "note": "RandomizedDelaySec= adds jitter \u2014 systemd-only." + }, + "cron_exact": false, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "first weekday of every month at 8am", + "expected": { + "cron": "0 8 1-3 * 1-5", + "systemd": "Mon..Fri *-*-01..03 08:00:00" + }, + "got": { + "cron": "0 8 1-3 * 1-5", + "systemd": "Mon..Fri *-*-01..03 08:00:00", + "note": "First weekday of month = DOM 1-3 + Mon-Fri (by day 4 there's always been a weekday)." + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "at the top of every hour", + "expected": { + "cron": "0 * * * *", + "systemd": "*-*-* *:00:00" + }, + "got": { + "cron": "0:00 * * * *", + "systemd": "*-*-* 00:00:00", + "note": "" + }, + "cron_exact": false, + "systemd_exact": false, + "cron_valid": false + }, + { + "nl": "every 15 minutes", + "expected": { + "cron": "*/15 * * * *", + "systemd": "*-*-* *:0/15:00" + }, + "got": { + "cron": "*/15 * * * *", + "systemd": "*-*-* *:0/15:00", + "note": "" + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "every 5 minutes", + "expected": { + "cron": "*/5 * * * *", + "systemd": "*-*-* *:0/5:00" + }, + "got": { + "cron": "*/5 * * * *", + "systemd": "*-*-* *:0/5:00", + "note": "" + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "every Sunday at 2:15am", + "expected": { + "cron": "15 2 * * 0", + "systemd": "Sun *-*-* 02:15:00" + }, + "got": { + "cron": "15 2 * * 0", + "systemd": "Sun *-*-* 02:15:00", + "note": "" + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "rotate logs nightly at 3am", + "expected": { + "cron": "0 3 * * *", + "systemd": "*-*-* 03:00:00" + }, + "got": { + "cron": "0 3 * * *", + "systemd": "*-*-* 03:00:00", + "note": "" + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "weekly maintenance Sunday at 4am", + "expected": { + "cron": "0 4 * * 0", + "systemd": "Sun *-*-* 04:00:00" + }, + "got": { + "cron": "0 4 * * 0", + "systemd": "Sun *-*-* 04:00:00", + "note": "" + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "first day of each quarter at midnight", + "expected": { + "cron": "0 0 1 1,4,7,10 *", + "systemd": "*-01,04,07,10-01 00:00:00" + }, + "got": { + "cron": "0 0 1 1,4,7,10 *", + "systemd": "*-01,04,07,10-01 00:00:00", + "note": "" + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "last day of each quarter at 6pm", + "expected": { + "cron": "0 18 28-31 3,6,9,12 *", + "systemd": "*-03,06,09,12-* 18:00:00" + }, + "got": { + "cron": "30 18 28-31 3,6,9,12 *", + "systemd": "*-03,06,09,12-* 18:00:00", + "note": "Last day of quarter \u2014 cron approximates with DOM 28-31, needs date check." + }, + "cron_exact": false, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "first Monday of each quarter", + "expected": { + "cron": "0 0 1-7 1,4,7,10 1", + "systemd": "Mon *-01,04,07,10-01..07 00:00:00" + }, + "got": { + "cron": "0 0 1-7 1,4,7,10 1", + "systemd": "Mon *-01,04,07,10-01..07 00:00:00", + "note": "" + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "every fiscal year start (April 1)", + "expected": { + "cron": "0 0 1 4 *", + "systemd": "*-04-01 00:00:00" + }, + "got": { + "cron": "0 0 1 4 *", + "systemd": "*-04-01 00:00:00", + "note": "" + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "twice an hour", + "expected": { + "cron": "0,30 * * * *", + "systemd": "*-*-* *:00,30:00" + }, + "got": { + "cron": "0,30 * * * *", + "systemd": "*-*-* *:00,30:00", + "note": "On the hour and half hour. Use list 0,30 not */30 to be explicit." + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "four times a day at quarter days", + "expected": { + "cron": "0 0,6,12,18 * * *", + "systemd": "*-*-* 00,06,12,18:00:00" + }, + "got": { + "cron": "0 9,15,19,21 * * *", + "systemd": "*-09,15,19,21-* 09,15,19,21", + "note": "" + }, + "cron_exact": false, + "systemd_exact": false, + "cron_valid": true + }, + { + "nl": "biweekly on Friday at 5pm", + "expected": { + "cron": "0 17 * * 5", + "systemd": "Fri *-*-* 17:00:00" + }, + "got": { + "cron": "0 17 * * 5", + "systemd": "Fri *-*-* 17:00:00", + "note": "Cron cannot express 'every other Friday' \u2014 runs this Friday; gate in script with day-of-month %2." + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "fortnightly on Monday morning", + "expected": { + "cron": "0 9 * * 1", + "systemd": "Mon *-*-* 09:00:00" + }, + "got": { + "cron": "0 9 * * 1", + "systemd": "Mon *-*-* 09:00:00", + "note": "Fortnightly = every 2 weeks. Cron cannot natively. Gate in script." + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "every minute between 9am and 5pm on weekdays", + "expected": { + "cron": "* 9-16 * * 1-5", + "systemd": "Mon..Fri *-*-* 09..16:*:00" + }, + "got": { + "cron": "* 9-16 * * 1-5", + "systemd": "Mon..Fri *-*-* 09..16:*:00", + "note": "9-16 inclusive covers 9:00 to 16:59 (just before 5pm)." + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "every 10 minutes from 8am to 6pm exclusive", + "expected": { + "cron": "*/10 8-17 * * *", + "systemd": "*-*-* 08..17:00/10:00" + }, + "got": { + "cron": "*/10 8-17 * * 1-5", + "systemd": "Mon..Fri *-*-* 08..17:00/10:00", + "note": "8-17 inclusive covers up to 17:59." + }, + "cron_exact": false, + "systemd_exact": false, + "cron_valid": true + }, + { + "nl": "at 11:59pm on December 31st", + "expected": { + "cron": "59 23 31 12 *", + "systemd": "*-12-31 23:59:00" + }, + "got": { + "cron": "59 23 31 12 *", + "systemd": "*-12-31 23:59:00", + "note": "" + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "noon on March 1st", + "expected": { + "cron": "0 12 1 3 *", + "systemd": "*-03-01 12:00:00" + }, + "got": { + "cron": "0 12 1 3 *", + "systemd": "*-03-01 12:00:00", + "note": "" + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "8am on the 15th of every month", + "expected": { + "cron": "0 8 15 * *", + "systemd": "*-*-15 08:00:00" + }, + "got": { + "cron": "0 8 15 * *", + "systemd": "*-*-15 08:00:00", + "note": "" + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "every Sunday at 6am", + "expected": { + "cron": "0 6 * * 0", + "systemd": "Sun *-*-* 06:00:00" + }, + "got": { + "cron": "0 6 * * 0", + "systemd": "Sun *-*-* 06:00:00", + "note": "" + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "every Saturday night at 11pm", + "expected": { + "cron": "0 23 * * 6", + "systemd": "Sat *-*-* 23:00:00" + }, + "got": { + "cron": "0 23 * * 6", + "systemd": "Sat *-*-* 23:00:00", + "note": "" + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "every day in March", + "expected": { + "cron": "0 0 * 3 *", + "systemd": "*-03-* 00:00:00" + }, + "got": { + "cron": "0 0 * 3 *", + "systemd": "*-03-* 00:00:00", + "note": "Defaults to midnight." + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "weekdays in Q1 at 9am", + "expected": { + "cron": "0 9 * 1-3 1-5", + "systemd": "Mon..Fri *-01..03-* 09:00:00" + }, + "got": { + "cron": "0 9 * 1-3 1-5", + "systemd": "Mon..Fri *-01..03-* 09:00:00", + "note": "" + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "every minute on the dot", + "expected": { + "cron": "* * * * *", + "systemd": "*-*-* *:*:00" + }, + "got": { + "cron": "* * * * *", + "systemd": "*-*-* *:*:00", + "note": "" + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "every Friday at 4:20pm", + "expected": { + "cron": "20 16 * * 5", + "systemd": "Fri *-*-* 16:20:00" + }, + "got": { + "cron": "20 16 * * 5", + "systemd": "Fri *-*-* 16:20:00", + "note": "" + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "every prime-numbered minute of every hour", + "expected": { + "cron": "2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59 * * * *", + "systemd": "*-*-* *:02,03,05,07,11,13,17,19,23,29,31,37,41,43,47,53,59:00" + }, + "got": { + "cron": "2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59 * * *", + "systemd": "*-*-* *:02,03,05,07,11,13,17,19,23,29,31,37,41,43,47,53,59:00", + "note": "Listed primes 0-59." + }, + "cron_exact": false, + "systemd_exact": true, + "cron_valid": false + }, + { + "nl": "every Monday and Wednesday at 6am from March to October", + "expected": { + "cron": "0 6 * 3-10 1,3", + "systemd": "Mon,Wed *-03..10-* 06:00:00" + }, + "got": { + "cron": "0 6 * 3-10 1,3", + "systemd": "Mon,Wed *-03..10-* 06:00:00", + "note": "Mon and Wed at 6am, March through October only." + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "every 45 minutes during weekday afternoons", + "expected": { + "cron": "0,45 12-16 * * 1-5\n30 13,15 * * 1-5", + "systemd": "Mon..Fri *-*-* 12..16:00/45:00" + }, + "got": { + "cron": "0,45 12-16 * * 1-5", + "systemd": "Mon..Fri *-*-* 12..16:00/45:00", + "note": "45-min interval during weekday afternoons; expanded." + }, + "cron_exact": false, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "every other Wednesday at 7pm", + "expected": { + "cron": "0 19 * * 3", + "systemd": "Wed *-*-* 19:00:00" + }, + "got": { + "cron": "0 19 * * 3", + "systemd": "Wed *-*-* 19:00:00", + "note": "Cron cannot express 'every other Wednesday' \u2014 runs every Wednesday at 7pm, gate in script with week-of-year %2." + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + }, + { + "nl": "sunset every Friday (7pm)", + "expected": { + "cron": "0 19 * * 5", + "systemd": "Fri *-*-* 19:00:00" + }, + "got": { + "cron": "0 19 * * 5", + "systemd": "Fri *-*-* 19:00:00", + "note": "'before bed' interpreted as 7pm." + }, + "cron_exact": true, + "systemd_exact": true, + "cron_valid": true + } + ] +} \ No newline at end of file diff --git a/example.py b/example.py new file mode 100644 index 0000000..cf148e9 --- /dev/null +++ b/example.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 +"""Minimal inference example for Shpigford/cron-mini.""" +from mlx_lm import load, generate + +model, tokenizer = load("Shpigford/cron-mini") + +SYSTEM = ("You convert natural-language schedules into cron expressions and " + "systemd OnCalendar strings. Output JSON with keys: cron, systemd, " + "note. If cron cannot exactly express the schedule, put the closest " + "valid cron and explain in note. Do not output anything else.") + +def schedule_to_cron(nl: str) -> str: + messages = [ + {"role": "system", "content": SYSTEM}, + {"role": "user", "content": f"Convert this schedule to cron and systemd OnCalendar: {nl}"}, + ] + prompt = tokenizer.apply_chat_template(messages, add_generation_prompt=True, tokenize=False) + return generate(model, tokenizer, prompt=prompt, max_tokens=200, temp=0.0) + +if __name__ == "__main__": + import sys + print(schedule_to_cron(" ".join(sys.argv[1:]) or "every weekday at 9am")) diff --git a/generation_config.json b/generation_config.json new file mode 100644 index 0000000..dfc1107 --- /dev/null +++ b/generation_config.json @@ -0,0 +1,14 @@ +{ + "bos_token_id": 151643, + "pad_token_id": 151643, + "do_sample": true, + "eos_token_id": [ + 151645, + 151643 + ], + "repetition_penalty": 1.1, + "temperature": 0.7, + "top_p": 0.8, + "top_k": 20, + "transformers_version": "4.37.0" +} diff --git a/model.safetensors b/model.safetensors new file mode 100644 index 0000000..f6bd4d6 --- /dev/null +++ b/model.safetensors @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:072605ba0699270bf57e8491b0b2d78304b5b71e653d177c5d2af3f47f4aad5c +size 3087467005 diff --git a/model.safetensors.index.json b/model.safetensors.index.json new file mode 100644 index 0000000..36ed6c9 --- /dev/null +++ b/model.safetensors.index.json @@ -0,0 +1,346 @@ +{ + "metadata": { + "total_size": 3087428608, + "total_parameters": 1543714304 + }, + "weight_map": { + "model.embed_tokens.weight": "model.safetensors", + "model.layers.0.input_layernorm.weight": "model.safetensors", + "model.layers.0.mlp.down_proj.weight": "model.safetensors", + "model.layers.0.mlp.gate_proj.weight": "model.safetensors", + "model.layers.0.mlp.up_proj.weight": "model.safetensors", + "model.layers.0.post_attention_layernorm.weight": "model.safetensors", + "model.layers.0.self_attn.k_proj.bias": "model.safetensors", + "model.layers.0.self_attn.k_proj.weight": "model.safetensors", + "model.layers.0.self_attn.o_proj.weight": "model.safetensors", + "model.layers.0.self_attn.q_proj.bias": "model.safetensors", + "model.layers.0.self_attn.q_proj.weight": "model.safetensors", + "model.layers.0.self_attn.v_proj.bias": "model.safetensors", + "model.layers.0.self_attn.v_proj.weight": "model.safetensors", + "model.layers.1.input_layernorm.weight": "model.safetensors", + "model.layers.1.mlp.down_proj.weight": "model.safetensors", + "model.layers.1.mlp.gate_proj.weight": "model.safetensors", + "model.layers.1.mlp.up_proj.weight": "model.safetensors", + "model.layers.1.post_attention_layernorm.weight": "model.safetensors", + "model.layers.1.self_attn.k_proj.bias": "model.safetensors", + "model.layers.1.self_attn.k_proj.weight": "model.safetensors", + "model.layers.1.self_attn.o_proj.weight": "model.safetensors", + "model.layers.1.self_attn.q_proj.bias": "model.safetensors", + "model.layers.1.self_attn.q_proj.weight": "model.safetensors", + "model.layers.1.self_attn.v_proj.bias": "model.safetensors", + "model.layers.1.self_attn.v_proj.weight": "model.safetensors", + "model.layers.10.input_layernorm.weight": "model.safetensors", + "model.layers.10.mlp.down_proj.weight": "model.safetensors", + "model.layers.10.mlp.gate_proj.weight": "model.safetensors", + "model.layers.10.mlp.up_proj.weight": "model.safetensors", + "model.layers.10.post_attention_layernorm.weight": "model.safetensors", + "model.layers.10.self_attn.k_proj.bias": "model.safetensors", + "model.layers.10.self_attn.k_proj.weight": "model.safetensors", + "model.layers.10.self_attn.o_proj.weight": "model.safetensors", + "model.layers.10.self_attn.q_proj.bias": "model.safetensors", + "model.layers.10.self_attn.q_proj.weight": "model.safetensors", + "model.layers.10.self_attn.v_proj.bias": "model.safetensors", + "model.layers.10.self_attn.v_proj.weight": "model.safetensors", + "model.layers.11.input_layernorm.weight": "model.safetensors", + "model.layers.11.mlp.down_proj.weight": "model.safetensors", + "model.layers.11.mlp.gate_proj.weight": "model.safetensors", + "model.layers.11.mlp.up_proj.weight": "model.safetensors", + "model.layers.11.post_attention_layernorm.weight": "model.safetensors", + "model.layers.11.self_attn.k_proj.bias": "model.safetensors", + "model.layers.11.self_attn.k_proj.weight": "model.safetensors", + "model.layers.11.self_attn.o_proj.weight": "model.safetensors", + "model.layers.11.self_attn.q_proj.bias": "model.safetensors", + "model.layers.11.self_attn.q_proj.weight": "model.safetensors", + "model.layers.11.self_attn.v_proj.bias": "model.safetensors", + "model.layers.11.self_attn.v_proj.weight": "model.safetensors", + "model.layers.12.input_layernorm.weight": "model.safetensors", + "model.layers.12.mlp.down_proj.weight": "model.safetensors", + "model.layers.12.mlp.gate_proj.weight": "model.safetensors", + "model.layers.12.mlp.up_proj.weight": "model.safetensors", + "model.layers.12.post_attention_layernorm.weight": "model.safetensors", + "model.layers.12.self_attn.k_proj.bias": "model.safetensors", + "model.layers.12.self_attn.k_proj.weight": "model.safetensors", + "model.layers.12.self_attn.o_proj.weight": "model.safetensors", + "model.layers.12.self_attn.q_proj.bias": "model.safetensors", + "model.layers.12.self_attn.q_proj.weight": "model.safetensors", + "model.layers.12.self_attn.v_proj.bias": "model.safetensors", + "model.layers.12.self_attn.v_proj.weight": "model.safetensors", + "model.layers.13.input_layernorm.weight": "model.safetensors", + "model.layers.13.mlp.down_proj.weight": "model.safetensors", + "model.layers.13.mlp.gate_proj.weight": "model.safetensors", + "model.layers.13.mlp.up_proj.weight": "model.safetensors", + "model.layers.13.post_attention_layernorm.weight": "model.safetensors", + "model.layers.13.self_attn.k_proj.bias": "model.safetensors", + "model.layers.13.self_attn.k_proj.weight": "model.safetensors", + "model.layers.13.self_attn.o_proj.weight": "model.safetensors", + "model.layers.13.self_attn.q_proj.bias": "model.safetensors", + "model.layers.13.self_attn.q_proj.weight": "model.safetensors", + "model.layers.13.self_attn.v_proj.bias": "model.safetensors", + "model.layers.13.self_attn.v_proj.weight": "model.safetensors", + "model.layers.14.input_layernorm.weight": "model.safetensors", + "model.layers.14.mlp.down_proj.weight": "model.safetensors", + "model.layers.14.mlp.gate_proj.weight": "model.safetensors", + "model.layers.14.mlp.up_proj.weight": "model.safetensors", + "model.layers.14.post_attention_layernorm.weight": "model.safetensors", + "model.layers.14.self_attn.k_proj.bias": "model.safetensors", + "model.layers.14.self_attn.k_proj.weight": "model.safetensors", + "model.layers.14.self_attn.o_proj.weight": "model.safetensors", + "model.layers.14.self_attn.q_proj.bias": "model.safetensors", + "model.layers.14.self_attn.q_proj.weight": "model.safetensors", + "model.layers.14.self_attn.v_proj.bias": "model.safetensors", + "model.layers.14.self_attn.v_proj.weight": "model.safetensors", + "model.layers.15.input_layernorm.weight": "model.safetensors", + "model.layers.15.mlp.down_proj.weight": "model.safetensors", + "model.layers.15.mlp.gate_proj.weight": "model.safetensors", + "model.layers.15.mlp.up_proj.weight": "model.safetensors", + "model.layers.15.post_attention_layernorm.weight": "model.safetensors", + "model.layers.15.self_attn.k_proj.bias": "model.safetensors", + "model.layers.15.self_attn.k_proj.weight": "model.safetensors", + "model.layers.15.self_attn.o_proj.weight": "model.safetensors", + "model.layers.15.self_attn.q_proj.bias": "model.safetensors", + "model.layers.15.self_attn.q_proj.weight": "model.safetensors", + "model.layers.15.self_attn.v_proj.bias": "model.safetensors", + "model.layers.15.self_attn.v_proj.weight": "model.safetensors", + "model.layers.16.input_layernorm.weight": "model.safetensors", + "model.layers.16.mlp.down_proj.weight": "model.safetensors", + "model.layers.16.mlp.gate_proj.weight": "model.safetensors", + "model.layers.16.mlp.up_proj.weight": "model.safetensors", + "model.layers.16.post_attention_layernorm.weight": "model.safetensors", + "model.layers.16.self_attn.k_proj.bias": "model.safetensors", + "model.layers.16.self_attn.k_proj.weight": "model.safetensors", + "model.layers.16.self_attn.o_proj.weight": "model.safetensors", + "model.layers.16.self_attn.q_proj.bias": "model.safetensors", + "model.layers.16.self_attn.q_proj.weight": "model.safetensors", + "model.layers.16.self_attn.v_proj.bias": "model.safetensors", + "model.layers.16.self_attn.v_proj.weight": "model.safetensors", + "model.layers.17.input_layernorm.weight": "model.safetensors", + "model.layers.17.mlp.down_proj.weight": "model.safetensors", + "model.layers.17.mlp.gate_proj.weight": "model.safetensors", + "model.layers.17.mlp.up_proj.weight": "model.safetensors", + "model.layers.17.post_attention_layernorm.weight": "model.safetensors", + "model.layers.17.self_attn.k_proj.bias": "model.safetensors", + "model.layers.17.self_attn.k_proj.weight": "model.safetensors", + "model.layers.17.self_attn.o_proj.weight": "model.safetensors", + "model.layers.17.self_attn.q_proj.bias": "model.safetensors", + "model.layers.17.self_attn.q_proj.weight": "model.safetensors", + "model.layers.17.self_attn.v_proj.bias": "model.safetensors", + "model.layers.17.self_attn.v_proj.weight": "model.safetensors", + "model.layers.18.input_layernorm.weight": "model.safetensors", + "model.layers.18.mlp.down_proj.weight": "model.safetensors", + "model.layers.18.mlp.gate_proj.weight": "model.safetensors", + "model.layers.18.mlp.up_proj.weight": "model.safetensors", + "model.layers.18.post_attention_layernorm.weight": "model.safetensors", + "model.layers.18.self_attn.k_proj.bias": "model.safetensors", + "model.layers.18.self_attn.k_proj.weight": "model.safetensors", + "model.layers.18.self_attn.o_proj.weight": "model.safetensors", + "model.layers.18.self_attn.q_proj.bias": "model.safetensors", + "model.layers.18.self_attn.q_proj.weight": "model.safetensors", + "model.layers.18.self_attn.v_proj.bias": "model.safetensors", + "model.layers.18.self_attn.v_proj.weight": "model.safetensors", + "model.layers.19.input_layernorm.weight": "model.safetensors", + "model.layers.19.mlp.down_proj.weight": "model.safetensors", + "model.layers.19.mlp.gate_proj.weight": "model.safetensors", + "model.layers.19.mlp.up_proj.weight": "model.safetensors", + "model.layers.19.post_attention_layernorm.weight": "model.safetensors", + "model.layers.19.self_attn.k_proj.bias": "model.safetensors", + "model.layers.19.self_attn.k_proj.weight": "model.safetensors", + "model.layers.19.self_attn.o_proj.weight": "model.safetensors", + "model.layers.19.self_attn.q_proj.bias": "model.safetensors", + "model.layers.19.self_attn.q_proj.weight": "model.safetensors", + "model.layers.19.self_attn.v_proj.bias": "model.safetensors", + "model.layers.19.self_attn.v_proj.weight": "model.safetensors", + "model.layers.2.input_layernorm.weight": "model.safetensors", + "model.layers.2.mlp.down_proj.weight": "model.safetensors", + "model.layers.2.mlp.gate_proj.weight": "model.safetensors", + "model.layers.2.mlp.up_proj.weight": "model.safetensors", + "model.layers.2.post_attention_layernorm.weight": "model.safetensors", + "model.layers.2.self_attn.k_proj.bias": "model.safetensors", + "model.layers.2.self_attn.k_proj.weight": "model.safetensors", + "model.layers.2.self_attn.o_proj.weight": "model.safetensors", + "model.layers.2.self_attn.q_proj.bias": "model.safetensors", + "model.layers.2.self_attn.q_proj.weight": "model.safetensors", + "model.layers.2.self_attn.v_proj.bias": "model.safetensors", + "model.layers.2.self_attn.v_proj.weight": "model.safetensors", + "model.layers.20.input_layernorm.weight": "model.safetensors", + "model.layers.20.mlp.down_proj.weight": "model.safetensors", + "model.layers.20.mlp.gate_proj.weight": "model.safetensors", + "model.layers.20.mlp.up_proj.weight": "model.safetensors", + "model.layers.20.post_attention_layernorm.weight": "model.safetensors", + "model.layers.20.self_attn.k_proj.bias": "model.safetensors", + "model.layers.20.self_attn.k_proj.weight": "model.safetensors", + "model.layers.20.self_attn.o_proj.weight": "model.safetensors", + "model.layers.20.self_attn.q_proj.bias": "model.safetensors", + "model.layers.20.self_attn.q_proj.weight": "model.safetensors", + "model.layers.20.self_attn.v_proj.bias": "model.safetensors", + "model.layers.20.self_attn.v_proj.weight": "model.safetensors", + "model.layers.21.input_layernorm.weight": "model.safetensors", + "model.layers.21.mlp.down_proj.weight": "model.safetensors", + "model.layers.21.mlp.gate_proj.weight": "model.safetensors", + "model.layers.21.mlp.up_proj.weight": "model.safetensors", + "model.layers.21.post_attention_layernorm.weight": "model.safetensors", + "model.layers.21.self_attn.k_proj.bias": "model.safetensors", + "model.layers.21.self_attn.k_proj.weight": "model.safetensors", + "model.layers.21.self_attn.o_proj.weight": "model.safetensors", + "model.layers.21.self_attn.q_proj.bias": "model.safetensors", + "model.layers.21.self_attn.q_proj.weight": "model.safetensors", + "model.layers.21.self_attn.v_proj.bias": "model.safetensors", + "model.layers.21.self_attn.v_proj.weight": "model.safetensors", + "model.layers.22.input_layernorm.weight": "model.safetensors", + "model.layers.22.mlp.down_proj.weight": "model.safetensors", + "model.layers.22.mlp.gate_proj.weight": "model.safetensors", + "model.layers.22.mlp.up_proj.weight": "model.safetensors", + "model.layers.22.post_attention_layernorm.weight": "model.safetensors", + "model.layers.22.self_attn.k_proj.bias": "model.safetensors", + "model.layers.22.self_attn.k_proj.weight": "model.safetensors", + "model.layers.22.self_attn.o_proj.weight": "model.safetensors", + "model.layers.22.self_attn.q_proj.bias": "model.safetensors", + "model.layers.22.self_attn.q_proj.weight": "model.safetensors", + "model.layers.22.self_attn.v_proj.bias": "model.safetensors", + "model.layers.22.self_attn.v_proj.weight": "model.safetensors", + "model.layers.23.input_layernorm.weight": "model.safetensors", + "model.layers.23.mlp.down_proj.weight": "model.safetensors", + "model.layers.23.mlp.gate_proj.weight": "model.safetensors", + "model.layers.23.mlp.up_proj.weight": "model.safetensors", + "model.layers.23.post_attention_layernorm.weight": "model.safetensors", + "model.layers.23.self_attn.k_proj.bias": "model.safetensors", + "model.layers.23.self_attn.k_proj.weight": "model.safetensors", + "model.layers.23.self_attn.o_proj.weight": "model.safetensors", + "model.layers.23.self_attn.q_proj.bias": "model.safetensors", + "model.layers.23.self_attn.q_proj.weight": "model.safetensors", + "model.layers.23.self_attn.v_proj.bias": "model.safetensors", + "model.layers.23.self_attn.v_proj.weight": "model.safetensors", + "model.layers.24.input_layernorm.weight": "model.safetensors", + "model.layers.24.mlp.down_proj.weight": "model.safetensors", + "model.layers.24.mlp.gate_proj.weight": "model.safetensors", + "model.layers.24.mlp.up_proj.weight": "model.safetensors", + "model.layers.24.post_attention_layernorm.weight": "model.safetensors", + "model.layers.24.self_attn.k_proj.bias": "model.safetensors", + "model.layers.24.self_attn.k_proj.weight": "model.safetensors", + "model.layers.24.self_attn.o_proj.weight": "model.safetensors", + "model.layers.24.self_attn.q_proj.bias": "model.safetensors", + "model.layers.24.self_attn.q_proj.weight": "model.safetensors", + "model.layers.24.self_attn.v_proj.bias": "model.safetensors", + "model.layers.24.self_attn.v_proj.weight": "model.safetensors", + "model.layers.25.input_layernorm.weight": "model.safetensors", + "model.layers.25.mlp.down_proj.weight": "model.safetensors", + "model.layers.25.mlp.gate_proj.weight": "model.safetensors", + "model.layers.25.mlp.up_proj.weight": "model.safetensors", + "model.layers.25.post_attention_layernorm.weight": "model.safetensors", + "model.layers.25.self_attn.k_proj.bias": "model.safetensors", + "model.layers.25.self_attn.k_proj.weight": "model.safetensors", + "model.layers.25.self_attn.o_proj.weight": "model.safetensors", + "model.layers.25.self_attn.q_proj.bias": "model.safetensors", + "model.layers.25.self_attn.q_proj.weight": "model.safetensors", + "model.layers.25.self_attn.v_proj.bias": "model.safetensors", + "model.layers.25.self_attn.v_proj.weight": "model.safetensors", + "model.layers.26.input_layernorm.weight": "model.safetensors", + "model.layers.26.mlp.down_proj.weight": "model.safetensors", + "model.layers.26.mlp.gate_proj.weight": "model.safetensors", + "model.layers.26.mlp.up_proj.weight": "model.safetensors", + "model.layers.26.post_attention_layernorm.weight": "model.safetensors", + "model.layers.26.self_attn.k_proj.bias": "model.safetensors", + "model.layers.26.self_attn.k_proj.weight": "model.safetensors", + "model.layers.26.self_attn.o_proj.weight": "model.safetensors", + "model.layers.26.self_attn.q_proj.bias": "model.safetensors", + "model.layers.26.self_attn.q_proj.weight": "model.safetensors", + "model.layers.26.self_attn.v_proj.bias": "model.safetensors", + "model.layers.26.self_attn.v_proj.weight": "model.safetensors", + "model.layers.27.input_layernorm.weight": "model.safetensors", + "model.layers.27.mlp.down_proj.weight": "model.safetensors", + "model.layers.27.mlp.gate_proj.weight": "model.safetensors", + "model.layers.27.mlp.up_proj.weight": "model.safetensors", + "model.layers.27.post_attention_layernorm.weight": "model.safetensors", + "model.layers.27.self_attn.k_proj.bias": "model.safetensors", + "model.layers.27.self_attn.k_proj.weight": "model.safetensors", + "model.layers.27.self_attn.o_proj.weight": "model.safetensors", + "model.layers.27.self_attn.q_proj.bias": "model.safetensors", + "model.layers.27.self_attn.q_proj.weight": "model.safetensors", + "model.layers.27.self_attn.v_proj.bias": "model.safetensors", + "model.layers.27.self_attn.v_proj.weight": "model.safetensors", + "model.layers.3.input_layernorm.weight": "model.safetensors", + "model.layers.3.mlp.down_proj.weight": "model.safetensors", + "model.layers.3.mlp.gate_proj.weight": "model.safetensors", + "model.layers.3.mlp.up_proj.weight": "model.safetensors", + "model.layers.3.post_attention_layernorm.weight": "model.safetensors", + "model.layers.3.self_attn.k_proj.bias": "model.safetensors", + "model.layers.3.self_attn.k_proj.weight": "model.safetensors", + "model.layers.3.self_attn.o_proj.weight": "model.safetensors", + "model.layers.3.self_attn.q_proj.bias": "model.safetensors", + "model.layers.3.self_attn.q_proj.weight": "model.safetensors", + "model.layers.3.self_attn.v_proj.bias": "model.safetensors", + "model.layers.3.self_attn.v_proj.weight": "model.safetensors", + "model.layers.4.input_layernorm.weight": "model.safetensors", + "model.layers.4.mlp.down_proj.weight": "model.safetensors", + "model.layers.4.mlp.gate_proj.weight": "model.safetensors", + "model.layers.4.mlp.up_proj.weight": "model.safetensors", + "model.layers.4.post_attention_layernorm.weight": "model.safetensors", + "model.layers.4.self_attn.k_proj.bias": "model.safetensors", + "model.layers.4.self_attn.k_proj.weight": "model.safetensors", + "model.layers.4.self_attn.o_proj.weight": "model.safetensors", + "model.layers.4.self_attn.q_proj.bias": "model.safetensors", + "model.layers.4.self_attn.q_proj.weight": "model.safetensors", + "model.layers.4.self_attn.v_proj.bias": "model.safetensors", + "model.layers.4.self_attn.v_proj.weight": "model.safetensors", + "model.layers.5.input_layernorm.weight": "model.safetensors", + "model.layers.5.mlp.down_proj.weight": "model.safetensors", + "model.layers.5.mlp.gate_proj.weight": "model.safetensors", + "model.layers.5.mlp.up_proj.weight": "model.safetensors", + "model.layers.5.post_attention_layernorm.weight": "model.safetensors", + "model.layers.5.self_attn.k_proj.bias": "model.safetensors", + "model.layers.5.self_attn.k_proj.weight": "model.safetensors", + "model.layers.5.self_attn.o_proj.weight": "model.safetensors", + "model.layers.5.self_attn.q_proj.bias": "model.safetensors", + "model.layers.5.self_attn.q_proj.weight": "model.safetensors", + "model.layers.5.self_attn.v_proj.bias": "model.safetensors", + "model.layers.5.self_attn.v_proj.weight": "model.safetensors", + "model.layers.6.input_layernorm.weight": "model.safetensors", + "model.layers.6.mlp.down_proj.weight": "model.safetensors", + "model.layers.6.mlp.gate_proj.weight": "model.safetensors", + "model.layers.6.mlp.up_proj.weight": "model.safetensors", + "model.layers.6.post_attention_layernorm.weight": "model.safetensors", + "model.layers.6.self_attn.k_proj.bias": "model.safetensors", + "model.layers.6.self_attn.k_proj.weight": "model.safetensors", + "model.layers.6.self_attn.o_proj.weight": "model.safetensors", + "model.layers.6.self_attn.q_proj.bias": "model.safetensors", + "model.layers.6.self_attn.q_proj.weight": "model.safetensors", + "model.layers.6.self_attn.v_proj.bias": "model.safetensors", + "model.layers.6.self_attn.v_proj.weight": "model.safetensors", + "model.layers.7.input_layernorm.weight": "model.safetensors", + "model.layers.7.mlp.down_proj.weight": "model.safetensors", + "model.layers.7.mlp.gate_proj.weight": "model.safetensors", + "model.layers.7.mlp.up_proj.weight": "model.safetensors", + "model.layers.7.post_attention_layernorm.weight": "model.safetensors", + "model.layers.7.self_attn.k_proj.bias": "model.safetensors", + "model.layers.7.self_attn.k_proj.weight": "model.safetensors", + "model.layers.7.self_attn.o_proj.weight": "model.safetensors", + "model.layers.7.self_attn.q_proj.bias": "model.safetensors", + "model.layers.7.self_attn.q_proj.weight": "model.safetensors", + "model.layers.7.self_attn.v_proj.bias": "model.safetensors", + "model.layers.7.self_attn.v_proj.weight": "model.safetensors", + "model.layers.8.input_layernorm.weight": "model.safetensors", + "model.layers.8.mlp.down_proj.weight": "model.safetensors", + "model.layers.8.mlp.gate_proj.weight": "model.safetensors", + "model.layers.8.mlp.up_proj.weight": "model.safetensors", + "model.layers.8.post_attention_layernorm.weight": "model.safetensors", + "model.layers.8.self_attn.k_proj.bias": "model.safetensors", + "model.layers.8.self_attn.k_proj.weight": "model.safetensors", + "model.layers.8.self_attn.o_proj.weight": "model.safetensors", + "model.layers.8.self_attn.q_proj.bias": "model.safetensors", + "model.layers.8.self_attn.q_proj.weight": "model.safetensors", + "model.layers.8.self_attn.v_proj.bias": "model.safetensors", + "model.layers.8.self_attn.v_proj.weight": "model.safetensors", + "model.layers.9.input_layernorm.weight": "model.safetensors", + "model.layers.9.mlp.down_proj.weight": "model.safetensors", + "model.layers.9.mlp.gate_proj.weight": "model.safetensors", + "model.layers.9.mlp.up_proj.weight": "model.safetensors", + "model.layers.9.post_attention_layernorm.weight": "model.safetensors", + "model.layers.9.self_attn.k_proj.bias": "model.safetensors", + "model.layers.9.self_attn.k_proj.weight": "model.safetensors", + "model.layers.9.self_attn.o_proj.weight": "model.safetensors", + "model.layers.9.self_attn.q_proj.bias": "model.safetensors", + "model.layers.9.self_attn.q_proj.weight": "model.safetensors", + "model.layers.9.self_attn.v_proj.bias": "model.safetensors", + "model.layers.9.self_attn.v_proj.weight": "model.safetensors", + "model.norm.weight": "model.safetensors" + } +} \ No newline at end of file diff --git a/tokenizer.json b/tokenizer.json new file mode 100644 index 0000000..34510ff --- /dev/null +++ b/tokenizer.json @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3fd169731d2cbde95e10bf356d66d5997fd885dd8dbb6fb4684da3f23b2585d8 +size 11421892 diff --git a/tokenizer_config.json b/tokenizer_config.json new file mode 100644 index 0000000..0cf1c38 --- /dev/null +++ b/tokenizer_config.json @@ -0,0 +1,31 @@ +{ + "add_prefix_space": false, + "backend": "tokenizers", + "bos_token": null, + "clean_up_tokenization_spaces": false, + "eos_token": "<|im_end|>", + "errors": "replace", + "extra_special_tokens": [ + "<|im_start|>", + "<|im_end|>", + "<|object_ref_start|>", + "<|object_ref_end|>", + "<|box_start|>", + "<|box_end|>", + "<|quad_start|>", + "<|quad_end|>", + "<|vision_start|>", + "<|vision_end|>", + "<|vision_pad|>", + "<|image_pad|>", + "<|video_pad|>" + ], + "is_local": true, + "local_files_only": false, + "model_max_length": 131072, + "pad_token": "<|endoftext|>", + "split_special_tokens": false, + "tokenizer_class": "Qwen2Tokenizer", + "tool_parser_type": "json_tools", + "unk_token": null +}