LaiLarry/Consulting_Assistant_Agent
1
1<!DOCTYPE html>2<html lang="en">3<head>4 <meta charset="UTF-8">5 <meta name="viewport" content="width=device-width, initial-scale=1.0">6 <title>Consulting Assistant</title>7 <script src="https://cdn.tailwindcss.com"></script>8 <style>9 /* Import Georgia (Body) and Roboto Slab (Buttons) */10 @import url('https://fonts.googleapis.com/css2?family=Georgia:wght@400;700&family=Roboto+Slab:wght=700&display=swap');11 12 body {13 /* Main body and response content remains Georgia */14 font-family: 'Georgia', sans-serif;15 background-color: #111827; /* Tailwind gray-900 equivalent */16 }17 18 /* * Main Title: Smaller font, centered, bold. 19 * We'll use this for the H1 tag generated by Markdown's '#' 20 */21 .ai-response-content h1 {22 font-size: 1.8rem;23 font-weight: 700;24 text-align: center;25 margin-bottom: 1rem;26 }27 28 /* * Key Sections: Smaller font than the title, bold, no bullet point. 29 * We'll use this for the H2 tag generated by Markdown's '##' 30 */31 .ai-response-content h2 {32 font-size: 1.3rem;33 font-weight: 700;34 margin-top: 1.5rem;35 margin-bottom: 0.5rem;36 color: #bef264 !important;37 }38 39 /* * Sub-sections within a section. 40 * We'll use this for the H3 tag generated by Markdown's '###' 41 */42 .ai-response-content h3 {43 font-size: 1.1rem; /* Slightly smaller for better hierarchy */44 font-weight: 700;45 margin-top: 1rem;46 margin-bottom: 0.5rem;47 color: #facc15 !important;48 }49 50 /* * Points in Sections: Bold, smaller than sections, larger than content. 51 * Markdown wraps these in a `<strong>` tag. 52 */53 .ai-response-content strong {54 font-size: 1rem;55 font-weight: 700;56 display: block; 57 margin-bottom: 0.25rem; 58 color: #facc15 !important;59 }60 61 /* Ensure bulleted lists are styled correctly and have a top margin */62 .ai-response-content ul {63 list-style-type: disc;64 padding-left: 2rem;65 margin-top: 0.5rem; /* Reduced margin since the strong tag now has margin-bottom */66 }67 68 /* Add a bottom margin to each list item for more spacing */69 .ai-response-content li {70 margin-bottom: 1.0rem;71 }72 73 /* Basic table styling for clarity */74 .ai-response-content table {75 width: 100%;76 border-collapse: collapse;77 margin-top: 1rem;78 font-size: 0.9rem;79 }80 81 .ai-response-content th, .ai-response-content td {82 border: 1px solid #d1d5db; /* Lighter border for contrast on dark background */83 padding: 0.75rem;84 text-align: left;85 width: 33%; 86 }87 88 .ai-response-content th {89 /* Darker table header background */90 background-color: #374151; /* Tailwind gray-700 equivalent */91 font-weight: 700;92 color: #f3f4f6;93 }94 95 .ai-response-content td {96 background-color: #1f2937; /* Tailwind gray-800 equivalent */97 }98 .main-title {99 font-size: 1.8rem;100 font-weight: 700;101 color: #f3f4f6; /* Tailwind gray-100 equivalent */102 }103 104 .sub-title {105 font-size: 1.125rem;106 color: #d1d5db; /* Tailwind gray-300 equivalent */107 margin-top: 0.25rem;108 }109 110 /* === Custom Button Style (Main Dropdowns) === */111 .prompt-btn, .dropdown-btn {112 /* --- MODIFIED FONT FAMILY, SIZE, AND WEIGHT --- */113 font-family: 'Roboto Slab', serif; 114 font-size: 0.8125rem; 115 font-weight: 700; 116 /* ----------------------------------------------- */117 118 /* Base styles */119 padding-left: 0.75rem;120 padding-right: 0.75rem;121 padding-top: 0.5rem; 122 padding-bottom: 0.5rem; 123 color: #065f46; /* Text-emerald-800 */124 background-color: #ecfdf5; /* Bg-emerald-50 (light emerald) */125 border-radius: 0.75rem; /* Rounded-xl */126 box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.06); /* Shadow-lg */127 128 /* Border */129 border-width: 2px; 130 border-color: #34d399; /* Tailwind emerald-400 for better visibility */131 132 /* Sizing and alignment */133 width: 11rem; /* Fixed width for consistent size (w-44) */134 height: 3rem; /* Fixed height for consistent size (h-12) */135 text-align: center;136 display: flex;137 align-items: center;138 justify-content: center;139 white-space: normal;140 141 /* Hover and transition effects */142 transition: all 0.2s ease-in-out;143 144 /* Ensure dropdown buttons inherit base style but can be overridden */145 cursor: pointer;146 }147 148 .prompt-btn:hover, .dropdown-btn:hover {149 background-color: #d1fae5; /* Hover:bg-emerald-100 */150 box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1); /* Hover:shadow-xl */151 transform: translateY(-2px); /* Subtle lift effect */152 }153 154 /* Added active state for a physical "press" effect */155 .prompt-btn:active, .dropdown-btn:active {156 border-color: #10b981; /* Tailwind emerald-600 */157 border-width: 3px; 158 transform: translateY(0); 159 box-shadow: none; 160 }161 /* === Custom Button Style (Sub-Menu Buttons) === */162 .sub-menu-btn {163 /* Define styles for individual, stacked buttons */164 background-color: #303030; /* Charcoal Grey */165 color: #f3f4f6; /* Tailwind gray-100 */166 width: 100%;167 text-align: left;168 padding: 0.5rem 1rem; /* py-2 px-4 */169 font-size: 0.875rem; /* text-sm */170 transition: all 0.15s ease-in-out;171 font-family: 'Georgia', sans-serif;172 cursor: pointer;173 174 /* Key changes for individual button look */175 border: 1px solid #d1d5db; /* Light Grey (Tailwind gray-300) */176 border-radius: 0.5rem; /* rounded-lg */177 margin-bottom: 0.25rem; /* space between buttons */178 box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);179 }180 181 .sub-menu-btn:hover {182 background-color: #4a4a4a; /* Slightly lighter Charcoal hover */183 transform: scale(1.01);184 }185 /* Ensure the last button doesn't have extra margin at the bottom */186 .sub-menu-btn:last-child {187 margin-bottom: 0;188 }189 /* Custom styles for the dynamic textarea */190 #userInput {191 /* Set initial row size and ensure dynamic growth */192 line-height: 1.5; 193 overflow-y: hidden; /* Hide scrollbar unless max height is reached */194 box-sizing: border-box; /* Include padding and border in the element's total width and height */195 resize: none; /* Prevent manual resizing */196 }197 </style>198 <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>199</head>200<body class="flex flex-col items-center justify-center min-h-screen p-4 bg-gray-900">201 <div class="bg-gray-800 text-gray-100 rounded-2xl shadow-xl w-full max-w-2xl p-6 md:p-8">202 <div class="flex items-center space-x-4 mb-6">203 <div class="p-3 bg-emerald-100 rounded-full">204 <svg xmlns="http://www.w3.org/2000/svg" fill="#10b981" viewBox="0 0 24 24" stroke-width="1.5" stroke="#10b981" class="w-6 h-6">205 <path stroke-linecap="round" stroke-linejoin="round" d="M11.48 3.499a.562.562 0 011.04 0l2.125 5.111a.563.563 0 00.475.345l5.518.442c.499.04.701.663.321.988l-4.225 3.658a.563.563 0 00-.182.557l1.285 5.385a.562.562 0 01-.84.6l-4.725-2.885a.563.563 0 00-.582 0l-4.725 2.885a.562.562 0 01-.84-.6l1.285-5.385a.562.562 0 00-.182-.557L3.991 10.49a.562.562 0 01.32-.988l5.518-.442a.563.563 0 00.475-.345l2.125-5.111z" />206 </svg>207 </div>208 <div>209 <h1 class="main-title">Bob, Your Consulting Assistant</h1>210 <p class="sub-title">You ask. Bob answers.</p>211 </div>212 </div>213 214 <div class="mb-6">215 <label for="apiKeyInput" class="block text-sm font-medium text-gray-100 mb-1">Enter your Gemini API Key:</label>216 <input type="password" id="apiKeyInput" class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-emerald-500 bg-gray-700 text-white" placeholder="Paste your API key here...">217 </div>218 219 <div class="flex justify-between mb-4">220 221 <div class="grid grid-cols-2 gap-4">222 223 <div class="flex flex-col gap-4">224 <div class="relative">225 <button id="initialSetupDropdownBtn" class="dropdown-btn flex items-center justify-center">226 Initial Setup227 <svg class="w-4 h-4 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg>228 </button>229 <div id="initialSetupMenu" class="absolute hidden top-full mt-2 w-56 bg-gray-800 rounded-lg shadow-2xl z-10 border border-emerald-500 p-2">230 </div>231 </div>232 <div class="relative">233 <button id="solutionDesignDropdownBtn" class="dropdown-btn flex items-center justify-center">234 Solution Design235 <svg class="w-4 h-4 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg>236 </button>237 <div id="solutionDesignMenu" class="absolute hidden top-full mt-2 w-56 bg-gray-800 rounded-lg shadow-2xl z-10 border border-emerald-500 p-2">238 </div>239 </div>240 </div>241 242 <div class="flex flex-col gap-4">243 <div class="relative">244 <button id="analysisDropdownBtn" class="dropdown-btn flex items-center justify-center">245 Analysis246 <svg class="w-4 h-4 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg>247 </button>248 <div id="analysisMenu" class="absolute hidden top-full mt-2 w-56 bg-gray-800 rounded-lg shadow-2xl z-10 border border-emerald-500 p-2">249 </div>250 </div>251 <div class="relative">252 <button id="executionDropdownBtn" class="dropdown-btn flex items-center justify-center">253 Execution254 <svg class="w-4 h-4 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg>255 </button>256 <div id="executionMenu" class="absolute hidden top-full mt-2 w-56 bg-gray-800 rounded-lg shadow-2xl z-10 border border-emerald-500 p-2">257 </div>258 </div>259 </div>260 </div> 261 262 <!-- Action Buttons Column (Top-Right) -->263 <div class="flex flex-col gap-4 items-end">264 <!-- My Prompts Button with Dropdown -->265 <div class="relative w-48">266 <button id="myPromptsDropdownBtn" class="w-full px-3 py-1.5 bg-gray-400 text-white rounded-lg hover:bg-gray-500 transition duration-200 inline-flex items-center justify-center font-bold text-xs">267 My Prompts268 <svg class="w-4 h-4 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg>269 </button>270 <div id="myPromptsMenu" class="absolute hidden top-full mt-2 w-56 bg-gray-800 rounded-lg shadow-2xl z-10 border border-emerald-500 p-2 right-0">271 </div>272 </div>273 274 <!-- Generate Takeaways Button -->275 <button id="generateTakeawaysBtn" class="w-48 px-3 py-1.5 bg-gray-400 text-white rounded-lg hover:bg-gray-500 transition duration-200 font-bold text-xs">276 Generate Takeaways277 </button>278 279 <!-- Run Workflow Button with Dropdown -->280 <div class="relative w-48">281 <button id="workflowBtn" class="w-full px-3 py-1.5 bg-gray-400 text-white rounded-lg hover:bg-gray-500 transition duration-200 font-bold text-xs inline-flex items-center justify-center">282 Run Workflow283 <svg class="w-3 h-3 ml-1.5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg>284 </button>285 <div id="workflowMenu" class="absolute hidden top-full right-0 mt-2 w-64 bg-gray-800 rounded-lg shadow-2xl z-10 border border-green-500 p-2">286 <button class="workflow-option w-full text-left px-3 py-2 text-sm text-gray-100 hover:bg-gray-700 rounded" data-workflow="market-entry-strategy">287 Market Entry Strategy288 </button>289 <button class="workflow-option w-full text-left px-3 py-2 text-sm text-gray-100 hover:bg-gray-700 rounded" data-workflow="business-health-check">290 Business Health Check291 </button>292 <button class="workflow-option w-full text-left px-3 py-2 text-sm text-gray-100 hover:bg-gray-700 rounded" data-workflow="competitive-analysis">293 Competitive Analysis294 </button>295 </div>296 </div>297 298 <!-- Export Chat Button -->299 <button id="exportBtn" class="w-48 px-3 py-1.5 bg-gray-400 text-white rounded-lg hover:bg-gray-500 transition duration-200 font-bold text-xs">300 Export Chat301 </button>302 </div>303 </div> 304 305 <!-- Chat Area -->306 <div id="chatArea" class="space-y-4 max-h-96 overflow-y-auto mb-4">307 </div>308 309 310 <!-- Greeting Message and Clear Chat Button -->311 <div class="flex justify-between items-start mb-4">312 <div class="bg-emerald-100 text-emerald-700 rounded-xl p-3 max-w-sm shadow-md">313 Hi there! I'm Bob. How can I assist you today?314 </div>315 <button id="clearChatBtn" class="px-3 py-1.5 bg-gray-400 text-white rounded-lg hover:bg-gray-500 transition duration-200 font-bold text-xs border-2 border-red-500">Clear Chat</button>316 </div>317 318 319 <div class="flex items-center space-x-2">320 <textarea id="userInput" placeholder="Ask a question... (Enter to Send, Shift + Enter for Newline)" rows="1" class="flex-grow px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-emerald-500 bg-gray-700 text-white resize-none overflow-y-hidden"></textarea>321 <button id="sendButton" class="px-6 py-2 bg-emerald-600 text-white font-semibold rounded-lg shadow-md hover:bg-emerald-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-emerald-500 disabled:bg-emerald-300 disabled:cursor-not-allowed" >Send</button>322 </div>323 </div>324 325 <script>326 (function() {327 const apiKeyInput = document.getElementById('apiKeyInput');328 const sendButton = document.getElementById('sendButton');329 const userInput = document.getElementById('userInput');330 const chatArea = document.getElementById('chatArea');331 const clearChatBtn = document.getElementById('clearChatBtn');332 const generateTakeawaysBtn = document.getElementById('generateTakeawaysBtn');333 334 // DROPDOWN ELEMENTS335 const initialSetupDropdownBtn = document.getElementById('initialSetupDropdownBtn');336 const initialSetupMenu = document.getElementById('initialSetupMenu');337 const analysisDropdownBtn = document.getElementById('analysisDropdownBtn');338 const analysisMenu = document.getElementById('analysisMenu');339 const solutionDesignDropdownBtn = document.getElementById('solutionDesignDropdownBtn');340 const solutionDesignMenu = document.getElementById('solutionDesignMenu');341 const executionDropdownBtn = document.getElementById('executionDropdownBtn');342 const executionMenu = document.getElementById('executionMenu');343 // NEW PROMPT ELEMENTS344 const myPromptsDropdownBtn = document.getElementById('myPromptsDropdownBtn'); // NEW345 const myPromptsMenu = document.getElementById('myPromptsMenu'); // NEW346 let MIN_HEIGHT = 0; // Calculated minimum height (1 line)347 348 // ===== PHASE 1 FEATURE: PERSISTENT MEMORY SYSTEM =====349 350 // User Profile Storage351 const USER_PROFILE_KEY = 'bobUserProfile';352 353 // Initialize or load user profile354 let userProfile = JSON.parse(localStorage.getItem(USER_PROFILE_KEY)) || {355 industry: '',356 consultingAreas: [],357 previousTopics: [],358 conversationSummaries: [],359 preferences: {360 preferredAnalysisTypes: [],361 favoritePrompts: []362 },363 lastVisit: null,364 totalInteractions: 0,365 createdAt: new Date().toISOString()366 };367 368 // Save user profile to localStorage369 function saveUserProfile() {370 userProfile.lastVisit = new Date().toISOString();371 localStorage.setItem(USER_PROFILE_KEY, JSON.stringify(userProfile));372 }373 374 // Extract topics from conversation375 function extractTopicsFromConversation() {376 const topics = [];377 chatHistory.forEach(entry => {378 if (entry.role === 'user') {379 const text = entry.parts[0].text.toLowerCase();380 // Simple keyword extraction381 if (text.includes('market')) topics.push('market analysis');382 if (text.includes('swot')) topics.push('SWOT analysis');383 if (text.includes('competitor')) topics.push('competitor analysis');384 if (text.includes('financial')) topics.push('financial analysis');385 if (text.includes('strategy')) topics.push('strategy');386 }387 });388 return [...new Set(topics)]; // Remove duplicates389 }390 391 // Add conversation summary to profile392 function saveConversationSummary() {393 if (chatHistory.length > 1) {394 const topics = extractTopicsFromConversation();395 const summary = {396 date: new Date().toISOString(),397 topics: topics,398 messageCount: chatHistory.length - 1,399 id: Date.now()400 };401 402 userProfile.conversationSummaries.push(summary);403 userProfile.previousTopics = [404 ...new Set([...userProfile.previousTopics, ...topics])405 ].slice(0, 20); // Keep last 20 unique topics406 407 userProfile.totalInteractions++;408 saveUserProfile();409 }410 }411 412 // ===== PHASE 1 FEATURE: PROACTIVE CHECK-INS =====413 414 // Check if returning user and show personalized welcome415 function checkForProactiveWelcome() {416 const lastVisit = userProfile.lastVisit ? new Date(userProfile.lastVisit) : null;417 const now = new Date();418 419 if (lastVisit) {420 const hoursSinceLastVisit = (now - lastVisit) / (1000 * 60 * 60);421 422 // If more than 24 hours since last visit423 if (hoursSinceLastVisit > 24 && userProfile.previousTopics.length > 0) {424 setTimeout(() => {425 const daysSince = Math.floor(hoursSinceLastVisit / 24);426 const topicsText = userProfile.previousTopics.slice(0, 3).join(', ');427 428 const welcomeBackMessage = `Welcome back! It's been ${daysSince} day${daysSince > 1 ? 's' : ''} since your last visit. 429 430I see we previously discussed: **${topicsText}**. 431 432Would you like to:433• Continue where we left off?434• Get updates on these topics?435• Start a new analysis?436 437How can I assist you today?`;438 439 createMessageBubble(welcomeBackMessage, 'model');440 }, 1500); // Show after 1.5 seconds441 } else if (hoursSinceLastVisit > 1 && userProfile.totalInteractions > 3) {442 // Short absence but active user443 setTimeout(() => {444 const recentTopics = userProfile.previousTopics.slice(0, 2).join(' and ');445 const quickWelcome = `Welcome back! Ready to continue with ${recentTopics || 'your consulting questions'}?`;446 447 createMessageBubble(quickWelcome, 'model');448 }, 1000);449 }450 }451 452 // Update last visit453 userProfile.lastVisit = now.toISOString();454 saveUserProfile();455 }456 457 // Call proactive welcome on page load458 setTimeout(() => {459 checkForProactiveWelcome();460 }, 500); // Wait 500ms after page loads461 462 463 // ===== PHASE 1 FEATURE: MULTI-STEP TASK TEMPLATES =====464 465 // Define multi-step workflows466 const WORKFLOWS = {467 'market-entry-strategy': {468 name: 'Complete Market Entry Strategy',469 steps: [470 'Industry Trends Snapshot',471 'Competitor Benchmarking',472 'SWOT Analysis',473 'Market Entry Strategy Framework'474 ],475 description: 'Full market entry analysis with trends, competitors, SWOT, and strategy'476 },477 'business-health-check': {478 name: 'Business Health Check',479 steps: [480 'SWOT Analysis',481 'Financial Health Snapshot',482 'Operational Efficiency Review'483 ],484 description: 'Comprehensive business health assessment'485 },486 'competitive-analysis': {487 name: 'Competitive Analysis Package',488 steps: [489 'Competitor Benchmarking',490 'Market Positioning Map',491 'Competitive Advantage Analysis'492 ],493 description: 'Deep dive into competitive landscape'494 }495 };496 497 // ===== PHASE 2 FEATURE: TOOL ORCHESTRATION FRAMEWORK =====498 499 // Available tools Bob can use500 const BOB_TOOLS = {501 googleSearch: {502 enabled: true,503 name: 'Google Search',504 description: 'Search the web for current information',505 icon: '🔍'506 },507 dataAnalysis: {508 enabled: true,509 name: 'Data Analysis',510 description: 'Perform calculations and analyze data',511 icon: '📊'512 },513 documentExport: {514 enabled: true,515 name: 'Document Export',516 description: 'Export conversation or analysis as text file',517 icon: '📄'518 },519 chartGeneration: {520 enabled: true,521 name: 'Chart Generation',522 description: 'Create visual charts and graphs',523 icon: '📈'524 }525 };526 527 // Tool usage tracking528 let toolUsageHistory = [];529 530 // Determine which tools are needed for a query531 function determineRequiredTools(userQuery) {532 const query = userQuery.toLowerCase();533 const tools = [];534 535 // Check for search needs536 if (query.includes('latest') || query.includes('current') || 537 query.includes('recent') || query.includes('trend')) {538 tools.push('googleSearch');539 }540 541 // Check for data analysis needs542 if (query.includes('calculate') || query.includes('analyze data') || 543 query.includes('numbers') || query.includes('statistics')) {544 tools.push('dataAnalysis');545 }546 547 // Check for export needs548 if (query.includes('export') || query.includes('download') || 549 query.includes('save as file')) {550 tools.push('documentExport');551 }552 553 // Check for visualization needs554 if (query.includes('chart') || query.includes('graph') || 555 query.includes('visualize') || query.includes('plot')) {556 tools.push('chartGeneration');557 }558 559 return tools;560 }561 562 // Execute document export tool563 function executeDocumentExport() {564 let exportText = 'BOB CONSULTING SESSION EXPORT\n';565 exportText += '='.repeat(50) + '\n';566 exportText += `Date: ${new Date().toLocaleString()}\n`;567 exportText += `Total Messages: ${chatHistory.length - 1}\n`;568 exportText += '='.repeat(50) + '\n\n';569 570 chatHistory.forEach((entry, index) => {571 if (index > 0) {572 const role = entry.role === 'user' ? 'YOU' : 'BOB';573 const text = entry.parts[0].text;574 exportText += `[${role}]\n${text}\n\n`;575 exportText += '-'.repeat(50) + '\n\n';576 }577 });578 579 const blob = new Blob([exportText], { type: 'text/plain' });580 const url = URL.createObjectURL(blob);581 const a = document.createElement('a');582 a.href = url;583 a.download = `bob-session-${Date.now()}.txt`;584 document.body.appendChild(a);585 a.click();586 document.body.removeChild(a);587 URL.revokeObjectURL(url);588 589 // Track tool usage590 toolUsageHistory.push({591 tool: 'documentExport',592 timestamp: new Date().toISOString()593 });594 595 return 'Document exported successfully!';596 }597 598 // Execute data analysis tool (simple implementation)599 function executeDataAnalysis(data) {600 // This is a simplified version - can be expanded601 try {602 const numbers = data.match(/\d+(\.\d+)?/g)?.map(Number) || [];603 604 if (numbers.length === 0) {605 return 'No numerical data found to analyse.';606 }607 608 const sum = numbers.reduce((a, b) => a + b, 0);609 const avg = sum / numbers.length;610 const max = Math.max(...numbers);611 const min = Math.min(...numbers);612 613 toolUsageHistory.push({614 tool: 'dataAnalysis',615 timestamp: new Date().toISOString()616 });617 618 return `Data Analysis Results:619- Count: ${numbers.length} values620- Sum: ${sum.toFixed(2)}621- Average: ${avg.toFixed(2)}622- Maximum: ${max}623- Minimum: ${min}`;624 } catch (error) {625 return 'Error analyzing data.';626 }627 }628 629 // Execute multi-step workflow630 async function executeWorkflow(workflowKey, context = '') {631 const workflow = WORKFLOWS[workflowKey];632 if (!workflow) {633 alert('Workflow not found');634 return;635 }636 637 // Show workflow initiation message638 const initiationMessage = `Starting **${workflow.name}** workflow...639 640This will execute ${workflow.steps.length} analysis steps:641${workflow.steps.map((step, i) => `${i + 1}. ${step}`).join('\n')}642 643${context ? `\nContext: ${context}` : ''}`;644 645 createMessageBubble(initiationMessage, 'model');646 647 // Execute each step648 for (let i = 0; i < workflow.steps.length; i++) {649 const step = workflow.steps[i];650 651 // Add user message for this step652 const stepMessage = `[Workflow Step ${i + 1}/${workflow.steps.length}] ${step}${context ? ': ' + context : ''}`;653 createMessageBubble(stepMessage, 'user');654 655 chatHistory.push({656 role: "user",657 parts: [{ text: stepMessage }]658 });659 660 // Execute the prompt using sendMessage logic661 await executePromptStep(PROMPT_MAP[step], context);662 663 // Small delay between steps664 await new Promise(resolve => setTimeout(resolve, 1000));665 }666 667 // Completion message668 const completionMessage = `✅ **${workflow.name}** complete! 669 670I've generated ${workflow.steps.length} comprehensive analyses. Review the insights above and let me know if you'd like to:671• Deep dive into any specific area672• Generate takeaways673• Start another workflow`;674 675 createMessageBubble(completionMessage, 'model');676 677 // Save this workflow execution to user profile678 userProfile.preferences.preferredAnalysisTypes.push(workflowKey);679 saveUserProfile();680 }681 682 // Execute individual prompt step (reuses existing API call logic)683 async function executePromptStep(promptTemplate, userContext) {684 const apiKey = apiKeyInput.value.trim();685 686 // Show "Thinking..." indicator687 const loadingBubble = document.createElement('div');688 loadingBubble.classList.add('flex', 'justify-start');689 loadingBubble.innerHTML = `690 <div class="bg-gray-700 text-gray-300 rounded-xl rounded-bl-none p-3 max-w-sm shadow-md">691 <div class="flex items-center">692 <svg class="animate-spin -ml-1 mr-3 h-5 w-5 text-gray-500" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">693 <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>694 <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>695 </svg>696 Thinking...697 </div>698 </div>699 `;700 chatArea.appendChild(loadingBubble);701 chatArea.scrollTop = chatArea.scrollHeight;702 703 try {704 const finalPrompt = promptTemplate.replace(/\[input[^\]]*\]/gi, userContext || '[No specific context provided]');705 706 chatHistory.push({707 role: "user",708 parts: [{ text: finalPrompt }]709 });710 711 const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-preview-05-20:generateContent?key=${apiKey}`;712 713 const payload = {714 systemInstruction: {715 parts: [{ text: `You are a professional business consultant named Bob. Your role is to provide clear, actionable, and well-structured responses to business-related queries. Use Markdown formatting.` }]716 },717 contents: chatHistory,718 tools: [{ "google_search": {} }],719 };720 721 const response = await fetch(apiUrl, {722 method: "POST",723 headers: { "Content-Type": "application/json" },724 body: JSON.stringify(payload)725 });726 727 const result = await response.json();728 const aiText = result?.candidates?.[0]?.content?.parts?.[0]?.text || "Sorry, I couldn't process that request.";729 730 chatArea.removeChild(loadingBubble);731 732 chatHistory.push({733 role: "model",734 parts: [{ text: aiText }]735 });736 737 createMessageBubble(aiText, 'model');738 739 } catch (error) {740 if (chatArea.contains(loadingBubble)) {741 chatArea.removeChild(loadingBubble);742 }743 console.error('Error in workflow step:', error);744 createMessageBubble('Error processing this step. Moving to next...', 'model');745 }746 }747 748 749 // ===== PHASE 2 FEATURE: GOAL-BASED REASONING =====750 751 // Decompose complex goals into sub-goals752 function decomposeGoal(goalStatement) {753 const goal = goalStatement.toLowerCase();754 const subGoals = [];755 756 // Pattern matching for common business goals757 if (goal.includes('launch') || goal.includes('start') || goal.includes('new business') || goal.includes('open')) {758 subGoals.push(759 { task: 'Industry Trends Snapshot', priority: 'high' },760 { task: 'Market Analysis', priority: 'high' },761 { task: 'Competitor Benchmarking', priority: 'high' },762 { task: 'Business Plan Outline', priority: 'medium' },763 { task: 'Go-to-market Strategy', priority: 'medium' }764 );765 } else if (goal.includes('expand') || goal.includes('growth') || goal.includes('scale') || goal.includes('grow')) {766 subGoals.push(767 { task: 'Market Analysis', priority: 'high' },768 { task: 'SWOT Analysis', priority: 'high' },769 { task: 'Ansoff Matrix', priority: 'high' },770 { task: 'Market Entry Strategy', priority: 'medium' },771 { task: 'Implementation Plan Outline', priority: 'medium' }772 );773 } else if (goal.includes('improve') || goal.includes('optimize') || goal.includes('enhance')) {774 subGoals.push(775 { task: 'SWOT Analysis', priority: 'high' },776 { task: '5 Forces Analysis', priority: 'high' },777 { task: 'Risk Analysis', priority: 'medium' },778 { task: 'KPI Dashboard Mockup', priority: 'medium' },779 { task: 'Implementation Plan Outline', priority: 'medium' }780 );781 } else {782 // Generic goal breakdown783 subGoals.push(784 { task: 'SWOT Analysis', priority: 'high' },785 { task: 'Market Analysis', priority: 'high' },786 { task: 'Risk Analysis', priority: 'medium' },787 { task: 'Implementation Plan Outline', priority: 'medium' }788 );789 }790 791 return subGoals;792 }793 794 795 // Create execution plan from sub-goals796 function createExecutionPlan(subGoals) {797 const plan = {798 highPriority: subGoals.filter(g => g.priority === 'high'),799 mediumPriority: subGoals.filter(g => g.priority === 'medium'),800 steps: subGoals.map((g, i) => ({801 step: i + 1,802 task: g.task,803 priority: g.priority,804 status: 'pending'805 }))806 };807 808 return plan;809 }810 811 812// Track if we're waiting for execution plan response813let awaitingPlanResponse = false;814 815// Execute goal plan automatically816async function executeGoalPlanAutomatically(goal, plan) {817 createMessageBubble(`🚀 Starting automatic execution of your goal plan...`, 'model');818 819 for (let i = 0; i < plan.steps.length; i++) {820 const step = plan.steps[i];821 822 // Show which step is being executed823 createMessageBubble(`\n**Step ${i + 1}/${plan.steps.length}: ${step.task}**\n*Priority: ${step.priority}*`, 'model');824 825 // Small delay between steps826 await new Promise(resolve => setTimeout(resolve, 1500));827 828 // Find matching prompt in PROMPT_MAP829 const promptKey = step.task;830 if (PROMPT_MAP[promptKey]) {831 await executePromptStep(PROMPT_MAP[promptKey], goal);832 } else {833 createMessageBubble(`⚠️ Prompt template not found for "${step.task}". Skipping...`, 'model');834 }835 836 // Delay before next step837 await new Promise(resolve => setTimeout(resolve, 2000));838 }839 840 createMessageBubble(`\n✅ **Goal Plan Complete!**\n\nI've executed all ${plan.steps.length} steps for your goal: "${goal}"\n\nReview the analyses above and let me know if you'd like to:\n• Deep dive into any specific area\n• Generate takeaways\n• Start a new goal`, 'model');841 842 // Reset flag843 awaitingPlanResponse = false;844}845 846 // Process and execute a complex goal847 async function processGoal(userGoal) {848 // Show goal analysis message849 const analysisMessage = `🎯 **Goal Analysis**850 851I'm breaking down your goal: "${userGoal}"852 853Let me identify the key steps needed...`;854 855 createMessageBubble(analysisMessage, 'model');856 857 // Small delay for effect858 await new Promise(resolve => setTimeout(resolve, 1000));859 860 // Decompose the goal861 const subGoals = decomposeGoal(userGoal);862 const plan = createExecutionPlan(subGoals);863 864 // Show the execution plan865 const planMessage = `📋 **Execution Plan**866 867I've identified ${plan.steps.length} key steps to achieve your goal:868 869**High Priority:**870${plan.highPriority.map((g, i) => `${i + 1}. ${g.task}`).join('\n')}871 872**Medium Priority:**873${plan.mediumPriority.map((g, i) => `${i + 1}. ${g.task}`).join('\n')}874 875Would you like me to:8761. Execute this plan automatically (runs all steps)8772. Walk through it step-by-step with you8783. Modify the plan first879 880Reply with 1, 2, or 3.`;881 882 createMessageBubble(planMessage, 'model');883 884 // Store the plan for potential execution885 window.currentGoalPlan = plan;886 window.currentGoal = userGoal;887 888 // Set flag to intercept next user message889 awaitingPlanResponse = true;890 891 return plan;892 893 }894 895 896 // ===== PHASE 2 FEATURE: CONTEXT-AWARE SUGGESTIONS =====897 898 // Analyze conversation patterns899 function identifyConversationPatterns(history) {900 const patterns = [];901 const recentMessages = history.slice(-6); // Last 6 messages902 903 // Pattern: Multiple questions about same topic904 const topics = {};905 recentMessages.forEach(msg => {906 if (msg.role === 'user') {907 const text = msg.parts[0].text.toLowerCase();908 if (text.includes('market')) topics.market = (topics.market || 0) + 1;909 if (text.includes('financial')) topics.financial = (topics.financial || 0) + 1;910 if (text.includes('competitor')) topics.competitor = (topics.competitor || 0) + 1;911 if (text.includes('strategy')) topics.strategy = (topics.strategy || 0) + 1;912 }913 });914 915 Object.keys(topics).forEach(topic => {916 if (topics[topic] >= 2) {917 patterns.push(`deep-dive-${topic}`);918 }919 });920 921 // Pattern: Incomplete analysis (SWOT without implementation)922 const hasSWOT = history.some(msg => 923 msg.parts[0].text.toLowerCase().includes('swot')924 );925 const hasImplementation = history.some(msg => 926 msg.parts[0].text.toLowerCase().includes('implementation') ||927 msg.parts[0].text.toLowerCase().includes('action plan')928 );929 930 if (hasSWOT && !hasImplementation) {931 patterns.push('swot-without-implementation');932 }933 934 // Pattern: Analysis without next steps935 const hasAnalysis = history.some(msg =>936 msg.parts[0].text.toLowerCase().includes('analysis') ||937 msg.parts[0].text.toLowerCase().includes('trends')938 );939 const hasNextSteps = history.some(msg =>940 msg.parts[0].text.toLowerCase().includes('next step') ||941 msg.parts[0].text.toLowerCase().includes('action')942 );943 944 if (hasAnalysis && !hasNextSteps && history.length > 4) {945 patterns.push('analysis-without-action');946 }947 948 return patterns;949 }950 951 // Generate proactive suggestions based on patterns952 function generateProactiveSuggestions(patterns) {953 const suggestions = [];954 955 patterns.forEach(pattern => {956 if (pattern === 'swot-without-implementation') {957 suggestions.push({958 message: "I notice we completed a SWOT analysis. Would you like me to create an implementation roadmap based on those insights?",959 action: 'create-implementation-plan'960 });961 }962 963 if (pattern === 'analysis-without-action') {964 suggestions.push({965 message: "We've done some great analysis! Would you like me to convert these insights into concrete action items?",966 action: 'generate-action-items'967 });968 }969 970 if (pattern.startsWith('deep-dive-')) {971 const topic = pattern.replace('deep-dive-', '');972 suggestions.push({973 message: `You seem very interested in ${topic} analysis. Would you like me to run a comprehensive ${topic} workflow?`,974 action: `workflow-${topic}`975 });976 }977 });978 979 return suggestions;980 }981 982 // Check and show proactive suggestions periodically983 let suggestionCheckInterval = null;984 985 function startContextAwareSuggestions() {986 // Check every 30 seconds if there are relevant suggestions987 suggestionCheckInterval = setInterval(() => {988 if (chatHistory.length > 4) {989 const patterns = identifyConversationPatterns(chatHistory);990 991 if (patterns.length > 0) {992 const suggestions = generateProactiveSuggestions(patterns);993 994 if (suggestions.length > 0 && Math.random() > 0.7) { // 30% chance to show995 const suggestion = suggestions[0]; // Show first suggestion996 997 const proactiveMessage = `💡 **Proactive Suggestion**998 999${suggestion.message}`;1000 1001 createMessageBubble(proactiveMessage, 'model');1002 1003 // Stop checking for a while after showing suggestion1004 clearInterval(suggestionCheckInterval);1005 setTimeout(() => {1006 startContextAwareSuggestions();1007 }, 120000); // Resume after 2 minutes1008 }1009 }1010 }1011 }, 30000); // Check every 30 seconds1012 }1013 1014 // Start context-aware suggestions on page load1015 setTimeout(() => {1016 startContextAwareSuggestions();1017 }, 60000); // Start checking after 1 minute of use1018 1019 // ===== PHASE 3 FEATURE: AUTONOMOUS RESEARCH AGENT =====1020 1021 let activeResearchSession = null;1022 1023 const RESEARCH_FRAMEWORK = {1024 phases: ['Discovery', 'Deep Dive', 'Synthesis', 'Validation'],1025 maxQueries: 5,1026 timeout: 1800001027 };1028 1029 async function startAutonomousResearch(topic, depth = 'standard') {1030 const sessionId = Date.now();1031 activeResearchSession = {1032 id: sessionId,1033 topic: topic,1034 depth: depth,1035 findings: [],1036 phase: 0,1037 startTime: new Date()1038 };1039 1040 createMessageBubble(`🔬 **Autonomous Research Initiated**1041 1042Topic: "${topic}"1043Depth: ${depth}1044 1045I'll conduct comprehensive research across multiple phases:10461. **Discovery** - Identifying key aspects10472. **Deep Dive** - Gathering detailed information10483. **Synthesis** - Connecting insights10494. **Validation** - Cross-referencing findings1050 1051Starting research...`, 'assistant');1052 1053 await executeResearchPhase('Discovery', topic);1054 await new Promise(resolve => setTimeout(resolve, 2000));1055 1056 await executeResearchPhase('Deep Dive', topic);1057 await new Promise(resolve => setTimeout(resolve, 2000));1058 1059 await executeResearchPhase('Synthesis', topic);1060 await new Promise(resolve => setTimeout(resolve, 2000));1061 1062 await executeResearchPhase('Validation', topic);1063 1064 await generateResearchReport(topic);1065 1066 activeResearchSession = null;1067 }1068 1069 async function executeResearchPhase(phase, topic) {1070 createMessageBubble(`📊 **Phase: ${phase}**1071 1072Analyzing ${topic}...`, 'assistant');1073 1074 let phasePrompt = '';1075 1076 switch(phase) {1077 case 'Discovery':1078 phasePrompt = `Analyze "${topic}" and provide EXACTLY 5 key aspects in this format:1079 1080 1. [Aspect Name]: [One sentence description]1081 2. [Aspect Name]: [One sentence description]1082 3. [Aspect Name]: [One sentence description]1083 4. [Aspect Name]: [One sentence description]1084 5. [Aspect Name]: [One sentence description]1085 1086 Keep each point to ONE sentence maximum. Be concise and specific.`;1087 break;1088 1089 case 'Deep Dive':1090 phasePrompt = `Analyze "${topic}" in this EXACT format:1091 1092 **Current Trends:**1093 • [Trend 1]1094 • [Trend 2]1095 • [Trend 3]1096 1097 **Key Players:**1098 • [Player 1 and their role]1099 • [Player 2 and their role]1100 1101 **Main Challenges:**1102 • [Challenge 1]1103 • [Challenge 2]1104 1105 **Key Opportunities:**1106 • [Opportunity 1]1107 • [Opportunity 2]1108 1109 Use bullet points. Keep each point to 1-2 sentences maximum.`;1110 break;1111 1112 case 'Synthesis':1113 phasePrompt = `Synthesize insights about "${topic}" in this EXACT format:1114 1115 **Key Patterns Identified:**1116 • [Pattern 1]1117 • [Pattern 2]1118 1119 **Strategic Connections:**1120 • [Connection 1]1121 • [Connection 2]1122 1123 **Business Implications:**1124 • [Implication 1]1125 • [Implication 2]1126 1127 Keep each point concise (1-2 sentences).`;1128 break;1129 1130 case 'Validation':1131 phasePrompt = `Validate findings about "${topic}" in this EXACT format:1132 1133 **Validated Key Findings:**1134 • [Finding 1]1135 • [Finding 2]1136 • [Finding 3]1137 1138 **Areas Requiring Further Investigation:**1139 • [Area 1]1140 • [Area 2]1141 1142 **Confidence Level:** [High/Medium/Low]1143 1144 Keep each point to 1-2 sentences.`;1145 break;1146 }1147 1148 1149 try {1150 const apiKey = apiKeyInput.value.trim();1151 const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-exp:generateContent?key=${apiKey}`;1152 1153 const payload = {1154 systemInstruction: {1155 parts: [{ text: `You are Bob, an autonomous research consultant conducting independent research. Provide thorough, well-researched insights.` }]1156 },1157 contents: [{1158 role: "user",1159 parts: [{ text: phasePrompt }]1160 }],1161 tools: [{ "google_search": {} }]1162 };1163 1164 const response = await fetch(apiUrl, {1165 method: "POST",1166 headers: { "Content-Type": "application/json" },1167 body: JSON.stringify(payload)1168 });1169 1170 const result = await response.json();1171 const findings = result?.candidates?.[0]?.content?.parts?.[0]?.text || "Research phase incomplete.";1172 1173 activeResearchSession.findings.push({1174 phase: phase,1175 content: findings1176 });1177 1178 createMessageBubble(`✅ ${phase} complete`, 'assistant');1179 1180 } catch (error) {1181 console.error(`Research phase ${phase} error:`, error);1182 createMessageBubble(`⚠️ ${phase} encountered issues, continuing...`, 'assistant');1183 }1184 }1185 1186 async function generateResearchReport(topic) {1187 const findings = activeResearchSession.findings1188 .map(f => `## ${f.phase} Phase\n\n${f.content}`)1189 .join('\n\n---\n\n');1190 1191 createMessageBubble(`# 📑 Comprehensive Research Report: ${topic}1192 1193 ${findings}1194 1195 ---1196 1197 ## 📊 Research Summary1198 1199 - **Total Phases Completed:** ${activeResearchSession.findings.length}1200 - **Research Duration:** ${Math.round((new Date() - activeResearchSession.startTime) / 1000)} seconds