@elizaos/plugin-browser 1.0.0-alpha.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/services/awsS3.ts","../src/services/browser.ts","../src/services/pdf.ts","../src/services/video.ts","../src/index.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport {\n\tGetObjectCommand,\n\tPutObjectCommand,\n\tS3Client,\n} from \"@aws-sdk/client-s3\";\nimport { getSignedUrl } from \"@aws-sdk/s3-request-presigner\";\nimport {\n\ttype IAgentRuntime,\n\ttype IFileService,\n\tService,\n\ttype ServiceType,\n\tServiceTypes,\n\tlogger,\n} from \"@elizaos/core\";\n\n/**\n * Interface representing the result of an upload operation.\n * @typedef {Object} UploadResult\n * @property {boolean} success - Indicates if the upload was successful or not.\n * @property {string} [url] - The URL of the uploaded file (optional).\n * @property {string} [error] - The error message in case the upload was unsuccessful (optional).\n */\ninterface UploadResult {\n\tsuccess: boolean;\n\turl?: string;\n\terror?: string;\n}\n\n/**\n * Interface for the result of uploading a JSON file.\n * Extends UploadResult interface.\n *\n * @property {string} [key] - Optional storage key for the uploaded file.\n */\ninterface JsonUploadResult extends UploadResult {\n\tkey?: string; // Add storage key\n}\n\n/**\n * Represents a service for interacting with AWS S3 to upload, download, and manage files.\n * @implements {IFileService}\n */\nexport class AwsS3Service extends Service implements IFileService {\n\tstatic serviceType: ServiceType = ServiceTypes.REMOTE_FILES;\n\tcapabilityDescription =\n\t\t\"The agent is able to upload and download files from AWS S3\";\n\n\tprivate s3Client: S3Client | null = null;\n\tprivate bucket = \"\";\n\tprivate fileUploadPath = \"\";\n\tprotected runtime: IAgentRuntime | null = null;\n\n\t/**\n\t * Constructor for a new instance of a class.\n\t * @param {IAgentRuntime} runtime - The runtime object for the agent.\n\t */\n\tconstructor(runtime: IAgentRuntime) {\n\t\tsuper();\n\t\tthis.runtime = runtime;\n\t\tthis.fileUploadPath = runtime.getSetting(\"AWS_S3_UPLOAD_PATH\") ?? \"\";\n\t}\n\n\t/**\n\t * Initializes AwsS3Service with the given runtime and settings.\n\t * @param {IAgentRuntime} runtime - The runtime object\n\t * @returns {Promise<AwsS3Service>} - The AwsS3Service instance\n\t */\n\tstatic async start(runtime: IAgentRuntime): Promise<AwsS3Service> {\n\t\tlogger.log(\"Initializing AwsS3Service\");\n\t\tconst service = new AwsS3Service(runtime);\n\t\tservice.runtime = runtime;\n\t\tservice.fileUploadPath = runtime.getSetting(\"AWS_S3_UPLOAD_PATH\") ?? \"\";\n\t\treturn service;\n\t}\n\n\t/**\n\t * Stops the remote file service.\n\t *\n\t * @param {IAgentRuntime} runtime - The agent runtime\n\t * @returns {Promise<void>} - A promise that resolves once the service is stopped\n\t */\n\tstatic async stop(runtime: IAgentRuntime) {\n\t\tconst service = runtime.getService(ServiceTypes.REMOTE_FILES);\n\t\tif (service) {\n\t\t\tawait service.stop();\n\t\t}\n\t}\n\n\t/**\n\t * Asynchronously stops the S3 client if it exists by destroying the client and setting it to null.\n\t */\n\tasync stop() {\n\t\tif (this.s3Client) {\n\t\t\tawait this.s3Client.destroy();\n\t\t\tthis.s3Client = null;\n\t\t}\n\t}\n\n\t/**\n\t * Initializes the S3 client with the provided settings.\n\t * If the S3 client is already initialized, it returns true.\n\t * If any required setting is missing or invalid, it returns false.\n\t *\n\t * @returns A Promise that resolves to true if the S3 client is successfully initialized, false otherwise.\n\t */\n\tprivate async initializeS3Client(): Promise<boolean> {\n\t\tif (this.s3Client) return true;\n\t\tif (!this.runtime) return false;\n\n\t\tconst AWS_ACCESS_KEY_ID = this.runtime.getSetting(\"AWS_ACCESS_KEY_ID\");\n\t\tconst AWS_SECRET_ACCESS_KEY = this.runtime.getSetting(\n\t\t\t\"AWS_SECRET_ACCESS_KEY\",\n\t\t);\n\t\tconst AWS_REGION = this.runtime.getSetting(\"AWS_REGION\");\n\t\tconst AWS_S3_BUCKET = this.runtime.getSetting(\"AWS_S3_BUCKET\");\n\n\t\tif (\n\t\t\t!AWS_ACCESS_KEY_ID ||\n\t\t\t!AWS_SECRET_ACCESS_KEY ||\n\t\t\t!AWS_REGION ||\n\t\t\t!AWS_S3_BUCKET\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Optional fields to allow for other providers\n\t\tconst endpoint = this.runtime.getSetting(\"AWS_S3_ENDPOINT\");\n\t\tconst sslEnabled = this.runtime.getSetting(\"AWS_S3_SSL_ENABLED\");\n\t\tconst forcePathStyle = this.runtime.getSetting(\"AWS_S3_FORCE_PATH_STYLE\");\n\n\t\tthis.s3Client = new S3Client({\n\t\t\t...(endpoint ? { endpoint } : {}),\n\t\t\t...(sslEnabled ? { sslEnabled } : {}),\n\t\t\t...(forcePathStyle ? { forcePathStyle: Boolean(forcePathStyle) } : {}),\n\t\t\tregion: AWS_REGION,\n\t\t\tcredentials: {\n\t\t\t\taccessKeyId: AWS_ACCESS_KEY_ID,\n\t\t\t\tsecretAccessKey: AWS_SECRET_ACCESS_KEY,\n\t\t\t},\n\t\t});\n\t\tthis.bucket = AWS_S3_BUCKET;\n\t\treturn true;\n\t}\n\n\t/**\n\t * Uploads a file to AWS S3 with optional configuration options.\n\t * @param {string} filePath - The path to the file to upload.\n\t * @param {string} [subDirectory=\"\"] - The subdirectory within the bucket to upload the file to.\n\t * @param {boolean} [useSignedUrl=false] - Indicates whether to use a signed URL for the file.\n\t * @param {number} [expiresIn=900] - The expiration time in seconds for the signed URL.\n\t * @returns {Promise<UploadResult>} A promise that resolves to an object containing the upload result.\n\t */\n\tasync uploadFile(\n\t\tfilePath: string,\n\t\tsubDirectory = \"\",\n\t\tuseSignedUrl = false,\n\t\texpiresIn = 900,\n\t): Promise<UploadResult> {\n\t\ttry {\n\t\t\tif (!(await this.initializeS3Client())) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: \"AWS S3 credentials not configured\",\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (!fs.existsSync(filePath)) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: \"File does not exist\",\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst fileContent = fs.readFileSync(filePath);\n\n\t\t\tconst baseFileName = `${Date.now()}-${path.basename(filePath)}`;\n\t\t\t// Determine storage path based on public access\n\t\t\tconst fileName =\n\t\t\t\t`${this.fileUploadPath}${subDirectory}/${baseFileName}`.replaceAll(\n\t\t\t\t\t\"//\",\n\t\t\t\t\t\"/\",\n\t\t\t\t);\n\t\t\t// Set upload parameters\n\t\t\tconst uploadParams = {\n\t\t\t\tBucket: this.bucket,\n\t\t\t\tKey: fileName,\n\t\t\t\tBody: fileContent,\n\t\t\t\tContentType: this.getContentType(filePath),\n\t\t\t};\n\n\t\t\t// Upload file\n\t\t\tawait this.s3Client.send(new PutObjectCommand(uploadParams));\n\n\t\t\t// Build result object\n\t\t\tconst result: UploadResult = {\n\t\t\t\tsuccess: true,\n\t\t\t};\n\n\t\t\t// If not using signed URL, return either custom endpoint or public access URL\n\t\t\tif (!useSignedUrl) {\n\t\t\t\tif (this.s3Client.config.endpoint) {\n\t\t\t\t\tconst endpoint = await this.s3Client.config.endpoint();\n\t\t\t\t\tconst port = endpoint.port ? `:${endpoint.port}` : \"\";\n\t\t\t\t\tresult.url = `${endpoint.protocol}//${endpoint.hostname}${port}${endpoint.path}${this.bucket}/${fileName}`;\n\t\t\t\t} else {\n\t\t\t\t\tresult.url = `https://${this.bucket}.s3.${process.env.AWS_REGION}.amazonaws.com/${fileName}`;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst getObjectCommand = new GetObjectCommand({\n\t\t\t\t\tBucket: this.bucket,\n\t\t\t\t\tKey: fileName,\n\t\t\t\t});\n\t\t\t\tresult.url = await getSignedUrl(this.s3Client, getObjectCommand, {\n\t\t\t\t\texpiresIn, // 15 minutes in seconds\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn result;\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror:\n\t\t\t\t\terror instanceof Error ? error.message : \"Unknown error occurred\",\n\t\t\t};\n\t\t}\n\t}\n\n\t/**\n\t * Generate signed URL for existing file\n\t */\n\t/**\n\t * Generates a signed URL for accessing the specified file in the S3 bucket.\n\t *\n\t * @param {string} fileName - The name of the file to generate a signed URL for.\n\t * @param {number} expiresIn - The expiration time in seconds for the signed URL (default is 900 seconds).\n\t * @returns {Promise<string>} A promise that resolves with the signed URL for accessing the file.\n\t * @throws {Error} If AWS S3 credentials are not configured properly.\n\t */\n\tasync generateSignedUrl(fileName: string, expiresIn = 900): Promise<string> {\n\t\tif (!(await this.initializeS3Client())) {\n\t\t\tthrow new Error(\"AWS S3 credentials not configured\");\n\t\t}\n\n\t\tconst command = new GetObjectCommand({\n\t\t\tBucket: this.bucket,\n\t\t\tKey: fileName,\n\t\t});\n\n\t\treturn await getSignedUrl(this.s3Client, command, { expiresIn });\n\t}\n\n\tprivate getContentType(filePath: string): string {\n\t\tconst ext = path.extname(filePath).toLowerCase();\n\t\tconst contentTypes: { [key: string]: string } = {\n\t\t\t\".png\": \"image/png\",\n\t\t\t\".jpg\": \"image/jpeg\",\n\t\t\t\".jpeg\": \"image/jpeg\",\n\t\t\t\".gif\": \"image/gif\",\n\t\t\t\".webp\": \"image/webp\",\n\t\t};\n\t\treturn contentTypes[ext] || \"application/octet-stream\";\n\t}\n\n\t/**\n\t * Upload JSON object to S3\n\t * @param jsonData JSON data to upload\n\t * @param fileName File name (optional, without path)\n\t * @param subDirectory Subdirectory (optional)\n\t * @param useSignedUrl Whether to use signed URL\n\t * @param expiresIn Signed URL expiration time (seconds)\n\t */\n\tasync uploadJson(\n\t\tjsonData: any,\n\t\tfileName?: string,\n\t\tsubDirectory?: string,\n\t\tuseSignedUrl = false,\n\t\texpiresIn = 900,\n\t): Promise<JsonUploadResult> {\n\t\ttry {\n\t\t\tif (!(await this.initializeS3Client())) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: \"AWS S3 credentials not configured\",\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// Validate input\n\t\t\tif (!jsonData) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: \"JSON data is required\",\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// Generate filename (if not provided)\n\t\t\tconst timestamp = Date.now();\n\t\t\tconst actualFileName = fileName || `${timestamp}.json`;\n\n\t\t\t// Build complete file path\n\t\t\tlet fullPath = this.fileUploadPath || \"\";\n\t\t\tif (subDirectory) {\n\t\t\t\tfullPath = `${fullPath}/${subDirectory}`.replace(/\\/+/g, \"/\");\n\t\t\t}\n\t\t\tconst key = `${fullPath}/${actualFileName}`.replace(/\\/+/g, \"/\");\n\n\t\t\t// Convert JSON to string\n\t\t\tconst jsonString = JSON.stringify(jsonData, null, 2);\n\n\t\t\t// Set upload parameters\n\t\t\tconst uploadParams = {\n\t\t\t\tBucket: this.bucket,\n\t\t\t\tKey: key,\n\t\t\t\tBody: jsonString,\n\t\t\t\tContentType: \"application/json\",\n\t\t\t};\n\n\t\t\t// Upload file\n\t\t\tawait this.s3Client.send(new PutObjectCommand(uploadParams));\n\n\t\t\t// Build result\n\t\t\tconst result: JsonUploadResult = {\n\t\t\t\tsuccess: true,\n\t\t\t\tkey: key,\n\t\t\t};\n\n\t\t\t// If not using signed URL, return either custom endpoint or public access URL\n\t\t\tif (!useSignedUrl) {\n\t\t\t\tif (this.s3Client.config.endpoint) {\n\t\t\t\t\tconst endpoint = await this.s3Client.config.endpoint();\n\t\t\t\t\tconst port = endpoint.port ? `:${endpoint.port}` : \"\";\n\t\t\t\t\tresult.url = `${endpoint.protocol}//${endpoint.hostname}${port}${endpoint.path}${this.bucket}/${key}`;\n\t\t\t\t} else {\n\t\t\t\t\tresult.url = `https://${this.bucket}.s3.${process.env.AWS_REGION}.amazonaws.com/${key}`;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst getObjectCommand = new GetObjectCommand({\n\t\t\t\t\tBucket: this.bucket,\n\t\t\t\t\tKey: key,\n\t\t\t\t});\n\t\t\t\tresult.url = await getSignedUrl(this.s3Client, getObjectCommand, {\n\t\t\t\t\texpiresIn,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn result;\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror:\n\t\t\t\t\terror instanceof Error ? error.message : \"Unknown error occurred\",\n\t\t\t};\n\t\t}\n\t}\n}\n\nexport default AwsS3Service;\n","import {\n\ttype IAgentRuntime,\n\ttype IBrowserService,\n\tModelTypes,\n\tService,\n\ttype ServiceType,\n\tServiceTypes,\n\tlogger,\n\tparseJSONObjectFromText,\n\tsettings,\n\tstringToUuid,\n\ttrimTokens,\n} from \"@elizaos/core\";\nimport CaptchaSolver from \"capsolver-npm\";\nimport {\n\ttype Browser,\n\ttype BrowserContext,\n\ttype Page,\n\tchromium,\n} from \"patchright\";\n\n/**\n * Asynchronously generates a summary for a given text using a machine learning model.\n *\n * @param {IAgentRuntime} runtime - The runtime environment for the agent\n * @param {string} text - The text to generate a summary for\n * @returns {Promise<{ title: string; description: string }>} A promise that resolves to an object containing the generated title and summary\n */\nasync function generateSummary(\n\truntime: IAgentRuntime,\n\ttext: string,\n): Promise<{ title: string; description: string }> {\n\t// make sure text is under 128k characters\n\ttext = await trimTokens(text, 100000, runtime);\n\n\tconst prompt = `Please generate a concise summary for the following text:\n\n Text: \"\"\"\n ${text}\n \"\"\"\n\n Respond with a JSON object in the following format:\n \\`\\`\\`json\n {\n \"title\": \"Generated Title\",\n \"summary\": \"Generated summary and/or description of the text\"\n }\n \\`\\`\\``;\n\n\tconst response = await runtime.useModel(ModelTypes.TEXT_SMALL, {\n\t\tprompt,\n\t});\n\n\tconst parsedResponse = parseJSONObjectFromText(response);\n\n\tif (parsedResponse?.title && parsedResponse?.summary) {\n\t\treturn {\n\t\t\ttitle: parsedResponse.title,\n\t\t\tdescription: parsedResponse.summary,\n\t\t};\n\t}\n\n\treturn {\n\t\ttitle: \"\",\n\t\tdescription: \"\",\n\t};\n}\n\n/**\n * Represents the content of a page.\n * @typedef { Object } PageContent\n * @property { string } title - The title of the page.\n * @property { string } description - The description of the page.\n * @property { string } bodyContent - The main content of the page.\n */\ntype PageContent = {\n\ttitle: string;\n\tdescription: string;\n\tbodyContent: string;\n};\n\n/**\n * Represents a BrowserService class that extends Service and implements IBrowserService interface.\n * Provides methods for initializing browser, stopping browser, fetching page content, solving CAPTCHAs, detecting CAPTCHAs, and getting cache key.\n * @extends Service\n * @implements IBrowserService\n */\nexport class BrowserService extends Service implements IBrowserService {\n\tprivate browser: Browser | undefined;\n\tprivate context: BrowserContext | undefined;\n\tprivate captchaSolver: CaptchaSolver;\n\tprivate cacheKey = \"content/browser\";\n\n\tstatic serviceType: ServiceType = ServiceTypes.BROWSER;\n\tcapabilityDescription =\n\t\t\"The agent is able to browse the web and fetch content\";\n\n\t/**\n\t * Constructor for the Agent class.\n\t * @param {IAgentRuntime} runtime - The runtime object for the agent.\n\t */\n\tconstructor(runtime: IAgentRuntime) {\n\t\tsuper();\n\t\tthis.runtime = runtime;\n\t\tthis.browser = undefined;\n\t\tthis.context = undefined;\n\t\tthis.captchaSolver = new CaptchaSolver(settings.CAPSOLVER_API_KEY || \"\");\n\t}\n\n\t/**\n\t * Starts the BrowserService asynchronously.\n\t *\n\t * @param {IAgentRuntime} runtime - The runtime for the agent.\n\t * @returns {Promise<BrowserService>} A promise that resolves to the initialized BrowserService.\n\t */\n\tstatic async start(runtime: IAgentRuntime): Promise<BrowserService> {\n\t\tconst service = new BrowserService(runtime);\n\t\tawait service.initializeBrowser();\n\t\treturn service;\n\t}\n\n\t/**\n\t * Function to stop the browser service asynchronously.\n\t *\n\t * @param {IAgentRuntime} runtime - The runtime environment for the agent.\n\t */\n\tstatic async stop(runtime: IAgentRuntime) {\n\t\tconst service = runtime.getService(ServiceTypes.BROWSER);\n\t\tif (service) {\n\t\t\tawait service.stop();\n\t\t}\n\t}\n\n\t/**\n\t * Initializes the browser by launching Chromium with specified options and setting the user agent based on the platform.\n\t * @returns {Promise<void>} A promise that resolves once the browser is successfully initialized.\n\t */\n\tasync initializeBrowser() {\n\t\tif (!this.browser) {\n\t\t\tthis.browser = await chromium.launch({\n\t\t\t\theadless: true,\n\t\t\t\targs: [\n\t\t\t\t\t\"--disable-dev-shm-usage\", // Uses /tmp instead of /dev/shm. Prevents memory issues on low-memory systems\n\t\t\t\t\t\"--block-new-web-contents\", // Prevents creation of new windows/tabs\n\t\t\t\t],\n\t\t\t});\n\n\t\t\tconst platform = process.platform;\n\t\t\tlet userAgent = \"\";\n\n\t\t\t// Change the user agent to match the platform to reduce bot detection\n\t\t\tswitch (platform) {\n\t\t\t\tcase \"darwin\":\n\t\t\t\t\tuserAgent =\n\t\t\t\t\t\t\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"win32\":\n\t\t\t\t\tuserAgent =\n\t\t\t\t\t\t\"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"linux\":\n\t\t\t\t\tuserAgent =\n\t\t\t\t\t\t\"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36\";\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tuserAgent =\n\t\t\t\t\t\t\"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36\";\n\t\t\t}\n\n\t\t\tthis.context = await this.browser.newContext({\n\t\t\t\tuserAgent,\n\t\t\t\tacceptDownloads: false,\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Asynchronously stops the browser and context if they are currently running.\n\t */\n\tasync stop() {\n\t\tif (this.context) {\n\t\t\tawait this.context.close();\n\t\t\tthis.context = undefined;\n\t\t}\n\t\tif (this.browser) {\n\t\t\tawait this.browser.close();\n\t\t\tthis.browser = undefined;\n\t\t}\n\t}\n\n\t/**\n\t * Asynchronously fetches the content of a web page.\n\t *\n\t * @param {string} url - The URL of the web page to fetch content from.\n\t * @param {IAgentRuntime} runtime - The runtime environment for the web scraping agent.\n\t * @returns {Promise<PageContent>} A Promise that resolves with the content of the web page.\n\t */\n\tasync getPageContent(\n\t\turl: string,\n\t\truntime: IAgentRuntime,\n\t): Promise<PageContent> {\n\t\tawait this.initializeBrowser();\n\t\treturn await this.fetchPageContent(url, runtime);\n\t}\n\n\t/**\n\t * Generates a cache key for the provided URL by converting it to a UUID string.\n\t *\n\t * @param {string} url - The URL for which a cache key is being generated.\n\t * @returns {string} A UUID string representing the cache key for the URL.\n\t */\n\tprivate getCacheKey(url: string): string {\n\t\treturn stringToUuid(url);\n\t}\n\n\t/**\n\t * Fetches the content of a page from the specified URL using a headless browser.\n\t *\n\t * @param {string} url - The URL of the page to fetch the content from.\n\t * @param {IAgentRuntime} runtime - The runtime environment for the agent.\n\t * @returns {Promise<PageContent>} A promise that resolves to the content of the fetched page.\n\t */\n\tprivate async fetchPageContent(\n\t\turl: string,\n\t\truntime: IAgentRuntime,\n\t): Promise<PageContent> {\n\t\tconst cacheKey = this.getCacheKey(url);\n\t\tconst cached = await runtime\n\t\t\t\n\t\t\t.getCache<any>(`${this.cacheKey}/${cacheKey}`);\n\n\t\tif (cached) {\n\t\t\treturn cached.content;\n\t\t}\n\n\t\tlet page: Page | undefined;\n\n\t\ttry {\n\t\t\tif (!this.context) {\n\t\t\t\tlogger.log(\n\t\t\t\t\t\"Browser context not initialized. Call initializeBrowser() first.\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tpage = await this.context.newPage();\n\n\t\t\t// Enable stealth mode\n\t\t\tawait page.setExtraHTTPHeaders({\n\t\t\t\t\"Accept-Language\": \"en-US,en;q=0.9\",\n\t\t\t});\n\n\t\t\tconst response = await page.goto(url, { waitUntil: \"networkidle\" });\n\n\t\t\tif (!response) {\n\t\t\t\tlogger.error(\"Failed to load the page\");\n\t\t\t}\n\n\t\t\tif (response.status() === 403 || response.status() === 404) {\n\t\t\t\treturn await this.tryAlternativeSources(url, runtime);\n\t\t\t}\n\n\t\t\t// Check for CAPTCHA\n\t\t\tconst captchaDetected = await this.detectCaptcha(page);\n\t\t\tif (captchaDetected) {\n\t\t\t\tawait this.solveCaptcha(page, url);\n\t\t\t}\n\t\t\tconst documentTitle = await page.evaluate(() => document.title);\n\t\t\tconst bodyContent = await page.evaluate(() => document.body.innerText);\n\t\t\tconst { title: parsedTitle, description } = await generateSummary(\n\t\t\t\truntime,\n\t\t\t\t`${documentTitle}\\n${bodyContent}`,\n\t\t\t);\n\t\t\tconst content = { title: parsedTitle, description, bodyContent };\n\t\t\tawait runtime\n\t\t\t\t\n\t\t\t\t.setCache<any>(`${this.cacheKey}/${cacheKey}`, {\n\t\t\t\t\turl,\n\t\t\t\t\tcontent,\n\t\t\t\t});\n\t\t\treturn content;\n\t\t} catch (error) {\n\t\t\tlogger.error(\"Error:\", error);\n\t\t\treturn {\n\t\t\t\ttitle: url,\n\t\t\t\tdescription: \"Error, could not fetch content\",\n\t\t\t\tbodyContent: \"\",\n\t\t\t};\n\t\t} finally {\n\t\t\tif (page) {\n\t\t\t\tawait page.close();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Detects if a captcha is present on the page based on the specified selectors.\n\t *\n\t * @param {Page} page The Puppeteer page to check for captcha.\n\t * @returns {Promise<boolean>} A boolean indicating whether a captcha was detected.\n\t */\n\tprivate async detectCaptcha(page: Page): Promise<boolean> {\n\t\tconst captchaSelectors = [\n\t\t\t'iframe[src*=\"captcha\"]',\n\t\t\t'div[class*=\"captcha\"]',\n\t\t\t\"#captcha\",\n\t\t\t\".g-recaptcha\",\n\t\t\t\".h-captcha\",\n\t\t];\n\n\t\tfor (const selector of captchaSelectors) {\n\t\t\tconst element = await page.$(selector);\n\t\t\tif (element) return true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Solves the CAPTCHA challenge on the provided page using either hCaptcha or reCaptcha.\n\t *\n\t * @param {Page} page - The page where the CAPTCHA challenge needs to be solved.\n\t * @param {string} url - The URL of the website with the CAPTCHA challenge.\n\t * @returns {Promise<void>} - A promise that resolves once the CAPTCHA is solved.\n\t */\n\tprivate async solveCaptcha(page: Page, url: string): Promise<void> {\n\t\ttry {\n\t\t\tconst hcaptchaKey = await this.getHCaptchaWebsiteKey(page);\n\t\t\tif (hcaptchaKey) {\n\t\t\t\tconst solution = await this.captchaSolver.hcaptchaProxyless({\n\t\t\t\t\twebsiteURL: url,\n\t\t\t\t\twebsiteKey: hcaptchaKey,\n\t\t\t\t});\n\t\t\t\tawait page.evaluate((token) => {\n\t\t\t\t\t// eslint-disable-next-line\n\t\t\t\t\t// @ts-ignore\n\t\t\t\t\twindow.hcaptcha.setResponse(token);\n\t\t\t\t}, solution.gRecaptchaResponse);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst recaptchaKey = await this.getReCaptchaWebsiteKey(page);\n\t\t\tif (recaptchaKey) {\n\t\t\t\tconst solution = await this.captchaSolver.recaptchaV2Proxyless({\n\t\t\t\t\twebsiteURL: url,\n\t\t\t\t\twebsiteKey: recaptchaKey,\n\t\t\t\t});\n\t\t\t\tawait page.evaluate((token) => {\n\t\t\t\t\t// eslint-disable-next-line\n\t\t\t\t\t// @ts-ignore\n\t\t\t\t\tdocument.getElementById(\"g-recaptcha-response\").innerHTML = token;\n\t\t\t\t}, solution.gRecaptchaResponse);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tlogger.error(\"Error solving CAPTCHA:\", error);\n\t\t}\n\t}\n\n\t/**\n\t * Get the hCaptcha website key from the given Page\n\t * @param {Page} page - The Page object to extract the hCaptcha website key from\n\t * @returns {Promise<string>} The hCaptcha website key\n\t */\n\tprivate async getHCaptchaWebsiteKey(page: Page): Promise<string> {\n\t\treturn page.evaluate(() => {\n\t\t\tconst hcaptchaIframe = document.querySelector(\n\t\t\t\t'iframe[src*=\"hcaptcha.com\"]',\n\t\t\t);\n\t\t\tif (hcaptchaIframe) {\n\t\t\t\tconst src = hcaptchaIframe.getAttribute(\"src\");\n\t\t\t\tconst match = src?.match(/sitekey=([^&]*)/);\n\t\t\t\treturn match ? match[1] : \"\";\n\t\t\t}\n\t\t\treturn \"\";\n\t\t});\n\t}\n\n\t/**\n\t * Retrieves the ReCaptcha website key from a given page.\n\t * @param {Page} page - The page to extract the ReCaptcha website key from.\n\t * @returns {Promise<string>} The ReCaptcha website key, or an empty string if not found.\n\t */\n\tprivate async getReCaptchaWebsiteKey(page: Page): Promise<string> {\n\t\treturn page.evaluate(() => {\n\t\t\tconst recaptchaElement = document.querySelector(\".g-recaptcha\");\n\t\t\treturn recaptchaElement\n\t\t\t\t? recaptchaElement.getAttribute(\"data-sitekey\") || \"\"\n\t\t\t\t: \"\";\n\t\t});\n\t}\n\n\t/**\n\t * Try fetching content from alternative sources if the original source fails.\n\t *\n\t * @param {string} url - The URL of the content to fetch.\n\t * @param {IAgentRuntime} runtime - The runtime environment.\n\t * @returns {Promise<{ title: string; description: string; bodyContent: string }>} The fetched content with title, description, and body.\n\t */\n\tprivate async tryAlternativeSources(\n\t\turl: string,\n\t\truntime: IAgentRuntime,\n\t): Promise<{ title: string; description: string; bodyContent: string }> {\n\t\t// because this (tryAlternativeSources) calls fetchPageContent\n\t\t// and fetchPageContent calls tryAlternativeSources\n\t\t// we need these url.matches to progress\n\t\t// through the things to try\n\t\tif (!url.match(/web.archive.org\\/web/)) {\n\t\t\t// Try Internet Archive\n\t\t\tconst archiveUrl = `https://web.archive.org/web/${url}`;\n\t\t\ttry {\n\t\t\t\treturn await this.fetchPageContent(archiveUrl, runtime);\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\"Error fetching from Internet Archive:\", error);\n\t\t\t}\n\t\t}\n\n\t\tif (!url.match(/www.google.com\\/search/)) {\n\t\t\t// Try Google Search as a last resort\n\t\t\tconst googleSearchUrl = `https://www.google.com/search?q=${encodeURIComponent(\n\t\t\t\turl,\n\t\t\t)}`;\n\t\t\ttry {\n\t\t\t\treturn await this.fetchPageContent(googleSearchUrl, runtime);\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\"Error fetching from Google Search:\", error);\n\t\t\t\tlogger.error(\"Failed to fetch content from alternative sources\");\n\t\t\t\treturn {\n\t\t\t\t\ttitle: url,\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Error, could not fetch content from alternative sources\",\n\t\t\t\t\tbodyContent: \"\",\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t}\n}\n","import {\n\ttype IAgentRuntime,\n\ttype IPdfService,\n\tService,\n\ttype ServiceType,\n\tServiceTypes,\n} from \"@elizaos/core\";\nimport { type PDFDocumentProxy, getDocument } from \"pdfjs-dist\";\nimport type {\n\tTextItem,\n\tTextMarkedContent,\n} from \"pdfjs-dist/types/src/display/api\";\n\n/**\n * Class representing a PDF service that can convert PDF files to text.\n * * @extends Service\n * @implements IPdfService\n */\nexport class PdfService extends Service implements IPdfService {\n\tstatic serviceType: ServiceType = ServiceTypes.PDF;\n\tcapabilityDescription = \"The agent is able to convert PDF files to text\";\n\n\t/**\n\t * Constructor for creating a new instance of the class.\n\t *\n\t * @param {IAgentRuntime} runtime - The runtime object passed to the constructor.\n\t */\n\tconstructor(runtime: IAgentRuntime) {\n\t\tsuper();\n\t\tthis.runtime = runtime;\n\t}\n\n\t/**\n\t * Starts the PdfService asynchronously.\n\t * @param {IAgentRuntime} runtime - The runtime object for the agent.\n\t * @returns {Promise<PdfService>} A promise that resolves with the PdfService instance.\n\t */\n\tstatic async start(runtime: IAgentRuntime): Promise<PdfService> {\n\t\tconst service = new PdfService(runtime);\n\t\treturn service;\n\t}\n\n\t/**\n\t * Stop the PDF service in the given runtime.\n\t *\n\t * @param {IAgentRuntime} runtime - The runtime to stop the PDF service in.\n\t * @returns {Promise<void>} - A promise that resolves once the PDF service is stopped.\n\t */\n\tstatic async stop(runtime: IAgentRuntime) {\n\t\tconst service = runtime.getService(ServiceTypes.PDF);\n\t\tif (service) {\n\t\t\tawait service.stop();\n\t\t}\n\t}\n\n\t/**\n\t * Asynchronously stops the process.\n\t * Does nothing.\n\t */\n\tasync stop() {\n\t\t// do nothing\n\t}\n\n\t/**\n\t * Converts a PDF Buffer to text.\n\t *\n\t * @param {Buffer} pdfBuffer - The PDF Buffer to convert to text.\n\t * @returns {Promise<string>} A Promise that resolves with the text content of the PDF.\n\t */\n\tasync convertPdfToText(pdfBuffer: Buffer): Promise<string> {\n\t\t// Convert Buffer to Uint8Array\n\t\tconst uint8Array = new Uint8Array(pdfBuffer);\n\n\t\tconst pdf: PDFDocumentProxy = await getDocument({ data: uint8Array })\n\t\t\t.promise;\n\t\tconst numPages = pdf.numPages;\n\t\tconst textPages: string[] = [];\n\n\t\tfor (let pageNum = 1; pageNum <= numPages; pageNum++) {\n\t\t\tconst page = await pdf.getPage(pageNum);\n\t\t\tconst textContent = await page.getTextContent();\n\t\t\tconst pageText = textContent.items\n\t\t\t\t.filter(isTextItem)\n\t\t\t\t.map((item) => item.str)\n\t\t\t\t.join(\" \");\n\t\t\ttextPages.push(pageText);\n\t\t}\n\n\t\treturn textPages.join(\"\\n\");\n\t}\n}\n\n// Type guard function\n/**\n * Check if the input is a TextItem.\n *\n * @param item - The input item to check.\n * @returns A boolean indicating if the input is a TextItem.\n */\nfunction isTextItem(item: TextItem | TextMarkedContent): item is TextItem {\n\treturn \"str\" in item;\n}\n","import fs from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport path from \"node:path\";\nimport {\n\ttype IAgentRuntime,\n\ttype IVideoService,\n\ttype Media,\n\tModelTypes,\n\tService,\n\ttype ServiceType,\n\tServiceTypes,\n\tlogger,\n\tstringToUuid,\n} from \"@elizaos/core\";\nimport ffmpeg from \"fluent-ffmpeg\";\nimport ytdl, { create } from \"youtube-dl-exec\";\n\n/**\n * Function to get the Youtube DL executable path.\n * It first checks if /usr/local/bin/yt-dlp exists,\n * if it does, it returns the path to that executable.\n * If not, it checks if /usr/bin/yt-dlp exists,\n * and returns the path if found.\n * If neither paths exist, it returns the default ytdl executable.\n * @returns {string} The path to the Youtube DL executable.\n */\nfunction getYoutubeDL() {\n\t// first check if /usr/local/bin/yt-dlp exists\n\tif (fs.existsSync(\"/usr/local/bin/yt-dlp\")) {\n\t\treturn create(\"/usr/local/bin/yt-dlp\");\n\t}\n\n\t// if not, check if /usr/bin/yt-dlp exists\n\tif (fs.existsSync(\"/usr/bin/yt-dlp\")) {\n\t\treturn create(\"/usr/bin/yt-dlp\");\n\t}\n\n\t// use default otherwise\n\treturn ytdl;\n}\n\n/**\n * VideoService class that extends Service and implements IVideoService interface.\n * Defines the service type as VIDEO and sets capability description for processing videos.\n * Manages caching of video content with cacheKey and dataDir properties.\n * Maintains a queue of video processing tasks and tracks processing status.\n */\nexport class VideoService extends Service implements IVideoService {\n\tstatic serviceType: ServiceType = ServiceTypes.VIDEO;\n\tcapabilityDescription = \"The agent is able to download and process videos\";\n\tprivate cacheKey = \"content/video\";\n\tprivate dataDir = \"./cache\";\n\n\tprivate queue: string[] = [];\n\tprivate processing = false;\n\n\t/**\n\t * Constructor for creating a new instance of the object.\n\t *\n\t * @param {IAgentRuntime} runtime - The runtime object to be used by the instance\n\t */\n\tconstructor(runtime: IAgentRuntime) {\n\t\tsuper();\n\t\tthis.runtime = runtime;\n\t\tthis.ensureDataDirectoryExists();\n\t}\n\n\t/**\n\t * Starts the VideoService by initializing it with the given IAgentRuntime instance.\n\t *\n\t * @param {IAgentRuntime} runtime - The IAgentRuntime instance to initialize the service with.\n\t * @returns {Promise<VideoService>} A promise that resolves to the initialized VideoService instance.\n\t */\n\tstatic async start(runtime: IAgentRuntime): Promise<VideoService> {\n\t\tconst service = new VideoService(runtime);\n\t\treturn service;\n\t}\n\n\t/**\n\t * Stops the video service if it is running.\n\t *\n\t * @param {IAgentRuntime} runtime - The agent runtime instance\n\t * @returns {Promise<void>} A promise that resolves once the video service is stopped\n\t */\n\tstatic async stop(runtime: IAgentRuntime) {\n\t\tconst service = runtime.getService(ServiceTypes.VIDEO);\n\t\tif (service) {\n\t\t\tawait service.stop();\n\t\t}\n\t}\n\n\t/**\n\t * Asynchronous method to stop the operation.\n\t */\n\tasync stop() {\n\t\t// do nothing\n\t}\n\n\t/**\n\t * Checks if the data directory exists, and if not, creates it.\n\t */\n\tprivate ensureDataDirectoryExists() {\n\t\tif (!fs.existsSync(this.dataDir)) {\n\t\t\tfs.mkdirSync(this.dataDir);\n\t\t}\n\t}\n\n\t/**\n\t * Check if a given URL is a video URL from YouTube or Vimeo.\n\t *\n\t * @param {string} url - The URL to check.\n\t * @return {boolean} Returns true if the URL is from YouTube or Vimeo, false otherwise.\n\t */\n\tpublic isVideoUrl(url: string): boolean {\n\t\treturn (\n\t\t\turl.includes(\"youtube.com\") ||\n\t\t\turl.includes(\"youtu.be\") ||\n\t\t\turl.includes(\"vimeo.com\")\n\t\t);\n\t}\n\n\t/**\n\t * Downloads media from a given URL. If the media already exists, it returns the file path.\n\t *\n\t * @param {string} url - The URL of the media to download.\n\t * @returns {Promise<string>} A promise that resolves to the file path of the downloaded media.\n\t * @throws {Error} If there is an error downloading the media.\n\t */\n\tpublic async downloadMedia(url: string): Promise<string> {\n\t\tconst videoId = this.getVideoId(url);\n\t\tconst outputFile = path.join(this.dataDir, `${videoId}.mp4`);\n\n\t\t// if it already exists, return it\n\t\tif (fs.existsSync(outputFile)) {\n\t\t\treturn outputFile;\n\t\t}\n\n\t\ttry {\n\t\t\tawait getYoutubeDL()(url, {\n\t\t\t\tverbose: true,\n\t\t\t\toutput: outputFile,\n\t\t\t\twriteInfoJson: true,\n\t\t\t});\n\t\t\treturn outputFile;\n\t\t} catch (error) {\n\t\t\tlogger.log(\"Error downloading media:\", error);\n\t\t\tthrow new Error(\"Failed to download media\");\n\t\t}\n\t}\n\n\t/**\n\t * Downloads a video using the videoInfo object provided and returns the path to the downloaded video file.\n\t * If the video file already exists, it will return the path without re-downloading.\n\t * @param {Object} videoInfo - Information about the video to download.\n\t * @returns {Promise<string>} - Path to the downloaded video file.\n\t */\n\tpublic async downloadVideo(videoInfo: any): Promise<string> {\n\t\tconst videoId = this.getVideoId(videoInfo.webpage_url);\n\t\tconst outputFile = path.join(this.dataDir, `${videoId}.mp4`);\n\n\t\t// if it already exists, return it\n\t\tif (fs.existsSync(outputFile)) {\n\t\t\treturn outputFile;\n\t\t}\n\n\t\ttry {\n\t\t\tawait getYoutubeDL()(videoInfo.webpage_url, {\n\t\t\t\tverbose: true,\n\t\t\t\toutput: outputFile,\n\t\t\t\tformat: \"bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best\",\n\t\t\t\twriteInfoJson: true,\n\t\t\t});\n\t\t\treturn outputFile;\n\t\t} catch (error) {\n\t\t\tlogger.log(\"Error downloading video:\", error);\n\t\t\tthrow new Error(\"Failed to download video\");\n\t\t}\n\t}\n\n\t/**\n\t * Process a video from the given URL using the provided agent runtime.\n\t *\n\t * @param {string} url - The URL of the video to be processed\n\t * @param {IAgentRuntime} runtime - The agent runtime to be used for processing the video\n\t * @returns {Promise<Media>} A promise that resolves to the processed media\n\t */\n\tpublic async processVideo(\n\t\turl: string,\n\t\truntime: IAgentRuntime,\n\t): Promise<Media> {\n\t\tthis.queue.push(url);\n\t\tawait this.processQueue(runtime);\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst checkQueue = async () => {\n\t\t\t\tconst index = this.queue.indexOf(url);\n\t\t\t\tif (index !== -1) {\n\t\t\t\t\tsetTimeout(checkQueue, 100);\n\t\t\t\t} else {\n\t\t\t\t\tthis.processVideoFromUrl(url, runtime).then(resolve).catch(reject);\n\t\t\t\t}\n\t\t\t};\n\t\t\tcheckQueue();\n\t\t});\n\t}\n\n\t/**\n\t * Processes the queue of URLs by calling processVideoFromUrl for each URL.\n\t *\n\t * @param {any} runtime - The runtime information for processing the videos.\n\t * @returns {Promise<void>} - A promise that resolves when the queue has been processed.\n\t */\n\tprivate async processQueue(runtime): Promise<void> {\n\t\tif (this.processing || this.queue.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.processing = true;\n\n\t\twhile (this.queue.length > 0) {\n\t\t\tconst url = this.queue.shift()!;\n\t\t\tawait this.processVideoFromUrl(url, runtime);\n\t\t}\n\n\t\tthis.processing = false;\n\t}\n\n\t/**\n\t * Processes a video from a given URL.\n\t * Retrieves video information, transcript, and caches the result.\n\t *\n\t * @param {string} url - The URL of the video to process.\n\t * @param {IAgentRuntime} runtime - The runtime environment for the agent.\n\t * @returns {Promise<Media>} A promise that resolves to the processed video data.\n\t * @throws {Error} If there is an error processing the video.\n\t */\n\tprivate async processVideoFromUrl(\n\t\turl: string,\n\t\truntime: IAgentRuntime,\n\t): Promise<Media> {\n\t\tconst videoId =\n\t\t\turl.match(\n\t\t\t\t/(?:youtu\\.be\\/|youtube\\.com(?:\\/embed\\/|\\/v\\/|\\/watch\\?v=|\\/watch\\?.+&v=))([^\\/&?]+)/, // eslint-disable-line\n\t\t\t)?.[1] || \"\";\n\t\tconst videoUuid = this.getVideoId(videoId);\n\t\tconst cacheKey = `${this.cacheKey}/${videoUuid}`;\n\n\t\tconst cached = await runtime.getCache<Media>(cacheKey);\n\n\t\tif (cached) {\n\t\t\tlogger.log(\"Returning cached video file\");\n\t\t\treturn cached;\n\t\t}\n\n\t\ttry {\n\t\t\tlogger.log(\"Cache miss, processing video\");\n\t\t\tlogger.log(\"Fetching video info\");\n\t\t\tconst videoInfo = await this.fetchVideoInfo(url);\n\t\t\tconsole.log(\"Getting transcript\");\n\t\t\tconst transcript = await this.getTranscript(url, videoInfo, runtime);\n\n\t\t\tconst result: Media = {\n\t\t\t\tid: videoUuid,\n\t\t\t\turl: url,\n\t\t\t\ttitle: videoInfo.title,\n\t\t\t\tsource: videoInfo.channel,\n\t\t\t\tdescription: videoInfo.description,\n\t\t\t\ttext: transcript,\n\t\t\t};\n\n\t\t\tawait runtime.setCache<Media>(cacheKey, result);\n\n\t\t\treturn result;\n\t\t} catch (error) {\n\t\t\tthrow new Error(`Error processing video: ${error.message || error}`);\n\t\t}\n\t}\n\n\t/**\n\t * Returns the unique video ID generated from the provided URL.\n\t * @param {string} url - The URL used to generate the video ID.\n\t * @returns {string} The unique video ID.\n\t */\n\tprivate getVideoId(url: string): string {\n\t\treturn stringToUuid(url);\n\t}\n\n\t/**\n\t * Asynchronously fetches video information from the provided URL. If the URL ends with \".mp4\" or includes \".mp4?\", attempts to fetch the video directly using fetch. If successful, returns a simplified video info object with title, description, and channel. If direct download fails, falls back to using youtube-dl to fetch video information. Utilizes options such as dumpJson, verbose, callHome, noCheckCertificates, preferFreeFormats, youtubeSkipDashManifest, writeSub, writeAutoSub, subLang, and skipDownload when calling youtube-dl. Throws an error if the response from youtube-dl is empty or if there is an error during the process.\n\t *\n\t * @param {string} url - The URL from which to fetch video information\n\t * @returns {Promise<any>} A Promise resolving to the fetched video information or rejecting with an error message\n\t */\n\tasync fetchVideoInfo(url: string): Promise<any> {\n\t\tconsole.log(\"url\", url);\n\t\tif (url.endsWith(\".mp4\") || url.includes(\".mp4?\")) {\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(url);\n\t\t\t\tif (response.ok) {\n\t\t\t\t\t// If the URL is a direct link to an MP4 file, return a simplified video info object\n\t\t\t\t\treturn {\n\t\t\t\t\t\ttitle: path.basename(url),\n\t\t\t\t\t\tdescription: \"\",\n\t\t\t\t\t\tchannel: \"\",\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tlogger.log(\"Error downloading MP4 file:\", error);\n\t\t\t\t// Fall back to using youtube-dl if direct download fails\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\t\t\tconst result = await getYoutubeDL()(url, {\n\t\t\t\tdumpJson: true,\n\t\t\t\tverbose: true,\n\t\t\t\tcallHome: false,\n\t\t\t\tnoCheckCertificates: true,\n\t\t\t\tpreferFreeFormats: true,\n\t\t\t\tyoutubeSkipDashManifest: true,\n\t\t\t\twriteSub: true,\n\t\t\t\twriteAutoSub: true,\n\t\t\t\tsubLang: \"en\",\n\t\t\t\tskipDownload: true,\n\t\t\t});\n\n\t\t\tif (!result || Object.keys(result).length === 0) {\n\t\t\t\tthrow new Error(\"Empty response from youtube-dl\");\n\t\t\t}\n\n\t\t\treturn result;\n\t\t} catch (error) {\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to fetch video information: ${error.message || error}`,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Asynchronously retrieves the transcript of a video based on the provided URL, video information, and runtime environment.\n\t *\n\t * @param {string} url - The URL of the video.\n\t * @param {any} videoInfo - Information about the video, including subtitles, automatic captions, and categories.\n\t * @param {IAgentRuntime} runtime - The runtime environment of the agent.\n\t * @returns {Promise<string>} A Promise that resolves to the transcript of the video.\n\t */\n\tprivate async getTranscript(\n\t\turl: string,\n\t\tvideoInfo: any,\n\t\truntime: IAgentRuntime,\n\t): Promise<string> {\n\t\tlogger.log(\"Getting transcript\");\n\t\ttry {\n\t\t\t// Check for manual subtitles\n\t\t\tif (videoInfo.subtitles?.en) {\n\t\t\t\tlogger.log(\"Manual subtitles found\");\n\t\t\t\tconst srtContent = await this.downloadSRT(\n\t\t\t\t\tvideoInfo.subtitles.en[0].url,\n\t\t\t\t);\n\t\t\t\treturn this.parseSRT(srtContent);\n\t\t\t}\n\n\t\t\t// Check for automatic captions\n\t\t\tif (videoInfo.automatic_captions?.en) {\n\t\t\t\tlogger.log(\"Automatic captions found\");\n\t\t\t\tconst captionUrl = videoInfo.automatic_captions.en[0].url;\n\t\t\t\tconst captionContent = await this.downloadCaption(captionUrl);\n\t\t\t\treturn this.parseCaption(captionContent);\n\t\t\t}\n\n\t\t\t// Check if it's a music video\n\t\t\tif (videoInfo.categories?.includes(\"Music\")) {\n\t\t\t\tlogger.log(\"Music video detected, no lyrics available\");\n\t\t\t\treturn \"No lyrics available.\";\n\t\t\t}\n\n\t\t\t// Fall back to audio transcription\n\t\t\tlogger.log(\n\t\t\t\t\"No subtitles or captions found, falling back to audio transcription\",\n\t\t\t);\n\t\t\treturn this.transcribeAudio(url, runtime);\n\t\t} catch (error) {\n\t\t\tlogger.log(\"Error in getTranscript:\", error);\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t/**\n\t * Downloads a caption from the specified URL.\n\t * @param {string} url - The URL from which to download the caption.\n\t * @returns {Promise<string>} A promise that resolves with the downloaded caption as a string.\n\t * @throws {Error} If the caption download fails, an error is thrown with the reason.\n\t */\n\tprivate async downloadCaption(url: string): Promise<string> {\n\t\tlogger.log(\"Downloading caption from:\", url);\n\t\tconst response = await fetch(url);\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(`Failed to download caption: ${response.statusText}`);\n\t\t}\n\t\treturn await response.text();\n\t}\n\n\t/**\n\t * Parses the given caption content to extract relevant information.\n\t *\n\t * @param {string} captionContent - The caption content to parse.\n\t * @returns {string} The extracted caption information as a string.\n\t */\n\tprivate parseCaption(captionContent: string): string {\n\t\tlogger.log(\"Parsing caption\");\n\t\ttry {\n\t\t\tconst jsonContent = JSON.parse(captionContent);\n\t\t\tif (jsonContent.events) {\n\t\t\t\treturn jsonContent.events\n\t\t\t\t\t.filter((event) => event.segs)\n\t\t\t\t\t.map((event) => event.segs.map((seg) => seg.utf8).join(\"\"))\n\t\t\t\t\t.join(\"\")\n\t\t\t\t\t.replace(\"\\n\", \" \");\n\t\t\t}\n\t\t\tlogger.log(\"Unexpected caption format:\", jsonContent);\n\t\t\treturn \"Error: Unable to parse captions\";\n\t\t} catch (error) {\n\t\t\tlogger.log(\"Error parsing caption:\", error);\n\t\t\treturn \"Error: Unable to parse captions\";\n\t\t}\n\t}\n\n\t/**\n\t * Parses SRT (SubRip) content to extract subtitles.\n\t *\n\t * @param {string} srtContent - The SRT content to parse.\n\t * @returns {string} The parsed subtitles as a single string.\n\t */\n\tprivate parseSRT(srtContent: string): string {\n\t\t// Simple SRT parser (replace with a more robust solution if needed)\n\t\treturn srtContent\n\t\t\t.split(\"\\n\\n\")\n\t\t\t.map((block) => block.split(\"\\n\").slice(2).join(\" \"))\n\t\t\t.join(\" \");\n\t}\n\n\t/**\n\t * Asynchronously downloads a SubRip subtitle file from the specified URL.\n\t *\n\t * @param {string} url - The URL of the subtitle file to download.\n\t * @returns {Promise<string>} A promise that resolves to the text content of the downloaded subtitle file.\n\t */\n\tprivate async downloadSRT(url: string): Promise<string> {\n\t\tlogger.log(\"downloadSRT\");\n\t\tconst response = await fetch(url);\n\t\treturn await response.text();\n\t}\n\n\t/**\n\t * Asynchronously transcribes audio from the provided URL using the agent runtime.\n\t *\n\t * @param {string} url - The URL of the audio file to transcribe.\n\t * @param {IAgentRuntime} runtime - The agent runtime to use for transcription.\n\t * @returns {Promise<string>} A promise that resolves with the transcription result, or \"Transcription failed\" if the process was unsuccessful.\n\t */\n\tasync transcribeAudio(url: string, runtime: IAgentRuntime): Promise<string> {\n\t\tlogger.log(\"Preparing audio for transcription...\");\n\n\t\t// Check if ffmpeg exists in PATH\n\t\ttry {\n\t\t\tawait new Promise((resolve, reject) => {\n\t\t\t\tffmpeg.getAvailableCodecs((err, _codecs) => {\n\t\t\t\t\tif (err) reject(err);\n\t\t\t\t\tresolve(null);\n\t\t\t\t});\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tlogger.log(\"FFmpeg not found:\", error);\n\t\t\treturn null;\n\t\t}\n\n\t\tconst mp4FilePath = path.join(this.dataDir, `${this.getVideoId(url)}.mp4`);\n\n\t\tconst webmFilePath = path.join(\n\t\t\tthis.dataDir,\n\t\t\t`${this.getVideoId(url)}.webm`,\n\t\t);\n\n\t\tconst mp3FilePath = path.join(this.dataDir, `${this.getVideoId(url)}.mp3`);\n\n\t\tif (!fs.existsSync(mp3FilePath)) {\n\t\t\tif (fs.existsSync(webmFilePath)) {\n\t\t\t\tlogger.log(\"WEBM file found. Converting to MP3...\");\n\t\t\t\tawait this.convertWebmToMp3(webmFilePath, mp3FilePath);\n\t\t\t} else if (fs.existsSync(mp4FilePath)) {\n\t\t\t\tlogger.log(\"MP4 file found. Converting to MP3...\");\n\t\t\t\tawait this.convertMp4ToMp3(mp4FilePath, mp3FilePath);\n\t\t\t} else {\n\t\t\t\tlogger.log(\"Downloading audio...\");\n\t\t\t\tawait this.downloadAudio(url, mp3FilePath);\n\t\t\t}\n\t\t}\n\n\t\tlogger.log(`Audio prepared at ${mp3FilePath}`);\n\n\t\tconst audioBuffer = fs.readFileSync(mp3FilePath);\n\t\tlogger.log(`Audio file size: ${audioBuffer.length} bytes`);\n\n\t\tlogger.log(\"Starting transcription...\");\n\t\tconst startTime = Date.now();\n\t\tconst transcript = await runtime.useModel(\n\t\t\tModelTypes.TRANSCRIPTION,\n\t\t\taudioBuffer,\n\t\t);\n\n\t\tconst endTime = Date.now();\n\t\tlogger.log(\n\t\t\t`Transcription completed in ${(endTime - startTime) / 1000} seconds`,\n\t\t);\n\n\t\t// Don't delete the MP3 file as it might be needed for future use\n\t\treturn transcript || \"Transcription failed\";\n\t}\n\n\t/**\n\t * Converts a given MP4 file to MP3 format.\n\t *\n\t * @param {string} inputPath - The path to the input MP4 file.\n\t * @param {string} outputPath - The desired path for the output MP3 file.\n\t * @returns {Promise<void>} A Promise that resolves once the conversion is complete or rejects with an error.\n\t */\n\tprivate async convertMp4ToMp3(\n\t\tinputPath: string,\n\t\toutputPath: string,\n\t): Promise<void> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tffmpeg(inputPath)\n\t\t\t\t.output(outputPath)\n\t\t\t\t.noVideo()\n\t\t\t\t.audioCodec(\"libmp3lame\")\n\t\t\t\t.on(\"end\", () => {\n\t\t\t\t\tlogger.log(\"Conversion to MP3 complete\");\n\t\t\t\t\tresolve();\n\t\t\t\t})\n\t\t\t\t.on(\"error\", (err) => {\n\t\t\t\t\tlogger.log(\"Error converting to MP3:\", err);\n\t\t\t\t\treject(err);\n\t\t\t\t})\n\t\t\t\t.run();\n\t\t});\n\t}\n\n\t/**\n\t * Convert a WebM file to MP3 format.\n\t *\n\t * @param {string} inputPath - The path of the WebM file to convert.\n\t * @param {string} outputPath - The path where the MP3 file will be saved.\n\t * @returns {Promise<void>} Promise that resolves when the conversion is complete.\n\t */\n\tprivate async convertWebmToMp3(\n\t\tinputPath: string,\n\t\toutputPath: string,\n\t): Promise<void> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tffmpeg(inputPath)\n\t\t\t\t.output(outputPath)\n\t\t\t\t.noVideo()\n\t\t\t\t.audioCodec(\"libmp3lame\")\n\t\t\t\t.on(\"end\", () => {\n\t\t\t\t\tlogger.log(\"Conversion to MP3 complete\");\n\t\t\t\t\tresolve();\n\t\t\t\t})\n\t\t\t\t.on(\"error\", (err) => {\n\t\t\t\t\tlogger.log(\"Error converting to MP3:\", err);\n\t\t\t\t\treject(err);\n\t\t\t\t})\n\t\t\t\t.run();\n\t\t});\n\t}\n\n\t/**\n\t * Downloads audio from a given URL and saves it to the specified output file.\n\t * If no output file is provided, it will default to saving the audio in the data directory with the video ID as the filename.\n\t * Supports downloading and converting MP4 files to MP3 as well as downloading audio from YouTube videos using youtube-dl.\n\t *\n\t * @param url - The URL of the audio to download.\n\t * @param outputFile - The path to save the downloaded audio file. If not provided, it defaults to saving in the data directory with the video ID as the filename.\n\t * @returns A Promise that resolves with the path to the downloaded audio file.\n\t * @throws Error if there is an issue during the download process.\n\t */\n\tprivate async downloadAudio(\n\t\turl: string,\n\t\toutputFile: string,\n\t): Promise<string> {\n\t\tlogger.log(\"Downloading audio\");\n\t\toutputFile =\n\t\t\toutputFile ?? path.join(this.dataDir, `${this.getVideoId(url)}.mp3`);\n\n\t\ttry {\n\t\t\tif (url.endsWith(\".mp4\") || url.includes(\".mp4?\")) {\n\t\t\t\tlogger.log(\n\t\t\t\t\t\"Direct MP4 file detected, downloading and converting to MP3\",\n\t\t\t\t);\n\t\t\t\tconst tempMp4File = path.join(tmpdir(), `${this.getVideoId(url)}.mp4`);\n\t\t\t\tconst response = await fetch(url);\n\t\t\t\tconst arrayBuffer = await response.arrayBuffer();\n\t\t\t\tconst buffer = Buffer.from(arrayBuffer);\n\t\t\t\tfs.writeFileSync(tempMp4File, buffer);\n\n\t\t\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\t\t\tffmpeg(tempMp4File)\n\t\t\t\t\t\t.output(outputFile)\n\t\t\t\t\t\t.noVideo()\n\t\t\t\t\t\t.audioCodec(\"libmp3lame\")\n\t\t\t\t\t\t.on(\"end\", () => {\n\t\t\t\t\t\t\tfs.unlinkSync(tempMp4File);\n\t\t\t\t\t\t\tresolve();\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.on(\"error\", (err) => {\n\t\t\t\t\t\t\treject(err);\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.run();\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tlogger.log(\"YouTube video detected, downloading audio with youtube-dl\");\n\t\t\t\tawait getYoutubeDL()(url, {\n\t\t\t\t\tverbose: true,\n\t\t\t\t\textractAudio: true,\n\t\t\t\t\taudioFormat: \"mp3\",\n\t\t\t\t\toutput: outputFile,\n\t\t\t\t\twriteInfoJson: true,\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn outputFile;\n\t\t} catch (error) {\n\t\t\tlogger.log(\"Error downloading audio:\", error);\n\t\t\tthrow new Error(\"Failed to download audio\");\n\t\t}\n\t}\n}\n","export * from \"./services/index\";\n\nimport type { Plugin } from \"@elizaos/core\";\n\nimport {\n\tAwsS3Service,\n\tBrowserService,\n\tPdfService,\n\tVideoService,\n} from \"./services/index\";\n\nexport const nodePlugin: Plugin = {\n\tname: \"default\",\n\tdescription: \"Default plugin, with basic actions and evaluators\",\n\tservices: [BrowserService, PdfService, VideoService, AwsS3Service],\n\tactions: [],\n};\n"],"mappings":"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","names":["Service","ServiceTypes","logger","Service","ServiceTypes","fs","path","ModelTypes","Service","ServiceTypes","logger","stringToUuid"]}
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@elizaos/plugin-browser",
3
+ "version": "1.0.0-alpha.26",
4
+ "type": "module",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/elizaos-plugins/plugin-browser"
11
+ },
12
+ "exports": {
13
+ "./package.json": "./package.json",
14
+ ".": {
15
+ "import": {
16
+ "types": "./dist/index.d.ts",
17
+ "default": "./dist/index.js"
18
+ }
19
+ }
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "scripts",
24
+ "package.json",
25
+ "LICENSE",
26
+ "tsup.config.ts"
27
+ ],
28
+ "dependencies": {
29
+ "@aws-sdk/client-s3": "^3.705.0",
30
+ "@aws-sdk/s3-request-presigner": "^3.705.0",
31
+ "@elizaos/core": "1.0.0-alpha.26",
32
+ "@types/uuid": "10.0.0",
33
+ "capsolver-npm": "2.0.2",
34
+ "fluent-ffmpeg": "2.1.3",
35
+ "glob": "11.0.0",
36
+ "patchright": "1.50.1",
37
+ "pdfjs-dist": "4.7.76",
38
+ "uuid": "11.0.3",
39
+ "youtube-dl-exec": "3.0.15"
40
+ },
41
+ "trustedDependencies": [
42
+ "youtube-dl-exec"
43
+ ],
44
+ "devDependencies": {
45
+ "@types/node": "22.8.4",
46
+ "tsup": "8.4.0"
47
+ },
48
+ "scripts": {
49
+ "build": "tsup",
50
+ "dev": "tsup --watch",
51
+ "postinstall": "node scripts/postinstall.js",
52
+ "lint": "biome check ./src --config-path=./ --apply-unsafe && biome format ./ --config-path=./ --write",
53
+ "clean": "rm -rf dist .turbo node_modules .turbo-tsconfig.json tsconfig.tsbuildinfo"
54
+ },
55
+ "peerDependencies": {
56
+ "whatwg-url": "7.1.0"
57
+ },
58
+ "publishConfig": {
59
+ "access": "public"
60
+ },
61
+ "gitHead": "bc8404af5c9e930c2de5c426c4bf730b86aacf8c"
62
+ }
@@ -0,0 +1,70 @@
1
+ import { execSync } from "node:child_process";
2
+ import fs from "node:fs";
3
+ import os from "node:os";
4
+
5
+ const platform = os.platform();
6
+ const rel = os.release();
7
+
8
+ if (platform !== "linux") {
9
+ console.log(
10
+ "Skipping [patchright] installation: non-Linux platform detected:",
11
+ platform,
12
+ );
13
+ process.exit(0);
14
+ }
15
+
16
+ function getDistroName() {
17
+ try {
18
+ const osReleaseContent = fs.readFileSync("/etc/os-release", "utf8");
19
+ const lines = osReleaseContent.split("\n");
20
+ const info = {};
21
+ for (const line of lines) {
22
+ const [key, value] = line.split("=");
23
+ if (key && value) {
24
+ info[key.toLowerCase()] = value.replace(/"/g, "").toLowerCase().trim();
25
+ }
26
+ }
27
+ return info.id || info.id_like || null;
28
+ } catch (err) {
29
+ console.error("Error reading /etc/os-release:", err.message);
30
+ }
31
+ return null;
32
+ }
33
+
34
+ const distro = getDistroName();
35
+ console.log("Detected Linux distribution:", distro || "unknown");
36
+
37
+ const supportedDistros = [
38
+ "ubuntu",
39
+ "debian",
40
+ "pve",
41
+ "raspbian",
42
+ "pop",
43
+ "zorin",
44
+ "linuxmint",
45
+ "elementary",
46
+ "pureos",
47
+ "kali",
48
+ ];
49
+
50
+ if (!distro || !supportedDistros.some((name) => distro.includes(name))) {
51
+ console.log(
52
+ "Skipping [patchright] installation on unsupported platform:",
53
+ platform,
54
+ rel,
55
+ distro || "unknown distro",
56
+ );
57
+ process.exit(0);
58
+ }
59
+
60
+ try {
61
+ execSync("npx patchright install", {
62
+ stdio: "inherit",
63
+ });
64
+ } catch (err) {
65
+ console.error(
66
+ "Failed to install [patchright] you may need to install [patchright] deps with 'sudo npx patchright install-deps'. Error: ",
67
+ err.message,
68
+ );
69
+ process.exit(1);
70
+ }
package/tsup.config.ts ADDED
@@ -0,0 +1,22 @@
1
+ import { defineConfig } from "tsup";
2
+
3
+ export default defineConfig({
4
+ entry: ["src/index.ts"],
5
+ outDir: "dist",
6
+ tsconfig: "./tsconfig.build.json", // Use build-specific tsconfig
7
+ sourcemap: true,
8
+ clean: true,
9
+ format: ["esm"], // Ensure you're targeting CommonJS
10
+ dts: false, // Skip DTS generation to avoid external import issues // Ensure you're targeting CommonJS
11
+ external: [
12
+ "dotenv", // Externalize dotenv to prevent bundling
13
+ "fs", // Externalize fs to use Node.js built-in module
14
+ "path", // Externalize other built-ins if necessary
15
+ "@reflink/reflink",
16
+ "https",
17
+ "http",
18
+ "agentkeepalive",
19
+ "zod",
20
+ // Add other modules you want to externalize
21
+ ],
22
+ });