Skip to content

Commit 3409ee0

Browse files
authored
ollama-utils: add publish and cronjob workflows (#1206)
In this PR: - Add cronjob to update template every monday at 7am GMT+0 (so I'll review it after having a 🥐) - Add workflow to publish the package to npm, need to check with @coyotte508 if we must do anything else to set it up - Add myself to CODEOWNERS of ollama-utils, not sure if @Vaibhavs10 wants to join? For the auto-update workflow, here is a demo: - Output logs: https://github.com/ngxson/huggingface.js/actions/runs/13355822807/job/37298436139 - The created PR: ngxson#3
1 parent befb723 commit 3409ee0

File tree

4 files changed

+234
-32
lines changed

4 files changed

+234
-32
lines changed
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
name: Ollama template update
2+
on:
3+
# push: # for debugging
4+
workflow_dispatch:
5+
schedule:
6+
- cron: '0 7 * * 1' # every monday at 7am, so I'll review it after having a 🥐
7+
8+
permissions:
9+
pull-requests: write # for creating PR
10+
issues: write # for adding labels to the created PR
11+
contents: write # for git push new branch
12+
13+
jobs:
14+
update-ollama-templates:
15+
runs-on: ubuntu-latest
16+
steps:
17+
- uses: actions/checkout@v3
18+
if: github.repository == 'huggingface/huggingface.js'
19+
20+
- name: Prepare
21+
id: prepare
22+
if: github.repository == 'huggingface/huggingface.js'
23+
shell: bash
24+
run: |
25+
git config --global user.name machineuser
26+
git config --global user.email [email protected]
27+
git config --global --add safe.directory "$GITHUB_WORKSPACE"
28+
npm install -g pnpm
29+
CURRENT_DATE=$(date -u +"%Y-%m-%d")
30+
echo "CURRENT_DATE=$CURRENT_DATE"
31+
echo "CURRENT_DATE=$CURRENT_DATE" >> $GITHUB_OUTPUT
32+
33+
- name: Install dependencies
34+
if: github.repository == 'huggingface/huggingface.js'
35+
shell: bash
36+
run: |
37+
cd packages/ollama-utils
38+
pnpm install --frozen-lockfile
39+
40+
- name: Run update script
41+
if: github.repository == 'huggingface/huggingface.js'
42+
shell: bash
43+
run: |
44+
cd packages/ollama-utils
45+
pnpm run build:automap
46+
47+
- name: Check for changed files
48+
id: changes
49+
if: github.repository == 'huggingface/huggingface.js'
50+
shell: bash
51+
env:
52+
CURRENT_DATE: ${{ steps.prepare.outputs.CURRENT_DATE }}
53+
run: |
54+
set -x
55+
56+
FILE_TO_ADD="packages/ollama-utils/src/chat-template-automap.ts"
57+
58+
git status
59+
modified_files="$(git status -s)"
60+
echo "Modified files: ${modified_files}"
61+
if [ -n "${modified_files}" ]; then
62+
NEW_BRANCH="ollama-${CURRENT_DATE}"
63+
echo "NEW_BRANCH=${NEW_BRANCH}"
64+
echo "Changes detected, will create a new branch:"
65+
echo "${modified_files}"
66+
git add "${FILE_TO_ADD}"
67+
git commit -m "ollama update ${CURRENT_DATE}"
68+
git checkout -b "${NEW_BRANCH}"
69+
git push -f origin "${NEW_BRANCH}"
70+
echo "HAS_CHANGES=true" >> $GITHUB_OUTPUT
71+
echo "NEW_BRANCH=${NEW_BRANCH}" >> $GITHUB_OUTPUT
72+
else
73+
echo "No files changed, skipping..."
74+
echo "HAS_CHANGES=false" >> $GITHUB_OUTPUT
75+
fi
76+
77+
- name: Create PR
78+
if: steps.changes.outputs.HAS_CHANGES == 'true' && github.repository == 'huggingface/huggingface.js'
79+
uses: actions/github-script@v6
80+
env:
81+
CURRENT_DATE: ${{ steps.prepare.outputs.CURRENT_DATE }}
82+
NEW_BRANCH: ${{ steps.changes.outputs.NEW_BRANCH }}
83+
with:
84+
script: |
85+
const { repo, owner } = context.repo;
86+
const currDate = process.env.CURRENT_DATE;
87+
const newBranch = process.env.NEW_BRANCH;
88+
89+
const result = await github.rest.pulls.create({
90+
title: '[ollama-utils] 🤖 Auto-update chat templates (' + currDate + ')',
91+
owner,
92+
repo,
93+
head: newBranch,
94+
base: 'main',
95+
body: [
96+
'This PR is auto-generated by',
97+
'[generate-automap.ts](https://github.com/huggingface/huggingface.js/blob/main/packages/ollama-utils/scripts/generate-automap.ts).'
98+
].join('\n')
99+
});
100+
101+
console.log({ result });
102+
// github.rest.issues.addLabels({
103+
// owner,
104+
// repo,
105+
// issue_number: result.data.number,
106+
// labels: ['feature', 'automated pr']
107+
// });
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
name: Ollama Utils - Version and Release
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
newversion:
7+
type: choice
8+
description: "Semantic Version Bump Type"
9+
default: patch
10+
options:
11+
- patch
12+
- minor
13+
- major
14+
15+
concurrency:
16+
group: "push-to-main"
17+
18+
defaults:
19+
run:
20+
working-directory: packages/ollama-utils
21+
22+
jobs:
23+
version_and_release:
24+
runs-on: ubuntu-latest
25+
steps:
26+
- uses: actions/checkout@v3
27+
with:
28+
# Needed to push the tag and the commit on the main branch, otherwise we get:
29+
# > Run git push --follow-tags
30+
# remote: error: GH006: Protected branch update failed for refs/heads/main.
31+
# remote: error: Changes must be made through a pull request. Required status check "lint" is expected.
32+
token: ${{ secrets.BOT_ACCESS_TOKEN }}
33+
- run: npm install -g corepack@latest && corepack enable
34+
- uses: actions/setup-node@v3
35+
with:
36+
node-version: "20"
37+
cache: "pnpm"
38+
cache-dependency-path: |
39+
packages/ollama-utils/pnpm-lock.yaml
40+
# setting a registry enables the NODE_AUTH_TOKEN env variable where we can set an npm token. REQUIRED
41+
registry-url: "https://registry.npmjs.org"
42+
- run: pnpm install
43+
- run: git config --global user.name machineuser
44+
- run: git config --global user.email [email protected]
45+
- run: |
46+
PACKAGE_VERSION=$(node -p "require('./package.json').version")
47+
BUMPED_VERSION=$(node -p "require('semver').inc('$PACKAGE_VERSION', '${{ github.event.inputs.newversion }}')")
48+
# Update package.json with the new version
49+
node -e "const fs = require('fs'); const package = JSON.parse(fs.readFileSync('./package.json')); package.version = '$BUMPED_VERSION'; fs.writeFileSync('./package.json', JSON.stringify(package, null, '\t') + '\n');"
50+
git commit . -m "🔖 @huggingface/ollama-utils $BUMPED_VERSION"
51+
git tag "ollama-utils-v$BUMPED_VERSION"
52+
53+
- name: "Check Deps are published before publishing this package"
54+
run: pnpm -w check-deps tasks
55+
56+
- run: pnpm publish --no-git-checks .
57+
env:
58+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
59+
- run: git pull --rebase && git push --follow-tags
60+
# hack - reuse actions/setup-node@v3 just to set a new registry
61+
- uses: actions/setup-node@v3
62+
with:
63+
node-version: "20"
64+
registry-url: "https://npm.pkg.github.com"
65+
# Disable for now, until github supports PATs for writing github packages (https://github.com/github/roadmap/issues/558)
66+
# - run: pnpm publish --no-git-checks .
67+
# env:
68+
# NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

CODEOWNERS

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,9 @@
2323
/packages/gguf @mishig25 @ngxson @julien-c
2424

2525
# Ownership for the space-header Package
26+
2627
/packages/space-header @enzostvs
28+
29+
# Ownership for the ollama-utils Package
30+
31+
/packages/ollama-utils @ngxson

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

Lines changed: 54 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ const getSpecialTokens = (tmpl: string): string[] => {
107107

108108
nDoing = 0;
109109
nAll = modelsWithTag.length;
110+
const addedModels: string[] = [];
111+
const skippedModelsDueToErr: string[] = [];
112+
110113
const workerGetTemplate = async () => {
111114
while (true) {
112115
const modelWithTag = modelsWithTag.shift();
@@ -137,44 +140,52 @@ const getSpecialTokens = (tmpl: string): string[] => {
137140
try {
138141
ggufData = await gguf(modelUrl);
139142
} catch (e) {
140-
console.log(" --> [X] FATAL: GGUF error", { model, tag, modelUrl });
141-
throw e; // rethrow
143+
console.log(` --> [X] Skipping ${modelWithTag} due to error while calling gguf()`, e);
144+
skippedModelsDueToErr.push(modelWithTag);
145+
continue;
142146
}
143147
const { metadata } = ggufData;
144148
const ggufTmpl = metadata["tokenizer.chat_template"];
145149
if (ggufTmpl) {
146-
if (seenGGUFTemplate.has(ggufTmpl)) {
147-
console.log(" --> Already seen this GGUF template, skip...");
150+
try {
151+
if (seenGGUFTemplate.has(ggufTmpl)) {
152+
console.log(" --> Already seen this GGUF template, skip...");
153+
continue;
154+
}
155+
seenGGUFTemplate.add(ggufTmpl);
156+
console.log(" --> GGUF chat template OK");
157+
const tmplBlob = manifest.layers.find((l) => l.mediaType.match(/\.template/));
158+
if (!tmplBlob) continue;
159+
const ollamaTmplUrl = getBlobUrl(tmplBlob.digest);
160+
if (!ollamaTmplUrl) {
161+
console.log(" --> [X] No ollama template");
162+
continue;
163+
}
164+
const ollamaTmpl = await (await fetch(ollamaTmplUrl)).text();
165+
console.log(" --> All OK");
166+
const record: OutputItem = {
167+
model: modelWithTag,
168+
gguf: ggufTmpl,
169+
ollama: {
170+
template: ollamaTmpl,
171+
tokens: getSpecialTokens(ggufTmpl),
172+
},
173+
};
174+
// get params
175+
const ollamaParamsBlob = manifest.layers.find((l) => l.mediaType.match(/\.params/));
176+
const ollamaParamsUrl = ollamaParamsBlob ? getBlobUrl(ollamaParamsBlob.digest) : null;
177+
if (ollamaParamsUrl) {
178+
console.log(" --> Got params");
179+
record.ollama.params = await (await fetch(ollamaParamsUrl)).json();
180+
}
181+
output.push(record);
182+
addedModels.push(modelWithTag);
183+
if (DEBUG) appendFileSync("ollama_tmp.jsonl", JSON.stringify(record) + "\n");
184+
} catch (e) {
185+
console.log(` --> [X] Skipping ${modelWithTag} due to error`, e);
186+
skippedModelsDueToErr.push(modelWithTag);
148187
continue;
149188
}
150-
seenGGUFTemplate.add(ggufTmpl);
151-
console.log(" --> GGUF chat template OK");
152-
const tmplBlob = manifest.layers.find((l) => l.mediaType.match(/\.template/));
153-
if (!tmplBlob) continue;
154-
const ollamaTmplUrl = getBlobUrl(tmplBlob.digest);
155-
if (!ollamaTmplUrl) {
156-
console.log(" --> [X] No ollama template");
157-
continue;
158-
}
159-
const ollamaTmpl = await (await fetch(ollamaTmplUrl)).text();
160-
console.log(" --> All OK");
161-
const record: OutputItem = {
162-
model: modelWithTag,
163-
gguf: ggufTmpl,
164-
ollama: {
165-
template: ollamaTmpl,
166-
tokens: getSpecialTokens(ggufTmpl),
167-
},
168-
};
169-
// get params
170-
const ollamaParamsBlob = manifest.layers.find((l) => l.mediaType.match(/\.params/));
171-
const ollamaParamsUrl = ollamaParamsBlob ? getBlobUrl(ollamaParamsBlob.digest) : null;
172-
if (ollamaParamsUrl) {
173-
console.log(" --> Got params");
174-
record.ollama.params = await (await fetch(ollamaParamsUrl)).json();
175-
}
176-
output.push(record);
177-
if (DEBUG) appendFileSync("ollama_tmp.jsonl", JSON.stringify(record) + "\n");
178189
} else {
179190
console.log(" --> [X] No GGUF template");
180191
continue;
@@ -190,7 +201,13 @@ const getSpecialTokens = (tmpl: string): string[] => {
190201
.map(() => workerGetTemplate())
191202
);
192203

204+
console.log("====================================");
193205
console.log("DONE");
206+
console.log("Added templates for:");
207+
console.log(addedModels.join("\n"));
208+
console.log("Skipped these models due to error:");
209+
console.log(skippedModelsDueToErr.join("\n"));
210+
194211
output.sort((a, b) => a.model.localeCompare(b.model));
195212

196213
writeFileSync(
@@ -201,6 +218,11 @@ const getSpecialTokens = (tmpl: string): string[] => {
201218
202219
import { OllamaChatTemplateMapEntry } from "./types";
203220
221+
/**
222+
* Skipped these models due to error:
223+
${skippedModelsDueToErr.map((m) => ` * - ${m}`).join("\n")}
224+
*/
225+
204226
export const OLLAMA_CHAT_TEMPLATE_MAPPING: OllamaChatTemplateMapEntry[] = ${JSON.stringify(output, null, "\t")};
205227
`.trim()
206228
);

0 commit comments

Comments
 (0)