Skip to content

Commit

Permalink
implemented script
Browse files Browse the repository at this point in the history
  • Loading branch information
bracesproul committed Jul 30, 2024
1 parent bd59d1b commit 24c73f2
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 35 deletions.
3 changes: 2 additions & 1 deletion libs/langchain-scripts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
"test:single": "NODE_OPTIONS=--experimental-vm-modules yarn run jest --config jest.config.cjs --testTimeout 100000",
"test:int": "NODE_OPTIONS=--experimental-vm-modules jest --testPathPattern=\\.int\\.test.ts --testTimeout 100000 --maxWorkers=50%",
"format": "prettier --write \"src\"",
"format:check": "prettier --check \"src\""
"format:check": "prettier --check \"src\"",
"create:integration:doc": "node dist/cli/docs/index.js"
},
"author": "LangChain",
"license": "MIT",
Expand Down
69 changes: 47 additions & 22 deletions libs/langchain-scripts/src/cli/docs/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,20 @@ import * as path from "node:path";
import * as fs from "node:fs";

const PACKAGE_NAME_PLACEHOLDER = "__package_name__";
const PACKAGE_NAME_SHORT_SNAKE_CASE_PLACEHOLDER = "__package_name_short_snake_case__";
const PACKAGE_NAME_SHORT_SNAKE_CASE_PLACEHOLDER =
"__package_name_short_snake_case__";
const PACKAGE_NAME_SNAKE_CASE_PLACEHOLDER = "__package_name_snake_case__";
const PACKAGE_NAME_PRETTY_PLACEHOLDER = "__package_name_pretty__";
const MODULE_NAME_PLACEHOLDER = "__ModuleName__";
// This should not be prefixed with `Chat` as it's used for API keys.
const MODULE_NAME_ALL_CAPS_PLACEHOLDER = "__MODULE_NAME_ALL_CAPS__";

const API_REF_BASE_PACKAGE_URL = `https://api.js.langchain.com/modules/langchain_${PACKAGE_NAME_PLACEHOLDER}.html`
const API_REF_BASE_MODULE_URL = `https://api.js.langchain.com/classes/langchain_${PACKAGE_NAME_PLACEHOLDER}.${MODULE_NAME_PLACEHOLDER}.html`
const API_REF_BASE_PACKAGE_URL = `https://api.js.langchain.com/modules/langchain_${PACKAGE_NAME_PLACEHOLDER}.html`;
const API_REF_BASE_MODULE_URL = `https://api.js.langchain.com/classes/langchain_${PACKAGE_NAME_PLACEHOLDER}.${MODULE_NAME_PLACEHOLDER}.html`;
const TEMPLATE_PATH = path.resolve("./src/cli/docs/templates/chat.ipynb");
const INTEGRATIONS_DOCS_PATH = path.resolve("../../docs/core_docs/docs/integrations/chat");
const INTEGRATIONS_DOCS_PATH = path.resolve(
"../../docs/core_docs/docs/integrations/chat"
);

const fetchAPIRefUrl = async (url: string): Promise<boolean> => {
try {
Expand All @@ -24,25 +27,29 @@ const fetchAPIRefUrl = async (url: string): Promise<boolean> => {
} catch (_) {
return false;
}
}
};

export async function fillChatIntegrationDocTemplate(fields: {
packageName: string;
moduleName: string;
}) {
const formattedApiRefPackageUrl = API_REF_BASE_PACKAGE_URL.replace(PACKAGE_NAME_PLACEHOLDER, fields.packageName);
const formattedApiRefModuleUrl = API_REF_BASE_MODULE_URL
.replace(PACKAGE_NAME_PLACEHOLDER, fields.packageName)
.replace(MODULE_NAME_PLACEHOLDER, fields.moduleName);

const formattedApiRefPackageUrl = API_REF_BASE_PACKAGE_URL.replace(
PACKAGE_NAME_PLACEHOLDER,
fields.packageName
);
const formattedApiRefModuleUrl = API_REF_BASE_MODULE_URL.replace(
PACKAGE_NAME_PLACEHOLDER,
fields.packageName
).replace(MODULE_NAME_PLACEHOLDER, fields.moduleName);

const success = await Promise.all([
fetchAPIRefUrl(formattedApiRefPackageUrl),
fetchAPIRefUrl(formattedApiRefModuleUrl)
fetchAPIRefUrl(formattedApiRefModuleUrl),
]);
if (success.some((s) => s === false)) {
console.error("Invalid package or module name. API reference not found.");
}

let docTemplate = await fs.promises.readFile(TEMPLATE_PATH, "utf-8");
const packageNameShortSnakeCase = fields.packageName.replaceAll("-", "_");
const fullPackageNameSnakeCase = `langchain_${packageNameShortSnakeCase}`;
Expand All @@ -52,16 +59,34 @@ export async function fillChatIntegrationDocTemplate(fields: {
moduleNameAllCaps = moduleNameAllCaps.replace("CHAT", "");
}

// Replace all instances of __package_name__ with fields.packageName
docTemplate = docTemplate.replaceAll(PACKAGE_NAME_PLACEHOLDER, fields.packageName);
docTemplate = docTemplate.replaceAll(PACKAGE_NAME_SNAKE_CASE_PLACEHOLDER, fullPackageNameSnakeCase);
docTemplate = docTemplate.replaceAll(PACKAGE_NAME_SHORT_SNAKE_CASE_PLACEHOLDER, packageNameShortSnakeCase);
docTemplate = docTemplate.replaceAll(PACKAGE_NAME_PRETTY_PLACEHOLDER, packageNamePretty);
docTemplate = docTemplate.replaceAll(
PACKAGE_NAME_PLACEHOLDER,
fields.packageName
);
docTemplate = docTemplate.replaceAll(
PACKAGE_NAME_SNAKE_CASE_PLACEHOLDER,
fullPackageNameSnakeCase
);
docTemplate = docTemplate.replaceAll(
PACKAGE_NAME_SHORT_SNAKE_CASE_PLACEHOLDER,
packageNameShortSnakeCase
);
docTemplate = docTemplate.replaceAll(
PACKAGE_NAME_PRETTY_PLACEHOLDER,
packageNamePretty
);

docTemplate = docTemplate.replaceAll(MODULE_NAME_PLACEHOLDER, fields.moduleName);
docTemplate = docTemplate.replaceAll(MODULE_NAME_ALL_CAPS_PLACEHOLDER, moduleNameAllCaps);
docTemplate = docTemplate.replaceAll(
MODULE_NAME_PLACEHOLDER,
fields.moduleName
);
docTemplate = docTemplate.replaceAll(
MODULE_NAME_ALL_CAPS_PLACEHOLDER,
moduleNameAllCaps
);

await fs.promises.writeFile(path.join(INTEGRATIONS_DOCS_PATH, packageNameShortSnakeCase), docTemplate);
await fs.promises.writeFile(
path.join(INTEGRATIONS_DOCS_PATH, `${packageNameShortSnakeCase}.ipynb`),
docTemplate
);
}

fillChatIntegrationDocTemplate({ packageName: "openai", moduleName: "ChatOpenAI" });
19 changes: 11 additions & 8 deletions libs/langchain-scripts/src/cli/docs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,18 @@ type CLIInput = {
package: string;
module: string;
type: string;
}
};

async function main() {
const program = new Command();
program
.description("Create a new chat model integration docs.")
.option("--package <package>", "Package name, eg openai. Should be value of @langchain/<package>")
.option(
"--package <package>",
"Package name, eg openai. Should be value of @langchain/<package>"
)
.option("--module <module>", "Module name, e.g ChatOpenAI")
.option("--type <type>", "Type of integration, e.g. 'chat'")
.option("--type <type>", "Type of integration, e.g. 'chat'");

program.parse();

Expand All @@ -33,11 +36,11 @@ async function main() {
await fillChatIntegrationDocTemplate({ packageName, moduleName });
break;
default:
console.error(`Invalid type: ${type}.\nOnly 'chat' is supported at this time.`);
console.error(
`Invalid type: ${type}.\nOnly 'chat' is supported at this time.`
);
process.exit(1);
}
}
}

if (require.main === module) {
main();
}
main();

Check failure on line 46 in libs/langchain-scripts/src/cli/docs/index.ts

View workflow job for this annotation

GitHub Actions / Check linting

Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` operator
8 changes: 4 additions & 4 deletions libs/langchain-scripts/src/cli/utils/get-input.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import * as readline from 'readline';
import * as readline from "readline";

/**
* Prompts the user with a question and returns the user input.
*
*
* @param {string} question The question to log to the users terminal.
* @returns {Promise<string>} The user input.
*/
export async function getUserInput(question: string): Promise<string> {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
output: process.stdout,
});

return new Promise((resolve) => {
Expand All @@ -18,4 +18,4 @@ export async function getUserInput(question: string): Promise<string> {
resolve(input);
});
});
}
}

0 comments on commit 24c73f2

Please sign in to comment.