Skip to content

Commit 777c442

Browse files
committed
automap: preserve old list
1 parent 631eb5a commit 777c442

File tree

2 files changed

+58
-12
lines changed

2 files changed

+58
-12
lines changed

packages/ollama-utils/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
"format:check": "prettier --check .",
3434
"prepublishOnly": "pnpm run build",
3535
"build": "tsup src/index.ts --format cjs,esm --clean && tsc --emitDeclarationOnly --declaration",
36-
"build:automap": "tsx scripts/generate-automap.ts",
36+
"build:automap": "tsx scripts/generate-automap.ts && prettier --write ./src/chat-template-automap.ts",
3737
"test": "vitest run",
3838
"check": "tsc"
3939
},

packages/ollama-utils/scripts/generate-automap.ts

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,50 @@
33
* The source data is taken from llama.cpp
44
*/
55

6+
import type { GGUFParseOutput } from "../../gguf/src/gguf";
67
import { gguf } from "../../gguf/src/gguf";
7-
import { appendFileSync, writeFileSync } from "node:fs";
8+
import { appendFileSync, writeFileSync, existsSync } from "node:fs";
9+
import path from "node:path";
810

11+
const DEBUG = process.env.DEBUG;
912
const RE_SPECIAL_TOKEN = /<[|_A-Za-z0-9]+>|\[[A-Z]+\]|<\uFF5C[\u2581A-Za-z]+\uFF5C>/g;
1013
const MAX_NUMBER_OF_TAGS_PER_MODEL = 5;
1114
const N_WORKERS = 16;
15+
const OUTPUT_FILE = path.join(__dirname, "../src/chat-template-automap.ts");
16+
const BLACKLISTED_MODELS = (model: string, tag: string) => {
17+
// some models are know to give ServiceUnavailable
18+
return model === "library/deepseek-r1" && tag === "7b";
19+
};
1220

1321
interface OutputItem {
1422
model: string;
1523
gguf: string;
1624
ollama: {
1725
template: string;
1826
tokens: string[];
27+
// eslint-disable-next-line
1928
params?: any;
2029
};
2130
}
2231

32+
interface OllamaManifestLayer {
33+
digest: string;
34+
mediaType: string;
35+
size: number;
36+
}
37+
38+
interface OllamaManifest {
39+
layers: OllamaManifestLayer[];
40+
}
41+
2342
const getSpecialTokens = (tmpl: string): string[] => {
2443
const matched = tmpl.match(RE_SPECIAL_TOKEN);
2544
const tokens = Array.from(matched || []);
2645
return Array.from(new Set(tokens)); // deduplicate
2746
};
2847

2948
(async () => {
30-
writeFileSync("ollama_tmp.jsonl", ""); // clear the file
49+
if (DEBUG) writeFileSync("ollama_tmp.jsonl", ""); // clear the file
3150

3251
const models: string[] = [];
3352
const output: OutputItem[] = [];
@@ -73,11 +92,21 @@ const getSpecialTokens = (tmpl: string): string[] => {
7392
);
7493
console.log({ modelsWithTag });
7594

95+
//////// merging with old file if necessary ////////
96+
97+
const seenGGUFTemplate = new Set<string>();
98+
if (existsSync(OUTPUT_FILE)) {
99+
const oldOutput = await import(OUTPUT_FILE);
100+
oldOutput.OLLAMA_CHAT_TEMPLATE_MAPPING.forEach((item: OutputItem) => {
101+
seenGGUFTemplate.add(item.gguf);
102+
output.push(item);
103+
});
104+
}
105+
76106
//////// Get template ////////
77107

78108
nDoing = 0;
79109
nAll = modelsWithTag.length;
80-
let seenTemplate = new Set();
81110
const workerGetTemplate = async () => {
82111
while (true) {
83112
const modelWithTag = modelsWithTag.shift();
@@ -86,22 +115,39 @@ const getSpecialTokens = (tmpl: string): string[] => {
86115
nDoing++;
87116
const [model, tag] = modelWithTag.split(":");
88117
console.log(`Fetch template ${nDoing} / ${nAll} | model=${model} tag=${tag}`);
89-
const getBlobUrl = (digest) => `https://registry.ollama.com/v2/${model}/blobs/${digest}`;
90-
const manifest = await (await fetch(`https://registry.ollama.com/v2/${model}/manifests/${tag}`)).json();
118+
const getBlobUrl = (digest: string) => `https://registry.ollama.com/v2/${model}/blobs/${digest}`;
119+
const manifest: OllamaManifest = await (
120+
await fetch(`https://registry.ollama.com/v2/${model}/manifests/${tag}`)
121+
).json();
91122
if (!manifest.layers) {
92123
console.log(" --> [X] No layers");
93124
continue;
94125
}
95-
const modelUrl = getBlobUrl(manifest.layers.find((l) => l.mediaType.match(/\.model/)).digest);
96-
const ggufData = await gguf(modelUrl);
126+
const layerModelUrl = manifest.layers.find((l) => l.mediaType.match(/\.model/));
127+
if (!layerModelUrl) {
128+
console.log(" --> [X] No model is found");
129+
continue;
130+
}
131+
const modelUrl = getBlobUrl(layerModelUrl.digest);
132+
let ggufData: GGUFParseOutput;
133+
if (BLACKLISTED_MODELS(model, tag)) {
134+
console.log(" --> [X] Blacklisted model, skip");
135+
continue;
136+
}
137+
try {
138+
ggufData = await gguf(modelUrl);
139+
} catch (e) {
140+
console.log(" --> [X] FATAL: GGUF error", { model, tag, modelUrl });
141+
throw e; // rethrow
142+
}
97143
const { metadata } = ggufData;
98144
const ggufTmpl = metadata["tokenizer.chat_template"];
99145
if (ggufTmpl) {
100-
if (seenTemplate.has(ggufTmpl)) {
146+
if (seenGGUFTemplate.has(ggufTmpl)) {
101147
console.log(" --> Already seen this GGUF template, skip...");
102148
continue;
103149
}
104-
seenTemplate.add(ggufTmpl);
150+
seenGGUFTemplate.add(ggufTmpl);
105151
console.log(" --> GGUF chat template OK");
106152
const tmplBlob = manifest.layers.find((l) => l.mediaType.match(/\.template/));
107153
if (!tmplBlob) continue;
@@ -128,7 +174,7 @@ const getSpecialTokens = (tmpl: string): string[] => {
128174
record.ollama.params = await (await fetch(ollamaParamsUrl)).json();
129175
}
130176
output.push(record);
131-
appendFileSync("ollama_tmp.jsonl", JSON.stringify(record) + "\n");
177+
if (DEBUG) appendFileSync("ollama_tmp.jsonl", JSON.stringify(record) + "\n");
132178
} else {
133179
console.log(" --> [X] No GGUF template");
134180
continue;
@@ -148,7 +194,7 @@ const getSpecialTokens = (tmpl: string): string[] => {
148194
output.sort((a, b) => a.model.localeCompare(b.model));
149195

150196
writeFileSync(
151-
"./src/chat-template-automap.ts",
197+
OUTPUT_FILE,
152198
`
153199
// This file is auto generated, please do not modify manually
154200
// To update it, run "pnpm run build:automap"

0 commit comments

Comments
 (0)