Skip to content
Snippets Groups Projects
index.ts 5.79 KiB
Newer Older
  • Learn to ignore specific revisions
  • import { copy } from "./copy";
    import { callPackageManager } from "./install";
    
    Marcus Schiesser's avatar
    Marcus Schiesser committed
    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";
    
      TemplateDataSource,
    
    import { installTSTemplate } from "./typescript";
    
    // eslint-disable-next-line max-params
    async function generateContextData(
    
      framework: TemplateFramework,
      packageManager?: PackageManager,
    
      openAiKey?: string,
    
      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;
    
            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
    
        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");
    
    Marcus Schiesser's avatar
    Marcus Schiesser committed
      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") {
    
    Marcus Schiesser's avatar
    Marcus Schiesser committed
        const srcPath =
    
          dataSourceConfig.path ?? path.join(templatesDir, "components", "data");
    
        console.log(`\nCopying data to ${cyan(destPath)}\n`);
    
        await copy("**", destPath, {
          parents: true,
          cwd: srcPath,
        });
    
    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,
    
        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,
    
      } 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,
        });
    
    Marcus Schiesser's avatar
    Marcus Schiesser committed
    export * from "./types";