diff --git a/.gitignore b/.gitignore index 9933f9e..6a5584f 100644 --- a/.gitignore +++ b/.gitignore @@ -35,4 +35,6 @@ uploads/* /memory.md /phases.md /architecture.md -/Guide.md \ No newline at end of file +/Guide.md +# Dedicated Documentation Folder +/documents/ diff --git a/Channel-Backend/api-test.js b/Channel-Backend/api-test.js deleted file mode 100644 index 3ce9808..0000000 --- a/Channel-Backend/api-test.js +++ /dev/null @@ -1,95 +0,0 @@ -const fs = require('fs'); - -async function runTests() { - const BASE_URL = 'http://localhost:5001/api/v1'; - let token = ''; - - try { - console.log('1. Testing Health Endpoint...'); - const health = await fetch(`${BASE_URL}/health`); - const healthData = await health.json(); - console.log('Health:', healthData); - if (!health.ok) throw new Error('Health check failed'); - - console.log('\n2. Testing Registration...'); - const regRes = await fetch(`${BASE_URL}/auth/register`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ email: 'admin@tech4biz.com', password: 'securepassword', role: 'ADMIN' }) - }); - console.log('Registration Status (Admin):', regRes.status); - if (!regRes.ok && regRes.status !== 400) throw new Error('Registration failed'); - - const regPartnerRes = await fetch(`${BASE_URL}/auth/register`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ email: 'partner@tech4biz.com', password: 'securepassword', role: 'PARTNER_USER' }) - }); - console.log('Registration Status (Partner):', regPartnerRes.status); - if (!regPartnerRes.ok && regPartnerRes.status !== 400) throw new Error('Partner Registration failed'); - - console.log('\n3. Testing Login...'); - const loginRes = await fetch(`${BASE_URL}/auth/login`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ email: 'admin@tech4biz.com', password: 'securepassword' }) - }); - const loginData = await loginRes.json(); - console.log('Login Status:', loginRes.status); - if (!loginRes.ok) throw new Error('Login failed'); - token = loginData.accessToken; - console.log('Received Access Token: ', token.substring(0, 15) + '...'); - - console.log('\n4. Testing Organization Creation...'); - const orgRes = await fetch(`${BASE_URL}/organizations`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${token}` - }, - body: JSON.stringify({ name: 'Tech4Biz Partners' }) - }); - const orgData = await orgRes.json(); - console.log('Organization Created:', orgData); - if (!orgRes.ok) throw new Error('Org creation failed'); - - console.log('\n5. Testing Legal Document Creation...'); - const legalRes = await fetch(`${BASE_URL}/legal/documents`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${token}` - }, - body: JSON.stringify({ type: 'NDA', version: '1.0', content: 'You must not disclose anything.' }) - }); - const legalData = await legalRes.json(); - console.log('Legal Document Created:', legalData); - if (!legalRes.ok) throw new Error('Legal creation failed'); - - console.log('\n6. Testing Asset Upload...'); - // Create a dummy file - fs.writeFileSync('test-file.txt', 'This is a test file for upload.'); - const formData = new FormData(); - const fileBlob = new Blob([fs.readFileSync('test-file.txt')], { type: 'text/plain' }); - formData.append('file', fileBlob, 'test-file.txt'); - formData.append('title', 'My Secret Document'); - - const uploadRes = await fetch(`${BASE_URL}/assets/upload`, { - method: 'POST', - headers: { - 'Authorization': `Bearer ${token}` - }, - body: formData - }); - const uploadData = await uploadRes.json(); - console.log('Asset Uploaded:', uploadData); - if (!uploadRes.ok) throw new Error('Upload failed'); - fs.unlinkSync('test-file.txt'); - - console.log('\n✅ ALL TESTS PASSED SUCCESSFULLY!'); - } catch (error) { - console.error('\n❌ TEST FAILED:', error); - } -} - -runTests(); diff --git a/Channel-Backend/prisma/schema.prisma b/Channel-Backend/prisma/schema.prisma index a842189..b70a701 100644 --- a/Channel-Backend/prisma/schema.prisma +++ b/Channel-Backend/prisma/schema.prisma @@ -78,13 +78,16 @@ model Asset { solution String? @db.Text contentType String? folderId String? - folder Folder? @relation(fields: [folderId], references: [id], onDelete: SetNull) - verticals Vertical[] @relation("AssetVerticals") + folder Folder? @relation(fields: [folderId], references: [id], onDelete: SetNull) + verticals Vertical[] @relation("AssetVerticals") + techStacks TechStack[] @relation("AssetTechStacks") + engagementTypes EngagementType[] @relation("AssetEngagementTypes") + complianceStandards ComplianceStandard[] @relation("AssetComplianceStandards") sharedWith SharedAsset[] downloadRequests DownloadRequest[] assetGroups AssetGroup[] - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt } model Vertical { @@ -101,6 +104,49 @@ model Vertical { updatedAt DateTime @updatedAt } +model TechStack { + id String @id @default(uuid()) + name String @unique + slug String @unique + category String // "Languages & Frameworks", "AI & ML", "Data & Backend", "Cloud & Infra" + icon String? + description String? + color String? + orderIndex Int @default(0) + isActive Boolean @default(true) + assets Asset[] @relation("AssetTechStacks") + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt +} + +model EngagementType { + id String @id @default(uuid()) + name String @unique + slug String @unique + icon String? + description String? + color String? + orderIndex Int @default(0) + isActive Boolean @default(true) + assets Asset[] @relation("AssetEngagementTypes") + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt +} + +model ComplianceStandard { + id String @id @default(uuid()) + name String @unique + slug String @unique + icon String? + description String? + color String? + orderIndex Int @default(0) + isActive Boolean @default(true) + assets Asset[] @relation("AssetComplianceStandards") + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt +} + model AssetNotification { id String @id @default(uuid()) title String diff --git a/Channel-Backend/seed.js b/Channel-Backend/seed.js deleted file mode 100644 index be2d132..0000000 --- a/Channel-Backend/seed.js +++ /dev/null @@ -1,26 +0,0 @@ -const { PrismaClient } = require('@prisma/client'); -const prisma = new PrismaClient(); - -async function seed() { - await prisma.legalDocument.create({ - data: { - type: 'NDA', - version: '1.0', - content: 'This is the standard Non-Disclosure Agreement content...', - isActive: true, - } - }); - - await prisma.legalDocument.create({ - data: { - type: 'MSA', - version: '1.0', - content: 'This is the standard Master Services Agreement content...', - isActive: true, - } - }); - - console.log('Documents seeded.'); -} - -seed().catch(console.error).finally(() => prisma.$disconnect()); diff --git a/Channel-Backend/seed.ts b/Channel-Backend/seed.ts index a58638c..44e4537 100644 --- a/Channel-Backend/seed.ts +++ b/Channel-Backend/seed.ts @@ -2,6 +2,7 @@ import dotenv from 'dotenv'; dotenv.config(); import prisma from './src/utils/db'; import bcrypt from 'bcrypt'; +import { seedFourGroupTaxonomy } from './src/utils/seed-taxonomy'; async function seed() { console.log('Starting database seeding...'); @@ -197,6 +198,9 @@ async function seed() { } console.log('Seeded Ecosystem Offerings.'); + // 6. Seed 4-Group Asset Taxonomy + await seedFourGroupTaxonomy(); + console.log('Seeding completed successfully.'); } diff --git a/Channel-Backend/src/controllers/asset.controller.ts b/Channel-Backend/src/controllers/asset.controller.ts index be0fc76..8ef8317 100644 --- a/Channel-Backend/src/controllers/asset.controller.ts +++ b/Channel-Backend/src/controllers/asset.controller.ts @@ -59,10 +59,18 @@ export class AssetController { fileUrl = req.body.url; } - let verticalIds = req.body.verticalIds; - if (typeof verticalIds === 'string' && verticalIds.trim()) { - try { verticalIds = JSON.parse(verticalIds); } catch { verticalIds = verticalIds.split(',').map((id: string) => id.trim()).filter(Boolean); } - } + const parseJsonOrArray = (val: any) => { + if (!val) return undefined; + if (typeof val === 'string' && val.trim()) { + try { return JSON.parse(val); } catch { return val.split(',').map((id: string) => id.trim()).filter(Boolean); } + } + return val; + }; + + let verticalIds = parseJsonOrArray(req.body.verticalIds); + let techStackIds = parseJsonOrArray(req.body.techStackIds); + let engagementTypeIds = parseJsonOrArray(req.body.engagementTypeIds); + let complianceIds = parseJsonOrArray(req.body.complianceIds); const assetData = { title: req.body.title || (req.file ? req.file.originalname : 'URL Asset'), @@ -81,6 +89,9 @@ export class AssetController { problemStatement: req.body.problemStatement || null, solution: req.body.solution || null, verticalIds, + techStackIds, + engagementTypeIds, + complianceIds, shares, sharedOrgIds: req.body.sharedOrgIds || null, }; @@ -96,6 +107,9 @@ export class AssetController { const filters = { search: req.query.search as string, verticalIds: req.query.verticalIds ? (req.query.verticalIds as string).split(',') : undefined, + techStackIds: req.query.techStackIds ? (req.query.techStackIds as string).split(',') : undefined, + engagementTypeIds: req.query.engagementTypeIds ? (req.query.engagementTypeIds as string).split(',') : undefined, + complianceIds: req.query.complianceIds ? (req.query.complianceIds as string).split(',') : undefined, contentTypes: req.query.contentTypes ? (req.query.contentTypes as string).split(',') : undefined, subcategories: req.query.subcategories ? (req.query.subcategories as string).split(',') : undefined, tags: req.query.tags ? (req.query.tags as string).split(',') : undefined, diff --git a/Channel-Backend/src/controllers/taxonomy.controller.ts b/Channel-Backend/src/controllers/taxonomy.controller.ts index 705ad81..1c9e8b9 100644 --- a/Channel-Backend/src/controllers/taxonomy.controller.ts +++ b/Channel-Backend/src/controllers/taxonomy.controller.ts @@ -19,15 +19,30 @@ export class TaxonomyController { } catch (err) { next(err); } }; - // Public/Authenticated: Get taxonomy metadata with real-time asset counts + // Public/Authenticated: Get taxonomy metadata with real-time asset counts across all 4 groups public getTaxonomyMeta = async (req: Request, res: Response, next: NextFunction) => { try { - const [verticals, assets] = await Promise.all([ + const [verticals, techStacks, engagementTypes, complianceStandards, assets] = await Promise.all([ prisma.vertical.findMany({ where: { isActive: true }, include: { _count: { select: { assets: true } } }, orderBy: { orderIndex: 'asc' }, }), + prisma.techStack.findMany({ + where: { isActive: true }, + include: { _count: { select: { assets: true } } }, + orderBy: { orderIndex: 'asc' }, + }), + prisma.engagementType.findMany({ + where: { isActive: true }, + include: { _count: { select: { assets: true } } }, + orderBy: { orderIndex: 'asc' }, + }), + prisma.complianceStandard.findMany({ + where: { isActive: true }, + include: { _count: { select: { assets: true } } }, + orderBy: { orderIndex: 'asc' }, + }), prisma.asset.findMany({ select: { categoryId: true, @@ -62,6 +77,9 @@ export class TaxonomyController { res.status(200).json({ verticals, + techStacks, + engagementTypes, + complianceStandards, categories: Object.entries(categoryCounts).map(([name, count]) => ({ name, count })), subcategories: Object.entries(subcategoryCounts).map(([name, count]) => ({ name, count })), contentTypes: Object.entries(contentTypeCounts).map(([name, count]) => ({ name, count })), @@ -117,4 +135,73 @@ export class TaxonomyController { res.status(204).send(); } catch (err) { next(err); } }; + + // Admin: Create Tech Stack + public createTechStack = async (req: AuthRequest, res: Response, next: NextFunction) => { + try { + const { name, category, icon, description, color } = req.body; + if (!name) return res.status(400).json({ error: 'Name is required' }); + const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)+/g, ''); + + const item = await prisma.techStack.create({ + data: { name, slug, category: category || 'Languages & Frameworks', icon, description, color: color || '#64748b' } + }); + res.status(201).json(item); + } catch (err) { next(err); } + }; + + // Admin: Delete Tech Stack + public deleteTechStack = async (req: AuthRequest, res: Response, next: NextFunction) => { + try { + const { id } = req.params; + await prisma.techStack.delete({ where: { id } }); + res.status(204).send(); + } catch (err) { next(err); } + }; + + // Admin: Create Engagement Type + public createEngagementType = async (req: AuthRequest, res: Response, next: NextFunction) => { + try { + const { name, icon, description, color } = req.body; + if (!name) return res.status(400).json({ error: 'Name is required' }); + const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)+/g, ''); + + const item = await prisma.engagementType.create({ + data: { name, slug, icon, description, color: color || '#0284c7' } + }); + res.status(201).json(item); + } catch (err) { next(err); } + }; + + // Admin: Delete Engagement Type + public deleteEngagementType = async (req: AuthRequest, res: Response, next: NextFunction) => { + try { + const { id } = req.params; + await prisma.engagementType.delete({ where: { id } }); + res.status(204).send(); + } catch (err) { next(err); } + }; + + // Admin: Create Compliance Standard + public createComplianceStandard = async (req: AuthRequest, res: Response, next: NextFunction) => { + try { + const { name, icon, description, color } = req.body; + if (!name) return res.status(400).json({ error: 'Name is required' }); + const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)+/g, ''); + + const item = await prisma.complianceStandard.create({ + data: { name, slug, icon, description, color: color || '#10b981' } + }); + res.status(201).json(item); + } catch (err) { next(err); } + }; + + // Admin: Delete Compliance Standard + public deleteComplianceStandard = async (req: AuthRequest, res: Response, next: NextFunction) => { + try { + const { id } = req.params; + await prisma.complianceStandard.delete({ where: { id } }); + res.status(204).send(); + } catch (err) { next(err); } + }; } diff --git a/Channel-Backend/src/routes/taxonomy.routes.ts b/Channel-Backend/src/routes/taxonomy.routes.ts index 2910a84..7cd859f 100644 --- a/Channel-Backend/src/routes/taxonomy.routes.ts +++ b/Channel-Backend/src/routes/taxonomy.routes.ts @@ -12,4 +12,13 @@ router.post('/verticals', authenticate, requireRole('ADMIN'), controller.createV router.put('/verticals/:id', authenticate, requireRole('ADMIN'), controller.updateVertical); router.delete('/verticals/:id', authenticate, requireRole('ADMIN'), controller.deleteVertical); +router.post('/tech-stacks', authenticate, requireRole('ADMIN'), controller.createTechStack); +router.delete('/tech-stacks/:id', authenticate, requireRole('ADMIN'), controller.deleteTechStack); + +router.post('/engagement-types', authenticate, requireRole('ADMIN'), controller.createEngagementType); +router.delete('/engagement-types/:id', authenticate, requireRole('ADMIN'), controller.deleteEngagementType); + +router.post('/compliance-standards', authenticate, requireRole('ADMIN'), controller.createComplianceStandard); +router.delete('/compliance-standards/:id', authenticate, requireRole('ADMIN'), controller.deleteComplianceStandard); + export default router; diff --git a/Channel-Backend/src/services/asset.service.ts b/Channel-Backend/src/services/asset.service.ts index c0c27da..d5231a6 100644 --- a/Channel-Backend/src/services/asset.service.ts +++ b/Channel-Backend/src/services/asset.service.ts @@ -55,7 +55,7 @@ export class AssetService { } public async createAsset(data: any) { - const { sharedOrgIds, shares, tags, verticalIds, ...rest } = data; + const { sharedOrgIds, shares, tags, verticalIds, techStackIds, engagementTypeIds, complianceIds, ...rest } = data; // Parse tags let parsedTags: string[] = []; @@ -69,27 +69,36 @@ export class AssetService { } } - // Parse verticalIds - let parsedVerticalIds: string[] = []; - if (Array.isArray(verticalIds)) { - parsedVerticalIds = verticalIds; - } else if (typeof verticalIds === 'string' && verticalIds.trim()) { - try { - parsedVerticalIds = JSON.parse(verticalIds); - } catch { - parsedVerticalIds = verticalIds.split(',').map((id: string) => id.trim()).filter(Boolean); + const parseIds = (val: any): string[] => { + if (Array.isArray(val)) return val; + if (typeof val === 'string' && val.trim()) { + try { return JSON.parse(val); } + catch { return val.split(',').map((s: string) => s.trim()).filter(Boolean); } } - } + return []; + }; + + const parsedVerticalIds = parseIds(verticalIds); + const parsedTechStackIds = parseIds(techStackIds); + const parsedEngagementTypeIds = parseIds(engagementTypeIds); + const parsedComplianceIds = parseIds(complianceIds); const asset = await prisma.asset.create({ data: { ...rest, tags: parsedTags, ...(parsedVerticalIds.length > 0 ? { - verticals: { - connect: parsedVerticalIds.map(id => ({ id })) - } - } : {}) + verticals: { connect: parsedVerticalIds.map(id => ({ id })) } + } : {}), + ...(parsedTechStackIds.length > 0 ? { + techStacks: { connect: parsedTechStackIds.map(id => ({ id })) } + } : {}), + ...(parsedEngagementTypeIds.length > 0 ? { + engagementTypes: { connect: parsedEngagementTypeIds.map(id => ({ id })) } + } : {}), + ...(parsedComplianceIds.length > 0 ? { + complianceStandards: { connect: parsedComplianceIds.map(id => ({ id })) } + } : {}), } }); @@ -160,6 +169,9 @@ export class AssetService { filters?: { search?: string; verticalIds?: string[]; + techStackIds?: string[]; + engagementTypeIds?: string[]; + complianceIds?: string[]; contentTypes?: string[]; subcategories?: string[]; tags?: string[]; @@ -235,9 +247,31 @@ export class AssetService { if (filters?.verticalIds && filters.verticalIds.length > 0) { andConditions.push({ verticals: { - some: { - id: { in: filters.verticalIds } - } + some: { id: { in: filters.verticalIds } } + } + }); + } + + if (filters?.techStackIds && filters.techStackIds.length > 0) { + andConditions.push({ + techStacks: { + some: { id: { in: filters.techStackIds } } + } + }); + } + + if (filters?.engagementTypeIds && filters.engagementTypeIds.length > 0) { + andConditions.push({ + engagementTypes: { + some: { id: { in: filters.engagementTypeIds } } + } + }); + } + + if (filters?.complianceIds && filters.complianceIds.length > 0) { + andConditions.push({ + complianceStandards: { + some: { id: { in: filters.complianceIds } } } }); } @@ -275,6 +309,9 @@ export class AssetService { where: whereClause, include: { verticals: true, + techStacks: true, + engagementTypes: true, + complianceStandards: true, sharedWith: { include: { organization: { @@ -301,6 +338,10 @@ export class AssetService { return await prisma.asset.findUnique({ where: { id }, include: { + verticals: true, + techStacks: true, + engagementTypes: true, + complianceStandards: true, sharedWith: { include: { organization: { @@ -323,7 +364,7 @@ export class AssetService { } public async updateAsset(id: string, data: any) { - const { shares, sharedOrgIds, tags, verticalIds, ...rest } = data; + const { shares, sharedOrgIds, tags, verticalIds, techStackIds, engagementTypeIds, complianceIds, ...rest } = data; const updateData: any = { ...rest }; @@ -341,20 +382,26 @@ export class AssetService { updateData.tags = parsedTags; } - if (verticalIds !== undefined) { - let parsedVerticalIds: string[] = []; - if (Array.isArray(verticalIds)) { - parsedVerticalIds = verticalIds; - } else if (typeof verticalIds === 'string') { - try { - parsedVerticalIds = JSON.parse(verticalIds); - } catch { - parsedVerticalIds = verticalIds.split(',').map((v: string) => v.trim()).filter(Boolean); - } + const parseIds = (val: any): string[] => { + if (Array.isArray(val)) return val; + if (typeof val === 'string') { + try { return JSON.parse(val); } + catch { return val.split(',').map((s: string) => s.trim()).filter(Boolean); } } - updateData.verticals = { - set: parsedVerticalIds.map(vid => ({ id: vid })) - }; + return []; + }; + + if (verticalIds !== undefined) { + updateData.verticals = { set: parseIds(verticalIds).map(vid => ({ id: vid })) }; + } + if (techStackIds !== undefined) { + updateData.techStacks = { set: parseIds(techStackIds).map(tid => ({ id: tid })) }; + } + if (engagementTypeIds !== undefined) { + updateData.engagementTypes = { set: parseIds(engagementTypeIds).map(eid => ({ id: eid })) }; + } + if (complianceIds !== undefined) { + updateData.complianceStandards = { set: parseIds(complianceIds).map(cid => ({ id: cid })) }; } await prisma.asset.update({ diff --git a/Channel-Backend/src/utils/seed-taxonomy.ts b/Channel-Backend/src/utils/seed-taxonomy.ts new file mode 100644 index 0000000..13e459e --- /dev/null +++ b/Channel-Backend/src/utils/seed-taxonomy.ts @@ -0,0 +1,108 @@ +import prisma from './db'; + +export async function seedFourGroupTaxonomy() { + console.log('[Taxonomy Seeder] Starting 4-Group Taxonomy Seeding...'); + + // 1. Group 1: Industry Verticals (AI & ML removed to prevent double-counting) + const verticalsData = [ + { name: 'Cybersecurity', slug: 'cybersecurity', color: '#3b82f6', description: 'OT, Infrastructure & Data Defense' }, + { name: 'Healthcare & Pharma', slug: 'healthcare-pharma', color: '#ec4899', description: 'Medical, Diagnostics & BioTech' }, + { name: 'Finance & Banking', slug: 'finance-banking', color: '#10b981', description: 'FinTech, Payments & Risk Analytics' }, + { name: 'Insurance', slug: 'insurance', color: '#6366f1', description: 'InsurTech, Claims & Underwriting' }, + { name: 'Energy & Utilities', slug: 'energy-utilities', color: '#f59e0b', description: 'Smart Grid, Power & Renewables' }, + { name: 'Agriculture', slug: 'agriculture', color: '#84cc16', description: 'AgriTech, Precision Farming & Supply' }, + { name: 'Education', slug: 'education', color: '#8b5cf6', description: 'EdTech, LMS & Digital Classrooms' }, + { name: 'Manufacturing & IoT', slug: 'manufacturing-iot', color: '#06b6d4', description: 'Industry 4.0, Robotics & Sensors' }, + { name: 'Automotive', slug: 'automotive', color: '#ef4444', description: 'EV, Autonomous Systems & Fleet' }, + { name: 'Retail & Supply Chain', slug: 'retail-supply-chain', color: '#f97316', description: 'E-Commerce, Logistics & Inventory' }, + { name: 'Blockchain', slug: 'blockchain', color: '#14b8a6', description: 'Web3, Smart Contracts & Distributed Ledgers' }, + ]; + + for (const [idx, v] of verticalsData.entries()) { + await prisma.vertical.upsert({ + where: { slug: v.slug }, + update: { name: v.name, color: v.color, description: v.description, orderIndex: idx, isActive: true }, + create: { name: v.name, slug: v.slug, color: v.color, description: v.description, orderIndex: idx, isActive: true }, + }); + } + + // Deactivate old legacy "AI & ML" entry if present in Verticals table to prevent double counting + await prisma.vertical.updateMany({ + where: { slug: 'ai-ml' }, + data: { isActive: false } + }).catch(() => {}); + + // 2. Group 2: Technology Stack + const techStacksData = [ + // Languages & Frameworks + { name: 'Java / Spring Boot', slug: 'java-spring-boot', category: 'Languages & Frameworks', color: '#f97316' }, + { name: 'Node.js', slug: 'nodejs', category: 'Languages & Frameworks', color: '#22c55e' }, + { name: 'Python', slug: 'python', category: 'Languages & Frameworks', color: '#3b82f6' }, + { name: 'React', slug: 'react', category: 'Languages & Frameworks', color: '#06b6d4' }, + { name: 'Go', slug: 'go', category: 'Languages & Frameworks', color: '#00add8' }, + { name: '.NET', slug: 'dotnet', category: 'Languages & Frameworks', color: '#512bd4' }, + + // AI & ML + { name: 'LLM / Agentic', slug: 'llm-agentic', category: 'AI & ML', color: '#8b5cf6' }, + { name: 'RAG Systems', slug: 'rag-systems', category: 'AI & ML', color: '#a855f7' }, + { name: 'Computer Vision', slug: 'computer-vision', category: 'AI & ML', color: '#d946ef' }, + { name: 'ML Pipelines', slug: 'ml-pipelines', category: 'AI & ML', color: '#ec4899' }, + { name: 'Deepfake / Detection', slug: 'deepfake-detection', category: 'AI & ML', color: '#f43f5e' }, + + // Data & Backend + { name: 'PostgreSQL', slug: 'postgresql', category: 'Data & Backend', color: '#336791' }, + { name: 'Temporal', slug: 'temporal', category: 'Data & Backend', color: '#111827' }, + { name: 'Kafka', slug: 'kafka', category: 'Data & Backend', color: '#231f20' }, + { name: 'Event-driven', slug: 'event-driven', category: 'Data & Backend', color: '#eab308' }, + { name: 'Microservices', slug: 'microservices', category: 'Data & Backend', color: '#10b981' }, + + // Cloud & Infra + { name: 'AWS', slug: 'aws', category: 'Cloud & Infra', color: '#ff9900' }, + { name: 'Sovereign / On-prem', slug: 'sovereign-onprem', category: 'Cloud & Infra', color: '#64748b' }, + { name: 'Kubernetes', slug: 'kubernetes', category: 'Cloud & Infra', color: '#326ce5' }, + { name: 'IaaS', slug: 'iaas', category: 'Cloud & Infra', color: '#0284c7' }, + ]; + + for (const [idx, t] of techStacksData.entries()) { + await prisma.techStack.upsert({ + where: { slug: t.slug }, + update: { name: t.name, category: t.category, color: t.color, orderIndex: idx, isActive: true }, + create: { name: t.name, slug: t.slug, category: t.category, color: t.color, orderIndex: idx, isActive: true }, + }); + } + + // 3. Group 3: Engagement Type + const engagementData = [ + { name: 'Build', slug: 'build', description: 'Greenfield architecture & end-to-end development', color: '#3b82f6' }, + { name: 'Rescue', slug: 'rescue', description: 'Turnaround, refactoring & distressed project recovery', color: '#ef4444' }, + { name: 'Scale', slug: 'scale', description: 'Performance tuning, cloud expansion & enterprise scaling', color: '#10b981' }, + { name: 'Due Diligence', slug: 'due-diligence', description: 'Tech audit, risk assessment & code quality review', color: '#f59e0b' }, + ]; + + for (const [idx, e] of engagementData.entries()) { + await prisma.engagementType.upsert({ + where: { slug: e.slug }, + update: { name: e.name, description: e.description, color: e.color, orderIndex: idx, isActive: true }, + create: { name: e.name, slug: e.slug, description: e.description, color: e.color, orderIndex: idx, isActive: true }, + }); + } + + // 4. Group 4: Compliance & Regulatory + const complianceData = [ + { name: 'HIPAA', slug: 'hipaa', description: 'Health Insurance Portability and Accountability Act', color: '#ec4899' }, + { name: 'GxP', slug: 'gxp', description: 'Good Practice regulations (FDA/EMEA Pharma)', color: '#8b5cf6' }, + { name: 'APRA CPS 230', slug: 'apra-cps-230', description: 'Operational Risk Management (Australian Prudential)', color: '#3b82f6' }, + { name: 'SOC 2', slug: 'soc-2', description: 'Security, Availability, and Confidentiality Trust Criteria', color: '#10b981' }, + { name: 'GDPR / Sovereign', slug: 'gdpr-sovereign', description: 'EU General Data Protection & Data Sovereignty', color: '#06b6d4' }, + ]; + + for (const [idx, c] of complianceData.entries()) { + await prisma.complianceStandard.upsert({ + where: { slug: c.slug }, + update: { name: c.name, description: c.description, color: c.color, orderIndex: idx, isActive: true }, + create: { name: c.name, slug: c.slug, description: c.description, color: c.color, orderIndex: idx, isActive: true }, + }); + } + + console.log('[Taxonomy Seeder] 4-Group Taxonomy Seeding completed successfully.'); +} diff --git a/Channel-Frontend/src/features/assets/components/AssetAdminManagerModal.tsx b/Channel-Frontend/src/features/assets/components/AssetAdminManagerModal.tsx index 5f357fe..d1358bc 100644 --- a/Channel-Frontend/src/features/assets/components/AssetAdminManagerModal.tsx +++ b/Channel-Frontend/src/features/assets/components/AssetAdminManagerModal.tsx @@ -1,7 +1,13 @@ import React, { useState } from 'react'; -import { X, Shield, Plus, Trash2, Send, Tag, CheckCircle2, AlertCircle, Bell } from 'lucide-react'; +import { X, Shield, Plus, Trash2, Tag, CheckCircle2, AlertCircle, Bell, Layers, Cpu, ShieldCheck, Send } from 'lucide-react'; import type { TaxonomyMeta, Organization, Asset } from '../../../types/assets'; -import { createVertical, deleteVertical, sendAssetAnnouncement } from '../../../services/assets-api'; +import { + createVertical, deleteVertical, + createTechStack, deleteTechStack, + createEngagementType, deleteEngagementType, + createComplianceStandard, deleteComplianceStandard, + sendAssetAnnouncement +} from '../../../services/assets-api'; interface AssetAdminManagerModalProps { isOpen: boolean; @@ -20,18 +26,31 @@ export const AssetAdminManagerModal: React.FC = ({ allAssets = [], onRefreshMeta, }) => { - const [activeTab, setActiveTab] = useState<'verticals' | 'taxonomy' | 'announcements'>('verticals'); + const [activeTab, setActiveTab] = useState<'verticals' | 'techStacks' | 'engagements' | 'compliance' | 'taxonomy' | 'announcements'>('verticals'); const [loading, setLoading] = useState(false); const [statusMsg, setStatusMsg] = useState<{ type: 'success' | 'error'; text: string } | null>(null); // Inspect filter state for Taxonomy Stats interactive list const [inspectFilter, setInspectFilter] = useState<{ type: 'Subcategory' | 'Vertical'; name: string; id?: string } | null>(null); - // New Vertical Form State + // Form State: Verticals const [newVerticalName, setNewVerticalName] = useState(''); const [newVerticalColor, setNewVerticalColor] = useState('#3b82f6'); const [newVerticalDesc, setNewVerticalDesc] = useState(''); + // Form State: Tech Stacks + const [newTechName, setNewTechName] = useState(''); + const [newTechCategory, setNewTechCategory] = useState('Languages & Frameworks'); + const [newTechColor, setNewTechColor] = useState('#64748b'); + + // Form State: Engagements + const [newEngagementName, setNewEngagementName] = useState(''); + const [newEngagementColor, setNewEngagementColor] = useState('#0284c7'); + + // Form State: Compliance + const [newComplianceName, setNewComplianceName] = useState(''); + const [newComplianceColor, setNewComplianceColor] = useState('#10b981'); + // Announcement Form State const [announcementTitle, setAnnouncementTitle] = useState(''); const [announcementMsg, setAnnouncementMsg] = useState(''); @@ -50,6 +69,7 @@ export const AssetAdminManagerModal: React.FC = ({ return false; }); + // Vertical CRUD const handleCreateVertical = async (e: React.FormEvent) => { e.preventDefault(); if (!newVerticalName.trim()) return; @@ -86,6 +106,109 @@ export const AssetAdminManagerModal: React.FC = ({ } }; + // Tech Stack CRUD + const handleCreateTechStack = async (e: React.FormEvent) => { + e.preventDefault(); + if (!newTechName.trim()) return; + setLoading(true); + try { + await createTechStack({ + name: newTechName.trim(), + category: newTechCategory, + color: newTechColor, + }); + setStatusMsg({ type: 'success', text: `Tech Stack item "${newTechName}" created successfully!` }); + setNewTechName(''); + onRefreshMeta(); + } catch (err: any) { + setStatusMsg({ type: 'error', text: err.response?.data?.error || 'Failed to create tech stack' }); + } finally { + setLoading(false); + } + }; + + const handleDeleteTechStack = async (id: string, name: string) => { + if (!window.confirm(`Are you sure you want to delete tech stack item "${name}"?`)) return; + setLoading(true); + try { + await deleteTechStack(id); + setStatusMsg({ type: 'success', text: `Tech Stack item "${name}" deleted` }); + onRefreshMeta(); + } catch (err: any) { + setStatusMsg({ type: 'error', text: 'Failed to delete tech stack item' }); + } finally { + setLoading(false); + } + }; + + // Engagement Type CRUD + const handleCreateEngagement = async (e: React.FormEvent) => { + e.preventDefault(); + if (!newEngagementName.trim()) return; + setLoading(true); + try { + await createEngagementType({ + name: newEngagementName.trim(), + color: newEngagementColor, + }); + setStatusMsg({ type: 'success', text: `Engagement Type "${newEngagementName}" created!` }); + setNewEngagementName(''); + onRefreshMeta(); + } catch (err: any) { + setStatusMsg({ type: 'error', text: err.response?.data?.error || 'Failed to create engagement type' }); + } finally { + setLoading(false); + } + }; + + const handleDeleteEngagement = async (id: string, name: string) => { + if (!window.confirm(`Are you sure you want to delete engagement type "${name}"?`)) return; + setLoading(true); + try { + await deleteEngagementType(id); + setStatusMsg({ type: 'success', text: `Engagement Type "${name}" deleted` }); + onRefreshMeta(); + } catch (err: any) { + setStatusMsg({ type: 'error', text: 'Failed to delete engagement type' }); + } finally { + setLoading(false); + } + }; + + // Compliance Standard CRUD + const handleCreateCompliance = async (e: React.FormEvent) => { + e.preventDefault(); + if (!newComplianceName.trim()) return; + setLoading(true); + try { + await createComplianceStandard({ + name: newComplianceName.trim(), + color: newComplianceColor, + }); + setStatusMsg({ type: 'success', text: `Compliance Standard "${newComplianceName}" created!` }); + setNewComplianceName(''); + onRefreshMeta(); + } catch (err: any) { + setStatusMsg({ type: 'error', text: err.response?.data?.error || 'Failed to create compliance standard' }); + } finally { + setLoading(false); + } + }; + + const handleDeleteCompliance = async (id: string, name: string) => { + if (!window.confirm(`Are you sure you want to delete compliance standard "${name}"?`)) return; + setLoading(true); + try { + await deleteComplianceStandard(id); + setStatusMsg({ type: 'success', text: `Compliance Standard "${name}" deleted` }); + onRefreshMeta(); + } catch (err: any) { + setStatusMsg({ type: 'error', text: 'Failed to delete compliance standard' }); + } finally { + setLoading(false); + } + }; + const handleSendAnnouncement = async (e: React.FormEvent) => { e.preventDefault(); if (!announcementTitle.trim() || !announcementMsg.trim()) return; @@ -108,7 +231,7 @@ export const AssetAdminManagerModal: React.FC = ({ return (
-
+
{/* Modal Header */}
@@ -118,10 +241,10 @@ export const AssetAdminManagerModal: React.FC = ({

- Taxonomy & Partner Announcements Control Panel + Taxonomy & Announcements Control Panel

- Manage industry verticals, taxonomy metadata, and partner communications + Manage 4-Group Taxonomy items, metadata stats, and partner notifications

@@ -134,39 +257,77 @@ export const AssetAdminManagerModal: React.FC = ({
{/* Tab Navigation */} -
+
+ + + + + + + +
@@ -284,72 +445,303 @@ export const AssetAdminManagerModal: React.FC = ({
)} - {/* TAB 2: Taxonomy Stats */} - {activeTab === 'taxonomy' && ( + {/* TAB 2: Tech Stacks */} + {activeTab === 'techStacks' && (
-
-
-
{meta?.totalAssets || 0}
-
Total Catalog Assets
-
-
-
{meta?.verticals.length || 0}
-
Industry Verticals
-
-
-
{meta?.subcategories.length || 0}
-
Subcategories
-
-
-
{meta?.tags.length || 0}
-
Unique Tags
-
-
- -
-

- Subcategory Breakdown (Click to Inspect Records) -

-
- {(meta?.subcategories || []).map(s => ( - +
+ + + {/* Tech Stack List */} +
+

+ Active Tech Stack Items ({meta?.techStacks?.length || 0}) +

+
+ {(meta?.techStacks || []).map(t => ( +
+
+ +
+
+ {t.name} + + {t.category} + + + {t._count?.assets ?? 0} assets + +
+
+
+ +
))}
+
+ )} + {/* TAB 3: Engagement Types */} + {activeTab === 'engagements' && ( +
+ {/* Create Engagement Form */} +
+

+ + Add New Engagement Type +

+
+
+ + setNewEngagementName(e.target.value)} + className="w-full px-3 py-2 text-xs rounded-lg border border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-800 text-slate-900 dark:text-slate-100" + /> +
+
+ + setNewEngagementColor(e.target.value)} + className="w-full h-9 p-0.5 rounded border border-slate-200 dark:border-slate-700 cursor-pointer" + /> +
+
+
+ +
+
+ + {/* Engagements List */} +
+

+ Active Engagement Types ({meta?.engagementTypes?.length || 0}) +

+
+ {(meta?.engagementTypes || []).map(e => ( +
+
+ + {e.name} + + {e._count?.assets ?? 0} assets + +
+ +
+ ))} +
+
+
+ )} + + {/* TAB 4: Compliance Standards */} + {activeTab === 'compliance' && ( +
+ {/* Create Compliance Form */} +
+

+ + Add New Compliance Standard / Regulatory Certification +

+
+
+ + setNewComplianceName(e.target.value)} + className="w-full px-3 py-2 text-xs rounded-lg border border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-800 text-slate-900 dark:text-slate-100" + /> +
+
+ + setNewComplianceColor(e.target.value)} + className="w-full h-9 p-0.5 rounded border border-slate-200 dark:border-slate-700 cursor-pointer" + /> +
+
+
+ +
+
+ + {/* Compliance List */} +
+

+ Active Compliance Standards ({meta?.complianceStandards?.length || 0}) +

+
+ {(meta?.complianceStandards || []).map(c => ( +
+
+ + + + {c.name} + + + {c._count?.assets ?? 0} assets + +
+ +
+ ))} +
+
+
+ )} + + {/* TAB 2: Taxonomy Stats */} + {activeTab === 'taxonomy' && ( +
+
+
+
{meta?.totalAssets || 0}
+
Total Assets
+
+
+
{meta?.verticals.length || 0}
+
1. Verticals
+
+
+
{meta?.techStacks?.length || 0}
+
2. Tech Stacks
+
+
+
{meta?.engagementTypes?.length || 0}
+
3. Engagements
+
+
+
{meta?.complianceStandards?.length || 0}
+
4. Compliance
+
+
+ + {/* 1. Industry Verticals Breakdown */}
-

- Vertical Domain Distribution +

+ 1. Industry Verticals Domain Distribution

{(meta?.verticals || []).map(v => ( @@ -357,6 +749,59 @@ export const AssetAdminManagerModal: React.FC = ({
+ {/* 2. Tech Stack Breakdown */} +
+

+ 2. Technology Stack & Capabilities +

+
+ {(meta?.techStacks || []).map(t => ( +
+ + {t.name} + ({t._count?.assets ?? 0}) +
+ ))} +
+
+ + {/* 3 & 4. Engagement & Compliance Grid */} +
+
+

+ 3. Engagement Types +

+
+ {(meta?.engagementTypes || []).map(e => ( +
+ {e.name} + ({e._count?.assets ?? 0} assets) +
+ ))} +
+
+ +
+

+ 4. Compliance & Regulatory +

+
+ {(meta?.complianceStandards || []).map(c => ( +
+ + + {c.name} + + ({c._count?.assets ?? 0} assets) +
+ ))} +
+
+
+ {/* Inspect Filter Asset List Details */} {inspectFilter && (
diff --git a/Channel-Frontend/src/features/assets/components/AssetCard.tsx b/Channel-Frontend/src/features/assets/components/AssetCard.tsx index 3793220..5be2c3f 100644 --- a/Channel-Frontend/src/features/assets/components/AssetCard.tsx +++ b/Channel-Frontend/src/features/assets/components/AssetCard.tsx @@ -14,7 +14,8 @@ import { Clock, AlertCircle, Globe, - Sparkles + Sparkles, + Shield } from 'lucide-react'; import type { Asset } from '../../../types/assets'; import type { User } from '../../../types/auth'; @@ -572,19 +573,54 @@ export const AssetCard: React.FC = ({
- {asset.verticals && asset.verticals.length > 0 && ( + {/* Group 1: Industry Verticals */} + {asset.verticals && asset.verticals.map(v => ( - - {asset.verticals[0].name} + + {v.name} - )} + ))} + + {/* Group 2: Tech Stack */} + {asset.techStacks && asset.techStacks.map(t => ( + + + {t.name} + + ))} + + {/* Group 3: Engagement Type */} + {asset.engagementTypes && asset.engagementTypes.map(e => ( + + {e.name} + + ))} + + {/* Group 4: Compliance Standards */} + {asset.complianceStandards && asset.complianceStandards.map(c => ( + + + {c.name} + + ))} +
{asset.subcategory || asset.categoryId || 'General'}
diff --git a/Channel-Frontend/src/features/assets/components/AssetTableView.tsx b/Channel-Frontend/src/features/assets/components/AssetTableView.tsx index 7d1edc6..b941384 100644 --- a/Channel-Frontend/src/features/assets/components/AssetTableView.tsx +++ b/Channel-Frontend/src/features/assets/components/AssetTableView.tsx @@ -50,7 +50,6 @@ export const AssetTableView: React.FC = ({ {assets.map((asset) => { const isSelected = selectedIds.includes(asset.id); const isRecommended = recommendedIds.includes(asset.id); - const primaryVertical = asset.verticals && asset.verticals.length > 0 ? asset.verticals[0] : null; return ( = ({
- {/* Vertical */} + {/* Taxonomy Classification */} - {primaryVertical ? ( - - - {primaryVertical.name} - - ) : ( - General - )} +
+ {asset.verticals && asset.verticals.map(v => ( + + + {v.name} + + ))} + + {asset.techStacks && asset.techStacks.map(t => ( + + {t.name} + + ))} + + {asset.engagementTypes && asset.engagementTypes.map(e => ( + + {e.name} + + ))} + + {asset.complianceStandards && asset.complianceStandards.map(c => ( + + {c.name} + + ))} + + {(!asset.verticals || asset.verticals.length === 0) && + (!asset.techStacks || asset.techStacks.length === 0) && + (!asset.engagementTypes || asset.engagementTypes.length === 0) && + (!asset.complianceStandards || asset.complianceStandards.length === 0) && ( + General + )} +
{/* Type */} diff --git a/Channel-Frontend/src/features/assets/components/EditAssetModal.tsx b/Channel-Frontend/src/features/assets/components/EditAssetModal.tsx index 581c6bd..9853d7b 100644 --- a/Channel-Frontend/src/features/assets/components/EditAssetModal.tsx +++ b/Channel-Frontend/src/features/assets/components/EditAssetModal.tsx @@ -1,6 +1,6 @@ import React, { useState, useEffect } from 'react'; -import { updateAsset, getVerticals } from '../../../services/assets-api'; -import type { Asset, Vertical } from '../../../types/assets'; +import { updateAsset, getTaxonomyMeta } from '../../../services/assets-api'; +import type { Asset, TaxonomyMeta } from '../../../types/assets'; import Modal from '../../../components/ui/Modal'; import Button from '../../../components/ui/Button'; import { useToast } from '../../../hooks/use-toast'; @@ -19,8 +19,13 @@ export const EditAssetModal: React.FC = ({ onSuccess }) => { const { success, error } = useToast(); - const [verticals, setVerticals] = useState([]); - const [editVerticalId, setEditVerticalId] = useState(''); + const [taxonomyMeta, setTaxonomyMeta] = useState(null); + + const [editVerticalIds, setEditVerticalIds] = useState([]); + const [editTechStackIds, setEditTechStackIds] = useState([]); + const [editEngagementTypeIds, setEditEngagementTypeIds] = useState([]); + const [editComplianceIds, setEditComplianceIds] = useState([]); + const [editTitle, setEditTitle] = useState(''); const [editDescription, setEditDescription] = useState(''); const [editCategory, setEditCategory] = useState('Marketing'); @@ -31,7 +36,7 @@ export const EditAssetModal: React.FC = ({ const [isSavingEdit, setIsSavingEdit] = useState(false); useEffect(() => { - getVerticals().then(setVerticals).catch(console.error); + getTaxonomyMeta().then(setTaxonomyMeta).catch(console.error); }, []); useEffect(() => { @@ -43,10 +48,18 @@ export const EditAssetModal: React.FC = ({ setEditTags(asset.tags.join(', ')); setEditGithubUrl(asset.githubUrl || ''); setEditIsDownloadable(asset.isDownloadable); - setEditVerticalId(asset.verticals && asset.verticals.length > 0 ? asset.verticals[0].id : ''); + + setEditVerticalIds(asset.verticals ? asset.verticals.map(v => v.id) : []); + setEditTechStackIds(asset.techStacks ? asset.techStacks.map(t => t.id) : []); + setEditEngagementTypeIds(asset.engagementTypes ? asset.engagementTypes.map(e => e.id) : []); + setEditComplianceIds(asset.complianceStandards ? asset.complianceStandards.map(c => c.id) : []); } }, [asset]); + const toggleSelection = (list: string[], item: string) => { + return list.includes(item) ? list.filter(i => i !== item) : [...list, item]; + }; + const handleEditSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!asset) return; @@ -58,7 +71,10 @@ export const EditAssetModal: React.FC = ({ description: editDescription, categoryId: editCategory, subcategory: editSubcategory, - verticalIds: editVerticalId ? [editVerticalId] : [], + verticalIds: editVerticalIds, + techStackIds: editTechStackIds, + engagementTypeIds: editEngagementTypeIds, + complianceIds: editComplianceIds, tags: editTags.split(',').map(t => t.trim()).filter(Boolean), githubUrl: editGithubUrl, isDownloadable: editIsDownloadable, @@ -115,43 +131,130 @@ export const EditAssetModal: React.FC = ({ />
-
+ {/* 4-Group Taxonomy Demarcation Selection */} +
+

+ Taxonomy Classification (Strict Admin-Managed) +

+ + {/* Group 1: Industry Verticals */}
- - + +
+ {(taxonomyMeta?.verticals || []).map(v => { + const isSelected = editVerticalIds.includes(v.id); + return ( + + ); + })} +
+ + {/* Group 2: Tech Stack */}
- - + +
+ {['Languages & Frameworks', 'AI & ML', 'Data & Backend', 'Cloud & Infra'].map(catName => { + const items = (taxonomyMeta?.techStacks || []).filter(t => t.category === catName || (!t.category && catName === 'Languages & Frameworks')); + if (items.length === 0) return null; + return ( +
+
+ {catName} +
+
+ {items.map(t => { + const isSelected = editTechStackIds.includes(t.id); + return ( + + ); + })} +
+
+ ); + })} +
-
- - setEditSubcategory(e.target.value)} - placeholder="e.g. Slide Deck" - className="w-full bg-ink-50 border border-ink-200 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ink-900/10 text-ink-900 placeholder-ink-400" - /> + + {/* Group 3 & Group 4 Grid */} +
+ {/* Group 3: Engagement Type */} +
+ +
+ {(taxonomyMeta?.engagementTypes || []).map(e => { + const isSelected = editEngagementTypeIds.includes(e.id); + return ( + + ); + })} +
+
+ + {/* Group 4: Compliance Standards */} +
+ +
+ {(taxonomyMeta?.complianceStandards || []).map(c => { + const isSelected = editComplianceIds.includes(c.id); + return ( + + ); + })} +
+
diff --git a/Channel-Frontend/src/features/assets/components/FilterDrawer.tsx b/Channel-Frontend/src/features/assets/components/FilterDrawer.tsx index efc2581..f6b79e3 100644 --- a/Channel-Frontend/src/features/assets/components/FilterDrawer.tsx +++ b/Channel-Frontend/src/features/assets/components/FilterDrawer.tsx @@ -129,10 +129,10 @@ export const FilterDrawer: React.FC = ({ {/* Body Content */}
- {/* 1. Industry Verticals */} + {/* 1. Industry Verticals (Group 1) */}

- Industry Verticals + 1. Industry Verticals ({filteredVerticals.length}) @@ -189,7 +189,130 @@ export const FilterDrawer: React.FC = ({

- {/* 2. Content Types */} + {/* 2. Technology Stack (Group 2) */} + {(meta?.techStacks || []).length > 0 && ( +
+

+ 2. Technology Stack + + ({(meta?.techStacks || []).length}) + +

+
+ {['Languages & Frameworks', 'AI & ML', 'Data & Backend', 'Cloud & Infra'].map(cat => { + const groupItems = (meta?.techStacks || []).filter(t => t.category === cat); + if (groupItems.length === 0) return null; + + return ( +
+
+ {cat} +
+
+ {groupItems.map(tech => { + const isSelected = filters.techStackIds?.includes(tech.id); + return ( + + ); + })} +
+
+ ); + })} +
+
+ )} + + {/* 3. Engagement Type (Group 3) */} + {(meta?.engagementTypes || []).length > 0 && ( +
+

+ 3. Engagement Type +

+
+ {(meta?.engagementTypes || []).map(eng => { + const isSelected = filters.engagementTypeIds?.includes(eng.id); + return ( + + ); + })} +
+
+ )} + + {/* 4. Compliance & Regulatory (Group 4) */} + {(meta?.complianceStandards || []).length > 0 && ( +
+

+ 4. Compliance & Governance +

+
+ {(meta?.complianceStandards || []).map(comp => { + const isSelected = filters.complianceIds?.includes(comp.id); + return ( + + ); + })} +
+
+ )} + + {/* 5. Content Types */}

Content Types @@ -237,7 +360,7 @@ export const FilterDrawer: React.FC = ({

- {/* 3. Subcategories */} + {/* 6. Subcategories */} {filteredSubcategories.length > 0 && (

@@ -269,7 +392,7 @@ export const FilterDrawer: React.FC = ({

)} - {/* 4. Tag Cloud */} + {/* 7. Tag Cloud */} {filteredTags.length > 0 && (

diff --git a/Channel-Frontend/src/features/assets/components/UploadAssetModal.tsx b/Channel-Frontend/src/features/assets/components/UploadAssetModal.tsx index 097d65a..550b4bc 100644 --- a/Channel-Frontend/src/features/assets/components/UploadAssetModal.tsx +++ b/Channel-Frontend/src/features/assets/components/UploadAssetModal.tsx @@ -1,7 +1,7 @@ import React, { useState, useEffect } from 'react'; import { X, UploadCloud, Eye, FileText, File } from 'lucide-react'; -import { uploadAsset, scrapeCaseStudy, getVerticals } from '../../../services/assets-api'; -import type { Vertical } from '../../../types/assets'; +import { uploadAsset, scrapeCaseStudy, getTaxonomyMeta } from '../../../services/assets-api'; +import type { TaxonomyMeta } from '../../../types/assets'; import Modal from '../../../components/ui/Modal'; import Button from '../../../components/ui/Button'; import { useToast } from '../../../hooks/use-toast'; @@ -18,8 +18,12 @@ export const UploadAssetModal: React.FC = ({ onSuccess }) => { const { success, error } = useToast(); - const [verticals, setVerticals] = useState([]); - const [selectedVerticalId, setSelectedVerticalId] = useState(''); + const [taxonomyMeta, setTaxonomyMeta] = useState(null); + + const [selectedVerticalIds, setSelectedVerticalIds] = useState([]); + const [selectedTechStackIds, setSelectedTechStackIds] = useState([]); + const [selectedEngagementTypeIds, setSelectedEngagementTypeIds] = useState([]); + const [selectedComplianceIds, setSelectedComplianceIds] = useState([]); const [uploadTab, setUploadTab] = useState<'file' | 'url' | 'case_study'>('file'); const [uploadFile, setUploadFile] = useState(null); @@ -41,7 +45,7 @@ export const UploadAssetModal: React.FC = ({ const [isUploading, setIsUploading] = useState(false); useEffect(() => { - getVerticals().then(setVerticals).catch(console.error); + getTaxonomyMeta().then(setTaxonomyMeta).catch(console.error); }, []); useEffect(() => { @@ -158,8 +162,17 @@ export const UploadAssetModal: React.FC = ({ formData.append('tags', JSON.stringify(uploadTags.split(',').map(t => t.trim()).filter(Boolean))); formData.append('githubUrl', uploadGithubUrl); formData.append('isDownloadable', String(uploadIsDownloadable)); - if (selectedVerticalId) { - formData.append('verticalIds', JSON.stringify([selectedVerticalId])); + if (selectedVerticalIds.length) { + formData.append('verticalIds', JSON.stringify(selectedVerticalIds)); + } + if (selectedTechStackIds.length) { + formData.append('techStackIds', JSON.stringify(selectedTechStackIds)); + } + if (selectedEngagementTypeIds.length) { + formData.append('engagementTypeIds', JSON.stringify(selectedEngagementTypeIds)); + } + if (selectedComplianceIds.length) { + formData.append('complianceIds', JSON.stringify(selectedComplianceIds)); } if (thumbnailUrl) { @@ -184,6 +197,10 @@ export const UploadAssetModal: React.FC = ({ setUploadSubcategory(''); setUploadTags(''); setUploadGithubUrl(''); + setSelectedVerticalIds([]); + setSelectedTechStackIds([]); + setSelectedEngagementTypeIds([]); + setSelectedComplianceIds([]); setUploadIsDownloadable(true); success('Asset published successfully', 'The asset has been added to the catalog.'); onSuccess(); @@ -196,6 +213,10 @@ export const UploadAssetModal: React.FC = ({ } }; + const toggleSelection = (list: string[], item: string) => { + return list.includes(item) ? list.filter(i => i !== item) : [...list, item]; + }; + return ( <> = ({ />

-
+ {/* 4-Group Taxonomy Demarcation Selection */} +
+

+ Taxonomy Classification (Strict Admin-Managed) +

+ + {/* Group 1: Industry Verticals */}
- - + +
+ {(taxonomyMeta?.verticals || []).map(v => { + const isSelected = selectedVerticalIds.includes(v.id); + return ( + + ); + })} +
+ + {/* Group 2: Tech Stack */}
- - + +
+ {['Languages & Frameworks', 'AI & ML', 'Data & Backend', 'Cloud & Infra'].map(catName => { + const items = (taxonomyMeta?.techStacks || []).filter(t => t.category === catName || (!t.category && catName === 'Languages & Frameworks')); + if (items.length === 0) return null; + return ( +
+
+ {catName} +
+
+ {items.map(t => { + const isSelected = selectedTechStackIds.includes(t.id); + return ( + + ); + })} +
+
+ ); + })} +
-
- - setUploadSubcategory(e.target.value)} - placeholder="e.g. Slide Deck" - className="w-full bg-ink-50 border border-ink-200 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ink-900/10 text-ink-900 placeholder-ink-400" - /> + + {/* Group 3 & Group 4 Grid */} +
+ {/* Group 3: Engagement Type */} +
+ +
+ {(taxonomyMeta?.engagementTypes || []).map(e => { + const isSelected = selectedEngagementTypeIds.includes(e.id); + return ( + + ); + })} +
+
+ + {/* Group 4: Compliance Standards */} +
+ +
+ {(taxonomyMeta?.complianceStandards || []).map(c => { + const isSelected = selectedComplianceIds.includes(c.id); + return ( + + ); + })} +
+
diff --git a/Channel-Frontend/src/pages/AssetsPage.tsx b/Channel-Frontend/src/pages/AssetsPage.tsx index 4bfaac1..8315cd0 100644 --- a/Channel-Frontend/src/pages/AssetsPage.tsx +++ b/Channel-Frontend/src/pages/AssetsPage.tsx @@ -314,7 +314,7 @@ export const AssetsPage = () => { const toolbarNode = (
- + {/* Search Bar */}
@@ -347,33 +347,30 @@ export const AssetsPage = () => {
@@ -583,11 +577,10 @@ export const AssetsPage = () => { variants={containerVariants} initial="hidden" animate="show" - className={`grid grid-cols-1 ${ - viewMode === 'compact' + className={`grid grid-cols-1 ${viewMode === 'compact' ? 'md:grid-cols-3 xl:grid-cols-5 gap-3' : 'md:grid-cols-2 xl:grid-cols-4 gap-4' - } items-start`} + } items-start`} > {filteredAssets.map((asset) => ( => { const params: Record = {}; if (filters?.search) params.search = filters.search; if (filters?.verticalIds?.length) params.verticalIds = filters.verticalIds.join(','); + if (filters?.techStackIds?.length) params.techStackIds = filters.techStackIds.join(','); + if (filters?.engagementTypeIds?.length) params.engagementTypeIds = filters.engagementTypeIds.join(','); + if (filters?.complianceIds?.length) params.complianceIds = filters.complianceIds.join(','); if (filters?.contentTypes?.length) params.contentTypes = filters.contentTypes.join(','); if (filters?.subcategories?.length) params.subcategories = filters.subcategories.join(','); if (filters?.tags?.length) params.tags = filters.tags.join(','); @@ -33,6 +36,9 @@ export const updateAsset = async ( categoryId?: string; subcategory?: string; verticalIds?: string[]; + techStackIds?: string[]; + engagementTypeIds?: string[]; + complianceIds?: string[]; tags?: string[]; githubUrl?: string; isDownloadable?: boolean; @@ -139,6 +145,33 @@ export const deleteVertical = async (id: string): Promise => { await axiosInstance.delete(`/taxonomy/verticals/${id}`); }; +export const createTechStack = async (payload: { name: string; category?: string; icon?: string; description?: string; color?: string }): Promise => { + const response = await axiosInstance.post('/taxonomy/tech-stacks', payload); + return response.data; +}; + +export const deleteTechStack = async (id: string): Promise => { + await axiosInstance.delete(`/taxonomy/tech-stacks/${id}`); +}; + +export const createEngagementType = async (payload: { name: string; icon?: string; description?: string; color?: string }): Promise => { + const response = await axiosInstance.post('/taxonomy/engagement-types', payload); + return response.data; +}; + +export const deleteEngagementType = async (id: string): Promise => { + await axiosInstance.delete(`/taxonomy/engagement-types/${id}`); +}; + +export const createComplianceStandard = async (payload: { name: string; icon?: string; description?: string; color?: string }): Promise => { + const response = await axiosInstance.post('/taxonomy/compliance-standards', payload); + return response.data; +}; + +export const deleteComplianceStandard = async (id: string): Promise => { + await axiosInstance.delete(`/taxonomy/compliance-standards/${id}`); +}; + // Notification API export const sendAssetAnnouncement = async (payload: { title: string; message: string; targetOrgIds?: string[]; assetIds?: string[] }): Promise => { await axiosInstance.post('/assets/notify', payload); diff --git a/Channel-Frontend/src/types/assets.ts b/Channel-Frontend/src/types/assets.ts index bf7c2bd..fcfe5c9 100644 --- a/Channel-Frontend/src/types/assets.ts +++ b/Channel-Frontend/src/types/assets.ts @@ -40,8 +40,54 @@ export interface Vertical { }; } +export interface TechStack { + id: string; + name: string; + slug: string; + category: string; + icon?: string | null; + description?: string | null; + color?: string | null; + orderIndex?: number; + isActive?: boolean; + _count?: { + assets: number; + }; +} + +export interface EngagementType { + id: string; + name: string; + slug: string; + icon?: string | null; + description?: string | null; + color?: string | null; + orderIndex?: number; + isActive?: boolean; + _count?: { + assets: number; + }; +} + +export interface ComplianceStandard { + id: string; + name: string; + slug: string; + icon?: string | null; + description?: string | null; + color?: string | null; + orderIndex?: number; + isActive?: boolean; + _count?: { + assets: number; + }; +} + export interface TaxonomyMeta { verticals: Vertical[]; + techStacks: TechStack[]; + engagementTypes: EngagementType[]; + complianceStandards: ComplianceStandard[]; categories: { name: string; count: number }[]; subcategories: { name: string; count: number }[]; contentTypes: { name: string; count: number }[]; @@ -52,6 +98,9 @@ export interface TaxonomyMeta { export interface AssetQueryFilters { search?: string; verticalIds?: string[]; + techStackIds?: string[]; + engagementTypeIds?: string[]; + complianceIds?: string[]; contentTypes?: string[]; subcategories?: string[]; tags?: string[]; @@ -80,6 +129,9 @@ export interface Asset { solution?: string | null; createdAt: string; verticals?: Vertical[]; + techStacks?: TechStack[]; + engagementTypes?: EngagementType[]; + complianceStandards?: ComplianceStandard[]; sharedWith?: SharedWithOrg[]; downloadRequests?: DownloadRequest[]; } diff --git a/player_response.json b/player_response.json deleted file mode 100644 index bb74b86..0000000 --- a/player_response.json +++ /dev/null @@ -1,2116 +0,0 @@ -{ - "responseContext": { - "serviceTrackingParams": [ - { - "service": "GFEEDBACK", - "params": [ - { - "key": "ipcc", - "value": "0" - }, - { - "key": "is_alc_surface", - "value": "false" - }, - { - "key": "is_viewed_live", - "value": "False" - }, - { - "key": "logged_in", - "value": "0" - }, - { - "key": "visitor_data", - "value": "CgtkYVJFOGxnbWptVSi9o-fSBjIKCgJJThIEGgAgL2LfAgrcAjIwLllUPUdEN0s2dW1TZFJtQ1FQQnRuLVhjcE5ra1BzSWt5Yi1xamNONnR0Z0JGU1QzblFJbmFrOGNCWktuSjQyc2FYbm5jbE9Qb3MxSzhfVFRINEpfZVNyQm1tSFdXcHRSREQzTWhDN3NrQmREdUtvT3E3ZFdDaEdCTmU1bElyWk4yVlFmeTRFRTBiSV9xdHBPem03bjNZZU94YXhEc01sdV9uQ3ZPUHlXRldHWDV5SVB1YzlwUk9MUW9ZM2pMa1VoS0FXSHYzUjAwQXRMbTZ2RUlrQVNaQmRibUV6bFVDVnVPd1JVVFd5MEVqdmtCb2xiYkJpTGgzdE51eVg2dVJ6b2ZwU3lIZDM0TTE2UWV2dThlVzFTR3ZiODN2MUNUb0JwT2xtcFA2d0htR19lWjdXY0lhWnpobzhVZlBWVkctTnczNC1qUEhRNElORjZ1SUlNUXQwQUZrQ1JNUQ%3D%3D" - } - ] - }, - { - "service": "CSI", - "params": [ - { - "key": "c", - "value": "WEB" - }, - { - "key": "cver", - "value": "2.20260714.05.00" - }, - { - "key": "yt_li", - "value": "0" - }, - { - "key": "GetPlayer_rid", - "value": "0x38e26ebc94d96a07" - } - ] - }, - { - "service": "GUIDED_HELP", - "params": [ - { - "key": "logged_in", - "value": "0" - } - ] - }, - { - "service": "ECATCHER", - "params": [ - { - "key": "client.version", - "value": "2.20260714" - }, - { - "key": "client.name", - "value": "WEB" - } - ] - } - ], - "maxAgeSeconds": 0, - "mainAppWebResponseContext": { - "loggedOut": true, - "trackingParam": "k5_fmPxhoXZRPYA0aSLgOYw4pQBky9mQ8R5PtqaQCO6P8tGvyi_wMoYTrzRMkuMYNLBwOcCw59TLtslLKPQGSS" - }, - "responseId": "IhMI5_ebxZDZlQMVuYesAh3j0zlD", - "webResponseContextExtensionData": { - "webResponseContextPreloadData": { - "preloadMessageNames": [ - "miniplayerRenderer", - "offlineabilityRenderer", - "playerCaptionsTracklistRenderer", - "playerAnnotationsExpandedRenderer", - "subscribeButtonRenderer", - "confirmDialogRenderer", - "buttonRenderer", - "playerStoryboardSpecRenderer", - "playerMicroformatRenderer", - "cardCollectionRenderer", - "cardRenderer", - "simpleCardTeaserRenderer", - "infoCardIconRenderer" - ] - }, - "hasDecorated": true - } - }, - "playabilityStatus": { - "status": "OK", - "playableInEmbed": true, - "offlineability": { - "offlineabilityRenderer": { - "offlineable": true, - "formats": [ - { - "name": { - "runs": [ - { - "text": "Full HD (1080p)" - } - ] - }, - "formatType": "HD_1080", - "availabilityType": "OFFLINEABILITY_AVAILABILITY_TYPE_PREMIUM_LOCKED", - "savedSettingShouldExpire": false - }, - { - "name": { - "runs": [ - { - "text": "High (720p)" - } - ] - }, - "formatType": "HD", - "availabilityType": "OFFLINEABILITY_AVAILABILITY_TYPE_PREMIUM_LOCKED", - "savedSettingShouldExpire": false - }, - { - "name": { - "runs": [ - { - "text": "Medium (360p)" - } - ] - }, - "formatType": "SD", - "availabilityType": "OFFLINEABILITY_AVAILABILITY_TYPE_FREE", - "savedSettingShouldExpire": true - }, - { - "name": { - "runs": [ - { - "text": "Low (144p)" - } - ] - }, - "formatType": "LD", - "availabilityType": "OFFLINEABILITY_AVAILABILITY_TYPE_FREE", - "savedSettingShouldExpire": true - } - ], - "clickTrackingParams": "CAwQxzciEwjn95vFkNmVAxW5h6wCHePTOUMyC29mZmxpbmVsaXN0ygEEQUvf1w==" - } - }, - "miniplayer": { - "miniplayerRenderer": { - "playbackMode": "PLAYBACK_MODE_ALLOW" - } - }, - "contextParams": "Q0FFU0FnZ0M=" - }, - "streamingData": { - "expiresInSeconds": "21540", - "adaptiveFormats": [ - { - "itag": 135, - "mimeType": "video/mp4; codecs=\"avc1.4d401f\"", - "bitrate": 882468, - "width": 854, - "height": 448, - "initRange": { - "start": "0", - "end": "740" - }, - "indexRange": { - "start": "741", - "end": "1276" - }, - "lastModified": "1749127605446987", - "contentLength": "12117844", - "quality": "large", - "fps": 30, - "qualityLabel": "480p", - "projectionType": "RECTANGULAR", - "averageBitrate": 396171, - "approxDurationMs": "244699", - "qualityOrdinal": "QUALITY_ORDINAL_480P" - }, - { - "itag": 134, - "mimeType": "video/mp4; codecs=\"avc1.4d401e\"", - "bitrate": 502684, - "width": 640, - "height": 336, - "initRange": { - "start": "0", - "end": "739" - }, - "indexRange": { - "start": "740", - "end": "1275" - }, - "lastModified": "1749127606149415", - "contentLength": "6699464", - "quality": "medium", - "fps": 30, - "qualityLabel": "360p", - "projectionType": "RECTANGULAR", - "averageBitrate": 219027, - "highReplication": true, - "approxDurationMs": "244699", - "qualityOrdinal": "QUALITY_ORDINAL_360P" - }, - { - "itag": 243, - "mimeType": "video/webm; codecs=\"vp9\"", - "bitrate": 370295, - "width": 640, - "height": 336, - "initRange": { - "start": "0", - "end": "219" - }, - "indexRange": { - "start": "220", - "end": "925" - }, - "lastModified": "1749127614817386", - "contentLength": "4470331", - "quality": "medium", - "fps": 30, - "qualityLabel": "360p", - "projectionType": "RECTANGULAR", - "averageBitrate": 146148, - "colorInfo": { - "primaries": "COLOR_PRIMARIES_BT709", - "transferCharacteristics": "COLOR_TRANSFER_CHARACTERISTICS_BT709", - "matrixCoefficients": "COLOR_MATRIX_COEFFICIENTS_BT709" - }, - "approxDurationMs": "244700", - "qualityOrdinal": "QUALITY_ORDINAL_360P" - }, - { - "itag": 160, - "mimeType": "video/mp4; codecs=\"avc1.4d400c\"", - "bitrate": 106802, - "width": 256, - "height": 134, - "initRange": { - "start": "0", - "end": "739" - }, - "indexRange": { - "start": "740", - "end": "1275" - }, - "lastModified": "1749127605729164", - "contentLength": "1611622", - "quality": "tiny", - "fps": 30, - "qualityLabel": "144p", - "projectionType": "RECTANGULAR", - "averageBitrate": 52689, - "approxDurationMs": "244699", - "qualityOrdinal": "QUALITY_ORDINAL_144P" - }, - { - "itag": 140, - "mimeType": "audio/mp4; codecs=\"mp4a.40.2\"", - "bitrate": 130485, - "initRange": { - "start": "0", - "end": "722" - }, - "indexRange": { - "start": "723", - "end": "1054" - }, - "lastModified": "1749127600547897", - "contentLength": "3962003", - "quality": "tiny", - "projectionType": "RECTANGULAR", - "averageBitrate": 129497, - "highReplication": true, - "audioQuality": "AUDIO_QUALITY_MEDIUM", - "approxDurationMs": "244761", - "audioSampleRate": "44100", - "audioChannels": 2, - "loudnessDb": -8.3500004, - "trackAbsoluteLoudnessLkfs": -22.35, - "qualityOrdinal": "QUALITY_ORDINAL_UNKNOWN" - }, - { - "itag": 251, - "mimeType": "audio/webm; codecs=\"opus\"", - "bitrate": 108526, - "initRange": { - "start": "0", - "end": "265" - }, - "indexRange": { - "start": "266", - "end": "687" - }, - "lastModified": "1749127616323340", - "contentLength": "3114188", - "quality": "tiny", - "projectionType": "RECTANGULAR", - "averageBitrate": 101795, - "audioQuality": "AUDIO_QUALITY_MEDIUM", - "approxDurationMs": "244741", - "audioSampleRate": "48000", - "audioChannels": 2, - "loudnessDb": -8.3500004, - "trackAbsoluteLoudnessLkfs": -22.35, - "qualityOrdinal": "QUALITY_ORDINAL_UNKNOWN" - } - ], - "serverAbrStreamingUrl": "https://rr4---sn-ci5gup-cagr.googlevideo.com/videoplayback?expire=1784292893&ei=vdFZaqelM7mPssUP46fnmQQ&ip=122.166.145.27&id=o-AC3AUNYh64jXxzTlJ2mzsT7Md9p2E-H2PO-yB08kn7_S&source=youtube&requiressl=yes&xpc=EgVo2aDSNQ%3D%3D&cps=281&met=1784271293%2C&mh=s9&mm=31%2C29&mn=sn-ci5gup-cagr%2Csn-ci5gup-h55y&ms=au%2Crdu&mv=m&mvi=4&pl=26&rms=au%2Cau&initcwndbps=2610000&spc=SQ-umqbc6Hz5h8Xgs8fGaWNyc0WFLIuv6npeMrLmpGy6ltnJNv3XGCVNLHkSOJgbgpZofQ&svpuc=1&ns=yX6OtG0tyPZT4oy-DYCd_0AW&sabr=1&rqh=1&mt=1784270931&fvip=5&keepalive=yes&fexp=51565115&c=WEB&n=57B9DxyCmtTSEr1x&sparams=expire%2Cei%2Cip%2Cid%2Csource%2Crequiressl%2Cxpc%2Cspc%2Csvpuc%2Cns%2Csabr%2Crqh&sig=AE0s2JYwRAIgf36w6Yom0ZWNmvDsr2m2FgkESCXnYTHL24n5wpNwOxsCIB7x0wCOXqw7J-S6C7565F4ndkdZsICijNrMJftWE0t5&lsparams=cps%2Cmet%2Cmh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Crms%2Cinitcwndbps&lsig=APaTxxMwRQIgcnwz7pWlr8qP1yo_24NNN1ORFdi-K7r7RId3yq-0EGUCIQCzStpOIzKq-II3YAHHUETAGMip_yTCZK4bvxdrAoZFcw%3D%3D" - }, - "playbackTracking": { - "videostatsPlaybackUrl": { - "baseUrl": "https://s.youtube.com/api/stats/playback?cl=946688434&docid=svJDGYlQLYw&ei=vdFZaqelM7mPssUP46fnmQQ&fexp=&ns=yt&plid=AAZWyQinMrP3ra9W&el=detailpage&len=245&of=_qCnwGk-KWlmu42OAuiBCg&vm=CAEQABgEOjJBSHFpSlRJV2R2Y1BtWUh3OG44TVFLM0hXNk9NWkRSQ09kVFJhb0pzeENjcUo2ZmxuQWJUQUxkcUFQTC01OG10aHl1N2hXaE91UXY5enZKSVYxVzhaQTJicHZRVkZHdDRmMFBadm90b0xQeDZhR25rbS16Qmx4U0FqY0JzVXZvTGtCWUltWHZP" - }, - "videostatsDelayplayUrl": { - "baseUrl": "https://s.youtube.com/api/stats/delayplay?cl=946688434&docid=svJDGYlQLYw&ei=vdFZaqelM7mPssUP46fnmQQ&fexp=&ns=yt&plid=AAZWyQinMrP3ra9W&el=detailpage&len=245&of=_qCnwGk-KWlmu42OAuiBCg&vm=CAEQABgEOjJBSHFpSlRJV2R2Y1BtWUh3OG44TVFLM0hXNk9NWkRSQ09kVFJhb0pzeENjcUo2ZmxuQWJUQUxkcUFQTC01OG10aHl1N2hXaE91UXY5enZKSVYxVzhaQTJicHZRVkZHdDRmMFBadm90b0xQeDZhR25rbS16Qmx4U0FqY0JzVXZvTGtCWUltWHZP" - }, - "videostatsWatchtimeUrl": { - "baseUrl": "https://s.youtube.com/api/stats/watchtime?cl=946688434&docid=svJDGYlQLYw&ei=vdFZaqelM7mPssUP46fnmQQ&fexp=&ns=yt&plid=AAZWyQinMrP3ra9W&el=detailpage&len=245&of=_qCnwGk-KWlmu42OAuiBCg&vm=CAEQABgEOjJBSHFpSlRJV2R2Y1BtWUh3OG44TVFLM0hXNk9NWkRSQ09kVFJhb0pzeENjcUo2ZmxuQWJUQUxkcUFQTC01OG10aHl1N2hXaE91UXY5enZKSVYxVzhaQTJicHZRVkZHdDRmMFBadm90b0xQeDZhR25rbS16Qmx4U0FqY0JzVXZvTGtCWUltWHZP" - }, - "ptrackingUrl": { - "baseUrl": "https://www.youtube.com/ptracking?ei=vdFZaqelM7mPssUP46fnmQQ&plid=AAZWyQinMrP3ra9W&pltype=contentugc&ptk=youtube_none&video_id=svJDGYlQLYw" - }, - "qoeUrl": { - "baseUrl": "https://s.youtube.com/api/stats/qoe?cl=946688434&docid=svJDGYlQLYw&ei=vdFZaqelM7mPssUP46fnmQQ&el=detailpage&event=streamingstats&fexp=&ns=yt&plid=AAZWyQinMrP3ra9W" - }, - "atrUrl": { - "baseUrl": "https://s.youtube.com/api/stats/atr?c=WEB&docid=svJDGYlQLYw&ei=vdFZaqelM7mPssUP46fnmQQ&len=245&ns=yt&plid=AAZWyQinMrP3ra9W&ver=2&vm=CAEQABgEOjJBSHFpSlRJV2R2Y1BtWUh3OG44TVFLM0hXNk9NWkRSQ09kVFJhb0pzeENjcUo2ZmxuQWJUQUxkcUFQTC01OG10aHl1N2hXaE91UXY5enZKSVYxVzhaQTJicHZRVkZHdDRmMFBadm90b0xQeDZhR25rbS16Qmx4U0FqY0JzVXZvTGtCWUltWHZP", - "elapsedMediaTimeSeconds": 5 - }, - "videostatsScheduledFlushWalltimeSeconds": [ - 10, - 20, - 30 - ], - "videostatsDefaultFlushIntervalSeconds": 40 - }, - "captions": { - "playerCaptionsTracklistRenderer": { - "captionTracks": [ - { - "baseUrl": "https://www.youtube.com/api/timedtext?v=svJDGYlQLYw&ei=vdFZaqelM7mPssUP46fnmQQ&caps=asr&opi=112496729&exp=xpe&xoaf=5&xowf=1&hl=en&ip=0.0.0.0&ipbits=0&expire=1784296493&sparams=ip,ipbits,expire,v,ei,caps,opi,exp,xoaf&signature=5C9452ED4A488393C3A8ED249A3792ED508B2A67.89D3035E8B7BD5291C8A0414B3E270673E95EA9A&key=yt8&kind=asr&lang=en", - "name": { - "simpleText": "English (auto-generated)" - }, - "vssId": "a.en", - "languageCode": "en", - "kind": "asr", - "isTranslatable": true, - "trackName": "" - } - ], - "audioTracks": [ - { - "captionTrackIndices": [ - 0 - ], - "defaultCaptionTrackIndex": 0, - "hasDefaultTrack": true, - "captionsInitialState": "CAPTIONS_INITIAL_STATE_OFF_RECOMMENDED" - } - ], - "translationLanguages": [ - { - "languageCode": "ab", - "languageName": { - "simpleText": "Abkhazian" - } - }, - { - "languageCode": "aa", - "languageName": { - "simpleText": "Afar" - } - }, - { - "languageCode": "af", - "languageName": { - "simpleText": "Afrikaans" - } - }, - { - "languageCode": "ak", - "languageName": { - "simpleText": "Akan" - } - }, - { - "languageCode": "sq", - "languageName": { - "simpleText": "Albanian" - } - }, - { - "languageCode": "am", - "languageName": { - "simpleText": "Amharic" - } - }, - { - "languageCode": "ar", - "languageName": { - "simpleText": "Arabic" - } - }, - { - "languageCode": "hy", - "languageName": { - "simpleText": "Armenian" - } - }, - { - "languageCode": "as", - "languageName": { - "simpleText": "Assamese" - } - }, - { - "languageCode": "ay", - "languageName": { - "simpleText": "Aymara" - } - }, - { - "languageCode": "az", - "languageName": { - "simpleText": "Azerbaijani" - } - }, - { - "languageCode": "bn", - "languageName": { - "simpleText": "Bangla" - } - }, - { - "languageCode": "ba", - "languageName": { - "simpleText": "Bashkir" - } - }, - { - "languageCode": "eu", - "languageName": { - "simpleText": "Basque" - } - }, - { - "languageCode": "be", - "languageName": { - "simpleText": "Belarusian" - } - }, - { - "languageCode": "bho", - "languageName": { - "simpleText": "Bhojpuri" - } - }, - { - "languageCode": "bs", - "languageName": { - "simpleText": "Bosnian" - } - }, - { - "languageCode": "br", - "languageName": { - "simpleText": "Breton" - } - }, - { - "languageCode": "bg", - "languageName": { - "simpleText": "Bulgarian" - } - }, - { - "languageCode": "my", - "languageName": { - "simpleText": "Burmese" - } - }, - { - "languageCode": "ca", - "languageName": { - "simpleText": "Catalan" - } - }, - { - "languageCode": "ceb", - "languageName": { - "simpleText": "Cebuano" - } - }, - { - "languageCode": "zh-Hans", - "languageName": { - "simpleText": "Chinese (Simplified)" - } - }, - { - "languageCode": "zh-Hant", - "languageName": { - "simpleText": "Chinese (Traditional)" - } - }, - { - "languageCode": "co", - "languageName": { - "simpleText": "Corsican" - } - }, - { - "languageCode": "hr", - "languageName": { - "simpleText": "Croatian" - } - }, - { - "languageCode": "cs", - "languageName": { - "simpleText": "Czech" - } - }, - { - "languageCode": "da", - "languageName": { - "simpleText": "Danish" - } - }, - { - "languageCode": "dv", - "languageName": { - "simpleText": "Divehi" - } - }, - { - "languageCode": "nl", - "languageName": { - "simpleText": "Dutch" - } - }, - { - "languageCode": "dz", - "languageName": { - "simpleText": "Dzongkha" - } - }, - { - "languageCode": "en", - "languageName": { - "simpleText": "English" - } - }, - { - "languageCode": "eo", - "languageName": { - "simpleText": "Esperanto" - } - }, - { - "languageCode": "et", - "languageName": { - "simpleText": "Estonian" - } - }, - { - "languageCode": "ee", - "languageName": { - "simpleText": "Ewe" - } - }, - { - "languageCode": "fo", - "languageName": { - "simpleText": "Faroese" - } - }, - { - "languageCode": "fj", - "languageName": { - "simpleText": "Fijian" - } - }, - { - "languageCode": "fil", - "languageName": { - "simpleText": "Filipino" - } - }, - { - "languageCode": "fi", - "languageName": { - "simpleText": "Finnish" - } - }, - { - "languageCode": "fr", - "languageName": { - "simpleText": "French" - } - }, - { - "languageCode": "gaa", - "languageName": { - "simpleText": "Ga" - } - }, - { - "languageCode": "gl", - "languageName": { - "simpleText": "Galician" - } - }, - { - "languageCode": "lg", - "languageName": { - "simpleText": "Ganda" - } - }, - { - "languageCode": "ka", - "languageName": { - "simpleText": "Georgian" - } - }, - { - "languageCode": "de", - "languageName": { - "simpleText": "German" - } - }, - { - "languageCode": "el", - "languageName": { - "simpleText": "Greek" - } - }, - { - "languageCode": "gn", - "languageName": { - "simpleText": "Guarani" - } - }, - { - "languageCode": "gu", - "languageName": { - "simpleText": "Gujarati" - } - }, - { - "languageCode": "ht", - "languageName": { - "simpleText": "Haitian Creole" - } - }, - { - "languageCode": "ha", - "languageName": { - "simpleText": "Hausa" - } - }, - { - "languageCode": "haw", - "languageName": { - "simpleText": "Hawaiian" - } - }, - { - "languageCode": "iw", - "languageName": { - "simpleText": "Hebrew" - } - }, - { - "languageCode": "hi", - "languageName": { - "simpleText": "Hindi" - } - }, - { - "languageCode": "hmn", - "languageName": { - "simpleText": "Hmong" - } - }, - { - "languageCode": "hu", - "languageName": { - "simpleText": "Hungarian" - } - }, - { - "languageCode": "is", - "languageName": { - "simpleText": "Icelandic" - } - }, - { - "languageCode": "ig", - "languageName": { - "simpleText": "Igbo" - } - }, - { - "languageCode": "id", - "languageName": { - "simpleText": "Indonesian" - } - }, - { - "languageCode": "iu", - "languageName": { - "simpleText": "Inuktitut" - } - }, - { - "languageCode": "ga", - "languageName": { - "simpleText": "Irish" - } - }, - { - "languageCode": "it", - "languageName": { - "simpleText": "Italian" - } - }, - { - "languageCode": "ja", - "languageName": { - "simpleText": "Japanese" - } - }, - { - "languageCode": "jv", - "languageName": { - "simpleText": "Javanese" - } - }, - { - "languageCode": "kl", - "languageName": { - "simpleText": "Kalaallisut" - } - }, - { - "languageCode": "kn", - "languageName": { - "simpleText": "Kannada" - } - }, - { - "languageCode": "kk", - "languageName": { - "simpleText": "Kazakh" - } - }, - { - "languageCode": "kha", - "languageName": { - "simpleText": "Khasi" - } - }, - { - "languageCode": "km", - "languageName": { - "simpleText": "Khmer" - } - }, - { - "languageCode": "rw", - "languageName": { - "simpleText": "Kinyarwanda" - } - }, - { - "languageCode": "ko", - "languageName": { - "simpleText": "Korean" - } - }, - { - "languageCode": "kri", - "languageName": { - "simpleText": "Krio" - } - }, - { - "languageCode": "ku", - "languageName": { - "simpleText": "Kurdish" - } - }, - { - "languageCode": "ky", - "languageName": { - "simpleText": "Kyrgyz" - } - }, - { - "languageCode": "lo", - "languageName": { - "simpleText": "Lao" - } - }, - { - "languageCode": "la", - "languageName": { - "simpleText": "Latin" - } - }, - { - "languageCode": "lv", - "languageName": { - "simpleText": "Latvian" - } - }, - { - "languageCode": "ln", - "languageName": { - "simpleText": "Lingala" - } - }, - { - "languageCode": "lt", - "languageName": { - "simpleText": "Lithuanian" - } - }, - { - "languageCode": "lua", - "languageName": { - "simpleText": "Luba-Lulua" - } - }, - { - "languageCode": "luo", - "languageName": { - "simpleText": "Luo" - } - }, - { - "languageCode": "lb", - "languageName": { - "simpleText": "Luxembourgish" - } - }, - { - "languageCode": "mk", - "languageName": { - "simpleText": "Macedonian" - } - }, - { - "languageCode": "mg", - "languageName": { - "simpleText": "Malagasy" - } - }, - { - "languageCode": "ms", - "languageName": { - "simpleText": "Malay" - } - }, - { - "languageCode": "ml", - "languageName": { - "simpleText": "Malayalam" - } - }, - { - "languageCode": "mt", - "languageName": { - "simpleText": "Maltese" - } - }, - { - "languageCode": "gv", - "languageName": { - "simpleText": "Manx" - } - }, - { - "languageCode": "mi", - "languageName": { - "simpleText": "Māori" - } - }, - { - "languageCode": "mr", - "languageName": { - "simpleText": "Marathi" - } - }, - { - "languageCode": "mn", - "languageName": { - "simpleText": "Mongolian" - } - }, - { - "languageCode": "mfe", - "languageName": { - "simpleText": "Morisyen" - } - }, - { - "languageCode": "ne", - "languageName": { - "simpleText": "Nepali" - } - }, - { - "languageCode": "new", - "languageName": { - "simpleText": "Newari" - } - }, - { - "languageCode": "nso", - "languageName": { - "simpleText": "Northern Sotho" - } - }, - { - "languageCode": "no", - "languageName": { - "simpleText": "Norwegian" - } - }, - { - "languageCode": "ny", - "languageName": { - "simpleText": "Nyanja" - } - }, - { - "languageCode": "oc", - "languageName": { - "simpleText": "Occitan" - } - }, - { - "languageCode": "or", - "languageName": { - "simpleText": "Odia" - } - }, - { - "languageCode": "om", - "languageName": { - "simpleText": "Oromo" - } - }, - { - "languageCode": "os", - "languageName": { - "simpleText": "Ossetic" - } - }, - { - "languageCode": "pam", - "languageName": { - "simpleText": "Pampanga" - } - }, - { - "languageCode": "ps", - "languageName": { - "simpleText": "Pashto" - } - }, - { - "languageCode": "fa", - "languageName": { - "simpleText": "Persian" - } - }, - { - "languageCode": "pl", - "languageName": { - "simpleText": "Polish" - } - }, - { - "languageCode": "pt", - "languageName": { - "simpleText": "Portuguese" - } - }, - { - "languageCode": "pt-PT", - "languageName": { - "simpleText": "Portuguese (Portugal)" - } - }, - { - "languageCode": "pa", - "languageName": { - "simpleText": "Punjabi" - } - }, - { - "languageCode": "qu", - "languageName": { - "simpleText": "Quechua" - } - }, - { - "languageCode": "ro", - "languageName": { - "simpleText": "Romanian" - } - }, - { - "languageCode": "rn", - "languageName": { - "simpleText": "Rundi" - } - }, - { - "languageCode": "ru", - "languageName": { - "simpleText": "Russian" - } - }, - { - "languageCode": "sm", - "languageName": { - "simpleText": "Samoan" - } - }, - { - "languageCode": "sg", - "languageName": { - "simpleText": "Sango" - } - }, - { - "languageCode": "sa", - "languageName": { - "simpleText": "Sanskrit" - } - }, - { - "languageCode": "gd", - "languageName": { - "simpleText": "Scottish Gaelic" - } - }, - { - "languageCode": "sr", - "languageName": { - "simpleText": "Serbian" - } - }, - { - "languageCode": "crs", - "languageName": { - "simpleText": "Seselwa Creole French" - } - }, - { - "languageCode": "sn", - "languageName": { - "simpleText": "Shona" - } - }, - { - "languageCode": "sd", - "languageName": { - "simpleText": "Sindhi" - } - }, - { - "languageCode": "si", - "languageName": { - "simpleText": "Sinhala" - } - }, - { - "languageCode": "sk", - "languageName": { - "simpleText": "Slovak" - } - }, - { - "languageCode": "sl", - "languageName": { - "simpleText": "Slovenian" - } - }, - { - "languageCode": "so", - "languageName": { - "simpleText": "Somali" - } - }, - { - "languageCode": "st", - "languageName": { - "simpleText": "Southern Sotho" - } - }, - { - "languageCode": "es", - "languageName": { - "simpleText": "Spanish" - } - }, - { - "languageCode": "su", - "languageName": { - "simpleText": "Sundanese" - } - }, - { - "languageCode": "sw", - "languageName": { - "simpleText": "Swahili" - } - }, - { - "languageCode": "ss", - "languageName": { - "simpleText": "Swati" - } - }, - { - "languageCode": "sv", - "languageName": { - "simpleText": "Swedish" - } - }, - { - "languageCode": "tg", - "languageName": { - "simpleText": "Tajik" - } - }, - { - "languageCode": "ta", - "languageName": { - "simpleText": "Tamil" - } - }, - { - "languageCode": "tt", - "languageName": { - "simpleText": "Tatar" - } - }, - { - "languageCode": "te", - "languageName": { - "simpleText": "Telugu" - } - }, - { - "languageCode": "th", - "languageName": { - "simpleText": "Thai" - } - }, - { - "languageCode": "bo", - "languageName": { - "simpleText": "Tibetan" - } - }, - { - "languageCode": "ti", - "languageName": { - "simpleText": "Tigrinya" - } - }, - { - "languageCode": "to", - "languageName": { - "simpleText": "Tongan" - } - }, - { - "languageCode": "ts", - "languageName": { - "simpleText": "Tsonga" - } - }, - { - "languageCode": "tn", - "languageName": { - "simpleText": "Tswana" - } - }, - { - "languageCode": "tum", - "languageName": { - "simpleText": "Tumbuka" - } - }, - { - "languageCode": "tr", - "languageName": { - "simpleText": "Turkish" - } - }, - { - "languageCode": "tk", - "languageName": { - "simpleText": "Turkmen" - } - }, - { - "languageCode": "uk", - "languageName": { - "simpleText": "Ukrainian" - } - }, - { - "languageCode": "ur", - "languageName": { - "simpleText": "Urdu" - } - }, - { - "languageCode": "ug", - "languageName": { - "simpleText": "Uyghur" - } - }, - { - "languageCode": "uz", - "languageName": { - "simpleText": "Uzbek" - } - }, - { - "languageCode": "ve", - "languageName": { - "simpleText": "Venda" - } - }, - { - "languageCode": "vi", - "languageName": { - "simpleText": "Vietnamese" - } - }, - { - "languageCode": "war", - "languageName": { - "simpleText": "Waray" - } - }, - { - "languageCode": "cy", - "languageName": { - "simpleText": "Welsh" - } - }, - { - "languageCode": "fy", - "languageName": { - "simpleText": "Western Frisian" - } - }, - { - "languageCode": "wo", - "languageName": { - "simpleText": "Wolof" - } - }, - { - "languageCode": "xh", - "languageName": { - "simpleText": "Xhosa" - } - }, - { - "languageCode": "yi", - "languageName": { - "simpleText": "Yiddish" - } - }, - { - "languageCode": "yo", - "languageName": { - "simpleText": "Yoruba" - } - }, - { - "languageCode": "zu", - "languageName": { - "simpleText": "Zulu" - } - } - ], - "defaultAudioTrackIndex": 0 - } - }, - "videoDetails": { - "videoId": "svJDGYlQLYw", - "title": "What If You Could Time Travel Inside a Diabetic Patient’s Body ||Digital Twin|| #digitaltwin", - "lengthSeconds": "245", - "channelId": "UCKubSS_AWg_qDwWNapGnCBw", - "isOwnerViewing": false, - "shortDescription": "𝗪𝗵𝗮𝘁 𝗶𝗳 𝘆𝗼𝘂 𝗰𝗼𝘂𝗹𝗱 𝘁𝗶𝗺𝗲-𝘁𝗿𝗮𝘃𝗲𝗹 𝗶𝗻𝘀𝗶𝗱𝗲 𝗮 𝗱𝗶𝗮𝗯𝗲𝘁𝗶𝗰 𝗽𝗮𝘁𝗶𝗲𝗻𝘁’𝘀 𝗯𝗼𝗱𝘆... 𝗯𝗲𝗳𝗼𝗿𝗲 𝘁𝗵𝗲𝗿𝗮𝗽𝘆 𝗯𝗲𝗴𝗶𝗻𝘀?\nWith our 𝗛𝘂𝗺𝗮𝗻 𝗗𝗶𝗴𝗶𝘁𝗮𝗹 𝗧𝘄𝗶𝗻 𝗳𝗼𝗿 𝗗𝗶𝗮𝗯𝗲𝘁𝗲𝘀 𝗧𝗵𝗲𝗿𝗮𝗽𝘆 (𝗛𝗗𝗧) — now, you can.\n In this video, you’re not just seeing software — you’re witnessing a 𝘀𝗶𝗺𝘂𝗹𝗮𝘁𝗶𝗼𝗻-𝗽𝗼𝘄𝗲𝗿𝗲𝗱 𝘁𝗿𝗮𝗻𝘀𝗳𝗼𝗿𝗺𝗮𝘁𝗶𝗼𝗻 of chronic care.\n\n Powered by AI, systems biology, and pharmacological modeling, HDT creates a 𝘃𝗶𝗿𝘁𝘂𝗮𝗹 𝗽𝗵𝘆𝘀𝗶𝗼𝗹𝗼𝗴𝗶𝗰𝗮𝗹 𝗿𝗲𝗽𝗹𝗶𝗰𝗮 of the human body — designed to simulate how it will react to:\n • Insulin and oral medications\n • Diet and glucose intake\n • Lifestyle changes over time\n\n𝗞𝗲𝘆 𝗧𝗲𝗰𝗵 𝗕𝗲𝗵𝗶𝗻𝗱 𝘁𝗵𝗲 𝗠𝗮𝗴𝗶𝗰\n • AI-driven glucose behavior prediction over weekly and monthly timelines\n • Visual deviation tracking (Red, Yellow, Green bands) for dose-response clarity\n • Time-series simulation of medicine impact and food habits\n • Smart alerts on therapy effectiveness and risk scenarios\n • Integration-ready architecture for EMR, vitals, and real-world datasets\n • Adaptive modeling engine for personalized therapeutic forecasting\n • Unlike traditional tools that show 𝘸𝘩𝘢𝘵 𝘩𝘢𝘴 𝘩𝘢𝘱𝘱𝘦𝘯𝘦𝘥, HDT shows 𝘸𝘩𝘢𝘵 𝘸𝘪𝘭𝘭 𝘩𝘢𝘱𝘱𝘦𝘯 — with scientific precision.\n\nThis is more than digital health — it’s 𝗽𝗿𝗲𝗱𝗶𝗰𝘁𝗶𝘃𝗲 𝗯𝗶𝗼-𝘀𝗶𝗺𝘂𝗹𝗮𝘁𝗶𝗼𝗻 at clinical-grade scale.\n\nFrom pharma R&D to clinical practice, the implementation of HDT bridges a massive gap:\n • Reduces guesswork in dosing\n • Accelerates therapy design\n • Enables proactive care\n • Builds confidence in patient outcomes\n\nNo more trial-and-error. No more post-fact regret. Just 𝗳𝗼𝗿𝘄𝗮𝗿𝗱-𝘁𝗶𝗺𝗲 𝗶𝗻𝘀𝗶𝗴𝗵𝘁 at your fingertips. Because the best therapy decisions aren’t reactive — they’re 𝗽𝗿𝗲-𝗲𝘅𝗽𝗲𝗿𝗶𝗲𝗻𝗰𝗲𝗱.\n\nDive into the video to see how we’re making digital twin the new standard in therapeutic design.Thanks to Prashanth Nagarajan, Kavya J, and our dedicated team, we’re making digital twins the new standard in therapeutic design.\n\nhashtag#DigitalTwin hashtag#DiabetesCare hashtag#PredictiveHealth hashtag#AIinMedicine hashtag#TherapySimulation hashtag#ClinicalAI hashtag#DigitalHealthTech hashtag#ChronicCareInnovation hashtag#HealthcareFuture hashtag#HumanDigitalTwin hashtag#BioSimulation hashtag#GlucoseMonitoring hashtag#TechInHealthcare hashtag#MedicalAI hashtag#PharmaTech", - "isCrawlable": true, - "thumbnail": { - "thumbnails": [ - { - "url": "https://i.ytimg.com/vi/svJDGYlQLYw/hqdefault.jpg?sqp=-oaymwE5CKgBEF5IVfKriqkDLAgBFQAAiEIYAXABwAEG8AEB-AHUBoACwAOKAgwIABABGFogZShlMA-4AvMY&rs=AOn4CLDmbMmNcXZa_vsasTLZdRMmujaVuA", - "width": 168, - "height": 94 - }, - { - "url": "https://i.ytimg.com/vi/svJDGYlQLYw/hqdefault.jpg?sqp=-oaymwE5CMQBEG5IVfKriqkDLAgBFQAAiEIYAXABwAEG8AEB-AHUBoACwAOKAgwIABABGFogZShlMA-4AvMY&rs=AOn4CLCXt2Ddjfs-9BMAMws-lfxa8nLxgQ", - "width": 196, - "height": 110 - }, - { - "url": "https://i.ytimg.com/vi/svJDGYlQLYw/hqdefault.jpg?sqp=-oaymwE6CPYBEIoBSFXyq4qpAywIARUAAIhCGAFwAcABBvABAfgB1AaAAsADigIMCAAQARhaIGUoZTAPuALzGA==&rs=AOn4CLAh47fXlRoX9AAmQTZeKonqjnKz_Q", - "width": 246, - "height": 138 - }, - { - "url": "https://i.ytimg.com/vi/svJDGYlQLYw/hqdefault.jpg?sqp=-oaymwE6CNACELwBSFXyq4qpAywIARUAAIhCGAFwAcABBvABAfgB1AaAAsADigIMCAAQARhaIGUoZTAPuALzGA==&rs=AOn4CLDr1CRue0LV_9jYDgZLzq03_uzKig", - "width": 336, - "height": 188 - } - ] - }, - "allowRatings": true, - "viewCount": "43", - "author": "Tech4Biz", - "isPrivate": false, - "isUnpluggedCorpus": false, - "isLiveContent": false, - "isTvfilmVideo": false - }, - "annotations": [ - { - "playerAnnotationsExpandedRenderer": { - "featuredChannel": { - "startTimeMs": "0", - "endTimeMs": "245000", - "watermark": { - "thumbnails": [ - { - "url": "https://i.ytimg.com/an/KubSS_AWg_qDwWNapGnCBw/featured_channel.jpg?v=65a8c848", - "width": 40, - "height": 40 - } - ] - }, - "trackingParams": "CAcQ8zciEwjn95vFkNmVAxW5h6wCHePTOUM=", - "navigationEndpoint": { - "clickTrackingParams": "CAcQ8zciEwjn95vFkNmVAxW5h6wCHePTOUMyAml2ygEEQUvf1w==", - "commandMetadata": { - "webCommandMetadata": { - "url": "/channel/UCKubSS_AWg_qDwWNapGnCBw", - "webPageType": "WEB_PAGE_TYPE_CHANNEL", - "rootVe": 3611, - "apiUrl": "/youtubei/v1/browse" - } - }, - "browseEndpoint": { - "browseId": "UCKubSS_AWg_qDwWNapGnCBw" - } - }, - "channelName": "Tech4biz", - "subscribeButton": { - "subscribeButtonRenderer": { - "buttonText": { - "runs": [ - { - "text": "SUBSCRIBE" - } - ] - }, - "subscribed": false, - "enabled": true, - "type": "FREE", - "channelId": "UCKubSS_AWg_qDwWNapGnCBw", - "showPreferences": false, - "subscribedButtonText": { - "runs": [ - { - "text": "SUBSCRIBED" - } - ] - }, - "unsubscribedButtonText": { - "runs": [ - { - "text": "SUBSCRIBE" - } - ] - }, - "trackingParams": "CAgQmysiEwjn95vFkNmVAxW5h6wCHePTOUMyAml2", - "unsubscribeButtonText": { - "runs": [ - { - "text": "UNSUBSCRIBE" - } - ] - }, - "serviceEndpoints": [ - { - "clickTrackingParams": "CAgQmysiEwjn95vFkNmVAxW5h6wCHePTOUMyAml2ygEEQUvf1w==", - "commandMetadata": { - "webCommandMetadata": { - "sendPost": true, - "apiUrl": "/youtubei/v1/subscription/subscribe" - } - }, - "subscribeEndpoint": { - "channelIds": [ - "UCKubSS_AWg_qDwWNapGnCBw" - ], - "params": "EgIIBBgAWAE%3D" - } - }, - { - "clickTrackingParams": "CAgQmysiEwjn95vFkNmVAxW5h6wCHePTOUPKAQRBS9_X", - "commandMetadata": { - "webCommandMetadata": { - "sendPost": true - } - }, - "signalServiceEndpoint": { - "signal": "CLIENT_SIGNAL", - "actions": [ - { - "clickTrackingParams": "CAgQmysiEwjn95vFkNmVAxW5h6wCHePTOUPKAQRBS9_X", - "openPopupAction": { - "popup": { - "confirmDialogRenderer": { - "trackingParams": "CAkQxjgiEwjn95vFkNmVAxW5h6wCHePTOUM=", - "dialogMessages": [ - { - "runs": [ - { - "text": "Unsubscribe from " - }, - { - "text": "Tech4biz" - }, - { - "text": "?" - } - ] - } - ], - "confirmButton": { - "buttonRenderer": { - "style": "STYLE_BLUE_TEXT", - "size": "SIZE_DEFAULT", - "isDisabled": false, - "text": { - "runs": [ - { - "text": "Unsubscribe" - } - ] - }, - "serviceEndpoint": { - "clickTrackingParams": "CAsQ8FsiEwjn95vFkNmVAxW5h6wCHePTOUMyAml2ygEEQUvf1w==", - "commandMetadata": { - "webCommandMetadata": { - "sendPost": true, - "apiUrl": "/youtubei/v1/subscription/unsubscribe" - } - }, - "unsubscribeEndpoint": { - "channelIds": [ - "UCKubSS_AWg_qDwWNapGnCBw" - ], - "params": "CgIIBBgAMAE%3D" - } - }, - "accessibility": { - "label": "Unsubscribe" - }, - "trackingParams": "CAsQ8FsiEwjn95vFkNmVAxW5h6wCHePTOUM=" - } - }, - "cancelButton": { - "buttonRenderer": { - "style": "STYLE_TEXT", - "size": "SIZE_DEFAULT", - "isDisabled": false, - "text": { - "runs": [ - { - "text": "Cancel" - } - ] - }, - "accessibility": { - "label": "Cancel" - }, - "trackingParams": "CAoQ8FsiEwjn95vFkNmVAxW5h6wCHePTOUM=" - } - }, - "primaryIsCancel": false - } - }, - "popupType": "DIALOG" - } - } - ] - } - } - ], - "subscribeAccessibility": { - "accessibilityData": { - "label": "Subscribe to Tech4biz." - } - }, - "unsubscribeAccessibility": { - "accessibilityData": { - "label": "Unsubscribe from Tech4biz." - } - }, - "signInEndpoint": { - "clickTrackingParams": "CAgQmysiEwjn95vFkNmVAxW5h6wCHePTOUPKAQRBS9_X", - "commandMetadata": { - "webCommandMetadata": { - "url": "https://accounts.google.com/ServiceLogin?service=youtube&uilel=3&passive=true&continue=http%3A%2F%2Fwww.youtube.com%2Fsignin%3Faction_handle_signin%3Dtrue%26app%3Ddesktop%26hl%3Den%26next%3Dhttps%253A%252F%252Fwww.youtube.com%252Fchannel%252FUCKubSS_AWg_qDwWNapGnCBw%26feature%3Div%26continue_action%3DQUFFLUhqblRvcGRzOVh0OHp2WXFzN3dMc1d5c0Y5UDl6d3xBQ3Jtc0trTE93SzRkZEVjZGQ0YXNpTVRnelhOdWNWZXRIQkJSX2ZTQ3FxbzVTeXBPd1IyamhwZWd6ZEZvN2VxOE5YM1d2YTZ2S0VYaTJsZk5COXV2eDh6cUdVaWhrN1JSN0p1N3gwYjRQQ3pfQnNTMlVyZVF0SGlvX1JUSlR2MG9MdHdXNWt2YVBBRm16b0FCSFF5ZExqbTRwaE9LQUVNdjBERGhsdF9SZFdfLWpuVkZIS3ZRUi03TktyMlBmYkZNa1RlYzBCbS1uZHk%253D&hl=en" - } - } - } - } - } - }, - "allowSwipeDismiss": true, - "annotationId": "65aeada8-0000-2548-a231-582429cab00c" - } - } - ], - "playerConfig": { - "granularVariableSpeedConfig": { - "minimumPlaybackRate": 25, - "maximumPlaybackRate": 200, - "stepSize": 5, - "defaultPlaybackRateOptions": [ - { - "label": "1.0", - "value": 100, - "isPremiumUpsell": false, - "priority": 5 - }, - { - "label": "1.25", - "value": 125, - "isPremiumUpsell": false, - "priority": 2 - }, - { - "label": "1.5", - "value": 150, - "isPremiumUpsell": false, - "priority": 3 - }, - { - "label": "1.75", - "value": 175, - "isPremiumUpsell": false, - "priority": 0 - }, - { - "label": "2.0", - "value": 200, - "isPremiumUpsell": false, - "priority": 4 - }, - { - "label": "3.0", - "value": 300, - "isPremiumUpsell": true, - "priority": 1 - } - ] - }, - "vssClientConfig": { - "vssUsePostRequest": true - }, - "audioConfig": { - "loudnessDb": -8.3500004, - "perceptualLoudnessDb": -22.35, - "enablePerFormatLoudness": true, - "trackAbsoluteLoudnessLkfs": -22.35, - "loudnessTargetLkfs": -14, - "loudnessNormalizationConfig": { - "applyStatefulNormalization": false, - "preserveStatefulLoudnessTarget": true, - "maxStatefulTimeThresholdSec": 300, - "minimumLoudnessTargetLkfs": -31 - } - }, - "streamSelectionConfig": { - "maxBitrate": "20880000" - }, - "playerControlsConfig": { - "showCachedInTimebar": true - }, - "daiConfig": { - "sendSsdaiMissingAdBreakReasons": true - }, - "mediaCommonConfig": { - "dynamicReadaheadConfig": { - "maxReadAheadMediaTimeMs": 120000, - "minReadAheadMediaTimeMs": 15000, - "readAheadGrowthRateMs": 1000 - }, - "mediaUstreamerRequestConfig": { - "videoPlaybackUstreamerConfig": "CtQGCq8FCAAlAACAPy0zM3M_NT0Klz9yBAoAGACgAQGoAQC4AgDaAoABELDqARiA3dsBIKCcASignAFwiCeAAfQD4AEDmAIM0AIC6AIEgAMCiAOIJ6gDA8ADAcgDAYAEAdAEAdgEAfgEB4AFfcAFAcgFAeAF0A_oBQH4BdAPkAYB0AYB8AYBgAfQD4AIAYgIAZ0IzcxMPqAI6AfgCAHoCP___________wH6AkWoAdCGA4UCmpkZP40CAACAP8AC3wP9As3MzD2QAwGdAwrXIz3VBAAAIEG1Br03hjW9BjMzg0DIBwHlBwCACUTwBwGACAGoAwGwAwPQAwHYAwHKBBwKEwjAqQcQmHUY6AclAAAAACgAMAAQ4NQDGNAP0gQPCggIsAkQsAkgASCIJygB2gQNCgYI8C4Q8C4g8C4oAZgGAagGgIAC0gYUCOgHEGQaDQiIJxUAAAA_Hc3MTD_YBgG4BwGgCAHSCAYIARABGAGpCQAAAAAAAPC_sQkAAAAAAADwv9AJAdoJJE83RVZpMCs5QkJZSnJTWk1ENXZKZDVLeCtwTjFaNHFOakFHbJgK5ZveGKIKFOKb3hjjm94Y5JveGOWb3hjmm94YqArim94Y6gsEiwaMBoAMAagMkAHgDQHIDwHQDwHoEAGQEQGgEQGyETBDQU1TSUJVWnViYkpESlFDbkE3NUZYYWdCdUFXcU5VUDNBTzZBdE1FQnZnRDBnRUXQEgHgEgGAEwGwEwHYEwDoEwGIFACRFAAAAAAAAPC_mRQAAAAAAADwv8oUEXYyMDI1MDkyMl8xMjI2LjAw2BSIJ-IUNAoAEjBDQU1TSUJVWnViYkpESlFDbkE3NUZYYWdCdUFXcU5VUDNBTzZBdE1FQnZnRDBnRUWBFQAAAAAAAPC_qBUBuBUBwBUBiKehygsBMgwIhwEQy9LbjKjajQMyDAiGARCnwoaNqNqNAzIMCPMBEOrIl5Go2o0DMgwIoAEQjO_sjKjajQMyDAiMARC50LCKqNqNAzIMCPsBEIy-85Go2o0DOgBSLRoFZW4tVVMoADIYVUNLdWJTU19BV2dfcUR3V05hcEduQ0J3OABAAFgAYAB4AKABAbABBboBAwQFMcIBCAECAwQFCCow0AEAgAIAEksAA40obDBEAiA58rbNG0OeOZjHjb7ZfdoI5nE_QCuUyUXP7wPg3GDwwQIgKiwzPV2CmaOCIYO1ACUAxXLD2wu1ja3ySeXaV1fdEhkaAmVp" - }, - "useServerDrivenAbr": true, - "serverPlaybackStartConfig": { - "enable": true, - "playbackStartPolicy": { - "startMinReadaheadPolicy": [ - { - "minReadaheadMs": 1200 - } - ] - } - }, - "platypusUseEnvoyNetFetch": false, - "fixLivePlaybackModelDefaultPosition": false - }, - "webPlayerConfig": { - "useCobaltTvosDash": true, - "webPlayerActionsPorting": { - "getSharePanelCommand": { - "clickTrackingParams": "CAAQu2kiEwjn95vFkNmVAxW5h6wCHePTOUPKAQRBS9_X", - "commandMetadata": { - "webCommandMetadata": { - "sendPost": true, - "apiUrl": "/youtubei/v1/share/get_web_player_share_panel" - } - }, - "webPlayerShareEntityServiceEndpoint": { - "serializedShareEntity": "CgtzdkpER1lsUUxZdw%3D%3D" - } - }, - "subscribeCommand": { - "clickTrackingParams": "CAAQu2kiEwjn95vFkNmVAxW5h6wCHePTOUPKAQRBS9_X", - "commandMetadata": { - "webCommandMetadata": { - "sendPost": true, - "apiUrl": "/youtubei/v1/subscription/subscribe" - } - }, - "subscribeEndpoint": { - "channelIds": [ - "UCKubSS_AWg_qDwWNapGnCBw" - ], - "params": "EgIIBxgA" - } - }, - "unsubscribeCommand": { - "clickTrackingParams": "CAAQu2kiEwjn95vFkNmVAxW5h6wCHePTOUPKAQRBS9_X", - "commandMetadata": { - "webCommandMetadata": { - "sendPost": true, - "apiUrl": "/youtubei/v1/subscription/unsubscribe" - } - }, - "unsubscribeEndpoint": { - "channelIds": [ - "UCKubSS_AWg_qDwWNapGnCBw" - ], - "params": "CgIIBxgA" - } - }, - "addToWatchLaterCommand": { - "clickTrackingParams": "CAAQu2kiEwjn95vFkNmVAxW5h6wCHePTOUPKAQRBS9_X", - "commandMetadata": { - "webCommandMetadata": { - "sendPost": true, - "apiUrl": "/youtubei/v1/browse/edit_playlist" - } - }, - "playlistEditEndpoint": { - "playlistId": "WL", - "actions": [ - { - "addedVideoId": "svJDGYlQLYw", - "action": "ACTION_ADD_VIDEO" - } - ] - } - }, - "removeFromWatchLaterCommand": { - "clickTrackingParams": "CAAQu2kiEwjn95vFkNmVAxW5h6wCHePTOUPKAQRBS9_X", - "commandMetadata": { - "webCommandMetadata": { - "sendPost": true, - "apiUrl": "/youtubei/v1/browse/edit_playlist" - } - }, - "playlistEditEndpoint": { - "playlistId": "WL", - "actions": [ - { - "action": "ACTION_REMOVE_VIDEO_BY_VIDEO_ID", - "removedVideoId": "svJDGYlQLYw" - } - ] - } - } - } - } - }, - "storyboards": { - "playerStoryboardSpecRenderer": { - "spec": "https://i.ytimg.com/sb/svJDGYlQLYw/storyboard3_L$L/$N.jpg?sqp=-oaymwENSDfyq4qpAwVwAcABBqLzl_8DBgj9o4bCBg==|48#27#100#10#10#0#default#rs$AOn4CLDxmUWejV26QHauH0N5YYGNY4yUkQ|85#45#124#10#10#2000#M$M#rs$AOn4CLBR-FCSgbUdx7gD97aWztb2hzmPiw|171#90#124#5#5#2000#M$M#rs$AOn4CLAM2VSSny3KPr6NmpUkpSlIxhWzCA|343#180#124#3#3#2000#M$M#rs$AOn4CLATHfUzsekrEYe7cVdBMKRW4e0wWA", - "recommendedLevel": 3, - "fineScrubbingRecommendedLevel": 2, - "highResolutionRecommendedLevel": 3 - } - }, - "microformat": { - "playerMicroformatRenderer": { - "thumbnail": { - "thumbnails": [ - { - "url": "https://i.ytimg.com/vi/svJDGYlQLYw/hqdefault.jpg?sqp=-oaymwEmCOADEOgC8quKqQMa8AEB-AHUBoACwAOKAgwIABABGFogZShlMA8=&rs=AOn4CLAjUdpa_A1yp61xA2iqpDpC7VcIHA", - "width": 480, - "height": 360 - } - ] - }, - "embed": { - "iframeUrl": "https://www.youtube.com/embed/svJDGYlQLYw", - "width": 640, - "height": 360 - }, - "title": { - "simpleText": "What If You Could Time Travel Inside a Diabetic Patient’s Body ||Digital Twin|| #digitaltwin" - }, - "description": { - "simpleText": "𝗪𝗵𝗮𝘁 𝗶𝗳 𝘆𝗼𝘂 𝗰𝗼𝘂𝗹𝗱 𝘁𝗶𝗺𝗲-𝘁𝗿𝗮𝘃𝗲𝗹 𝗶𝗻𝘀𝗶𝗱𝗲 𝗮 𝗱𝗶𝗮𝗯𝗲𝘁𝗶𝗰 𝗽𝗮𝘁𝗶𝗲𝗻𝘁’𝘀 𝗯𝗼𝗱𝘆... 𝗯𝗲𝗳𝗼𝗿𝗲 𝘁𝗵𝗲𝗿𝗮𝗽𝘆 𝗯𝗲𝗴𝗶𝗻𝘀?\nWith our 𝗛𝘂𝗺𝗮𝗻 𝗗𝗶𝗴𝗶𝘁𝗮𝗹 𝗧𝘄𝗶𝗻 𝗳𝗼𝗿 𝗗𝗶𝗮𝗯𝗲𝘁𝗲𝘀 𝗧𝗵𝗲𝗿𝗮𝗽𝘆 (𝗛𝗗𝗧) — now, you can.\n In this video, you’re not just seeing software — you’re witnessing a 𝘀𝗶𝗺𝘂𝗹𝗮𝘁𝗶𝗼𝗻-𝗽𝗼𝘄𝗲𝗿𝗲𝗱 𝘁𝗿𝗮𝗻𝘀𝗳𝗼𝗿𝗺𝗮𝘁𝗶𝗼𝗻 of chronic care.\n\n Powered by AI, systems biology, and pharmacological modeling, HDT creates a 𝘃𝗶𝗿𝘁𝘂𝗮𝗹 𝗽𝗵𝘆𝘀𝗶𝗼𝗹𝗼𝗴𝗶𝗰𝗮𝗹 𝗿𝗲𝗽𝗹𝗶𝗰𝗮 of the human body — designed to simulate how it will react to:\n • Insulin and oral medications\n • Diet and glucose intake\n • Lifestyle changes over time\n\n𝗞𝗲𝘆 𝗧𝗲𝗰𝗵 𝗕𝗲𝗵𝗶𝗻𝗱 𝘁𝗵𝗲 𝗠𝗮𝗴𝗶𝗰\n • AI-driven glucose behavior prediction over weekly and monthly timelines\n • Visual deviation tracking (Red, Yellow, Green bands) for dose-response clarity\n • Time-series simulation of medicine impact and food habits\n • Smart alerts on therapy effectiveness and risk scenarios\n • Integration-ready architecture for EMR, vitals, and real-world datasets\n • Adaptive modeling engine for personalized therapeutic forecasting\n • Unlike traditional tools that show 𝘸𝘩𝘢𝘵 𝘩𝘢𝘴 𝘩𝘢𝘱𝘱𝘦𝘯𝘦𝘥, HDT shows 𝘸𝘩𝘢𝘵 𝘸𝘪𝘭𝘭 𝘩𝘢𝘱𝘱𝘦𝘯 — with scientific precision.\n\nThis is more than digital health — it’s 𝗽𝗿𝗲𝗱𝗶𝗰𝘁𝗶𝘃𝗲 𝗯𝗶𝗼-𝘀𝗶𝗺𝘂𝗹𝗮𝘁𝗶𝗼𝗻 at clinical-grade scale.\n\nFrom pharma R&D to clinical practice, the implementation of HDT bridges a massive gap:\n • Reduces guesswork in dosing\n • Accelerates therapy design\n • Enables proactive care\n • Builds confidence in patient outcomes\n\nNo more trial-and-error. No more post-fact regret. Just 𝗳𝗼𝗿𝘄𝗮𝗿𝗱-𝘁𝗶𝗺𝗲 𝗶𝗻𝘀𝗶𝗴𝗵𝘁 at your fingertips. Because the best therapy decisions aren’t reactive — they’re 𝗽𝗿𝗲-𝗲𝘅𝗽𝗲𝗿𝗶𝗲𝗻𝗰𝗲𝗱.\n\nDive into the video to see how we’re making digital twin the new standard in therapeutic design.Thanks to Prashanth Nagarajan, Kavya J, and our dedicated team, we’re making digital twins the new standard in therapeutic design.\n\nhashtag#DigitalTwin hashtag#DiabetesCare hashtag#PredictiveHealth hashtag#AIinMedicine hashtag#TherapySimulation hashtag#ClinicalAI hashtag#DigitalHealthTech hashtag#ChronicCareInnovation hashtag#HealthcareFuture hashtag#HumanDigitalTwin hashtag#BioSimulation hashtag#GlucoseMonitoring hashtag#TechInHealthcare hashtag#MedicalAI hashtag#PharmaTech" - }, - "lengthSeconds": "245", - "ownerProfileUrl": "http://www.youtube.com/@Tech4bizz", - "externalChannelId": "UCKubSS_AWg_qDwWNapGnCBw", - "isFamilySafe": true, - "availableCountries": [ - "AD", - "AE", - "AF", - "AG", - "AI", - "AL", - "AM", - "AO", - "AQ", - "AR", - "AS", - "AT", - "AU", - "AW", - "AX", - "AZ", - "BA", - "BB", - "BD", - "BE", - "BF", - "BG", - "BH", - "BI", - "BJ", - "BL", - "BM", - "BN", - "BO", - "BQ", - "BR", - "BS", - "BT", - "BV", - "BW", - "BY", - "BZ", - "CA", - "CC", - "CD", - "CF", - "CG", - "CH", - "CI", - "CK", - "CL", - "CM", - "CN", - "CO", - "CR", - "CU", - "CV", - "CW", - "CX", - "CY", - "CZ", - "DE", - "DJ", - "DK", - "DM", - "DO", - "DZ", - "EC", - "EE", - "EG", - "EH", - "ER", - "ES", - "ET", - "FI", - "FJ", - "FK", - "FM", - "FO", - "FR", - "GA", - "GB", - "GD", - "GE", - "GF", - "GG", - "GH", - "GI", - "GL", - "GM", - "GN", - "GP", - "GQ", - "GR", - "GS", - "GT", - "GU", - "GW", - "GY", - "HK", - "HM", - "HN", - "HR", - "HT", - "HU", - "ID", - "IE", - "IL", - "IM", - "IN", - "IO", - "IQ", - "IR", - "IS", - "IT", - "JE", - "JM", - "JO", - "JP", - "KE", - "KG", - "KH", - "KI", - "KM", - "KN", - "KP", - "KR", - "KW", - "KY", - "KZ", - "LA", - "LB", - "LC", - "LI", - "LK", - "LR", - "LS", - "LT", - "LU", - "LV", - "LY", - "MA", - "MC", - "MD", - "ME", - "MF", - "MG", - "MH", - "MK", - "ML", - "MM", - "MN", - "MO", - "MP", - "MQ", - "MR", - "MS", - "MT", - "MU", - "MV", - "MW", - "MX", - "MY", - "MZ", - "NA", - "NC", - "NE", - "NF", - "NG", - "NI", - "NL", - "NO", - "NP", - "NR", - "NU", - "NZ", - "OM", - "PA", - "PE", - "PF", - "PG", - "PH", - "PK", - "PL", - "PM", - "PN", - "PR", - "PS", - "PT", - "PW", - "PY", - "QA", - "RE", - "RO", - "RS", - "RU", - "RW", - "SA", - "SB", - "SC", - "SD", - "SE", - "SG", - "SH", - "SI", - "SJ", - "SK", - "SL", - "SM", - "SN", - "SO", - "SR", - "SS", - "ST", - "SV", - "SX", - "SY", - "SZ", - "TC", - "TD", - "TF", - "TG", - "TH", - "TJ", - "TK", - "TL", - "TM", - "TN", - "TO", - "TR", - "TT", - "TV", - "TW", - "TZ", - "UA", - "UG", - "UM", - "US", - "UY", - "UZ", - "VA", - "VC", - "VE", - "VG", - "VI", - "VN", - "VU", - "WF", - "WS", - "YE", - "YT", - "ZA", - "ZM", - "ZW" - ], - "isUnlisted": false, - "hasYpcMetadata": false, - "viewCount": "43", - "category": "Science & Technology", - "publishDate": "2025-06-05T05:46:49-07:00", - "ownerChannelName": "Tech4Biz", - "uploadDate": "2025-06-05T05:46:49-07:00", - "isShortsEligible": false, - "externalVideoId": "svJDGYlQLYw", - "likeCount": "4", - "canonicalUrl": "https://www.youtube.com/watch?v=svJDGYlQLYw" - } - }, - "cards": { - "cardCollectionRenderer": { - "cards": [ - { - "cardRenderer": { - "teaser": { - "simpleCardTeaserRenderer": { - "message": { - "simpleText": "View corrections" - }, - "trackingParams": "CAYQ0DYiEwjn95vFkNmVAxW5h6wCHePTOUM=", - "prominent": true, - "logVisibilityUpdates": true, - "onTapCommand": { - "clickTrackingParams": "CAYQ0DYiEwjn95vFkNmVAxW5h6wCHePTOUPKAQRBS9_X", - "changeEngagementPanelVisibilityAction": { - "targetId": "engagement-panel-error-corrections", - "visibility": "ENGAGEMENT_PANEL_VISIBILITY_EXPANDED" - } - } - } - }, - "cueRanges": [ - { - "startCardActiveMs": "0", - "endCardActiveMs": "5000", - "teaserDurationMs": "6000", - "iconAfterTeaserMs": "5000" - } - ], - "trackingParams": "CAUQtZcBGAAiEwjn95vFkNmVAxW5h6wCHePTOUM=" - } - } - ], - "headerText": { - "simpleText": "From Tech4biz" - }, - "icon": { - "infoCardIconRenderer": { - "trackingParams": "CAQQsJcBIhMI5_ebxZDZlQMVuYesAh3j0zlD" - } - }, - "closeButton": { - "infoCardIconRenderer": { - "trackingParams": "CAMQsZcBIhMI5_ebxZDZlQMVuYesAh3j0zlD" - } - }, - "trackingParams": "CAIQwjciEwjn95vFkNmVAxW5h6wCHePTOUM=", - "allowTeaserDismiss": true, - "logIconVisibilityUpdates": true - } - }, - "trackingParams": "CAAQu2kiEwjn95vFkNmVAxW5h6wCHePTOUPKAQRBS9_X", - "adBreakHeartbeatParams": "Q0FBJTNE", - "frameworkUpdates": { - "entityBatchUpdate": { - "mutations": [ - { - "entityKey": "Eg0KC3N2SkRHWWxRTFl3IPYBKAE%3D", - "type": "ENTITY_MUTATION_TYPE_REPLACE", - "payload": { - "offlineabilityEntity": { - "key": "Eg0KC3N2SkRHWWxRTFl3IPYBKAE%3D", - "offlineabilityRenderer": "CAEaGwoTChEKD0Z1bGwgSEQgKDEwODBwKRgHIAIoABoXCg8KDQoLSGlnaCAoNzIwcCkYAiACKAAaGQoRCg8KDU1lZGl1bSAoMzYwcCkYASABKAEaFgoOCgwKCkxvdyAoMTQ0cCkYBCABKAEiDTILb2ZmbGluZWxpc3Q=", - "addToOfflineButtonState": "ADD_TO_OFFLINE_BUTTON_STATE_ENABLED", - "contentCheckOk": false, - "racyCheckOk": false, - "loggingDirectives": { - "trackingParams": "CAEQxzciEwjn95vFkNmVAxW5h6wCHePTOUM=", - "visibility": { - "types": "4" - } - } - } - } - } - ], - "timestamp": { - "seconds": "1784271293", - "nanos": 910117572 - } - } - } -} \ No newline at end of file diff --git a/youtube.html b/youtube.html deleted file mode 100644 index 969e464..0000000 --- a/youtube.html +++ /dev/null @@ -1,83 +0,0 @@ - - YouTube
AboutPressCopyrightContact usCreatorsAdvertiseDevelopersTermsPrivacyPolicy & SafetyHow YouTube worksTest new features
\ No newline at end of file diff --git a/youtube_correct.html b/youtube_correct.html deleted file mode 100644 index 2f51384..0000000 --- a/youtube_correct.html +++ /dev/null @@ -1,83 +0,0 @@ -What If You Could Time Travel Inside a Diabetic Patient’s Body ||Digital Twin|| #digitaltwin - YouTube
AboutPressCopyrightContact usCreatorsAdvertiseDevelopersTermsPrivacyPolicy & SafetyHow YouTube worksTest new features
\ No newline at end of file diff --git a/youtube_l.html b/youtube_l.html deleted file mode 100644 index 9a4a13c..0000000 --- a/youtube_l.html +++ /dev/null @@ -1,83 +0,0 @@ - - YouTube
AboutPressCopyrightContact usCreatorsAdvertiseDevelopersTermsPrivacyPolicy & SafetyHow YouTube worksTest new features
\ No newline at end of file diff --git a/ytInitialData.json b/ytInitialData.json deleted file mode 100644 index 0f1ffdf..0000000 --- a/ytInitialData.json +++ /dev/null @@ -1,1132 +0,0 @@ -{ - "responseContext": { - "serviceTrackingParams": [ - { - "service": "CSI", - "params": [ - { - "key": "c", - "value": "WEB" - }, - { - "key": "cver", - "value": "2.20260714.05.00" - }, - { - "key": "yt_li", - "value": "0" - }, - { - "key": "GetWatchPage_rid", - "value": "0x1a6ed3c8d068e68a" - } - ] - }, - { - "service": "GFEEDBACK", - "params": [ - { - "key": "logged_in", - "value": "0" - }, - { - "key": "visitor_data", - "value": "Cgt4OFFPMWtsREhjcyj6oOfSBjIKCgJJThIEGgAgXGLfAgrcAjIwLllUPVhTcmlVODQwM3h3OHIyRU5DYXlfbE5xXzJsQzFOY1VYdDIzUlp2b21mNnljdUZ2ZmE2cTk4aGYwOW9WY3lKamhVelNGcHV2LUNScnNRMEVscUU3enFDWUhzOTR6aU43TlZVWWlYSTRiVndxQmNkR0ZtRzF0VXFLU0RnbzhtLWs4MzcwUkFNOVc0YVJvLWVDdGx0VnhDMjJtbDJwakJ4dTBpbS1EOW1JMW9hbG0xN2RfYTBlUDFvcl9KekZxd1JkOTFTbmY1dXU3STliMWdTTmlLWDFwS3VPcHJzeF9LVkVfNFA4YmNfaFlqcUxLbWdPV1pfcGg3Mm0wSEVNOWVzbHZuTUhPNzJRMHZhMW82bXpndEprcUhhN1A3Q3o4dGxlNGtCN01kMl95T0VhOTZjekZ4dzYzQzZfRkFBM0hwUF9FUFV0cEJYUUZXWE1EZmhWNm12MEU3Zw%3D%3D" - } - ] - }, - { - "service": "GUIDED_HELP", - "params": [ - { - "key": "logged_in", - "value": "0" - } - ] - }, - { - "service": "ECATCHER", - "params": [ - { - "key": "client.version", - "value": "2.20260714" - }, - { - "key": "client.name", - "value": "WEB" - } - ] - } - ], - "mainAppWebResponseContext": { - "loggedOut": true, - "trackingParam": "k5_fmPxhoXZRWydYMDbgOYh8fEO8hDS40d7zMwY82yoHZNFTSiWws8PLkHRMkusYh7BwOcCw59TLtslLKPQGSS" - }, - "responseId": "IhMI7_H-qo_ZlQMVDaDYBR1X1QIc", - "webResponseContextExtensionData": { - "webResponseContextPreloadData": { - "preloadMessageNames": [ - "twoColumnWatchNextResults", - "results", - "itemSectionRenderer", - "backgroundPromoRenderer", - "buttonRenderer", - "engagementPanelSectionListRenderer", - "adsEngagementPanelContentRenderer", - "desktopTopbarRenderer", - "topbarLogoRenderer", - "fusionSearchboxRenderer", - "dialogViewModel", - "dialogHeaderViewModel", - "panelFooterViewModel", - "buttonViewModel", - "basicContentViewModel", - "topbarMenuButtonRenderer", - "multiPageMenuRenderer", - "hotkeyDialogRenderer", - "hotkeyDialogSectionRenderer", - "hotkeyDialogSectionOptionRenderer", - "voiceSearchDialogRenderer" - ] - }, - "ytConfigData": { - "visitorData": "Cgt4OFFPMWtsREhjcyj6oOfSBjIKCgJJThIEGgAgXGLfAgrcAjIwLllUPVhTcmlVODQwM3h3OHIyRU5DYXlfbE5xXzJsQzFOY1VYdDIzUlp2b21mNnljdUZ2ZmE2cTk4aGYwOW9WY3lKamhVelNGcHV2LUNScnNRMEVscUU3enFDWUhzOTR6aU43TlZVWWlYSTRiVndxQmNkR0ZtRzF0VXFLU0RnbzhtLWs4MzcwUkFNOVc0YVJvLWVDdGx0VnhDMjJtbDJwakJ4dTBpbS1EOW1JMW9hbG0xN2RfYTBlUDFvcl9KekZxd1JkOTFTbmY1dXU3STliMWdTTmlLWDFwS3VPcHJzeF9LVkVfNFA4YmNfaFlqcUxLbWdPV1pfcGg3Mm0wSEVNOWVzbHZuTUhPNzJRMHZhMW82bXpndEprcUhhN1A3Q3o4dGxlNGtCN01kMl95T0VhOTZjekZ4dzYzQzZfRkFBM0hwUF9FUFV0cEJYUUZXWE1EZmhWNm12MEU3Zw%3D%3D", - "rootVisualElementType": 3832 - }, - "hasDecorated": true - } - }, - "contents": { - "twoColumnWatchNextResults": { - "results": { - "results": { - "contents": [ - { - "itemSectionRenderer": { - "contents": [ - { - "backgroundPromoRenderer": { - "title": { - "runs": [ - { - "text": "This video isn't available anymore" - } - ] - }, - "trackingParams": "CBUQ92QYACITCO_x_qqP2ZUDFQ2g2AUdV9UCHA==", - "thumbnail": { - "thumbnails": [ - { - "url": "https://www.youtube.com/img/desktop/unavailable/unavailable_video.png", - "width": 278, - "height": 161 - } - ] - }, - "ctaButton": { - "buttonRenderer": { - "style": "STYLE_SUGGESTIVE", - "size": "SIZE_SMALL", - "text": { - "simpleText": "GO TO HOME" - }, - "navigationEndpoint": { - "clickTrackingParams": "CBYQup8IIhMI7_H-qo_ZlQMVDaDYBR1X1QIcygEEnxYDcw==", - "commandMetadata": { - "webCommandMetadata": { - "url": "/", - "webPageType": "WEB_PAGE_TYPE_BROWSE", - "rootVe": 3854, - "apiUrl": "/youtubei/v1/browse" - } - }, - "browseEndpoint": { - "browseId": "FEwhat_to_watch" - } - }, - "trackingParams": "CBYQup8IIhMI7_H-qo_ZlQMVDaDYBR1X1QIc" - } - }, - "style": { - "value": "BACKGROUND_PROMO_STYLE_TYPE_FULL_HEIGHT" - } - } - } - ], - "trackingParams": "CBQQuy8YACITCO_x_qqP2ZUDFQ2g2AUdV9UCHA==" - } - } - ], - "trackingParams": "CBMQui8iEwjv8f6qj9mVAxUNoNgFHVfVAhw=" - } - } - } - }, - "currentVideoEndpoint": { - "clickTrackingParams": "CAAQg2ciEwjv8f6qj9mVAxUNoNgFHVfVAhzKAQSfFgNz", - "commandMetadata": { - "webCommandMetadata": { - "url": "/watch?v=svJDGYiQlYw", - "webPageType": "WEB_PAGE_TYPE_WATCH", - "rootVe": 3832 - } - }, - "watchEndpoint": { - "videoId": "svJDGYiQlYw", - "watchEndpointSupportedOnesieConfig": { - "html5PlaybackOnesieConfig": { - "commonConfig": { - "url": "https://rr4---sn-ci5gup-cag6.googlevideo.com/initplayback?source=youtube&oeis=1&c=WEB&oad=3200&ovd=3200&oaad=11000&oavd=11000&ocs=700&oewis=1&oputc=1&ofpcc=1&msp=1&odepv=1&id=b2f243198890958c&ip=122.166.145.27&initcwndbps=2402500&mt=1784270691&oweuc=&pxtags=Cg4KAnR4Egg1MTkyOTU2OA&rxtags=Cg4KAnR4Egg1MTkyOTU2Ng%2CCg4KAnR4Egg1MTkyOTU2Nw%2CCg4KAnR4Egg1MTkyOTU2OA" - } - } - } - } - }, - "trackingParams": "CAAQg2ciEwjv8f6qj9mVAxUNoNgFHVfVAhzKAQSfFgNz", - "onResponseReceivedEndpoints": [ - { - "clickTrackingParams": "CAAQg2ciEwjv8f6qj9mVAxUNoNgFHVfVAhzKAQSfFgNz", - "commandMetadata": { - "webCommandMetadata": { - "sendPost": true - } - }, - "signalServiceEndpoint": { - "signal": "CLIENT_SIGNAL", - "actions": [ - { - "clickTrackingParams": "CAAQg2ciEwjv8f6qj9mVAxUNoNgFHVfVAhzKAQSfFgNz", - "signalAction": { - "signal": "ENABLE_CHROME_NOTIFICATIONS" - } - } - ] - } - } - ], - "engagementPanels": [ - { - "engagementPanelSectionListRenderer": { - "content": { - "adsEngagementPanelContentRenderer": { - "hack": true - } - }, - "targetId": "engagement-panel-ads", - "visibility": "ENGAGEMENT_PANEL_VISIBILITY_HIDDEN", - "loggingDirectives": { - "trackingParams": "CBIQ040EGAEiEwjv8f6qj9mVAxUNoNgFHVfVAhw=", - "visibility": { - "types": "12" - } - } - } - } - ], - "topbar": { - "desktopTopbarRenderer": { - "logo": { - "topbarLogoRenderer": { - "iconImage": { - "iconType": "YOUTUBE_LOGO" - }, - "tooltipText": { - "runs": [ - { - "text": "YouTube Home" - } - ] - }, - "endpoint": { - "clickTrackingParams": "CBEQsV4iEwjv8f6qj9mVAxUNoNgFHVfVAhzKAQSfFgNz", - "commandMetadata": { - "webCommandMetadata": { - "url": "/", - "webPageType": "WEB_PAGE_TYPE_BROWSE", - "rootVe": 3854, - "apiUrl": "/youtubei/v1/browse" - } - }, - "browseEndpoint": { - "browseId": "FEwhat_to_watch" - } - }, - "trackingParams": "CBEQsV4iEwjv8f6qj9mVAxUNoNgFHVfVAhw=", - "overrideEntityKey": "EgZ0b3BiYXIg9QEoAQ%3D%3D" - } - }, - "searchbox": { - "fusionSearchboxRenderer": { - "icon": { - "iconType": "SEARCH" - }, - "placeholderText": { - "runs": [ - { - "text": "Search" - } - ] - }, - "config": { - "webSearchboxConfig": { - "requestLanguage": "en", - "requestDomain": "in", - "hasOnscreenKeyboard": false, - "focusSearchbox": true - } - }, - "trackingParams": "CA0Q7VAiEwjv8f6qj9mVAxUNoNgFHVfVAhw=", - "searchEndpoint": { - "clickTrackingParams": "CA0Q7VAiEwjv8f6qj9mVAxUNoNgFHVfVAhzKAQSfFgNz", - "commandMetadata": { - "webCommandMetadata": { - "url": "/results?search_query=", - "webPageType": "WEB_PAGE_TYPE_SEARCH", - "rootVe": 4724 - } - }, - "searchEndpoint": { - "query": "" - } - }, - "clearButton": { - "buttonRenderer": { - "style": "STYLE_DEFAULT", - "size": "SIZE_DEFAULT", - "isDisabled": false, - "icon": { - "iconType": "CLOSE" - }, - "trackingParams": "CBAQ8FsiEwjv8f6qj9mVAxUNoNgFHVfVAhw=", - "accessibilityData": { - "accessibilityData": { - "label": "Clear search query" - } - } - } - }, - "showImageSourceDialog": { - "clickTrackingParams": "CA0Q7VAiEwjv8f6qj9mVAxUNoNgFHVfVAhzKAQSfFgNz", - "showDialogCommand": { - "panelLoadingStrategy": { - "inlineContent": { - "dialogViewModel": { - "header": { - "dialogHeaderViewModel": { - "headline": { - "content": "Image source" - } - } - }, - "footer": { - "panelFooterViewModel": { - "primaryButton": { - "buttonViewModel": { - "title": "Visit source", - "style": "BUTTON_VIEW_MODEL_STYLE_MONO", - "trackingParams": "CA8Q8FsiEwjv8f6qj9mVAxUNoNgFHVfVAhw=", - "isFullWidth": true, - "type": "BUTTON_VIEW_MODEL_TYPE_FILLED" - } - }, - "secondaryButton": { - "buttonViewModel": { - "title": "Cancel", - "style": "BUTTON_VIEW_MODEL_STYLE_MONO", - "trackingParams": "CA4Q8FsiEwjv8f6qj9mVAxUNoNgFHVfVAhw=", - "isFullWidth": true, - "type": "BUTTON_VIEW_MODEL_TYPE_TONAL" - } - }, - "shouldHideDivider": true - } - }, - "content": { - "basicContentViewModel": { - "paragraphs": [ - { - "text": { - "content": "Visit image source website?" - } - } - ] - } - } - } - } - } - } - }, - "disableAiAppearance": true - } - }, - "trackingParams": "CAEQq6wBIhMI7_H-qo_ZlQMVDaDYBR1X1QIc", - "countryCode": "IN", - "topbarButtons": [ - { - "topbarMenuButtonRenderer": { - "icon": { - "iconType": "MORE_VERT" - }, - "menuRequest": { - "clickTrackingParams": "CAsQ_qsBGAAiEwjv8f6qj9mVAxUNoNgFHVfVAhzKAQSfFgNz", - "commandMetadata": { - "webCommandMetadata": { - "sendPost": true, - "apiUrl": "/youtubei/v1/account/account_menu" - } - }, - "signalServiceEndpoint": { - "signal": "GET_ACCOUNT_MENU", - "actions": [ - { - "clickTrackingParams": "CAsQ_qsBGAAiEwjv8f6qj9mVAxUNoNgFHVfVAhzKAQSfFgNz", - "openPopupAction": { - "popup": { - "multiPageMenuRenderer": { - "trackingParams": "CAwQ_6sBIhMI7_H-qo_ZlQMVDaDYBR1X1QIc", - "style": "MULTI_PAGE_MENU_STYLE_TYPE_SYSTEM", - "showLoadingSpinner": true - } - }, - "popupType": "DROPDOWN", - "beReused": true - } - } - ] - } - }, - "trackingParams": "CAsQ_qsBGAAiEwjv8f6qj9mVAxUNoNgFHVfVAhw=", - "accessibility": { - "accessibilityData": { - "label": "Settings" - } - }, - "tooltip": "Settings", - "style": "STYLE_DEFAULT" - } - }, - { - "buttonRenderer": { - "style": "STYLE_SUGGESTIVE", - "size": "SIZE_SMALL", - "text": { - "runs": [ - { - "text": "Sign in" - } - ] - }, - "icon": { - "iconType": "AVATAR_LOGGED_OUT" - }, - "navigationEndpoint": { - "clickTrackingParams": "CAoQ1IAEGAEiEwjv8f6qj9mVAxUNoNgFHVfVAhzKAQSfFgNz", - "commandMetadata": { - "webCommandMetadata": { - "url": "https://accounts.google.com/ServiceLogin?service=youtube&uilel=3&passive=true&continue=https%3A%2F%2Fwww.youtube.com%2Fsignin%3Faction_handle_signin%3Dtrue%26app%3Ddesktop%26hl%3Den%26next%3Dhttps%253A%252F%252Fwww.youtube.com%252Fwatch%253Fv%253DsvJDGYiQlYw&hl=en&ec=65620", - "webPageType": "WEB_PAGE_TYPE_UNKNOWN", - "rootVe": 83769 - } - }, - "signInEndpoint": { - "idamTag": "65620" - } - }, - "trackingParams": "CAoQ1IAEGAEiEwjv8f6qj9mVAxUNoNgFHVfVAhw=", - "targetId": "topbar-signin" - } - } - ], - "hotkeyDialog": { - "hotkeyDialogRenderer": { - "title": { - "runs": [ - { - "text": "Keyboard shortcuts" - } - ] - }, - "sections": [ - { - "hotkeyDialogSectionRenderer": { - "title": { - "runs": [ - { - "text": "Playback" - } - ] - }, - "options": [ - { - "hotkeyDialogSectionOptionRenderer": { - "label": { - "runs": [ - { - "text": "Toggle play/pause" - } - ] - }, - "hotkey": "k" - } - }, - { - "hotkeyDialogSectionOptionRenderer": { - "label": { - "runs": [ - { - "text": "Rewind 10 seconds" - } - ] - }, - "hotkey": "j" - } - }, - { - "hotkeyDialogSectionOptionRenderer": { - "label": { - "runs": [ - { - "text": "Fast forward 10 seconds" - } - ] - }, - "hotkey": "l" - } - }, - { - "hotkeyDialogSectionOptionRenderer": { - "label": { - "runs": [ - { - "text": "Previous video" - } - ] - }, - "hotkey": "P (SHIFT+p)" - } - }, - { - "hotkeyDialogSectionOptionRenderer": { - "label": { - "runs": [ - { - "text": "Next video" - } - ] - }, - "hotkey": "N (SHIFT+n)" - } - }, - { - "hotkeyDialogSectionOptionRenderer": { - "label": { - "runs": [ - { - "text": "Previous frame (while paused)" - } - ] - }, - "hotkey": ",", - "hotkeyAccessibilityLabel": { - "accessibilityData": { - "label": "Comma" - } - } - } - }, - { - "hotkeyDialogSectionOptionRenderer": { - "label": { - "runs": [ - { - "text": "Next frame (while paused)" - } - ] - }, - "hotkey": ".", - "hotkeyAccessibilityLabel": { - "accessibilityData": { - "label": "Period" - } - } - } - }, - { - "hotkeyDialogSectionOptionRenderer": { - "label": { - "runs": [ - { - "text": "Decrease playback rate" - } - ] - }, - "hotkey": "< (SHIFT+,)", - "hotkeyAccessibilityLabel": { - "accessibilityData": { - "label": "Less than or SHIFT + comma" - } - } - } - }, - { - "hotkeyDialogSectionOptionRenderer": { - "label": { - "runs": [ - { - "text": "Increase playback rate" - } - ] - }, - "hotkey": "> (SHIFT+.)", - "hotkeyAccessibilityLabel": { - "accessibilityData": { - "label": "Greater than or SHIFT + period" - } - } - } - }, - { - "hotkeyDialogSectionOptionRenderer": { - "label": { - "runs": [ - { - "text": "Seek to specific point in the video (7 advances to 70% of duration)" - } - ] - }, - "hotkey": "0..9" - } - }, - { - "hotkeyDialogSectionOptionRenderer": { - "label": { - "runs": [ - { - "text": "Seek to previous chapter" - } - ] - }, - "hotkey": "CONTROL + ←" - } - }, - { - "hotkeyDialogSectionOptionRenderer": { - "label": { - "runs": [ - { - "text": "Seek to next chapter" - } - ] - }, - "hotkey": "CONTROL + →" - } - } - ] - } - }, - { - "hotkeyDialogSectionRenderer": { - "title": { - "runs": [ - { - "text": "General" - } - ] - }, - "options": [ - { - "hotkeyDialogSectionOptionRenderer": { - "label": { - "runs": [ - { - "text": "Toggle full screen" - } - ] - }, - "hotkey": "f" - } - }, - { - "hotkeyDialogSectionOptionRenderer": { - "label": { - "runs": [ - { - "text": "Toggle theater mode" - } - ] - }, - "hotkey": "t" - } - }, - { - "hotkeyDialogSectionOptionRenderer": { - "label": { - "runs": [ - { - "text": "Toggle miniplayer" - } - ] - }, - "hotkey": "i" - } - }, - { - "hotkeyDialogSectionOptionRenderer": { - "label": { - "runs": [ - { - "text": "Close miniplayer or current dialog" - } - ] - }, - "hotkey": "ESCAPE" - } - }, - { - "hotkeyDialogSectionOptionRenderer": { - "label": { - "runs": [ - { - "text": "Toggle mute" - } - ] - }, - "hotkey": "m" - } - } - ] - } - }, - { - "hotkeyDialogSectionRenderer": { - "title": { - "runs": [ - { - "text": "Subtitles and closed captions" - } - ] - }, - "options": [ - { - "hotkeyDialogSectionOptionRenderer": { - "label": { - "runs": [ - { - "text": "If the video supports captions, toggle captions ON/OFF" - } - ] - }, - "hotkey": "c" - } - }, - { - "hotkeyDialogSectionOptionRenderer": { - "label": { - "runs": [ - { - "text": "Rotate through different text opacity levels" - } - ] - }, - "hotkey": "o" - } - }, - { - "hotkeyDialogSectionOptionRenderer": { - "label": { - "runs": [ - { - "text": "Rotate through different window opacity levels" - } - ] - }, - "hotkey": "w" - } - }, - { - "hotkeyDialogSectionOptionRenderer": { - "label": { - "runs": [ - { - "text": "Rotate through font sizes (increasing)" - } - ] - }, - "hotkey": "+" - } - }, - { - "hotkeyDialogSectionOptionRenderer": { - "label": { - "runs": [ - { - "text": "Rotate through font sizes (decreasing)" - } - ] - }, - "hotkey": "-", - "hotkeyAccessibilityLabel": { - "accessibilityData": { - "label": "Minus" - } - } - } - } - ] - } - }, - { - "hotkeyDialogSectionRenderer": { - "title": { - "runs": [ - { - "text": "Spherical Videos" - } - ] - }, - "options": [ - { - "hotkeyDialogSectionOptionRenderer": { - "label": { - "runs": [ - { - "text": "Pan up" - } - ] - }, - "hotkey": "w" - } - }, - { - "hotkeyDialogSectionOptionRenderer": { - "label": { - "runs": [ - { - "text": "Pan left" - } - ] - }, - "hotkey": "a" - } - }, - { - "hotkeyDialogSectionOptionRenderer": { - "label": { - "runs": [ - { - "text": "Pan down" - } - ] - }, - "hotkey": "s" - } - }, - { - "hotkeyDialogSectionOptionRenderer": { - "label": { - "runs": [ - { - "text": "Pan right" - } - ] - }, - "hotkey": "d" - } - }, - { - "hotkeyDialogSectionOptionRenderer": { - "label": { - "runs": [ - { - "text": "Zoom in" - } - ] - }, - "hotkey": "+ on numpad or ]", - "hotkeyAccessibilityLabel": { - "accessibilityData": { - "label": "Plus on number pad or right bracket" - } - } - } - }, - { - "hotkeyDialogSectionOptionRenderer": { - "label": { - "runs": [ - { - "text": "Zoom out" - } - ] - }, - "hotkey": "- on numpad or [", - "hotkeyAccessibilityLabel": { - "accessibilityData": { - "label": "Minus on number pad or left bracket" - } - } - } - } - ] - } - } - ], - "dismissButton": { - "buttonRenderer": { - "style": "STYLE_BLUE_TEXT", - "size": "SIZE_DEFAULT", - "isDisabled": false, - "text": { - "runs": [ - { - "text": "Dismiss" - } - ] - }, - "trackingParams": "CAkQ8FsiEwjv8f6qj9mVAxUNoNgFHVfVAhw=" - } - }, - "trackingParams": "CAgQteYDIhMI7_H-qo_ZlQMVDaDYBR1X1QIc" - } - }, - "backButton": { - "buttonRenderer": { - "trackingParams": "CAcQvIYDIhMI7_H-qo_ZlQMVDaDYBR1X1QIc", - "command": { - "clickTrackingParams": "CAcQvIYDIhMI7_H-qo_ZlQMVDaDYBR1X1QIcygEEnxYDcw==", - "commandMetadata": { - "webCommandMetadata": { - "sendPost": true - } - }, - "signalServiceEndpoint": { - "signal": "CLIENT_SIGNAL", - "actions": [ - { - "clickTrackingParams": "CAcQvIYDIhMI7_H-qo_ZlQMVDaDYBR1X1QIcygEEnxYDcw==", - "signalAction": { - "signal": "HISTORY_BACK" - } - } - ] - } - } - } - }, - "forwardButton": { - "buttonRenderer": { - "trackingParams": "CAYQvYYDIhMI7_H-qo_ZlQMVDaDYBR1X1QIc", - "command": { - "clickTrackingParams": "CAYQvYYDIhMI7_H-qo_ZlQMVDaDYBR1X1QIcygEEnxYDcw==", - "commandMetadata": { - "webCommandMetadata": { - "sendPost": true - } - }, - "signalServiceEndpoint": { - "signal": "CLIENT_SIGNAL", - "actions": [ - { - "clickTrackingParams": "CAYQvYYDIhMI7_H-qo_ZlQMVDaDYBR1X1QIcygEEnxYDcw==", - "signalAction": { - "signal": "HISTORY_FORWARD" - } - } - ] - } - } - } - }, - "a11ySkipNavigationButton": { - "buttonRenderer": { - "style": "STYLE_DEFAULT", - "size": "SIZE_DEFAULT", - "isDisabled": false, - "text": { - "runs": [ - { - "text": "Skip navigation" - } - ] - }, - "trackingParams": "CAUQ8FsiEwjv8f6qj9mVAxUNoNgFHVfVAhw=", - "command": { - "clickTrackingParams": "CAUQ8FsiEwjv8f6qj9mVAxUNoNgFHVfVAhzKAQSfFgNz", - "commandMetadata": { - "webCommandMetadata": { - "sendPost": true - } - }, - "signalServiceEndpoint": { - "signal": "CLIENT_SIGNAL", - "actions": [ - { - "clickTrackingParams": "CAUQ8FsiEwjv8f6qj9mVAxUNoNgFHVfVAhzKAQSfFgNz", - "signalAction": { - "signal": "SKIP_NAVIGATION" - } - } - ] - } - } - } - }, - "voiceSearchButton": { - "buttonRenderer": { - "style": "STYLE_DEFAULT", - "size": "SIZE_DEFAULT", - "isDisabled": false, - "serviceEndpoint": { - "clickTrackingParams": "CAIQ7a8FIhMI7_H-qo_ZlQMVDaDYBR1X1QIcygEEnxYDcw==", - "commandMetadata": { - "webCommandMetadata": { - "sendPost": true - } - }, - "signalServiceEndpoint": { - "signal": "CLIENT_SIGNAL", - "actions": [ - { - "clickTrackingParams": "CAIQ7a8FIhMI7_H-qo_ZlQMVDaDYBR1X1QIcygEEnxYDcw==", - "openPopupAction": { - "popup": { - "voiceSearchDialogRenderer": { - "placeholderHeader": { - "runs": [ - { - "text": "Listening..." - } - ] - }, - "promptHeader": { - "runs": [ - { - "text": "Didn't hear that. Try again." - } - ] - }, - "exampleQuery1": { - "runs": [ - { - "text": "\"Play Dua Lipa\"" - } - ] - }, - "exampleQuery2": { - "runs": [ - { - "text": "\"Show me my subscriptions\"" - } - ] - }, - "promptMicrophoneLabel": { - "runs": [ - { - "text": "Tap microphone to try again" - } - ] - }, - "loadingHeader": { - "runs": [ - { - "text": "Working..." - } - ] - }, - "connectionErrorHeader": { - "runs": [ - { - "text": "No connection" - } - ] - }, - "connectionErrorMicrophoneLabel": { - "runs": [ - { - "text": "Check your connection and try again" - } - ] - }, - "permissionsHeader": { - "runs": [ - { - "text": "Waiting for permission" - } - ] - }, - "permissionsSubtext": { - "runs": [ - { - "text": "Allow microphone access to search with voice" - } - ] - }, - "disabledHeader": { - "runs": [ - { - "text": "Search with your voice" - } - ] - }, - "disabledSubtext": { - "runs": [ - { - "text": "To search by voice, go to your browser settings and allow access to microphone" - } - ] - }, - "microphoneButtonAriaLabel": { - "runs": [ - { - "text": "Cancel" - } - ] - }, - "exitButton": { - "buttonRenderer": { - "style": "STYLE_DEFAULT", - "size": "SIZE_DEFAULT", - "isDisabled": false, - "icon": { - "iconType": "CLOSE" - }, - "trackingParams": "CAQQ0LEFIhMI7_H-qo_ZlQMVDaDYBR1X1QIc", - "accessibilityData": { - "accessibilityData": { - "label": "Cancel" - } - } - } - }, - "trackingParams": "CAMQ7q8FIhMI7_H-qo_ZlQMVDaDYBR1X1QIc", - "microphoneOffPromptHeader": { - "runs": [ - { - "text": "Microphone off. Try again." - } - ] - } - } - }, - "popupType": "TOP_ALIGNED_DIALOG" - } - } - ] - } - }, - "icon": { - "iconType": "MICROPHONE_ON" - }, - "tooltip": "Search with your voice", - "trackingParams": "CAIQ7a8FIhMI7_H-qo_ZlQMVDaDYBR1X1QIc", - "accessibilityData": { - "accessibilityData": { - "label": "Search with your voice" - } - } - } - } - } - } -} \ No newline at end of file