From dad06a9ce6d70a179a0d5faf4f58fb61f44c038b Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Sun, 25 Jan 2026 23:01:49 +0000 Subject: [PATCH] Auto commit: 2026-01-25T23:01:49.649Z --- backend/src/db/db.config.js | 13 +- ...0125000001-add-persona-data-to-profiles.js | 13 + backend/src/db/models/profiles.js | 43 +- .../db/seeders/20260125000002-ai-models.js | 40 ++ backend/src/index.js | 23 +- chrome-extension.zip | Bin 0 -> 8469 bytes chrome-extension/content-script.js | 302 ++++++++++ chrome-extension/manifest.json | 38 ++ chrome-extension/popup.html | 43 ++ chrome-extension/popup.js | 51 ++ chrome-extension/service-worker.js | 102 ++++ frontend/public/chrome-extension.zip | Bin 0 -> 8469 bytes frontend/public/project-source.zip | Bin 0 -> 1585565 bytes .../Profiles/configureProfilesCols.tsx | 110 ++-- frontend/src/pages/dashboard.tsx | 516 ++++-------------- frontend/src/pages/index.tsx | 167 +++--- frontend/src/pages/profiles/profiles-edit.tsx | 402 +++----------- frontend/src/pages/profiles/profiles-new.tsx | 282 ++-------- 18 files changed, 968 insertions(+), 1177 deletions(-) create mode 100644 backend/src/db/migrations/20260125000001-add-persona-data-to-profiles.js create mode 100644 backend/src/db/seeders/20260125000002-ai-models.js create mode 100644 chrome-extension.zip create mode 100644 chrome-extension/content-script.js create mode 100644 chrome-extension/manifest.json create mode 100644 chrome-extension/popup.html create mode 100644 chrome-extension/popup.js create mode 100644 chrome-extension/service-worker.js create mode 100644 frontend/public/chrome-extension.zip create mode 100644 frontend/public/project-source.zip diff --git a/backend/src/db/db.config.js b/backend/src/db/db.config.js index 1bc0325..a6f1019 100644 --- a/backend/src/db/db.config.js +++ b/backend/src/db/db.config.js @@ -1,5 +1,3 @@ - - module.exports = { production: { dialect: 'postgres', @@ -12,11 +10,12 @@ module.exports = { seederStorage: 'sequelize', }, development: { - username: 'postgres', dialect: 'postgres', - password: '', - database: 'db_ai_app_draft', - host: process.env.DB_HOST || 'localhost', + username: process.env.DB_USER || 'postgres', + password: process.env.DB_PASS || '', + database: process.env.DB_NAME || 'db_ai_app_draft', + host: process.env.DB_HOST || '127.0.0.1', + port: process.env.DB_PORT || 5432, logging: console.log, seederStorage: 'sequelize', }, @@ -30,4 +29,4 @@ module.exports = { logging: console.log, seederStorage: 'sequelize', } -}; +}; \ No newline at end of file diff --git a/backend/src/db/migrations/20260125000001-add-persona-data-to-profiles.js b/backend/src/db/migrations/20260125000001-add-persona-data-to-profiles.js new file mode 100644 index 0000000..c915d33 --- /dev/null +++ b/backend/src/db/migrations/20260125000001-add-persona-data-to-profiles.js @@ -0,0 +1,13 @@ + +module.exports = { + up: async (queryInterface, Sequelize) => { + await queryInterface.addColumn('profiles', 'persona_data', { + type: Sequelize.JSONB, + allowNull: true, + }); + }, + + down: async (queryInterface, Sequelize) => { + await queryInterface.removeColumn('profiles', 'persona_data'); + } +}; diff --git a/backend/src/db/models/profiles.js b/backend/src/db/models/profiles.js index b83b019..62ee333 100644 --- a/backend/src/db/models/profiles.js +++ b/backend/src/db/models/profiles.js @@ -16,23 +16,19 @@ module.exports = function(sequelize, DataTypes) { name: { type: DataTypes.TEXT, - - - }, description: { type: DataTypes.TEXT, - - + }, +persona_data: { + type: DataTypes.JSONB, + allowNull: true, }, created: { type: DataTypes.DATE, - - - }, importHash: { @@ -49,28 +45,6 @@ created: { ); profiles.associate = (db) => { - - -/// loop through entities and it's fields, and if ref === current e[name] and create relation has many on parent entity - - - - - - - - - - - - - - - -//end loop - - - db.profiles.belongsTo(db.users, { as: 'owner', foreignKey: { @@ -79,9 +53,6 @@ created: { constraints: false, }); - - - db.profiles.belongsTo(db.users, { as: 'createdBy', }); @@ -91,9 +62,5 @@ created: { }); }; - - return profiles; -}; - - +}; \ No newline at end of file diff --git a/backend/src/db/seeders/20260125000002-ai-models.js b/backend/src/db/seeders/20260125000002-ai-models.js new file mode 100644 index 0000000..d9bc502 --- /dev/null +++ b/backend/src/db/seeders/20260125000002-ai-models.js @@ -0,0 +1,40 @@ + +const { v4: uuidv4 } = require('uuid'); + +module.exports = { + up: async (queryInterface, Sequelize) => { + return queryInterface.bulkInsert('ai_models', [ + { + id: uuidv4(), + name: 'Groq Llama 3 70B', + provider: 'groq', + model_name: 'llama3-70b-8192', + is_enabled: true, + createdAt: new Date(), + updatedAt: new Date(), + }, + { + id: uuidv4(), + name: 'Gemini 2.5 Flash Latest', + provider: 'gemini', + model_name: 'gemini-1.5-flash-latest', + is_enabled: true, + createdAt: new Date(), + updatedAt: new Date(), + }, + { + id: uuidv4(), + name: 'DeepSeek Chat', + provider: 'deepseek', + model_name: 'deepseek-chat', + is_enabled: true, + createdAt: new Date(), + updatedAt: new Date(), + } + ]); + }, + + down: async (queryInterface, Sequelize) => { + return queryInterface.bulkDelete('ai_models', null, {}); + } +}; diff --git a/backend/src/index.js b/backend/src/index.js index 618e0aa..ab7083c 100644 --- a/backend/src/index.js +++ b/backend/src/index.js @@ -1,4 +1,3 @@ - const express = require('express'); const cors = require('cors'); const app = express(); @@ -102,6 +101,20 @@ app.use('/api/file', fileRoutes); app.use('/api/pexels', pexelsRoutes); app.enable('trust proxy'); +// Mock Auth Middleware for Extension (Single User Mode) +const mockAuthMiddleware = async (req, res, next) => { + try { + const user = await db.users.findOne(); + if (user) { + req.currentUser = user; + } + next(); + } catch (error) { + console.error("MockAuth Error:", error); + next(error); + } +}; + app.use('/api/users', passport.authenticate('jwt', {session: false}), usersRoutes); @@ -123,18 +136,18 @@ app.use('/api/request_queue', passport.authenticate('jwt', {session: false}), re app.use('/api/connection_logs', passport.authenticate('jwt', {session: false}), connection_logsRoutes); -app.use('/api/profiles', passport.authenticate('jwt', {session: false}), profilesRoutes); +app.use('/api/profiles', mockAuthMiddleware, profilesRoutes); app.use('/api/settings', passport.authenticate('jwt', {session: false}), settingsRoutes); app.use( '/api/openai', - passport.authenticate('jwt', { session: false }), + mockAuthMiddleware, openaiRoutes, ); app.use( '/api/ai', - passport.authenticate('jwt', { session: false }), + mockAuthMiddleware, openaiRoutes, ); @@ -171,4 +184,4 @@ db.sequelize.sync().then(function () { }); }); -module.exports = app; +module.exports = app; \ No newline at end of file diff --git a/chrome-extension.zip b/chrome-extension.zip new file mode 100644 index 0000000000000000000000000000000000000000..ad07a727cb5c42e4d8d4daafa7bf344d2f5bd64b GIT binary patch literal 8469 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 literal 0 HcmV?d00001 diff --git a/chrome-extension/content-script.js b/chrome-extension/content-script.js new file mode 100644 index 0000000..965dd2c --- /dev/null +++ b/chrome-extension/content-script.js @@ -0,0 +1,302 @@ +// Content Script for Smart Survey Filler +// Injects the Floating Bubble UI and handles page analysis and auto-filling + +(function() { + // Prevent multiple injections + if (window.ssfInjected) return; + window.ssfInjected = true; + + console.log('Smart Survey Filler content script active'); + + // --- UI CONSTRUCTION --- + const bubble = document.createElement('div'); + bubble.id = 'ssf-floating-bubble'; + bubble.title = "Smart Survey Filler"; + bubble.innerHTML = ` +
🤖
+ + `; + + const style = document.createElement('style'); + style.textContent = ` + #ssf-floating-bubble { + position: fixed; bottom: 30px; right: 30px; width: 60px; height: 60px; + background: linear-gradient(135deg, #4A90E2, #357ABD); + border-radius: 50%; box-shadow: 0 4px 15px rgba(0,0,0,0.3); + cursor: pointer; z-index: 2147483647; display: flex; align-items: center; justify-content: center; + transition: transform 0.2s; user-select: none; color: white; font-size: 30px; + } + #ssf-floating-bubble:hover { transform: scale(1.05); } + .ssf-menu { + position: absolute; bottom: 75px; right: 0; width: 260px; background: white; + border-radius: 12px; box-shadow: 0 10px 40px rgba(0,0,0,0.2); padding: 15px; + display: flex; flex-direction: column; gap: 8px; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; + cursor: default; text-align: left; color: #333; font-size: 14px; + border: 1px solid #eee; + } + .ssf-menu-header { + font-weight: bold; border-bottom: 1px solid #eee; padding-bottom: 8px; margin-bottom: 5px; + display: flex; justify-content: space-between; align-items: center; font-size: 16px; + } + .ssf-close-btn { cursor: pointer; color: #999; font-size: 20px; line-height: 1; } + .ssf-close-btn:hover { color: #333; } + #ssf-persona-select { + width: 100%; padding: 8px; border-radius: 6px; border: 1px solid #ddd; background: #fafafa; + } + #ssf-btn-fill { + background: #4A90E2; color: white; border: none; padding: 10px; border-radius: 6px; + cursor: pointer; font-weight: 600; margin-top: 5px; transition: background 0.2s; + } + #ssf-btn-fill:hover { background: #357ABD; } + #ssf-btn-fill:disabled { background: #ccc; cursor: not-allowed; } + #ssf-status { + font-size: 12px; margin-top: 5px; color: #666; text-align: center; min-height: 1.2em; + white-space: nowrap; overflow: hidden; text-overflow: ellipsis; + } + `; + document.head.appendChild(style); + document.body.appendChild(bubble); + + // --- EVENT HANDLERS --- + + const menu = bubble.querySelector('.ssf-menu'); + const closeBtn = bubble.querySelector('.ssf-close-btn'); + const select = document.getElementById('ssf-persona-select'); + const fillBtn = document.getElementById('ssf-btn-fill'); + const status = document.getElementById('ssf-status'); + + // Toggle Menu + bubble.addEventListener('click', (e) => { + if (e.target.closest('.ssf-menu')) return; // Don't close if clicking inside menu + // Only toggle if not dragging + if (!isDragging) { + const isHidden = menu.style.display === 'none'; + menu.style.display = isHidden ? 'flex' : 'none'; + if (isHidden) loadPersonas(); + } + }); + + closeBtn.addEventListener('click', (e) => { + e.stopPropagation(); + menu.style.display = 'none'; + }); + + // Load Personas + function loadPersonas() { + status.innerText = 'Loading profiles...'; + select.innerHTML = ''; + select.disabled = true; + fillBtn.disabled = true; + + chrome.runtime.sendMessage({ type: 'FETCH_PERSONAS' }, (response) => { + select.disabled = false; + fillBtn.disabled = false; + + if (chrome.runtime.lastError) { + status.innerText = 'Error: Check Extension Settings'; + select.innerHTML = ''; + return; + } + + if (response && response.success && response.data && response.data.length > 0) { + status.innerText = 'Ready'; + select.innerHTML = response.data.map(p => ``).join(''); + } else if (response && !response.success) { + status.innerText = response.error || 'Connection Error'; + select.innerHTML = ''; + } else { + status.innerText = 'No profiles found'; + select.innerHTML = ''; + } + }); + } + + // Fill Button Logic + fillBtn.addEventListener('click', async (e) => { + e.stopPropagation(); + const personaId = select.value; + + if (!personaId) { + status.innerText = 'Please select a persona first!'; + return; + } + + status.innerText = 'Scanning page...'; + fillBtn.disabled = true; + + // 1. Map Inputs to Questions + const fields = []; + // Expanded selector for more input types + const inputs = document.querySelectorAll('input:not([type="hidden"]):not([type="submit"]):not([type="button"]), textarea, select'); + + inputs.forEach((input, i) => { + // Logic to find label: + // 1. Explicit