Transform prompts with AI-powered optimization, multi-platform workflow integration, and intelligent creative assistance for Perplexity, Gemini, Bolt.new, and more
Size
56.1 KB
Version
1.0.1
Created
Jan 7, 2026
Updated
28 days ago
1// ==UserScript==
2// @name Perplexity AI Assistant - Prompt Optimizer & Workflow Orchestrator
3// @description Transform prompts with AI-powered optimization, multi-platform workflow integration, and intelligent creative assistance for Perplexity, Gemini, Bolt.new, and more
4// @version 1.0.1
5// @match https://*.perplexity.ai/*
6// @icon https://www.perplexity.ai/favicon.ico
7// ==/UserScript==
8(function() {
9 'use strict';
10
11 // ============================================================================
12 // PERPLEXITY AI ASSISTANT - CORE ENGINE
13 // ============================================================================
14
15 console.log('🚀 Perplexity AI Assistant initializing...');
16
17 // Configuration
18 const CONFIG = {
19 platforms: {
20 perplexity: { name: 'Perplexity', modes: ['Search', 'Research', 'Labs', 'Playground'] },
21 gemini: { name: 'Google Gemini Pro', url: 'https://gemini.google.com' },
22 aiStudio: { name: 'Google AI Studio', url: 'https://aistudio.google.com' },
23 bolt: { name: 'Bolt.new', url: 'https://bolt.new' },
24 lovable: { name: 'Lovable', url: 'https://lovable.dev' },
25 framer: { name: 'Framer', url: 'https://framer.com' }
26 },
27 promptStyles: [
28 'Concise Answer',
29 'Creative Output',
30 'Technical Explanation',
31 'Innovative Project',
32 'Research Deep-Dive',
33 'Multi-Step Reasoning',
34 'Visual-Ready Output',
35 'Role-Based Prompt'
36 ],
37 storageKeys: {
38 history: 'ai_assistant_history',
39 preferences: 'ai_assistant_preferences',
40 templates: 'ai_assistant_templates',
41 workflows: 'ai_assistant_workflows'
42 }
43 };
44
45 // ============================================================================
46 // UTILITY FUNCTIONS
47 // ============================================================================
48
49 function debounce(func, wait) {
50 let timeout;
51 return function executedFunction(...args) {
52 const later = () => {
53 clearTimeout(timeout);
54 func(...args);
55 };
56 clearTimeout(timeout);
57 timeout = setTimeout(later, wait);
58 };
59 }
60
61 function generateId() {
62 return Date.now().toString(36) + Math.random().toString(36).substr(2);
63 }
64
65 // ============================================================================
66 // STORAGE MANAGER
67 // ============================================================================
68
69 class StorageManager {
70 static async get(key, defaultValue = null) {
71 try {
72 const value = await GM.getValue(key, defaultValue);
73 return value ? JSON.parse(value) : defaultValue;
74 } catch (error) {
75 console.error('Storage get error:', error);
76 return defaultValue;
77 }
78 }
79
80 static async set(key, value) {
81 try {
82 await GM.setValue(key, JSON.stringify(value));
83 return true;
84 } catch (error) {
85 console.error('Storage set error:', error);
86 return false;
87 }
88 }
89
90 static async append(key, item) {
91 const items = await this.get(key, []);
92 items.unshift(item);
93 if (items.length > 100) items.pop(); // Keep last 100 items
94 await this.set(key, items);
95 }
96 }
97
98 // ============================================================================
99 // PROMPT ANALYZER & OPTIMIZER
100 // ============================================================================
101
102 class PromptOptimizer {
103 static async analyzePrompt(prompt) {
104 console.log('🔍 Analyzing prompt:', prompt);
105
106 try {
107 const analysis = await RM.aiCall(
108 `Analyze this user prompt for clarity, completeness, and effectiveness. Identify any vagueness, ambiguity, or missing context that could improve the response quality.
109
110Prompt: "${prompt}"
111
112Provide a detailed analysis including:
1131. Clarity score (0-10)
1142. Completeness score (0-10)
1153. Identified issues
1164. Missing context or elements
1175. Suggested improvements`,
118 {
119 type: "json_schema",
120 json_schema: {
121 name: "prompt_analysis",
122 schema: {
123 type: "object",
124 properties: {
125 clarityScore: { type: "number", minimum: 0, maximum: 10 },
126 completenessScore: { type: "number", minimum: 0, maximum: 10 },
127 issues: { type: "array", items: { type: "string" } },
128 missingElements: { type: "array", items: { type: "string" } },
129 suggestions: { type: "array", items: { type: "string" } }
130 },
131 required: ["clarityScore", "completenessScore", "issues", "suggestions"]
132 }
133 }
134 }
135 );
136
137 console.log('✅ Analysis complete:', analysis);
138 return analysis;
139 } catch (error) {
140 console.error('❌ Analysis error:', error);
141 return {
142 clarityScore: 5,
143 completenessScore: 5,
144 issues: ['Unable to analyze prompt'],
145 missingElements: [],
146 suggestions: ['Try rephrasing your prompt with more specific details']
147 };
148 }
149 }
150
151 static async generateVariations(prompt, styles = CONFIG.promptStyles) {
152 console.log('🎨 Generating prompt variations for:', prompt);
153
154 try {
155 const variations = await RM.aiCall(
156 `Rewrite the following prompt in multiple variations optimized for different purposes and platforms (Perplexity, Gemini, Bolt.new, etc.).
157
158Original Prompt: "${prompt}"
159
160Generate variations for these styles:
161${styles.map((style, i) => `${i + 1}. ${style}`).join('\n')}
162
163Each variation should be optimized for its specific purpose while maintaining the core intent.`,
164 {
165 type: "json_schema",
166 json_schema: {
167 name: "prompt_variations",
168 schema: {
169 type: "object",
170 properties: {
171 variations: {
172 type: "array",
173 items: {
174 type: "object",
175 properties: {
176 style: { type: "string" },
177 prompt: { type: "string" },
178 platform: { type: "string" },
179 reasoning: { type: "string" }
180 },
181 required: ["style", "prompt", "platform"]
182 }
183 }
184 },
185 required: ["variations"]
186 }
187 }
188 }
189 );
190
191 console.log('✅ Generated variations:', variations);
192 return variations.variations;
193 } catch (error) {
194 console.error('❌ Variation generation error:', error);
195 return [];
196 }
197 }
198
199 static async generateClarifyingQuestions(prompt, analysis) {
200 console.log('❓ Generating clarifying questions...');
201
202 try {
203 const questions = await RM.aiCall(
204 `Based on this prompt and its analysis, generate 3-5 clarifying questions that would help refine the user's intent and improve the output quality.
205
206Prompt: "${prompt}"
207Issues: ${analysis.issues.join(', ')}
208Missing Elements: ${analysis.missingElements.join(', ')}
209
210Generate questions that are:
211- Specific and actionable
212- Help gather missing context
213- Guide the user to better articulate their needs`,
214 {
215 type: "json_schema",
216 json_schema: {
217 name: "clarifying_questions",
218 schema: {
219 type: "object",
220 properties: {
221 questions: {
222 type: "array",
223 items: {
224 type: "object",
225 properties: {
226 question: { type: "string" },
227 purpose: { type: "string" }
228 },
229 required: ["question", "purpose"]
230 }
231 }
232 },
233 required: ["questions"]
234 }
235 }
236 }
237 );
238
239 return questions.questions;
240 } catch (error) {
241 console.error('❌ Question generation error:', error);
242 return [];
243 }
244 }
245 }
246
247 // ============================================================================
248 // WORKFLOW ORCHESTRATOR
249 // ============================================================================
250
251 class WorkflowOrchestrator {
252 static async generateWorkflow(goal, platforms = []) {
253 console.log('🔄 Generating workflow for goal:', goal);
254
255 try {
256 const workflow = await RM.aiCall(
257 `Create a comprehensive multi-platform workflow to achieve this goal: "${goal}"
258
259Available platforms: ${Object.values(CONFIG.platforms).map(p => p.name).join(', ')}
260${platforms.length > 0 ? `Preferred platforms: ${platforms.join(', ')}` : ''}
261
262Generate a step-by-step workflow that:
2631. Breaks down the goal into actionable steps
2642. Assigns each step to the most appropriate platform
2653. Defines inputs, outputs, and handoffs between steps
2664. Includes research, creation, and production phases
2675. Provides specific prompts or actions for each step`,
268 {
269 type: "json_schema",
270 json_schema: {
271 name: "workflow_generation",
272 schema: {
273 type: "object",
274 properties: {
275 workflowName: { type: "string" },
276 description: { type: "string" },
277 estimatedTime: { type: "string" },
278 steps: {
279 type: "array",
280 items: {
281 type: "object",
282 properties: {
283 stepNumber: { type: "number" },
284 title: { type: "string" },
285 platform: { type: "string" },
286 action: { type: "string" },
287 prompt: { type: "string" },
288 expectedOutput: { type: "string" },
289 nextStep: { type: "string" }
290 },
291 required: ["stepNumber", "title", "platform", "action"]
292 }
293 }
294 },
295 required: ["workflowName", "steps"]
296 }
297 }
298 }
299 );
300
301 // Save workflow
302 await StorageManager.append(CONFIG.storageKeys.workflows, {
303 id: generateId(),
304 goal,
305 workflow,
306 createdAt: new Date().toISOString()
307 });
308
309 return workflow;
310 } catch (error) {
311 console.error('❌ Workflow generation error:', error);
312 return null;
313 }
314 }
315
316 static async suggestNextSteps(currentContext) {
317 console.log('🎯 Suggesting next steps...');
318
319 try {
320 const suggestions = await RM.aiCall(
321 `Based on the current context, suggest logical next steps for research or creative exploration.
322
323Context: ${JSON.stringify(currentContext)}
324
325Provide 3-5 actionable next steps with specific prompts or actions.`,
326 {
327 type: "json_schema",
328 json_schema: {
329 name: "next_steps",
330 schema: {
331 type: "object",
332 properties: {
333 suggestions: {
334 type: "array",
335 items: {
336 type: "object",
337 properties: {
338 title: { type: "string" },
339 description: { type: "string" },
340 platform: { type: "string" },
341 prompt: { type: "string" }
342 },
343 required: ["title", "description", "platform"]
344 }
345 }
346 },
347 required: ["suggestions"]
348 }
349 }
350 }
351 );
352
353 return suggestions.suggestions;
354 } catch (error) {
355 console.error('❌ Next steps error:', error);
356 return [];
357 }
358 }
359 }
360
361 // ============================================================================
362 // USE CASE GENERATOR
363 // ============================================================================
364
365 class UseCaseGenerator {
366 static async generateUseCases(topic, count = 5) {
367 console.log('💡 Generating use cases for:', topic);
368
369 try {
370 const useCases = await RM.aiCall(
371 `Generate ${count} innovative and practical use cases for: "${topic}"
372
373Each use case should:
374- Be unique and creative
375- Leverage AI capabilities effectively
376- Include specific implementation ideas
377- Span different domains (research, creative, technical, business)
378- Be actionable with current AI tools`,
379 {
380 type: "json_schema",
381 json_schema: {
382 name: "use_cases",
383 schema: {
384 type: "object",
385 properties: {
386 useCases: {
387 type: "array",
388 items: {
389 type: "object",
390 properties: {
391 title: { type: "string" },
392 description: { type: "string" },
393 domain: { type: "string" },
394 implementation: { type: "string" },
395 platforms: { type: "array", items: { type: "string" } },
396 difficulty: { type: "string", enum: ["Beginner", "Intermediate", "Advanced"] }
397 },
398 required: ["title", "description", "domain", "implementation"]
399 }
400 }
401 },
402 required: ["useCases"]
403 }
404 }
405 }
406 );
407
408 return useCases.useCases;
409 } catch (error) {
410 console.error('❌ Use case generation error:', error);
411 return [];
412 }
413 }
414 }
415
416 // ============================================================================
417 // UI MANAGER
418 // ============================================================================
419
420 class UIManager {
421 static injectStyles() {
422 const styles = `
423 .ai-assistant-container {
424 position: fixed;
425 bottom: 20px;
426 right: 20px;
427 z-index: 999999;
428 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
429 }
430
431 .ai-assistant-button {
432 width: 60px;
433 height: 60px;
434 border-radius: 50%;
435 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
436 border: none;
437 color: white;
438 font-size: 24px;
439 cursor: pointer;
440 box-shadow: 0 4px 20px rgba(102, 126, 234, 0.4);
441 transition: all 0.3s ease;
442 display: flex;
443 align-items: center;
444 justify-content: center;
445 }
446
447 .ai-assistant-button:hover {
448 transform: scale(1.1);
449 box-shadow: 0 6px 30px rgba(102, 126, 234, 0.6);
450 }
451
452 .ai-assistant-panel {
453 position: fixed;
454 bottom: 90px;
455 right: 20px;
456 width: 450px;
457 max-height: 600px;
458 background: white;
459 border-radius: 16px;
460 box-shadow: 0 10px 50px rgba(0, 0, 0, 0.2);
461 display: none;
462 flex-direction: column;
463 overflow: hidden;
464 z-index: 999998;
465 }
466
467 .ai-assistant-panel.active {
468 display: flex;
469 animation: slideUp 0.3s ease;
470 }
471
472 @keyframes slideUp {
473 from {
474 opacity: 0;
475 transform: translateY(20px);
476 }
477 to {
478 opacity: 1;
479 transform: translateY(0);
480 }
481 }
482
483 .ai-assistant-header {
484 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
485 color: white;
486 padding: 20px;
487 font-weight: 600;
488 font-size: 16px;
489 display: flex;
490 align-items: center;
491 justify-content: space-between;
492 }
493
494 .ai-assistant-close {
495 background: none;
496 border: none;
497 color: white;
498 font-size: 24px;
499 cursor: pointer;
500 padding: 0;
501 width: 30px;
502 height: 30px;
503 display: flex;
504 align-items: center;
505 justify-content: center;
506 border-radius: 50%;
507 transition: background 0.2s;
508 }
509
510 .ai-assistant-close:hover {
511 background: rgba(255, 255, 255, 0.2);
512 }
513
514 .ai-assistant-tabs {
515 display: flex;
516 background: #f8f9fa;
517 border-bottom: 1px solid #e9ecef;
518 overflow-x: auto;
519 }
520
521 .ai-assistant-tab {
522 padding: 12px 16px;
523 background: none;
524 border: none;
525 cursor: pointer;
526 font-size: 13px;
527 font-weight: 500;
528 color: #6c757d;
529 border-bottom: 2px solid transparent;
530 transition: all 0.2s;
531 white-space: nowrap;
532 }
533
534 .ai-assistant-tab:hover {
535 color: #667eea;
536 }
537
538 .ai-assistant-tab.active {
539 color: #667eea;
540 border-bottom-color: #667eea;
541 }
542
543 .ai-assistant-content {
544 flex: 1;
545 overflow-y: auto;
546 padding: 20px;
547 }
548
549 .ai-assistant-input-group {
550 margin-bottom: 16px;
551 }
552
553 .ai-assistant-label {
554 display: block;
555 font-size: 13px;
556 font-weight: 600;
557 color: #495057;
558 margin-bottom: 8px;
559 }
560
561 .ai-assistant-textarea {
562 width: 100%;
563 min-height: 100px;
564 padding: 12px;
565 border: 2px solid #e9ecef;
566 border-radius: 8px;
567 font-size: 14px;
568 font-family: inherit;
569 resize: vertical;
570 transition: border-color 0.2s;
571 }
572
573 .ai-assistant-textarea:focus {
574 outline: none;
575 border-color: #667eea;
576 }
577
578 .ai-assistant-button-primary {
579 width: 100%;
580 padding: 12px;
581 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
582 color: white;
583 border: none;
584 border-radius: 8px;
585 font-size: 14px;
586 font-weight: 600;
587 cursor: pointer;
588 transition: transform 0.2s, box-shadow 0.2s;
589 }
590
591 .ai-assistant-button-primary:hover {
592 transform: translateY(-2px);
593 box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
594 }
595
596 .ai-assistant-button-primary:disabled {
597 opacity: 0.6;
598 cursor: not-allowed;
599 transform: none;
600 }
601
602 .ai-assistant-loading {
603 text-align: center;
604 padding: 40px 20px;
605 color: #6c757d;
606 }
607
608 .ai-assistant-spinner {
609 width: 40px;
610 height: 40px;
611 border: 4px solid #f3f3f3;
612 border-top: 4px solid #667eea;
613 border-radius: 50%;
614 animation: spin 1s linear infinite;
615 margin: 0 auto 16px;
616 }
617
618 @keyframes spin {
619 0% { transform: rotate(0deg); }
620 100% { transform: rotate(360deg); }
621 }
622
623 .ai-assistant-result {
624 background: #f8f9fa;
625 border-radius: 8px;
626 padding: 16px;
627 margin-bottom: 16px;
628 }
629
630 .ai-assistant-result-title {
631 font-weight: 600;
632 color: #212529;
633 margin-bottom: 8px;
634 font-size: 14px;
635 }
636
637 .ai-assistant-result-content {
638 font-size: 13px;
639 color: #495057;
640 line-height: 1.6;
641 }
642
643 .ai-assistant-score {
644 display: inline-flex;
645 align-items: center;
646 gap: 8px;
647 padding: 6px 12px;
648 background: white;
649 border-radius: 20px;
650 font-size: 13px;
651 font-weight: 600;
652 margin-bottom: 12px;
653 }
654
655 .ai-assistant-score-bar {
656 width: 60px;
657 height: 6px;
658 background: #e9ecef;
659 border-radius: 3px;
660 overflow: hidden;
661 }
662
663 .ai-assistant-score-fill {
664 height: 100%;
665 background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
666 transition: width 0.3s ease;
667 }
668
669 .ai-assistant-list {
670 list-style: none;
671 padding: 0;
672 margin: 0;
673 }
674
675 .ai-assistant-list-item {
676 padding: 12px;
677 background: white;
678 border-radius: 8px;
679 margin-bottom: 8px;
680 border: 1px solid #e9ecef;
681 font-size: 13px;
682 line-height: 1.5;
683 }
684
685 .ai-assistant-variation {
686 background: white;
687 border: 2px solid #e9ecef;
688 border-radius: 8px;
689 padding: 16px;
690 margin-bottom: 12px;
691 transition: border-color 0.2s;
692 cursor: pointer;
693 }
694
695 .ai-assistant-variation:hover {
696 border-color: #667eea;
697 }
698
699 .ai-assistant-variation-header {
700 display: flex;
701 justify-content: space-between;
702 align-items: center;
703 margin-bottom: 8px;
704 }
705
706 .ai-assistant-variation-style {
707 font-weight: 600;
708 color: #667eea;
709 font-size: 13px;
710 }
711
712 .ai-assistant-variation-platform {
713 font-size: 11px;
714 color: #6c757d;
715 background: #f8f9fa;
716 padding: 4px 8px;
717 border-radius: 4px;
718 }
719
720 .ai-assistant-variation-prompt {
721 font-size: 13px;
722 color: #495057;
723 line-height: 1.6;
724 margin-bottom: 8px;
725 }
726
727 .ai-assistant-variation-actions {
728 display: flex;
729 gap: 8px;
730 }
731
732 .ai-assistant-button-small {
733 padding: 6px 12px;
734 background: #667eea;
735 color: white;
736 border: none;
737 border-radius: 6px;
738 font-size: 12px;
739 cursor: pointer;
740 transition: background 0.2s;
741 }
742
743 .ai-assistant-button-small:hover {
744 background: #5568d3;
745 }
746
747 .ai-assistant-button-secondary {
748 background: #6c757d;
749 }
750
751 .ai-assistant-button-secondary:hover {
752 background: #5a6268;
753 }
754
755 .ai-assistant-workflow-step {
756 background: white;
757 border-left: 4px solid #667eea;
758 padding: 16px;
759 margin-bottom: 12px;
760 border-radius: 8px;
761 box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
762 }
763
764 .ai-assistant-workflow-step-number {
765 display: inline-block;
766 width: 28px;
767 height: 28px;
768 background: #667eea;
769 color: white;
770 border-radius: 50%;
771 text-align: center;
772 line-height: 28px;
773 font-weight: 600;
774 font-size: 13px;
775 margin-right: 12px;
776 }
777
778 .ai-assistant-workflow-step-title {
779 font-weight: 600;
780 color: #212529;
781 font-size: 14px;
782 margin-bottom: 8px;
783 }
784
785 .ai-assistant-workflow-step-platform {
786 display: inline-block;
787 background: #f8f9fa;
788 color: #667eea;
789 padding: 4px 10px;
790 border-radius: 12px;
791 font-size: 11px;
792 font-weight: 600;
793 margin-bottom: 8px;
794 }
795
796 .ai-assistant-workflow-step-action {
797 font-size: 13px;
798 color: #495057;
799 line-height: 1.6;
800 }
801
802 .ai-assistant-empty {
803 text-align: center;
804 padding: 40px 20px;
805 color: #6c757d;
806 font-size: 14px;
807 }
808
809 .ai-assistant-history-item {
810 background: white;
811 border: 1px solid #e9ecef;
812 border-radius: 8px;
813 padding: 12px;
814 margin-bottom: 12px;
815 cursor: pointer;
816 transition: border-color 0.2s, box-shadow 0.2s;
817 }
818
819 .ai-assistant-history-item:hover {
820 border-color: #667eea;
821 box-shadow: 0 2px 8px rgba(102, 126, 234, 0.1);
822 }
823
824 .ai-assistant-history-prompt {
825 font-size: 13px;
826 color: #212529;
827 font-weight: 500;
828 margin-bottom: 6px;
829 display: -webkit-box;
830 -webkit-line-clamp: 2;
831 -webkit-box-orient: vertical;
832 overflow: hidden;
833 }
834
835 .ai-assistant-history-date {
836 font-size: 11px;
837 color: #6c757d;
838 }
839
840 .ai-assistant-badge {
841 display: inline-block;
842 padding: 4px 8px;
843 background: #667eea;
844 color: white;
845 border-radius: 12px;
846 font-size: 11px;
847 font-weight: 600;
848 margin-left: 8px;
849 }
850 `;
851
852 TM_addStyle(styles);
853 }
854
855 static createMainUI() {
856 const container = document.createElement('div');
857 container.className = 'ai-assistant-container';
858 container.innerHTML = `
859 <button class="ai-assistant-button" id="ai-assistant-toggle" title="AI Assistant">
860 ✨
861 </button>
862 <div class="ai-assistant-panel" id="ai-assistant-panel">
863 <div class="ai-assistant-header">
864 <span>🚀 AI Assistant</span>
865 <button class="ai-assistant-close" id="ai-assistant-close">×</button>
866 </div>
867 <div class="ai-assistant-tabs">
868 <button class="ai-assistant-tab active" data-tab="optimize">Optimize</button>
869 <button class="ai-assistant-tab" data-tab="variations">Variations</button>
870 <button class="ai-assistant-tab" data-tab="workflow">Workflow</button>
871 <button class="ai-assistant-tab" data-tab="use-cases">Use Cases</button>
872 <button class="ai-assistant-tab" data-tab="history">History</button>
873 </div>
874 <div class="ai-assistant-content" id="ai-assistant-content">
875 ${this.getOptimizeTabContent()}
876 </div>
877 </div>
878 `;
879
880 document.body.appendChild(container);
881 this.attachEventListeners();
882 }
883
884 static getOptimizeTabContent() {
885 return `
886 <div class="ai-assistant-input-group">
887 <label class="ai-assistant-label">Enter your prompt to analyze and optimize:</label>
888 <textarea
889 class="ai-assistant-textarea"
890 id="ai-assistant-prompt-input"
891 placeholder="Example: Write a blog post about AI..."
892 ></textarea>
893 </div>
894 <button class="ai-assistant-button-primary" id="ai-assistant-analyze">
895 🔍 Analyze & Optimize
896 </button>
897 <div id="ai-assistant-results"></div>
898 `;
899 }
900
901 static getVariationsTabContent() {
902 return `
903 <div class="ai-assistant-input-group">
904 <label class="ai-assistant-label">Enter your prompt to generate variations:</label>
905 <textarea
906 class="ai-assistant-textarea"
907 id="ai-assistant-variations-input"
908 placeholder="Example: Explain quantum computing..."
909 ></textarea>
910 </div>
911 <button class="ai-assistant-button-primary" id="ai-assistant-generate-variations">
912 🎨 Generate Variations
913 </button>
914 <div id="ai-assistant-variations-results"></div>
915 `;
916 }
917
918 static getWorkflowTabContent() {
919 return `
920 <div class="ai-assistant-input-group">
921 <label class="ai-assistant-label">Describe your goal or project:</label>
922 <textarea
923 class="ai-assistant-textarea"
924 id="ai-assistant-workflow-input"
925 placeholder="Example: Create a landing page for a SaaS product..."
926 ></textarea>
927 </div>
928 <button class="ai-assistant-button-primary" id="ai-assistant-generate-workflow">
929 🔄 Generate Workflow
930 </button>
931 <div id="ai-assistant-workflow-results"></div>
932 `;
933 }
934
935 static getUseCasesTabContent() {
936 return `
937 <div class="ai-assistant-input-group">
938 <label class="ai-assistant-label">Enter a topic or technology:</label>
939 <textarea
940 class="ai-assistant-textarea"
941 id="ai-assistant-usecase-input"
942 placeholder="Example: AI in healthcare, blockchain, etc..."
943 ></textarea>
944 </div>
945 <button class="ai-assistant-button-primary" id="ai-assistant-generate-usecases">
946 💡 Generate Use Cases
947 </button>
948 <div id="ai-assistant-usecases-results"></div>
949 `;
950 }
951
952 static async getHistoryTabContent() {
953 const history = await StorageManager.get(CONFIG.storageKeys.history, []);
954
955 if (history.length === 0) {
956 return `
957 <div class="ai-assistant-empty">
958 📝 No history yet. Start analyzing prompts to build your history!
959 </div>
960 `;
961 }
962
963 return `
964 <div class="ai-assistant-list">
965 ${history.map(item => `
966 <div class="ai-assistant-history-item" data-prompt="${this.escapeHtml(item.prompt)}">
967 <div class="ai-assistant-history-prompt">${this.escapeHtml(item.prompt)}</div>
968 <div class="ai-assistant-history-date">${new Date(item.timestamp).toLocaleString()}</div>
969 </div>
970 `).join('')}
971 </div>
972 `;
973 }
974
975 static escapeHtml(text) {
976 const div = document.createElement('div');
977 div.textContent = text;
978 return div.innerHTML;
979 }
980
981 static attachEventListeners() {
982 // Toggle panel
983 document.getElementById('ai-assistant-toggle').addEventListener('click', () => {
984 document.getElementById('ai-assistant-panel').classList.toggle('active');
985 });
986
987 document.getElementById('ai-assistant-close').addEventListener('click', () => {
988 document.getElementById('ai-assistant-panel').classList.remove('active');
989 });
990
991 // Tab switching
992 document.querySelectorAll('.ai-assistant-tab').forEach(tab => {
993 tab.addEventListener('click', async (e) => {
994 document.querySelectorAll('.ai-assistant-tab').forEach(t => t.classList.remove('active'));
995 e.target.classList.add('active');
996
997 const tabName = e.target.dataset.tab;
998 const content = document.getElementById('ai-assistant-content');
999
1000 switch(tabName) {
1001 case 'optimize':
1002 content.innerHTML = this.getOptimizeTabContent();
1003 this.attachOptimizeListeners();
1004 break;
1005 case 'variations':
1006 content.innerHTML = this.getVariationsTabContent();
1007 this.attachVariationsListeners();
1008 break;
1009 case 'workflow':
1010 content.innerHTML = this.getWorkflowTabContent();
1011 this.attachWorkflowListeners();
1012 break;
1013 case 'use-cases':
1014 content.innerHTML = this.getUseCasesTabContent();
1015 this.attachUseCasesListeners();
1016 break;
1017 case 'history':
1018 content.innerHTML = await this.getHistoryTabContent();
1019 this.attachHistoryListeners();
1020 break;
1021 }
1022 });
1023 });
1024
1025 // Initial listeners
1026 this.attachOptimizeListeners();
1027 }
1028
1029 static attachOptimizeListeners() {
1030 const analyzeBtn = document.getElementById('ai-assistant-analyze');
1031 if (analyzeBtn) {
1032 analyzeBtn.addEventListener('click', async () => {
1033 const prompt = document.getElementById('ai-assistant-prompt-input').value.trim();
1034 if (!prompt) {
1035 alert('Please enter a prompt to analyze');
1036 return;
1037 }
1038
1039 analyzeBtn.disabled = true;
1040 analyzeBtn.textContent = '⏳ Analyzing...';
1041
1042 const resultsDiv = document.getElementById('ai-assistant-results');
1043 resultsDiv.innerHTML = `
1044 <div class="ai-assistant-loading">
1045 <div class="ai-assistant-spinner"></div>
1046 <div>Analyzing your prompt with AI...</div>
1047 </div>
1048 `;
1049
1050 try {
1051 const analysis = await PromptOptimizer.analyzePrompt(prompt);
1052 const questions = await PromptOptimizer.generateClarifyingQuestions(prompt, analysis);
1053
1054 // Save to history
1055 await StorageManager.append(CONFIG.storageKeys.history, {
1056 prompt,
1057 analysis,
1058 timestamp: new Date().toISOString()
1059 });
1060
1061 resultsDiv.innerHTML = this.renderAnalysisResults(analysis, questions);
1062 } catch (error) {
1063 resultsDiv.innerHTML = `
1064 <div class="ai-assistant-result">
1065 <div class="ai-assistant-result-title">❌ Error</div>
1066 <div class="ai-assistant-result-content">${error.message}</div>
1067 </div>
1068 `;
1069 } finally {
1070 analyzeBtn.disabled = false;
1071 analyzeBtn.textContent = '🔍 Analyze & Optimize';
1072 }
1073 });
1074 }
1075 }
1076
1077 static attachVariationsListeners() {
1078 const generateBtn = document.getElementById('ai-assistant-generate-variations');
1079 if (generateBtn) {
1080 generateBtn.addEventListener('click', async () => {
1081 const prompt = document.getElementById('ai-assistant-variations-input').value.trim();
1082 if (!prompt) {
1083 alert('Please enter a prompt to generate variations');
1084 return;
1085 }
1086
1087 generateBtn.disabled = true;
1088 generateBtn.textContent = '⏳ Generating...';
1089
1090 const resultsDiv = document.getElementById('ai-assistant-variations-results');
1091 resultsDiv.innerHTML = `
1092 <div class="ai-assistant-loading">
1093 <div class="ai-assistant-spinner"></div>
1094 <div>Generating prompt variations...</div>
1095 </div>
1096 `;
1097
1098 try {
1099 const variations = await PromptOptimizer.generateVariations(prompt);
1100 resultsDiv.innerHTML = this.renderVariations(variations);
1101 } catch (error) {
1102 resultsDiv.innerHTML = `
1103 <div class="ai-assistant-result">
1104 <div class="ai-assistant-result-title">❌ Error</div>
1105 <div class="ai-assistant-result-content">${error.message}</div>
1106 </div>
1107 `;
1108 } finally {
1109 generateBtn.disabled = false;
1110 generateBtn.textContent = '🎨 Generate Variations';
1111 }
1112 });
1113 }
1114 }
1115
1116 static attachWorkflowListeners() {
1117 const generateBtn = document.getElementById('ai-assistant-generate-workflow');
1118 if (generateBtn) {
1119 generateBtn.addEventListener('click', async () => {
1120 const goal = document.getElementById('ai-assistant-workflow-input').value.trim();
1121 if (!goal) {
1122 alert('Please describe your goal or project');
1123 return;
1124 }
1125
1126 generateBtn.disabled = true;
1127 generateBtn.textContent = '⏳ Generating...';
1128
1129 const resultsDiv = document.getElementById('ai-assistant-workflow-results');
1130 resultsDiv.innerHTML = `
1131 <div class="ai-assistant-loading">
1132 <div class="ai-assistant-spinner"></div>
1133 <div>Creating your workflow...</div>
1134 </div>
1135 `;
1136
1137 try {
1138 const workflow = await WorkflowOrchestrator.generateWorkflow(goal);
1139 resultsDiv.innerHTML = this.renderWorkflow(workflow);
1140 } catch (error) {
1141 resultsDiv.innerHTML = `
1142 <div class="ai-assistant-result">
1143 <div class="ai-assistant-result-title">❌ Error</div>
1144 <div class="ai-assistant-result-content">${error.message}</div>
1145 </div>
1146 `;
1147 } finally {
1148 generateBtn.disabled = false;
1149 generateBtn.textContent = '🔄 Generate Workflow';
1150 }
1151 });
1152 }
1153 }
1154
1155 static attachUseCasesListeners() {
1156 const generateBtn = document.getElementById('ai-assistant-generate-usecases');
1157 if (generateBtn) {
1158 generateBtn.addEventListener('click', async () => {
1159 const topic = document.getElementById('ai-assistant-usecase-input').value.trim();
1160 if (!topic) {
1161 alert('Please enter a topic or technology');
1162 return;
1163 }
1164
1165 generateBtn.disabled = true;
1166 generateBtn.textContent = '⏳ Generating...';
1167
1168 const resultsDiv = document.getElementById('ai-assistant-usecases-results');
1169 resultsDiv.innerHTML = `
1170 <div class="ai-assistant-loading">
1171 <div class="ai-assistant-spinner"></div>
1172 <div>Generating innovative use cases...</div>
1173 </div>
1174 `;
1175
1176 try {
1177 const useCases = await UseCaseGenerator.generateUseCases(topic);
1178 resultsDiv.innerHTML = this.renderUseCases(useCases);
1179 } catch (error) {
1180 resultsDiv.innerHTML = `
1181 <div class="ai-assistant-result">
1182 <div class="ai-assistant-result-title">❌ Error</div>
1183 <div class="ai-assistant-result-content">${error.message}</div>
1184 </div>
1185 `;
1186 } finally {
1187 generateBtn.disabled = false;
1188 generateBtn.textContent = '💡 Generate Use Cases';
1189 }
1190 });
1191 }
1192 }
1193
1194 static attachHistoryListeners() {
1195 document.querySelectorAll('.ai-assistant-history-item').forEach(item => {
1196 item.addEventListener('click', () => {
1197 const prompt = item.dataset.prompt;
1198 document.querySelector('.ai-assistant-tab[data-tab="optimize"]').click();
1199 setTimeout(() => {
1200 document.getElementById('ai-assistant-prompt-input').value = prompt;
1201 }, 100);
1202 });
1203 });
1204 }
1205
1206 static renderAnalysisResults(analysis, questions) {
1207 return `
1208 <div class="ai-assistant-result">
1209 <div class="ai-assistant-result-title">📊 Analysis Results</div>
1210 <div class="ai-assistant-score">
1211 Clarity: ${analysis.clarityScore}/10
1212 <div class="ai-assistant-score-bar">
1213 <div class="ai-assistant-score-fill" style="width: ${analysis.clarityScore * 10}%"></div>
1214 </div>
1215 </div>
1216 <div class="ai-assistant-score">
1217 Completeness: ${analysis.completenessScore}/10
1218 <div class="ai-assistant-score-bar">
1219 <div class="ai-assistant-score-fill" style="width: ${analysis.completenessScore * 10}%"></div>
1220 </div>
1221 </div>
1222 </div>
1223
1224 ${analysis.issues.length > 0 ? `
1225 <div class="ai-assistant-result">
1226 <div class="ai-assistant-result-title">⚠️ Issues Identified</div>
1227 <ul class="ai-assistant-list">
1228 ${analysis.issues.map(issue => `
1229 <li class="ai-assistant-list-item">${this.escapeHtml(issue)}</li>
1230 `).join('')}
1231 </ul>
1232 </div>
1233 ` : ''}
1234
1235 ${analysis.suggestions.length > 0 ? `
1236 <div class="ai-assistant-result">
1237 <div class="ai-assistant-result-title">💡 Suggestions</div>
1238 <ul class="ai-assistant-list">
1239 ${analysis.suggestions.map(suggestion => `
1240 <li class="ai-assistant-list-item">${this.escapeHtml(suggestion)}</li>
1241 `).join('')}
1242 </ul>
1243 </div>
1244 ` : ''}
1245
1246 ${questions.length > 0 ? `
1247 <div class="ai-assistant-result">
1248 <div class="ai-assistant-result-title">❓ Clarifying Questions</div>
1249 <ul class="ai-assistant-list">
1250 ${questions.map(q => `
1251 <li class="ai-assistant-list-item">
1252 <strong>${this.escapeHtml(q.question)}</strong><br>
1253 <small style="color: #6c757d;">${this.escapeHtml(q.purpose)}</small>
1254 </li>
1255 `).join('')}
1256 </ul>
1257 </div>
1258 ` : ''}
1259 `;
1260 }
1261
1262 static renderVariations(variations) {
1263 if (!variations || variations.length === 0) {
1264 return '<div class="ai-assistant-empty">No variations generated</div>';
1265 }
1266
1267 return variations.map(v => `
1268 <div class="ai-assistant-variation">
1269 <div class="ai-assistant-variation-header">
1270 <span class="ai-assistant-variation-style">${this.escapeHtml(v.style)}</span>
1271 <span class="ai-assistant-variation-platform">${this.escapeHtml(v.platform)}</span>
1272 </div>
1273 <div class="ai-assistant-variation-prompt">${this.escapeHtml(v.prompt)}</div>
1274 ${v.reasoning ? `<div class="ai-assistant-result-content" style="font-size: 12px; color: #6c757d; margin-bottom: 8px;">${this.escapeHtml(v.reasoning)}</div>` : ''}
1275 <div class="ai-assistant-variation-actions">
1276 <button class="ai-assistant-button-small" onclick="navigator.clipboard.writeText('${this.escapeHtml(v.prompt).replace(/'/g, "\\'")}'); this.textContent='✓ Copied!'">
1277 📋 Copy
1278 </button>
1279 <button class="ai-assistant-button-small ai-assistant-button-secondary" onclick="window.open('${this.getPlatformUrl(v.platform)}', '_blank')">
1280 🚀 Open ${this.escapeHtml(v.platform)}
1281 </button>
1282 </div>
1283 </div>
1284 `).join('');
1285 }
1286
1287 static renderWorkflow(workflow) {
1288 if (!workflow || !workflow.steps) {
1289 return '<div class="ai-assistant-empty">No workflow generated</div>';
1290 }
1291
1292 return `
1293 <div class="ai-assistant-result">
1294 <div class="ai-assistant-result-title">🔄 ${this.escapeHtml(workflow.workflowName)}</div>
1295 ${workflow.description ? `<div class="ai-assistant-result-content">${this.escapeHtml(workflow.description)}</div>` : ''}
1296 ${workflow.estimatedTime ? `<div class="ai-assistant-badge">⏱️ ${this.escapeHtml(workflow.estimatedTime)}</div>` : ''}
1297 </div>
1298
1299 ${workflow.steps.map(step => `
1300 <div class="ai-assistant-workflow-step">
1301 <div>
1302 <span class="ai-assistant-workflow-step-number">${step.stepNumber}</span>
1303 <span class="ai-assistant-workflow-step-title">${this.escapeHtml(step.title)}</span>
1304 </div>
1305 <div class="ai-assistant-workflow-step-platform">${this.escapeHtml(step.platform)}</div>
1306 <div class="ai-assistant-workflow-step-action">${this.escapeHtml(step.action)}</div>
1307 ${step.prompt ? `
1308 <div style="margin-top: 8px;">
1309 <button class="ai-assistant-button-small" onclick="navigator.clipboard.writeText('${this.escapeHtml(step.prompt).replace(/'/g, "\\'")}'); this.textContent='✓ Copied!'">
1310 📋 Copy Prompt
1311 </button>
1312 </div>
1313 ` : ''}
1314 </div>
1315 `).join('')}
1316 `;
1317 }
1318
1319 static renderUseCases(useCases) {
1320 if (!useCases || useCases.length === 0) {
1321 return '<div class="ai-assistant-empty">No use cases generated</div>';
1322 }
1323
1324 return useCases.map(uc => `
1325 <div class="ai-assistant-result">
1326 <div class="ai-assistant-result-title">
1327 ${this.escapeHtml(uc.title)}
1328 ${uc.difficulty ? `<span class="ai-assistant-badge">${this.escapeHtml(uc.difficulty)}</span>` : ''}
1329 </div>
1330 ${uc.domain ? `<div style="font-size: 12px; color: #667eea; font-weight: 600; margin-bottom: 8px;">📁 ${this.escapeHtml(uc.domain)}</div>` : ''}
1331 <div class="ai-assistant-result-content">${this.escapeHtml(uc.description)}</div>
1332 ${uc.implementation ? `
1333 <div style="margin-top: 12px; padding-top: 12px; border-top: 1px solid #e9ecef;">
1334 <div style="font-weight: 600; font-size: 12px; color: #495057; margin-bottom: 6px;">Implementation:</div>
1335 <div class="ai-assistant-result-content">${this.escapeHtml(uc.implementation)}</div>
1336 </div>
1337 ` : ''}
1338 ${uc.platforms && uc.platforms.length > 0 ? `
1339 <div style="margin-top: 8px;">
1340 ${uc.platforms.map(p => `<span class="ai-assistant-badge" style="background: #6c757d;">${this.escapeHtml(p)}</span>`).join(' ')}
1341 </div>
1342 ` : ''}
1343 </div>
1344 `).join('');
1345 }
1346
1347 static getPlatformUrl(platformName) {
1348 const platform = Object.values(CONFIG.platforms).find(p =>
1349 p.name.toLowerCase().includes(platformName.toLowerCase())
1350 );
1351 return platform?.url || 'https://perplexity.ai';
1352 }
1353 }
1354
1355 // ============================================================================
1356 // INITIALIZATION
1357 // ============================================================================
1358
1359 async function init() {
1360 console.log('🎯 Initializing Perplexity AI Assistant...');
1361
1362 // Wait for page to be ready
1363 if (document.readyState === 'loading') {
1364 document.addEventListener('DOMContentLoaded', init);
1365 return;
1366 }
1367
1368 // Inject styles and create UI
1369 UIManager.injectStyles();
1370
1371 // Wait a bit for page to fully load
1372 setTimeout(() => {
1373 UIManager.createMainUI();
1374 console.log('✅ Perplexity AI Assistant ready!');
1375 }, 1000);
1376 }
1377
1378 // Start the extension
1379 init();
1380
1381})();