CKT commited on
Commit
2630422
·
1 Parent(s): 3f6f4f8

v0.1.1 e2e testing

Browse files
app.py CHANGED
@@ -64,7 +64,7 @@ def save_json_data(filepath, data):
64
 
65
  # --- Start of MCP Matchmaker Tools ---
66
 
67
- def profile_questionnaire(request: gr.Request):
68
  """
69
  Generates and returns a profile questionnaire, a new public profile_id,
70
  and a new private auth_id. Also creates an initial profile stub.
@@ -72,7 +72,7 @@ def profile_questionnaire(request: gr.Request):
72
  # 1. Generate profile_id and auth_id
73
  profile_id = f"user_{''.join(random.choices('abcdefghijklmnopqrstuvwxyz0123456789', k=8))}"
74
  auth_id = str(uuid.uuid4())
75
- print(f"profile_questionnaire with Profile ID: {profile_id} and Auth ID: {auth_id}")
76
 
77
  # 2. Read questionnaire.json
78
  questionnaire_data = load_json_data(QUESTIONNAIRE_FILE, default_data={"title": "Error Loading Questionnaire", "questions": []})
@@ -85,23 +85,21 @@ def profile_questionnaire(request: gr.Request):
85
  # Ensure timestamp is timezone-aware (UTC)
86
  timestamp = datetime.now(timezone.utc).isoformat()
87
 
88
- profiles[profile_id] = {
89
- "profile_id": profile_id,
90
  "auth_id": auth_id,
91
  "created_at": timestamp,
92
  "updated_at": timestamp,
93
- "name": "",
94
- "profile_image_filename": None,
95
- "profile_summary": "",
96
  "answers": {}
97
  }
 
98
  if not save_json_data(PROFILES_FILE, profiles):
99
  print(f"Critical Error: Failed to save profile for {profile_id} to {PROFILES_FILE}")
100
  # Decide how to handle this error - maybe return an error to the client?
101
 
102
  # 4. Return IDs, questionnaire data, and instructions
103
- instructions_for_agent = "You have received a `profile_id` (public identifier for this user\'s profile) and an `auth_id` (private key for authentication for this user). Please ask the user to store both securely. The `auth_id` must be sent as an `X-Auth-ID` header in subsequent requests that require authentication for this user (e.g., `update_profile_answers`, `get_matches`, `get_messages`, `get_profile` for own profile, `send_message`). The `profile_id` is used to publicly identify this user to others (e.g., in matches, or when sending/receiving messages). You must now walk the user through the questionnaire, preferably question by question, and collect the answers (in preparation to update the user's profile using update_profile_answers)."
104
- instructions_for_user = "Your profile creation process has started! You\'ve been assigned a unique Profile ID and a secret Auth ID. Your AI agent will use these to manage your profile and interactions. You must now walk through the questionnaire, preferably question by question, and provide your answers."
105
 
106
  return {
107
  "profile_id": profile_id,
@@ -154,11 +152,11 @@ def update_profile_answers(answers_payload_str: str, request: gr.Request):
154
 
155
  if question_details.get("purpose") == "metadata":
156
  field_to_map = question_details.get("maps_to_field")
157
- if field_to_map and field_to_map in user_profile:
158
  user_profile[field_to_map] = answer_value
159
  updated_fields = True
160
  else:
161
- print(f"Warning: Metadata question '{question_id}' has no valid 'maps_to_field' or field not in profile. Skipping.")
162
  elif question_details.get("purpose") == "matchmaking":
163
  user_profile["answers"][question_id] = answer_value
164
  updated_fields = True
@@ -192,31 +190,79 @@ def get_matches(request: gr.Request):
192
  profiles = load_json_data(PROFILES_FILE, default_data={})
193
 
194
  requester_profile_id = None
 
195
  for pid, profile_data in profiles.items():
196
  if profile_data.get("auth_id") == auth_id_header:
197
  requester_profile_id = pid
 
198
  break
199
 
200
- if not requester_profile_id:
201
  return {"status": "error", "message": "Authentication failed: Invalid X-Auth-ID."}
202
 
203
- # Filter for potential matches: not the user themselves, and have a non-blank name.
204
- potential_matches_profiles = [
205
- profile for pid, profile in profiles.items()
206
- if pid != requester_profile_id and profile.get("name")
207
- ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
208
 
209
- # Randomly select up to 3 matches from the filtered list
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
210
  num_matches = min(len(potential_matches_profiles), 3)
211
  selected_matches = random.sample(potential_matches_profiles, k=num_matches)
212
 
 
 
 
 
213
  matches_list = []
214
  for match_profile in selected_matches:
 
 
 
 
 
215
  matches_list.append({
216
  "profile_id": match_profile.get("profile_id"),
217
  "name": match_profile.get("name"),
 
218
  "profile_summary": match_profile.get("profile_summary"),
219
- "profile_image_filename": match_profile.get("profile_image_filename")
220
  })
221
 
222
  return {
@@ -257,6 +303,16 @@ def get_profile(profile_id_to_get: str, request: gr.Request):
257
  # For security, never return the auth_id
258
  target_profile.pop("auth_id", None)
259
 
 
 
 
 
 
 
 
 
 
 
260
  cost_incurred = 0.0
261
  instructions_for_agent = f"You have retrieved the profile for {profile_id_to_get}."
262
  instructions_for_user = f"Here is the profile for {profile_id_to_get}."
@@ -385,6 +441,69 @@ def get_messages(request: gr.Request):
385
  "instructions_for_user": "Here are your messages."
386
  }
387
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
388
  def print_headers(text, request: gr.Request):
389
  """Print the headers of the request for debugging purposes."""
390
  print(f"Headers for print_headers request: {request.headers}")
@@ -405,8 +524,8 @@ headers_demo = gr.Interface(
405
  )
406
 
407
  # --- Start of New Profile Questionnaire Interface ---
408
- profile_questionnaire_demo = gr.Interface(
409
- fn=profile_questionnaire,
410
  inputs=None, # No direct input from user for this one, it's triggered by the agent
411
  outputs=gr.JSON(label="Questionnaire, IDs, and Instructions"),
412
  title="Profile Questionnaire",
@@ -467,11 +586,25 @@ get_messages_demo = gr.Interface(
467
  )
468
  # --- End of Get Messages Interface ---
469
 
 
 
 
 
 
 
 
 
 
 
470
  # Adjusted TabbedInterface to include the new tool
471
  demo = gr.TabbedInterface(
472
- [profile_questionnaire_demo, update_profile_answers_demo, get_matches_demo, get_profile_demo, send_message_demo, get_messages_demo, headers_demo],
473
- ["Profile Questionnaire", "Update Profile Answers", "Get Matches", "Get Profile", "Send Message", "Get Messages", "Headers Debug"]
474
  )
475
 
476
  if __name__ == "__main__":
477
- demo.launch(mcp_server=True)
 
 
 
 
 
64
 
65
  # --- Start of MCP Matchmaker Tools ---
66
 
67
+ def new_profile(request: gr.Request):
68
  """
69
  Generates and returns a profile questionnaire, a new public profile_id,
70
  and a new private auth_id. Also creates an initial profile stub.
 
72
  # 1. Generate profile_id and auth_id
73
  profile_id = f"user_{''.join(random.choices('abcdefghijklmnopqrstuvwxyz0123456789', k=8))}"
74
  auth_id = str(uuid.uuid4())
75
+ print(f"new_profile with Profile ID: {profile_id} and Auth ID: {auth_id}")
76
 
77
  # 2. Read questionnaire.json
78
  questionnaire_data = load_json_data(QUESTIONNAIRE_FILE, default_data={"title": "Error Loading Questionnaire", "questions": []})
 
85
  # Ensure timestamp is timezone-aware (UTC)
86
  timestamp = datetime.now(timezone.utc).isoformat()
87
 
88
+ new_profile = {
 
89
  "auth_id": auth_id,
90
  "created_at": timestamp,
91
  "updated_at": timestamp,
92
+ "profile_image_filename": "default.jpg",
 
 
93
  "answers": {}
94
  }
95
+ profiles[profile_id] = new_profile
96
  if not save_json_data(PROFILES_FILE, profiles):
97
  print(f"Critical Error: Failed to save profile for {profile_id} to {PROFILES_FILE}")
98
  # Decide how to handle this error - maybe return an error to the client?
99
 
100
  # 4. Return IDs, questionnaire data, and instructions
101
+ instructions_for_agent = "You have received a `profile_id` (public identifier for this user\'s profile) and an `auth_id` (private key for authentication for this user). Please ask the user to store both securely. The `auth_id` must be sent as an `X-Auth-ID` header in subsequent requests that require authentication for this user (e.g., `update_profile_answers`, `get_matches`, `get_messages`, `get_profile` for own profile, `send_message`). The `profile_id` is used to publicly identify this user to others (e.g., in matches, or when sending/receiving messages). You must now walk the user through the questionnaire, preferably question by question, and collect the answers (in preparation to update the user's profile using update_profile_answers). If the user provides answers that are not in the list of valid answers, please ask them to provide a valid answer."
102
+ instructions_for_user = "Your profile creation process has started! You\'ve been assigned a unique Profile ID and a secret Auth ID. Your AI agent will use these to manage your profile and interactions. Please walk through the questionnaire with your Agent, and provide your answers."
103
 
104
  return {
105
  "profile_id": profile_id,
 
152
 
153
  if question_details.get("purpose") == "metadata":
154
  field_to_map = question_details.get("maps_to_field")
155
+ if field_to_map:
156
  user_profile[field_to_map] = answer_value
157
  updated_fields = True
158
  else:
159
+ print(f"Warning: Metadata question '{question_id}' has no valid 'maps_to_field'. Skipping.")
160
  elif question_details.get("purpose") == "matchmaking":
161
  user_profile["answers"][question_id] = answer_value
162
  updated_fields = True
 
190
  profiles = load_json_data(PROFILES_FILE, default_data={})
191
 
192
  requester_profile_id = None
193
+ requester_profile = None
194
  for pid, profile_data in profiles.items():
195
  if profile_data.get("auth_id") == auth_id_header:
196
  requester_profile_id = pid
197
+ requester_profile = profile_data
198
  break
199
 
200
+ if not requester_profile:
201
  return {"status": "error", "message": "Authentication failed: Invalid X-Auth-ID."}
202
 
203
+ # Get the requester's gender and preference for matching logic
204
+ requester_gender = requester_profile.get("gender")
205
+ requester_preference = requester_profile.get("answers", {}).get("q_gender_preference")
206
+
207
+ # If the user hasn't specified their gender/preference, we can't find matches.
208
+ if not requester_gender or not requester_preference:
209
+ return {
210
+ "status": "success",
211
+ "matches": [],
212
+ "instructions_for_agent": "The user has not specified their gender and/or gender preference in their profile. Please ask them to update their profile before getting matches.",
213
+ "instructions_for_user": "Please complete your gender and preference information in your profile to get matches."
214
+ }
215
+
216
+ potential_matches_profiles = []
217
+ for pid, potential_match in profiles.items():
218
+ if pid == requester_profile_id or not potential_match.get("name"):
219
+ continue # Skip self and profiles with no name
220
+
221
+ match_gender = potential_match.get("gender")
222
+ match_preference = potential_match.get("answers", {}).get("q_gender_preference")
223
 
224
+ # Handle cases where gender/preference might not be filled out for a profile
225
+ if not match_gender or not match_preference:
226
+ continue
227
+
228
+ # Correctly map gender to preference strings
229
+ gender_map = {"Man": "Men", "Woman": "Women"}
230
+
231
+ requester_is_interested = (
232
+ requester_preference == "All" or
233
+ requester_preference == gender_map.get(match_gender)
234
+ )
235
+
236
+ # Check if the potential match is interested in the requester
237
+ match_is_interested = (
238
+ match_preference == "All" or
239
+ match_preference == gender_map.get(requester_gender)
240
+ )
241
+
242
+ if requester_is_interested and match_is_interested:
243
+ potential_matches_profiles.append(potential_match)
244
+
245
+ # From the list of potential matches, randomly select up to 3
246
  num_matches = min(len(potential_matches_profiles), 3)
247
  selected_matches = random.sample(potential_matches_profiles, k=num_matches)
248
 
249
+ # Base URL for constructing image paths. We assume http for local dev.
250
+ # A production environment would need to handle https.
251
+ base_url = f"http://{request.headers.get('host', 'localhost:7860')}"
252
+
253
  matches_list = []
254
  for match_profile in selected_matches:
255
+ image_filename = match_profile.get("profile_image_filename")
256
+ image_url = None
257
+ if image_filename:
258
+ image_url = f"{base_url}/gradio_api/file=data/profile_images/{image_filename}"
259
+
260
  matches_list.append({
261
  "profile_id": match_profile.get("profile_id"),
262
  "name": match_profile.get("name"),
263
+ "gender": match_profile.get("gender"),
264
  "profile_summary": match_profile.get("profile_summary"),
265
+ "profile_image_url": image_url
266
  })
267
 
268
  return {
 
303
  # For security, never return the auth_id
304
  target_profile.pop("auth_id", None)
305
 
306
+ # Construct and add the full image URL, then remove the old filename key
307
+ base_url = f"http://{request.headers.get('host', 'localhost:7860')}"
308
+ image_filename = target_profile.get("profile_image_filename")
309
+ image_url = None
310
+ if image_filename:
311
+ image_url = f"{base_url}/gradio_api/file=data/profile_images/{image_filename}"
312
+
313
+ target_profile['profile_image_url'] = image_url
314
+ target_profile.pop("profile_image_filename", None)
315
+
316
  cost_incurred = 0.0
317
  instructions_for_agent = f"You have retrieved the profile for {profile_id_to_get}."
318
  instructions_for_user = f"Here is the profile for {profile_id_to_get}."
 
441
  "instructions_for_user": "Here are your messages."
442
  }
443
 
444
+ def upload_profile_picture(image_upload, request: gr.Request):
445
+ """
446
+ Uploads a profile picture for the authenticated user.
447
+ The new filename will be based on the user's profile_id.
448
+ Requires X-Auth-ID header for authentication.
449
+ """
450
+ auth_id_header = request.headers.get("x-auth-id")
451
+ if not auth_id_header:
452
+ return {"status": "error", "message": "Authentication failed: X-Auth-ID header is missing."}
453
+
454
+ if image_upload is None:
455
+ return {"status": "error", "message": "No image file provided."}
456
+
457
+ profiles = load_json_data(PROFILES_FILE, default_data={})
458
+
459
+ user_profile = None
460
+ target_profile_id = None
461
+ for pid, profile_data in profiles.items():
462
+ if profile_data.get("auth_id") == auth_id_header:
463
+ user_profile = profile_data
464
+ target_profile_id = pid
465
+ break
466
+
467
+ if not user_profile:
468
+ return {"status": "error", "message": "Authentication failed: Invalid X-Auth-ID."}
469
+
470
+ # The 'image_upload' from gr.Image is a temporary file path
471
+ temp_path = image_upload
472
+
473
+ # Get the file extension
474
+ file_ext = os.path.splitext(temp_path)[1]
475
+ if not file_ext:
476
+ file_ext = ".png" # Default to png if no extension
477
+
478
+ # Create a new unique filename based on the user's profile_id
479
+ new_filename = f"{target_profile_id}{file_ext}"
480
+
481
+ # Construct the destination path
482
+ base_dir = os.path.dirname(os.path.abspath(__file__))
483
+ destination_path = os.path.join(base_dir, "data", "profile_images", new_filename)
484
+
485
+ try:
486
+ # Copy the uploaded file to its new permanent location
487
+ os.rename(temp_path, destination_path)
488
+ except Exception as e:
489
+ return {"status": "error", "message": f"Failed to save image file: {e}"}
490
+
491
+ # Update the profile with the new filename
492
+ user_profile["profile_image_filename"] = new_filename
493
+ user_profile["updated_at"] = datetime.now(timezone.utc).isoformat()
494
+ profiles[target_profile_id] = user_profile
495
+
496
+ if not save_json_data(PROFILES_FILE, profiles):
497
+ return {"status": "error", "message": "Failed to update profile with new image filename."}
498
+
499
+ image_url = f"http://{request.headers.get('host', 'localhost:7860')}/gradio_api/file=data/profile_images/{new_filename}"
500
+
501
+ return {
502
+ "status": "success",
503
+ "message": "Profile picture updated successfully.",
504
+ "new_image_url": image_url
505
+ }
506
+
507
  def print_headers(text, request: gr.Request):
508
  """Print the headers of the request for debugging purposes."""
509
  print(f"Headers for print_headers request: {request.headers}")
 
524
  )
525
 
526
  # --- Start of New Profile Questionnaire Interface ---
527
+ new_profile_demo = gr.Interface(
528
+ fn=new_profile,
529
  inputs=None, # No direct input from user for this one, it's triggered by the agent
530
  outputs=gr.JSON(label="Questionnaire, IDs, and Instructions"),
531
  title="Profile Questionnaire",
 
586
  )
587
  # --- End of Get Messages Interface ---
588
 
589
+ # --- Start of Upload Profile Picture Interface ---
590
+ upload_profile_picture_demo = gr.Interface(
591
+ fn=upload_profile_picture,
592
+ inputs=[gr.Image(type="filepath", label="Upload Profile Picture")],
593
+ outputs=gr.JSON(label="Upload Status"),
594
+ title="Upload Profile Picture",
595
+ description="Uploads a profile picture for the authenticated user. Requires X-Auth-ID header."
596
+ )
597
+ # --- End of Upload Profile Picture Interface ---
598
+
599
  # Adjusted TabbedInterface to include the new tool
600
  demo = gr.TabbedInterface(
601
+ [new_profile_demo, update_profile_answers_demo, get_matches_demo, get_profile_demo, send_message_demo, get_messages_demo, upload_profile_picture_demo, headers_demo],
602
+ ["New Profile", "Update Profile Answers", "Get Matches", "Get Profile", "Send Message", "Get Messages", "Upload Profile Picture", "Headers Debug"]
603
  )
604
 
605
  if __name__ == "__main__":
606
+ # Construct the absolute path to the allowed directory, relative to this script's location
607
+ base_dir = os.path.dirname(os.path.abspath(__file__))
608
+ allowed_images_path = os.path.join(base_dir, "data", "profile_images")
609
+
610
+ demo.launch(mcp_server=True, allowed_paths=[allowed_images_path])
data/profile_images/default.jpg ADDED
data/profiles.json CHANGED
@@ -15,12 +15,14 @@
15
  "created_at": "2025-06-05T16:49:53.871722+00:00",
16
  "updated_at": "2025-06-05T17:00:46.839293+00:00",
17
  "name": "User",
18
- "profile_image_filename": "placeholder.png",
19
  "profile_summary": "I am very cool, please date me.",
 
20
  "answers": {
21
  "q_hobby": "My main hobby is coding.",
22
  "q_looking_for": "I'm looking for someone who is as cool as me.",
23
- "q_vibe": "My general vibe is... coding."
 
24
  }
25
  },
26
  "user_h7bafk3d": {
@@ -29,12 +31,14 @@
29
  "created_at": "2025-06-05T17:10:00.000000+00:00",
30
  "updated_at": "2025-06-05T17:10:00.000000+00:00",
31
  "name": "Alex",
32
- "profile_image_filename": "placeholder.png",
 
33
  "profile_summary": "Loves hiking and exploring new cafes.",
34
  "answers": {
35
  "q_hobby": "Hiking, photography, trying new recipes.",
36
  "q_looking_for": "Someone adventurous and kind.",
37
- "q_vibe": "Outdoorsy and creative."
 
38
  }
39
  },
40
  "user_p9zqwxv8": {
@@ -43,12 +47,14 @@
43
  "created_at": "2025-06-05T17:11:00.000000+00:00",
44
  "updated_at": "2025-06-05T17:11:00.000000+00:00",
45
  "name": "Bella",
46
- "profile_image_filename": "placeholder.png",
 
47
  "profile_summary": "Bookworm, artist, and enjoys quiet nights in.",
48
  "answers": {
49
  "q_hobby": "Reading, painting, watching classic movies.",
50
  "q_looking_for": "A thoughtful person to share deep conversations with.",
51
- "q_vibe": "Cozy and artistic."
 
52
  }
53
  },
54
  "user_t2ysgmnp": {
@@ -57,12 +63,14 @@
57
  "created_at": "2025-06-05T17:12:00.000000+00:00",
58
  "updated_at": "2025-06-05T17:12:00.000000+00:00",
59
  "name": "Charlie",
60
- "profile_image_filename": "placeholder.png",
 
61
  "profile_summary": "Tech enthusiast and loves a good board game.",
62
  "answers": {
63
  "q_hobby": "Building PCs, board games, sci-fi novels.",
64
  "q_looking_for": "A partner-in-crime for game nights and tech talks.",
65
- "q_vibe": "Geeky and friendly."
 
66
  }
67
  },
68
  "user_gq61ow1v": {
@@ -81,7 +89,7 @@
81
  "created_at": "2025-06-06T07:00:38.209630+00:00",
82
  "updated_at": "2025-06-06T07:04:31.734665+00:00",
83
  "name": "Chris",
84
- "profile_image_filename": "placeholder.png",
85
  "profile_summary": "I am a fun guy.",
86
  "answers": {
87
  "q_hobby": "I like to play video games.",
@@ -108,5 +116,21 @@
108
  "profile_image_filename": null,
109
  "profile_summary": "",
110
  "answers": {}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
  }
112
  }
 
15
  "created_at": "2025-06-05T16:49:53.871722+00:00",
16
  "updated_at": "2025-06-05T17:00:46.839293+00:00",
17
  "name": "User",
18
+ "profile_image_filename": "default.jpg",
19
  "profile_summary": "I am very cool, please date me.",
20
+ "gender": "Man",
21
  "answers": {
22
  "q_hobby": "My main hobby is coding.",
23
  "q_looking_for": "I'm looking for someone who is as cool as me.",
24
+ "q_vibe": "My general vibe is... coding.",
25
+ "q_gender_preference": "Women"
26
  }
27
  },
28
  "user_h7bafk3d": {
 
31
  "created_at": "2025-06-05T17:10:00.000000+00:00",
32
  "updated_at": "2025-06-05T17:10:00.000000+00:00",
33
  "name": "Alex",
34
+ "gender": "Non-binary",
35
+ "profile_image_filename": "default.jpg",
36
  "profile_summary": "Loves hiking and exploring new cafes.",
37
  "answers": {
38
  "q_hobby": "Hiking, photography, trying new recipes.",
39
  "q_looking_for": "Someone adventurous and kind.",
40
+ "q_vibe": "Outdoorsy and creative.",
41
+ "q_gender_preference": "All"
42
  }
43
  },
44
  "user_p9zqwxv8": {
 
47
  "created_at": "2025-06-05T17:11:00.000000+00:00",
48
  "updated_at": "2025-06-05T17:11:00.000000+00:00",
49
  "name": "Bella",
50
+ "gender": "Woman",
51
+ "profile_image_filename": "default.jpg",
52
  "profile_summary": "Bookworm, artist, and enjoys quiet nights in.",
53
  "answers": {
54
  "q_hobby": "Reading, painting, watching classic movies.",
55
  "q_looking_for": "A thoughtful person to share deep conversations with.",
56
+ "q_vibe": "Cozy and artistic.",
57
+ "q_gender_preference": "Men"
58
  }
59
  },
60
  "user_t2ysgmnp": {
 
63
  "created_at": "2025-06-05T17:12:00.000000+00:00",
64
  "updated_at": "2025-06-05T17:12:00.000000+00:00",
65
  "name": "Charlie",
66
+ "gender": "Man",
67
+ "profile_image_filename": "default.jpg",
68
  "profile_summary": "Tech enthusiast and loves a good board game.",
69
  "answers": {
70
  "q_hobby": "Building PCs, board games, sci-fi novels.",
71
  "q_looking_for": "A partner-in-crime for game nights and tech talks.",
72
+ "q_vibe": "Geeky and friendly.",
73
+ "q_gender_preference": "All"
74
  }
75
  },
76
  "user_gq61ow1v": {
 
89
  "created_at": "2025-06-06T07:00:38.209630+00:00",
90
  "updated_at": "2025-06-06T07:04:31.734665+00:00",
91
  "name": "Chris",
92
+ "profile_image_filename": "default.jpg",
93
  "profile_summary": "I am a fun guy.",
94
  "answers": {
95
  "q_hobby": "I like to play video games.",
 
116
  "profile_image_filename": null,
117
  "profile_summary": "",
118
  "answers": {}
119
+ },
120
+ "user_aki9die1": {
121
+ "profile_id": "user_aki9die1",
122
+ "auth_id": "ef896a9c-01dd-4113-b996-820fd4919c17",
123
+ "created_at": "2025-06-06T08:08:36.438861+00:00",
124
+ "updated_at": "2025-06-06T08:27:00.737853+00:00",
125
+ "name": "Bob",
126
+ "gender": "Man",
127
+ "profile_image_filename": "default.jpg",
128
+ "profile_summary": "Bob is a builder",
129
+ "answers": {
130
+ "q_hobby": "Building things.",
131
+ "q_looking_for": "Someone who also likes to build things.",
132
+ "q_vibe": "Intellectual",
133
+ "q_gender_preference": "Women"
134
+ }
135
  }
136
  }
data/questionnaire.json CHANGED
@@ -2,10 +2,16 @@
2
  "title": "MCP Matchmaker Profile Questionnaire",
3
  "questions": [
4
  { "id": "q_name", "text": "What is your name?", "type": "text", "purpose": "metadata", "maps_to_field": "name" },
5
- { "id": "q_profile_image_filename", "text": "Enter the filename for your profile picture (e.g., my_image.jpg):", "type": "text", "purpose": "metadata", "maps_to_field": "profile_image_filename" },
 
6
  { "id": "q_profile_summary", "text": "Write a brief introduction for your profile (1-2 sentences):", "type": "text", "purpose": "metadata", "maps_to_field": "profile_summary" },
7
  { "id": "q_hobby", "text": "What are your main hobbies or interests?", "type": "text", "purpose": "matchmaking" },
8
  { "id": "q_looking_for", "text": "What are you looking for in a match?", "type": "long_text", "purpose": "matchmaking" },
9
- { "id": "q_vibe", "text": "Describe your general vibe (e.g., adventurous, homebody, intellectual)?", "type": "text", "purpose": "matchmaking" }
 
 
 
 
 
10
  ]
11
  }
 
2
  "title": "MCP Matchmaker Profile Questionnaire",
3
  "questions": [
4
  { "id": "q_name", "text": "What is your name?", "type": "text", "purpose": "metadata", "maps_to_field": "name" },
5
+ { "id": "q_gender", "text": "What is your gender? Please choose one from: Man, Woman, Non-binary", "type": "text", "purpose": "metadata", "maps_to_field": "gender" },
6
+ { "id": "q_gender_preference", "text": "What gender are you interested in matching with? Please choose one from: Men, Women, All", "type": "text", "purpose": "matchmaking" },
7
  { "id": "q_profile_summary", "text": "Write a brief introduction for your profile (1-2 sentences):", "type": "text", "purpose": "metadata", "maps_to_field": "profile_summary" },
8
  { "id": "q_hobby", "text": "What are your main hobbies or interests?", "type": "text", "purpose": "matchmaking" },
9
  { "id": "q_looking_for", "text": "What are you looking for in a match?", "type": "long_text", "purpose": "matchmaking" },
10
+ { "id": "q_vibe", "text": "Describe your general vibe (e.g., adventurous, homebody, intellectual)?", "type": "text", "purpose": "matchmaking" },
11
+ {
12
+ "id": "q_instruct_upload",
13
+ "question_text": "Your profile has been updated. Would you like to upload a profile picture now? If so, you can use the 'upload_profile_picture' tool. Otherwise, you can do this later.",
14
+ "type": "instruction"
15
+ }
16
  ]
17
  }