UNPKG

locatai-ts

Version:

Enterprise-grade AI-powered element locator for Selenium WebDriver - TypeScript implementation

194 lines 7.89 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.OllamaProvider = void 0; const readline = __importStar(require("readline")); const node_fetch_1 = __importDefault(require("node-fetch")); class OllamaProvider { constructor(config) { // Get API endpoint URL from config const apiUrl = config?.apiKey || 'http://localhost:11434'; // Set model from config or default this.model = config?.model || 'llama2:latest'; // Make sure the URL doesn't have a trailing slash this.baseUrl = apiUrl.endsWith('/') ? apiUrl.slice(0, -1) : apiUrl; console.log(`Initialized Ollama provider with model ${this.model} and API URL ${this.baseUrl}`); } createInterface() { return readline.createInterface({ input: process.stdin, output: process.stdout }); } async getUserInput(prompt) { const rl = this.createInterface(); return new Promise((resolve) => { rl.question(prompt, (answer) => { rl.close(); resolve(answer); }); }); } async generateResponse(userInput, systemPrompt) { try { // Apply input shortening to optimize the prompt for Ollama const shortenedInput = this.shortenUserInput(userInput); const requestBody = { model: this.model, prompt: shortenedInput, stream: false, options: { temperature: 0.7 } }; // Add system prompt if provided if (systemPrompt) { requestBody.system = systemPrompt; } const response = await (0, node_fetch_1.default)(`${this.baseUrl}/api/generate`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(requestBody) }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); // Clean the response before returning it return this.cleanOllamaResponse(data.response); } catch (error) { console.error('Error calling Ollama API:', error); throw error; } } async interact() { console.log(`Ollama ${this.model} Chat (Type 'exit' to quit)`); while (true) { const userInput = await this.getUserInput("\nYou: "); if (userInput.toLowerCase() === 'exit') { console.log("Goodbye!"); break; } console.log("\nThinking..."); try { const response = await this.generateResponse(userInput); console.log(`\nAI: ${response}`); } catch (error) { console.log("Sorry, there was an error generating a response."); } } } /** * Cleans Ollama's response by removing markdown formatting and standardizing locator formats */ cleanOllamaResponse(response) { if (!response) return ''; // Remove markdown bold formatting let cleanedResponse = response.replace(/\*\*([^*]+)\*\*/g, '$1'); // Remove backticks and code blocks cleanedResponse = cleanedResponse.replace(/```[\s\S]*?```/g, ''); cleanedResponse = cleanedResponse.replace(/`/g, ''); // Convert "xpath: //div" format to "xpath=//div" cleanedResponse = cleanedResponse.replace(/([a-z-]+):\s+/gi, '$1='); // Convert confidence descriptions to numeric values const confidenceMap = { '(Low)': '|confidence=0.5', '(Medium)': '|confidence=0.7', '(High)': '|confidence=0.9', 'high confidence': '|confidence=0.9', 'medium confidence': '|confidence=0.7', 'low confidence': '|confidence=0.5', 'very confident': '|confidence=0.95', 'confident': '|confidence=0.8', 'somewhat confident': '|confidence=0.6', 'not confident': '|confidence=0.3' }; Object.entries(confidenceMap).forEach(([text, value]) => { const regex = new RegExp(text, 'gi'); cleanedResponse = cleanedResponse.replace(regex, value); }); // Remove numbering (like 1., 2., etc.) cleanedResponse = cleanedResponse.replace(/^\d+\.\s+/gm, ''); // Filter out explanation lines that don't contain = or : const lines = cleanedResponse.split('\n').filter(line => { const trimmedLine = line.trim(); return (trimmedLine.includes('=') || trimmedLine.includes(':') || /^[a-z]+ selector/i.test(trimmedLine)); }); return lines.join('\n').trim(); } /** * Shortens and simplifies the user input for better results with Ollama */ shortenUserInput(userInput) { if (!userInput) return ''; // Extract element description from the prompt const elementMatch = userInput.match(/Generate a locator for: (.+?)$/m); if (!elementMatch) return userInput; const elementDescription = elementMatch[1]; // Extract a short snippet of HTML instead of the full page const truncatedHTML = this.extractRelevantHTML(userInput); return `HTML: ${truncatedHTML}\n\nFind element: ${elementDescription}`; } /** * Extracts a shorter, more relevant HTML snippet to reduce token count */ extractRelevantHTML(userInput) { // Extract HTML content between DOM Content: and Generate a locator const match = userInput.match(/DOM Content:\s*(.+?)(?=\s*\n\s*Generate a locator)/s); if (match && match[1]) { const fullHtml = match[1]; // For simplicity, just return a truncated version to reduce token count if (fullHtml.length > 2000) { return fullHtml.substring(0, 2000) + "..."; } return fullHtml; } return ""; // Fallback if no HTML is found } } exports.OllamaProvider = OllamaProvider; //# sourceMappingURL=OllamaProvider.js.map