@@ -5,6 +5,7 @@ import { Group } from "../database/entities/Group";
55import { Repository } from "typeorm" ;
66import { MatchNotificationService } from "./MatchNotificationService" ;
77import { MatchingService , MatchResult , WishlistData , GroupData } from "./MatchingService" ;
8+ import { withOperationContext } from "../context/OperationContext" ;
89import OpenAI from "openai" ;
910
1011export class AIMatchingService {
@@ -29,85 +30,90 @@ export class AIMatchingService {
2930 async findMatches ( ) : Promise < void > {
3031 console . log ( "🤖 Starting AI matching process..." ) ;
3132
32- const wishlists = await this . getWishlistsForMatching ( ) ;
33- console . log ( `📋 Found ${ wishlists . length } wishlists to analyze` ) ;
34-
35- // Get existing groups for context
36- const existingGroups = await this . getExistingGroups ( ) ;
37- console . log ( `🏠 Found ${ existingGroups . length } existing groups to consider` ) ;
38-
39- // Convert to shared service format
40- const wishlistData : WishlistData [ ] = wishlists . map ( wishlist => ( {
41- id : wishlist . id ,
42- content : wishlist . content ,
43- userId : wishlist . userId ,
44- user : {
45- id : wishlist . user . id ,
46- name : wishlist . user . name || wishlist . user . ename ,
47- ename : wishlist . user . ename
48- }
49- } ) ) ;
50-
51- // Use matching service for parallel processing
52- const matchResults = await this . matchingService . findMatches ( wishlistData , existingGroups ) ;
53-
54- // Create database matches from results
55- let totalMatches = 0 ;
56- for ( const matchResult of matchResults ) {
57- // Find the original wishlists for all users in the match
58- const matchWishlists = matchResult . userIds . map ( userId =>
59- wishlists . find ( w => w . userId === userId )
60- ) . filter ( Boolean ) as Wishlist [ ] ;
61-
62- if ( matchWishlists . length !== matchResult . userIds . length ) {
63- console . log ( `❌ Could not find all wishlists for match: ${ matchResult . userIds . join ( ', ' ) } ` ) ;
64- continue ;
65- }
33+ // Generate unique operation ID for this matching process
34+ const operationId = `ai-matching-${ Date . now ( ) } -${ Math . random ( ) . toString ( 36 ) . substr ( 2 , 9 ) } ` ;
35+
36+ return withOperationContext ( 'AIMatchingService' , operationId , async ( ) => {
37+ const wishlists = await this . getWishlistsForMatching ( ) ;
38+ console . log ( `📋 Found ${ wishlists . length } wishlists to analyze` ) ;
39+
40+ // Get existing groups for context
41+ const existingGroups = await this . getExistingGroups ( ) ;
42+ console . log ( `🏠 Found ${ existingGroups . length } existing groups to consider` ) ;
43+
44+ // Convert to shared service format
45+ const wishlistData : WishlistData [ ] = wishlists . map ( wishlist => ( {
46+ id : wishlist . id ,
47+ content : wishlist . content ,
48+ userId : wishlist . userId ,
49+ user : {
50+ id : wishlist . user . id ,
51+ name : wishlist . user . name || wishlist . user . ename ,
52+ ename : wishlist . user . ename
53+ }
54+ } ) ) ;
55+
56+ // Use matching service for parallel processing
57+ const matchResults = await this . matchingService . findMatches ( wishlistData , existingGroups ) ;
58+
59+ // Create database matches from results
60+ let totalMatches = 0 ;
61+ for ( const matchResult of matchResults ) {
62+ // Find the original wishlists for all users in the match
63+ const matchWishlists = matchResult . userIds . map ( userId =>
64+ wishlists . find ( w => w . userId === userId )
65+ ) . filter ( Boolean ) as Wishlist [ ] ;
66+
67+ if ( matchWishlists . length !== matchResult . userIds . length ) {
68+ console . log ( `❌ Could not find all wishlists for match: ${ matchResult . userIds . join ( ', ' ) } ` ) ;
69+ continue ;
70+ }
6671
67- // Check if match already exists (any combination of these users)
68- // Skip this check for JOIN_EXISTING_GROUP matches since they're joining existing groups
69- const isJoinExistingGroup = matchResult . suggestedActivities ?. some ( ( activity : any ) =>
70- typeof activity === 'string' && activity . startsWith ( 'JOIN_EXISTING_GROUP:' )
71- ) ;
72-
73- if ( ! isJoinExistingGroup ) {
74- const existingMatch = await this . checkForExistingMatch ( matchResult . userIds , matchResult . activityCategory ) ;
75- if ( existingMatch ) {
76- continue ;
72+ // Check if match already exists (any combination of these users)
73+ // Skip this check for JOIN_EXISTING_GROUP matches since they're joining existing groups
74+ const isJoinExistingGroup = matchResult . suggestedActivities ?. some ( ( activity : any ) =>
75+ typeof activity === 'string' && activity . startsWith ( 'JOIN_EXISTING_GROUP:' )
76+ ) ;
77+
78+ if ( ! isJoinExistingGroup ) {
79+ const existingMatch = await this . checkForExistingMatch ( matchResult . userIds , matchResult . activityCategory ) ;
80+ if ( existingMatch ) {
81+ continue ;
82+ }
7783 }
78- }
79-
80- // Handle JOIN_EXISTING_GROUP matches differently
81- if ( isJoinExistingGroup ) {
82- const groupId = matchResult . suggestedActivities ?. find ( ( activity : any ) =>
83- typeof activity === 'string' && activity . startsWith ( 'JOIN_EXISTING_GROUP:' )
84- ) ?. split ( ':' ) [ 1 ] ;
8584
86- if ( groupId ) {
87- await this . handleJoinExistingGroupMatch ( matchWishlists , matchResult , groupId ) ;
85+ // Handle JOIN_EXISTING_GROUP matches differently
86+ if ( isJoinExistingGroup ) {
87+ const groupId = matchResult . suggestedActivities ?. find ( ( activity : any ) =>
88+ typeof activity === 'string' && activity . startsWith ( 'JOIN_EXISTING_GROUP:' )
89+ ) ?. split ( ':' ) [ 1 ] ;
90+
91+ if ( groupId ) {
92+ await this . handleJoinExistingGroupMatch ( matchWishlists , matchResult , groupId ) ;
93+ totalMatches ++ ;
94+ }
95+ } else {
96+ await this . createMatch ( matchWishlists , matchResult ) ;
8897 totalMatches ++ ;
8998 }
90- } else {
91- await this . createMatch ( matchWishlists , matchResult ) ;
92- totalMatches ++ ;
93- }
94- }
99+ }
95100
96- // Mark wishlists as analyzed
97- for ( const wishlist of wishlists ) {
98- await this . wishlistRepository . update ( wishlist . id , {
99- metadata : {
100- ...wishlist . metadata ,
101- lastAnalyzed : new Date ( ) ,
102- analysisVersion : ( wishlist . metadata ?. analysisVersion || 1 ) + 1
103- }
104- } ) ;
105- }
101+ // Mark wishlists as analyzed
102+ for ( const wishlist of wishlists ) {
103+ await this . wishlistRepository . update ( wishlist . id , {
104+ metadata : {
105+ ...wishlist . metadata ,
106+ lastAnalyzed : new Date ( ) ,
107+ analysisVersion : ( wishlist . metadata ?. analysisVersion || 1 ) + 1
108+ }
109+ } ) ;
110+ }
106111
107- console . log ( `🎉 AI matching process completed! Created ${ totalMatches } matches from ${ matchResults . length } AI results` ) ;
108-
109- // Process any existing matches that haven't been messaged yet
110- await this . processUnmessagedMatches ( ) ;
112+ console . log ( `🎉 AI matching process completed! Created ${ totalMatches } matches from ${ matchResults . length } AI results` ) ;
113+
114+ // Process any existing matches that haven't been messaged yet
115+ await this . processUnmessagedMatches ( ) ;
116+ } ) ;
111117 }
112118
113119 /**
0 commit comments