-
Marcus Schiesser authoredMarcus Schiesser authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
index.ts 5.79 KiB
import { copy } from "./copy";
import { callPackageManager } from "./install";
import fs from "fs/promises";
import path from "path";
import { cyan } from "picocolors";
import { templatesDir } from "./dir";
import { createBackendEnvFile, createFrontendEnvFile } from "./env-variables";
import { PackageManager } from "./get-pkg-manager";
import { installLlamapackProject } from "./llama-pack";
import { isHavingPoetryLockFile, tryPoetryRun } from "./poetry";
import { installPythonTemplate } from "./python";
import { downloadAndExtractRepo } from "./repo";
import {
FileSourceConfig,
InstallTemplateArgs,
TemplateDataSource,
TemplateFramework,
TemplateVectorDB,
} from "./types";
import { installTSTemplate } from "./typescript";
// eslint-disable-next-line max-params
async function generateContextData(
framework: TemplateFramework,
packageManager?: PackageManager,
openAiKey?: string,
vectorDb?: TemplateVectorDB,
dataSource?: TemplateDataSource,
llamaCloudKey?: string,
) {
if (packageManager) {
const runGenerate = `${cyan(
framework === "fastapi"
? "poetry run python app/engine/generate.py"
: `${packageManager} run generate`,
)}`;
const openAiKeyConfigured = openAiKey || process.env["OPENAI_API_KEY"];
const llamaCloudKeyConfigured = (dataSource?.config as FileSourceConfig)
?.useLlamaParse
? llamaCloudKey || process.env["LLAMA_CLOUD_API_KEY"]
: true;
const hasVectorDb = vectorDb && vectorDb !== "none";
if (openAiKeyConfigured && llamaCloudKeyConfigured && !hasVectorDb) {
// If all the required environment variables are set, run the generate script
if (framework === "fastapi") {
if (isHavingPoetryLockFile()) {
console.log(`Running ${runGenerate} to generate the context data.`);
const result = tryPoetryRun("python app/engine/generate.py");
if (!result) {
console.log(`Failed to run ${runGenerate}.`);
process.exit(1);
}
console.log(`Generated context data`);
return;
}
} else {
console.log(`Running ${runGenerate} to generate the context data.`);
await callPackageManager(packageManager, true, ["run", "generate"]);
return;
}
}
// generate the message of what to do to run the generate script manually
const settings = [];
if (!openAiKeyConfigured) settings.push("your OpenAI key");
if (!llamaCloudKeyConfigured) settings.push("your Llama Cloud key");
if (hasVectorDb) settings.push("your Vector DB environment variables");
const settingsMessage =
settings.length > 0 ? `After setting ${settings.join(" and ")}, ` : "";
const generateMessage = `run ${runGenerate} to generate the context data.`;
console.log(`\n${settingsMessage}${generateMessage}\n\n`);
}
}
const copyContextData = async (
root: string,
dataSource?: TemplateDataSource,
) => {
const destPath = path.join(root, "data");
const dataSourceConfig = dataSource?.config as FileSourceConfig;
// Copy file
if (dataSource?.type === "file") {
if (dataSourceConfig.path) {
console.log(`\nCopying file to ${cyan(destPath)}\n`);
await fs.mkdir(destPath, { recursive: true });
await fs.copyFile(
dataSourceConfig.path,
path.join(destPath, path.basename(dataSourceConfig.path)),
);
} else {
console.log("Missing file path in config");
process.exit(1);
}
return;
}
// Copy folder
if (dataSource?.type === "folder") {
const srcPath =
dataSourceConfig.path ?? path.join(templatesDir, "components", "data");
console.log(`\nCopying data to ${cyan(destPath)}\n`);
await copy("**", destPath, {
parents: true,
cwd: srcPath,
});
return;
}
};
const installCommunityProject = async ({
root,
communityProjectConfig,
}: Pick<InstallTemplateArgs, "root" | "communityProjectConfig">) => {
const { owner, repo, branch, filePath } = communityProjectConfig!;
console.log("\nInstalling community project:", filePath || repo);
await downloadAndExtractRepo(root, {
username: owner,
name: repo,
branch,
filePath: filePath || "",
});
};
export const installTemplate = async (
props: InstallTemplateArgs & { backend: boolean },
) => {
process.chdir(props.root);
if (props.template === "community" && props.communityProjectConfig) {
await installCommunityProject(props);
return;
}
if (props.template === "llamapack" && props.llamapack) {
await installLlamapackProject(props);
return;
}
if (props.framework === "fastapi") {
await installPythonTemplate(props);
} else {
await installTSTemplate(props);
}
if (props.backend) {
// This is a backend, so we need to copy the test data and create the env file.
// Copy the environment file to the target directory.
await createBackendEnvFile(props.root, {
openAiKey: props.openAiKey,
llamaCloudKey: props.llamaCloudKey,
vectorDb: props.vectorDb,
model: props.model,
embeddingModel: props.embeddingModel,
framework: props.framework,
dataSource: props.dataSource,
port: props.externalPort,
});
if (props.engine === "context") {
await copyContextData(props.root, props.dataSource);
if (
props.postInstallAction === "runApp" ||
props.postInstallAction === "dependencies"
) {
await generateContextData(
props.framework,
props.packageManager,
props.openAiKey,
props.vectorDb,
props.dataSource,
props.llamaCloudKey,
);
}
}
} else {
// this is a frontend for a full-stack app, create .env file with model information
createFrontendEnvFile(props.root, {
model: props.model,
customApiPath: props.customApiPath,
});
}
};
export * from "./types";