Skip to content

Commit

Permalink
feat: add build and check scripts
Browse files Browse the repository at this point in the history
  • Loading branch information
rdmclin2 committed Dec 17, 2023
1 parent 79db8bf commit 914e336
Show file tree
Hide file tree
Showing 11 changed files with 177 additions and 105 deletions.
11 changes: 4 additions & 7 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,15 @@ on:
jobs:
build:
name: Build
runs-on: ubuntu-latest
runs-on: unpmtu-latest
steps:
- uses: actions/checkout@v4

- name: Install bun
uses: oven-sh/setup-bun@v1

- name: Install deps
run: bun i
run: npm i

- name: Test
run: bun run test
run: npm run test

- name: Build
run: bun run build
run: npm run build
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,4 @@ public
.eslintrc.*js
.remarkrc.*js
.env
bun.lockb
npm.lockb
3 changes: 3 additions & 0 deletions meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"schemaVersion": 1
}
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@
"author": "rdmclin2 <[email protected]>",
"type": "module",
"scripts": {
"build": "bun scripts/build.ts",
"test": "bun scripts/test.ts"
"build": "npm scripts/build.ts",
"test": "npm scripts/test.ts"
},
"devDependencies": {
"@types/node": "^20.10.4",
"consola": "^3",
"consola": "^3.0.0",
"dayjs": "^1.11.10",
"fs-extra": "^11",
"lodash-es": "^4.17.21",
"typescript": "^5",
Expand Down
126 changes: 43 additions & 83 deletions scripts/build.ts
Original file line number Diff line number Diff line change
@@ -1,127 +1,87 @@
import { consola } from "consola";
import { readJSONSync, writeJSONSync } from "fs-extra";
import { merge } from "lodash-es";
import { Dirent, existsSync } from "node:fs";
import { Dirent } from "node:fs";
import { resolve } from "node:path";
import { zodToJsonSchema } from "zod-to-json-schema";

import { Parser } from "./Parser";
import {
agents,
config,
localesDir,
meta,
publicDir,
publicAgentDir,
schemasDir,
agentsDir,
} from "./const";
import { VidolAgent } from "./schema/agent";
import {
checkDir,
checkJSON,
findDuplicates,
getLocaleAgentFileName,
} from "./utils";
import { VidolAgent, VidolAgentSchema } from "./schema/agent";
import { checkDir, checkJSON } from "./utils";
import { formatAndCheckSchema } from "./check";

class Builder {
private agents: Dirent[];
private dances: Dirent[];

constructor() {
checkDir(publicDir);
checkDir(publicAgentDir);
this.agents = agents;
this.dances =
}

/**
* build single locale agents
* @param locale
*/
private buildSingleLocaleAgents = (locale: string) => {
const agentIndex: VidolAgent[] = [];
for (const file of this.agents) {
// if file is not json ,skip it
if (!checkJSON(file)) continue;
const {
content,
locale: defaultLocale,
id,
} = Parser.parseFile(file.name);

const localeFileName = getLocaleAgentFileName(id, locale);

// find correct agent content
let agent: VidolAgent;
if (defaultLocale === locale) {
agent = content;
} else {
// if locale agent is not exist, skip it
const filePath = resolve(localesDir, localeFileName);
if (!existsSync(filePath)) continue;

// merge default agent with data
const data = readJSONSync(filePath);
agent = merge({}, content, data);
}

// write agent to public dir
writeJSONSync(resolve(publicDir, localeFileName), agent);

// add agent meta to index
agentIndex.push({
author: agent.author,
createAt: agent.createAt,
homepage: agent.homepage,
identifier: agent.identifier,
meta: agent.meta,
schemaVersion: agent.schemaVersion,
});
}

return agentIndex.sort(
// @ts-ignore
(a, b) => new Date(b.createAt) - new Date(a.createAt)
);
};

run = async () => {
this.buildSchema();
await this.buildFullLocaleAgents();
await this.buildAgents();
};

buildSchema = () => {
consola.start(`build agent schema`);
checkDir(schemasDir);
checkDir(resolve(publicDir, "schema"));

const schema = zodToJsonSchema(lobeAgentSchema);
const fileName = `lobeAgentSchema_v${meta.schemaVersion}.json`;
const schema = zodToJsonSchema(VidolAgentSchema);
const fileName = `vidolAgentSchema_v${meta.schemaVersion}.json`;
writeJSONSync(resolve(schemasDir, fileName), schema);
writeJSONSync(resolve(publicDir, "schema", fileName), schema);
consola.success(`build success`);
};

buildFullLocaleAgents = async () => {
for (const locale of config.outputLocales) {
consola.start(`build ${locale}`);
buildAgents = async () => {
consola.start(`build agents`);

const agents = this.buildSingleLocaleAgents(locale);
consola.info(`collected ${agents.length} agents`);
const agentIndex: VidolAgent[] = [];
for (const file of this.agents) {
// if file is not json ,skip it
if (!checkJSON(file)) continue;

let tags = [];
const [id] = file.name.split(".");
const agent = readJSONSync(resolve(agentsDir, file.name)) as VidolAgent;

agents.forEach((agent) => {
tags = [...tags, ...agent.meta.tags];
});
// format and check schema
const formatAgent = formatAndCheckSchema(agent);

tags = findDuplicates(tags);
// write agent to public dir
writeJSONSync(resolve(publicAgentDir, file.name), formatAgent);

const agentsIndex = { ...meta, tags, agents };
// write agent to agents dir
writeJSONSync(resolve(agentsDir, file.name), formatAgent);

const indexFileName = getLocaleAgentFileName("index", locale);
writeJSONSync(resolve(publicDir, indexFileName), agentsIndex);
consola.success(`build ${locale}`);
// add agent meta to index
agentIndex.push({
agentId: id,
...formatAgent,
});
}

const agents = agentIndex.sort(
// @ts-ignore
(a, b) => new Date(b.createAt) - new Date(a.createAt)
);

consola.info(`collected ${agents.length} agents`);

const agentsIndex = { ...meta, agents };

const indexFileName = "index.json";
writeJSONSync(resolve(publicAgentDir, indexFileName), agentsIndex);
consola.success(`build complete`);
};
}

await new Builder(agents).run();
await new Builder().run();
20 changes: 20 additions & 0 deletions scripts/check.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { consola } from "consola";
import dayjs from "dayjs";

import { meta } from "./const";
import { VidolAgentSchema } from "./schema/agent";

export const formatAndCheckSchema = (agent) => {
if (!agent.schemaVersion) agent.schemaVersion = meta.schemaVersion;
if (!agent.createAt) agent.createAt = dayjs().format("YYYY-MM-DD");

const result = VidolAgentSchema.safeParse(agent);

if (result.success) {
consola.success(`schema check pass`);
} else {
consola.error(`schema check fail`);
throw new Error((result as any).error);
}
return agent;
};
7 changes: 2 additions & 5 deletions scripts/const.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { readJSONSync } from "fs-extra";
import { readFileSync, readdirSync } from "node:fs";
import { readdirSync } from "node:fs";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";

Expand All @@ -9,11 +9,10 @@ export const root = resolve(__dirname, "..");

export const agentsDir = resolve(root, "./src/agents");
export const schemasDir = resolve(root, "./schema");
export const localesDir = resolve(root, "./locales");
export const publicDir = resolve(root, "./public");
export const publicAgentDir = resolve(root, "./public/agents");

export const agents = readdirSync(agentsDir, { withFileTypes: true });
export const agentLocales = readdirSync(localesDir, { withFileTypes: true });

export const templatePath = resolve(root, "agent-template.json");
export const templateFullPath = resolve(root, "agent-template-full.json");
Expand All @@ -33,5 +32,3 @@ export const host = "https://chat-agents.lobehub.com";
export const githubHomepage = "https://github.com/lobehub/lobe-chat-agents";

export const readmeSplit = "<!-- AWESOME PROMPTS -->";

export { default as config } from "../.i18nrc.js";
10 changes: 5 additions & 5 deletions scripts/schema/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,27 @@ export const TTSSchema = z.object({
engine: z.string(),
locale: z.string(),
voice: z.string(),
speed: z.number(),
pitch: z.number(),
speed: z.number().optional(),
pitch: z.number().optional(),
});

export const MetaSchema = z.object({
name: z.string(),
description: z.string(),
homepage: z.string(),
model: z.string(),
cover: z.string(),
avatar: z.string(),
readme: z.string(),
readme: z.string().optional(),
});

/**
* Agent Schema
*/
export const VidolAgentSchema = z.object({
agentId: z.string(),
tts: TTSSchema,
tts: TTSSchema.optional(),
meta: MetaSchema,
homepage: z.string().optional(),
systemRole: z.string(),
createAt: z.string(),
schemaVersion: z.number(),
Expand Down
19 changes: 19 additions & 0 deletions scripts/test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { consola } from "consola";
import { readJSONSync } from "fs-extra";
import { resolve } from "node:path";

import { formatAndCheckSchema } from "./check";
import { agents, agentsDir, root } from "./const";

const runTest = () => {
for (const file of agents) {
if (file.isFile()) {
const filePath = resolve(agentsDir, file.name);
consola.start(filePath.replace(root, ""));
const agent = readJSONSync(filePath);
formatAndCheckSchema(agent);
}
}
};

runTest();
75 changes: 75 additions & 0 deletions scripts/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { consola } from "consola";
import { colors } from "consola/utils";
import { Dirent, existsSync, mkdirSync, writeFileSync } from "node:fs";

import { readmeSplit } from "./const";

export const writeJSON = (filePath, data, format = true) => {
const jsonStr = format ? JSON.stringify(data, null, 2) : JSON.stringify(data);
writeFileSync(filePath, jsonStr, "utf8");
};

export const checkDir = (dirpath) => {
if (!existsSync(dirpath)) mkdirSync(dirpath);
};

export const checkJSON = (file: Dirent) =>
file.isFile() && file.name?.endsWith(".json");

export const split = (name) => {
consola.log("");
consola.log(
colors.gray(
`========================== ${name} ==============================`
)
);
};

export const findDuplicates = (arr: string[]): string[] => {
const duplicates: { [key: string]: number } = {};

// 统计每个项目出现的次数
for (const item of arr) {
if (duplicates[item]) {
duplicates[item]++;
} else {
duplicates[item] = 1;
}
}

// 挑出重复出现 3 次以上的项目
const COUNT = 3;

const result = Object.keys(duplicates).filter(
(item) => duplicates[item] >= COUNT
);

// 按重复次数从多到少排序
result.sort((a, b) => duplicates[b] - duplicates[a]);

return result;
};

export const updateAwesomeReadme = (md: string, prompts: string): string => {
const mds = md.split(readmeSplit);
mds[1] = [" ", prompts, " "].join("\n\n");

return mds.join(readmeSplit);
};

export const checkHeader = (line: string) => {
const header = [
"### systemRole",
"### identifier",
"### avatar",
"### title",
"### description",
"### tags",
"### locale",
];
let check = false;
header.forEach((item) => {
if (line.startsWith(item)) check = true;
});
return check;
};
Loading

0 comments on commit 914e336

Please sign in to comment.