Let me continue with the matching algorithm code:
matching-algorithmapplication/vnd.ant.codePersonality-Based Matching Algorithmupdate
// services/matchingService.js
const User = require('../models/User');
const Match = require('../models/Match');
const MatchRequest = require('../models/MatchRequest');
const { calculateCompatibilityScore } = require('./compatibilityService');
/**
* Find potential matches for a user
* @param {String} userId - ID of the user to find matches for
* @param {Number} limit - Maximum number of potential matches to return
* @returns {Array} Array of potential matches with compatibility scores
*/
async function findPotentialMatches(userId, limit = 20) {
try {
// Get user's profile and preferences
const user = await User.findById(userId);
if (!user) {
throw new Error('User not found');
}
// Get user's existing matches and match requests to exclude them
const existingMatches = await Match.find({
$or: [{ user1: userId }, { user2: userId }],
status: { $in: ['active', 'paused'] }
});
const sentRequests = await MatchRequest.find({
sender: userId,
status: 'pending'
});
const receivedRequests = await MatchRequest.find({
receiver: userId,
status: 'pending'
});
// Create list of users to exclude from potential matches
const excludeUserIds = [
userId, // Exclude self
...existingMatches.map(match =>
match.user1.toString() === userId.toString()
? match.user2.toString()
: match.user1.toString()
),
...sentRequests.map(req => req.receiver.toString()),
...receivedRequests.map(req => req.sender.toString())
];
// Build query for finding potential matches
const matchQuery = {
_id: { $nin: excludeUserIds },
isActive: true,
isVerified: true,
// Filter by gender preferences
gender: { $in: user.lookingFor },
lookingFor: { $in: [user.gender] }
};
// Add age range filter if specified
if (user.ageRangeMin && user.ageRangeMax) {
const minDate = new Date();
minDate.setFullYear(minDate.getFullYear() - user.ageRangeMax);
const maxDate = new Date();
maxDate.setFullYear(maxDate.getFullYear() - user.ageRangeMin);
matchQuery.birthdate = { $gte: minDate, $lte: maxDate };
}
// Find potential matches based on initial criteria
const potentialMatches = await User.find(matchQuery)
.select('_id displayName birthdate gender interests values personalityTraits communicationStyle location lastActive')
.limit(limit * 2); // Get extra matches to filter down after scoring
// Calculate compatibility scores for each potential match
const scoredMatches = await Promise.all(
potentialMatches.map(async match => {
const compatibilityScore = await calculateCompatibilityScore(user, match);
return {
user: match,
score: compatibilityScore,
distanceKm: calculateDistance(
user.location.coordinates,
match.location.coordinates
),
lastActive: match.lastActive
};
})
);
// Sort by compatibility score and limit results
return scoredMatches
.sort((a, b) => b.score - a.score)
.slice(0, limit);
} catch (error) {
console.error('Error finding potential matches:', error);
throw error;
}
}
/**
* Calculate compatibility score between two users
* This is imported from compatibilityService.js in the actual implementation
* but included here for reference
*
* @param {Object} user1 - First user
* @param {Object} user2 - Second user
* @returns {Number} Compatibility score (0-100)
*/
function calculateCompatibilityScore(user1, user2) {
// Initialize score components
let personalityScore = 0;
let interestsScore = 0;
let valuesScore = 0;
let communicationScore = 0;
// 1. Personality traits comparison (40% of total score)
// Compare each personality trait dimension
const personalityTraits = [
'openness', 'conscientiousness', 'extraversion',
'agreeableness', 'neuroticism'
];
let personalityDiffSum = 0;
for (const trait of personalityTraits) {
if (user1.personalityTraits.has(trait) && user2.personalityTraits.has(trait)) {
// Calculate difference (0-1 scale)
const diff = Math.abs(
user1.personalityTraits.get(trait) - user2.personalityTraits.get(trait)
);
personalityDiffSum += diff;
}
}
// Convert difference to similarity score (0-40)
personalityScore = 40 * (1 - (personalityDiffSum / personalityTraits.length));
// 2. Shared interests comparison (25% of total score)
const user1Interests = new Set(user1.interests);
const user2Interests = new Set(user2.interests);
// Count shared interests
let sharedInterests = 0;
for (const interest of user1Interests) {
if (user2Interests.has(interest)) {
sharedInterests++;
}
}
// Calculate interest score based on overlap percentage
const totalInterests = Math.max(1, user1Interests.size + user2Interests.size - sharedInterests);
interestsScore = 25 * (sharedInterests / totalInterests);
// 3. Shared values comparison (25% of total score)
const user1Values = new Set(user1.values);
const user2Values = new Set(user2.values);
// Count shared values
let sharedValues = 0;
for (const value of user1Values) {
if (user2Values.has(value)) {
sharedValues++;
}
}
// Calculate values score based on overlap percentage
const totalValues = Math.max(1, user1Values.size + user2Values.size - sharedValues);
valuesScore = 25 * (sharedValues / totalValues);
// 4. Communication style compatibility (10% of total score)
// Predefined compatibility matrix for communication styles
const communicationCompatibility = {
'direct': { 'direct': 1.0, 'thoughtful': 0.7, 'humorous': 0.8, 'deep': 0.6, 'casual': 0.7 },
'thoughtful': { 'direct': 0.7, 'thoughtful': 1.0, 'humorous': 0.6, 'deep': 0.9, 'casual': 0.5 },
'humorous': { 'direct': 0.8, 'thoughtful': 0.6, 'humorous': 1.0, 'deep': 0.7, 'casual': 0.9 },
'deep': { 'direct': 0.6, 'thoughtful': 0.9, 'humorous': 0.7, 'deep': 1.0, 'casual': 0.5 },
'casual': { 'direct': 0.7, 'thoughtful': 0.5, 'humorous': 0.9, 'deep': 0.5, 'casual': 1.0 }
};
// Calculate communication style compatibility
if (user1.communicationStyle && user2.communicationStyle) {
const compatibilityValue = communicationCompatibility[user1.communicationStyle][user2.communicationStyle] || 0.5;
communicationScore = 10 * compatibilityValue;
} else {
// Default if communication style not specified
communicationScore = 5;
}
// Calculate total score (0-100)
const totalScore = personalityScore + interestsScore + valuesScore + communicationScore;
return Math.round(totalScore);
}
/**
* Calculate distance between two points in kilometers
* Using Haversine formula
*
* @param {Array} coords1 - [longitude, latitude] of first point
* @param {Array} coords2 - [longitude, latitude] of second point
* @returns {Number} Distance in kilometers
*/
function calculateDistance(coords1, coords2) {
// Earth's radius in kilometers
const R = 6371;
const [lon1, lat1] = coords1;
const [lon2, lat2] = coords2;
// Convert to radians
const dLat = (lat2 - lat1) * Math.PI / 180;
const dLon = (lon2 - lon1) * Math.PI / 180;
const a =
Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
Math.sin(dLon/2) * Math.sin(dLon/2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
const distance = R * c;
return distance;
}
/**
* Send a match request to another user
*
* @param {String} senderId - ID of the sending user
* @param {String} receiverId - ID of the receiving user
* @returns {Object} Created match request
*/
async function sendMatchRequest(senderId, receiverId) {
try {
// Check if users exist
const [sender, receiver] = await Promise.all([
User.findById(senderId),
User.findById(receiverId)
]);
if (!sender || !receiver) {
throw new Error('User not found');
}
// Check if there's already a match between these users
const existingMatch = await Match.findOne({
$or: [
{ user1: senderId, user2: receiverId },
{ user1: receiverId, user2: senderId }
],
status: { $in: ['active', 'paused'] }
});
if (existingMatch) {
throw new Error('Match already exists between these users');
}
// Check if there's already a pending request in either direction
const existingRequest = await MatchRequest.findOne({
$or: [
{ sender: senderId, receiver: receiverId },
{ sender: receiverId, receiver: senderId }
],
status: 'pending'
});
// If receiver already sent a request to sender, create a match
if (existingRequest && existingRequest.sender.toString() === receiverId.toString()) {
existingRequest.status = 'accepted';
await existingRequest.save();
// Create a new match
const newMatch = new Match({
user1: senderId,
user2: receiverId,
stage: 'text',
stageStartDate: new Date(),
status: 'active'
});
await newMatch.save();
return {
matchCreated: true,
match: newMatch
};
}
// If sender already sent a request, return it
if (existingRequest) {
return {
matchCreated: false,
request: existingRequest
};
}
// Create a new match request
const newRequest = new MatchRequest({
sender: senderId,
receiver: receiverId,
status: 'pending',
sentAt: new Date()
});
await newRequest.save();
return {
matchCreated: false,
request: newRequest
};
} catch (error) {
console.error('Error sending match request:', error);
throw error;
}
}
/**
* Get recommended matches sorted by compatibility
* For the app's home screen
*
* @param {String} userId
* @param {Number} limit
* @returns {Array} Recommended matches
*/
async function getRecommendedMatches(userId, limit = 10) {
try {
const potentialMatches = await findPotentialMatches(userId, limit * 2);
// Apply additional filtering and sorting for recommendations
const recommendedMatches = potentialMatches
// Filter for higher compatibility
.filter(match => match.score >= 60)
// Sort by mix of compatibility and recency
.sort((a, b) => {
// Calculate a combined score that weights compatibility (70%) and recency (30%)
const recencyScoreA = getRecencyScore(a.user.lastActive);
const recencyScoreB = getRecencyScore(b.user.lastActive);
const combinedScoreA = (a.score * 0.7) + (recencyScoreA * 0.3);
const combinedScoreB = (b.score * 0.7) + (recencyScoreB * 0.3);
return combinedScoreB - combinedScoreA;
})
.slice(0, limit);
return recommendedMatches;
} catch (error) {
console.error('Error getting recommended matches:', error);
throw error;
}
}
/**
* Calculate recency score based on user's last activity
* Returns a score 0-100 where 100 is most recent
*
* @param {Date} lastActive
* @returns {Number} Recency score 0-100
*/
function getRecencyScore(lastActive) {
if (!lastActive) return 0;
const now = new Date();
const hoursAgo = (now - lastActive) / (1000 * 60 * 60);
// Score decreases as hours increase
// Users active within last 24 hours get 80-100
// Users active within last week get 50-80
// Users active within last month get 10-50
// Others get 0-10
if (hoursAgo < 24) {
return 100 - (hoursAgo / 24 * 20);
} else if (hoursAgo < 168) { // 7 days
return 80 - ((hoursAgo - 24) / 144 * 30);
} else if (hoursAgo < 720) { // 30 days
return 50 - ((hoursAgo - 168) / 552 * 40);
} else {
return Math.max(0, 10 - ((hoursAgo - 720) / 720 * 10));
}
}
module.exports = {
findPotentialMatches,
calculateCompatibilityScore,
sendMatchRequest,
getRecommendedMatches
};
javascriptHome | My Site 3
top of page
BLIND LOVE
Eyes closed
Closed eyes
Closed Eye
Eyes closed
1/9
Finding your perfect match ​
Get Started
FILL OUT THIS FORM:
​
​
​
​
Love
​About Blind Love
Welcome to Blind Love, a unique dating service that prioritizes meaningful conversations. At Blind Love, we believe that genuine connections are built through engaging communication. Join us and experience a new way of finding love.
​Our Approach
At Blind Love, we are committed to fostering relationships based on genuine interactions. Our approach is centered around encouraging users to connect through texts for the first month, allowing them to truly get to know each other without the influence of visual judgments.
I found my soulmate through Blind Love. The emphasis on communication allowed us to form a deep bond before ever meeting in person. I highly recommend this service to anyone seeking a meaningful relationship.
Blind Love provided me with the opportunity to connect with someone on a level I hadn't experienced before. The initial focus on conversation allowed us to establish a strong foundation for our relationship.
I was initially skeptical about the concept of Blind Love, but it completely changed my perspective. The emphasis on communication proved to be the key in finding my perfect match.