Software: Apache. PHP/8.1.30 uname -a: Linux server1.tuhinhossain.com 5.15.0-163-generic #173-Ubuntu SMP Tue Oct 14 17:51:00 UTC uid=1002(picotech) gid=1003(picotech) groups=1003(picotech),0(root) Safe-mode: OFF (not secure) /home/picotech/domains/note.picotech.app/public_html/src/models/ drwxr-xr-x | |
| Viewing file: Select action/file-type: const { DataTypes } = require('sequelize');
const { sequelize } = require('../config/database');
const Transcript = sequelize.define('Transcript', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
recording_id: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: 'recordings',
key: 'id',
},
onDelete: 'CASCADE',
},
meeting_id: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: 'meetings',
key: 'id',
},
onDelete: 'CASCADE',
},
content: {
type: DataTypes.TEXT('long'),
allowNull: false,
validate: {
notEmpty: true,
},
},
speaker_count: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 0,
validate: {
notEmpty: true,
},
},
speaker_data: {
type: DataTypes.JSON,
allowNull: true,
defaultValue: [],
comment: 'Array of speaker segments with timestamps and speaker IDs'
},
confidence: {
type: DataTypes.DECIMAL(3, 2),
allowNull: false,
defaultValue: 0.00,
validate: {
min: 0.00,
max: 1.00,
},
comment: 'Overall transcription confidence score (0.00 to 1.00)',
},
language: {
type: DataTypes.STRING(10),
allowNull: false,
defaultValue: 'unknown',
},
word_count: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 0,
},
processing_time: {
type: DataTypes.INTEGER,
allowNull: true,
comment: 'Time taken to process transcription in seconds',
},
service_provider: {
type: DataTypes.ENUM('openai_whisper', 'google_speech', 'azure_speech', 'aws_transcribe', 'local','elevenlabs','openrouter'),
allowNull: false,
defaultValue: 'elevenlabs',
},
model_version: {
type: DataTypes.STRING(50),
allowNull: true,
comment: 'Version of the transcription model used',
},
timestamps: {
type: DataTypes.JSON,
allowNull: true,
defaultValue: [],
comment: 'Word-level timestamps for precise alignment',
},
keywords: {
type: DataTypes.JSON,
allowNull: true,
defaultValue: [],
comment: 'Extracted keywords and key phrases',
},
sentiment_score: {
type: DataTypes.DECIMAL(3, 2),
allowNull: true,
validate: {
min: -1.00,
max: 1.00,
},
comment: 'Overall sentiment score (-1.00 to 1.00)',
},
topics: {
type: DataTypes.JSON,
allowNull: true,
defaultValue: [],
comment: 'Identified topics and themes',
},
status: {
type: DataTypes.ENUM('processing', 'completed', 'failed', 'reviewed'),
allowNull: false,
defaultValue: 'processing',
},
error_message: {
type: DataTypes.TEXT,
allowNull: true,
comment: 'Error message if transcription failed',
},
is_edited: {
type: DataTypes.BOOLEAN,
defaultValue: false,
comment: 'Whether the transcript has been manually edited',
},
edited_by: {
type: DataTypes.INTEGER,
allowNull: true,
references: {
model: 'users',
key: 'id',
},
comment: 'User who last edited the transcript',
},
edit_history: {
type: DataTypes.JSON,
allowNull: true,
defaultValue: [],
comment: 'History of edits made to the transcript',
},
}, {
tableName: 'transcripts',
timestamps: true,
indexes: [
{
fields: ['recording_id'],
unique: true,
},
{
fields: ['meeting_id'],
},
{
fields: ['status'],
},
{
fields: ['language'],
},
{
fields: ['service_provider'],
},
],
hooks: {
beforeSave: (transcript) => {
// Calculate word count
if (transcript.content) {
const words = transcript.content.trim().split(/\s+/).filter(word => word.length > 0);
transcript.word_count = words.length;
}
},
},
});
// Instance methods
Transcript.prototype.getPlainText = function() {
return this.content.replace(/<[^>]*>/g, '').trim();
};
Transcript.prototype.getDurationCovered = function() {
if (!this.speaker_data || !Array.isArray(this.speaker_data) || this.speaker_data.length === 0) {
return 0;
}
const lastSegment = this.speaker_data[this.speaker_data.length - 1];
const firstSegment = this.speaker_data[0];
return (lastSegment.end_time || 0) - (firstSegment.start_time || 0);
};
Transcript.prototype.getSegmentsBySpeaker = function(speakerId) {
if (!this.speaker_data || !Array.isArray(this.speaker_data)) {
return [];
}
return this.speaker_data.filter(segment => segment.speaker_id === speakerId);
};
Transcript.prototype.searchText = function(query) {
const content = this.getPlainText().toLowerCase();
const searchTerm = query.toLowerCase();
const matches = [];
let index = content.indexOf(searchTerm);
while (index !== -1) {
const start = Math.max(0, index - 50);
const end = Math.min(content.length, index + searchTerm.length + 50);
const snippet = content.substring(start, end);
matches.push({
index,
snippet: snippet.trim(),
context: {
before: content.substring(start, index),
match: content.substring(index, index + searchTerm.length),
after: content.substring(index + searchTerm.length, end),
},
});
index = content.indexOf(searchTerm, index + 1);
}
return matches;
};
Transcript.prototype.addEdit = function(userId, changes, reason = '') {
if (!this.edit_history) {
this.edit_history = [];
}
this.edit_history.push({
timestamp: new Date().toISOString(),
user_id: userId,
changes,
reason,
});
this.is_edited = true;
this.edited_by = userId;
return this;
};
Transcript.prototype.markAsCompleted = async function() {
this.status = 'completed';
return this.save();
};
Transcript.prototype.markAsFailed = async function(errorMessage) {
this.status = 'failed';
this.error_message = errorMessage;
return this.save();
};
// Class methods
Transcript.findByRecording = function(recordingId) {
return this.findOne({
where: { recording_id: recordingId },
});
};
Transcript.findByMeeting = function(meetingId, options = {}) {
return this.findAll({
where: {
meeting_id: meetingId,
...options.where,
},
order: options.order || [['created_at', 'ASC']],
...options,
});
};
Transcript.findPendingProcessing = function(limit = 10) {
return this.findAll({
where: {
status: 'processing',
},
order: [['created_at', 'ASC']],
limit,
});
};
Transcript.searchContent = function(searchTerm, options = {}) {
const { Op } = sequelize.Sequelize;
return this.findAll({
where: {
content: {
[Op.like]: `%${searchTerm}%`,
},
status: 'completed',
...options.where,
},
order: options.order || [['created_at', 'DESC']],
limit: options.limit || 50,
});
};
Transcript.getStatsByMeeting = async function(meetingId) {
const transcripts = await this.findByMeeting(meetingId);
const stats = {
total_transcripts: transcripts.length,
total_words: transcripts.reduce((sum, t) => sum + t.word_count, 0),
average_confidence: transcripts.length > 0
? transcripts.reduce((sum, t) => sum + parseFloat(t.confidence), 0) / transcripts.length
: 0,
languages: [...new Set(transcripts.map(t => t.language))],
speakers: transcripts.reduce((speakers, t) => {
const speakerCount = t.getSpeakerCount();
return Math.max(speakers, speakerCount);
}, 0),
};
return stats;
};
module.exports = Transcript; |
:: Command execute :: | |
--[ c99shell v. 2.5 [PHP 8 Update] [24.05.2025] | Generation time: 0.0031 ]-- |