Skip to content

Commit f5e16f6

Browse files
committed
Refine LLM profile extraction: validate pref_age_min/pref_age_max ranges, ensure logical consistency, remove null/undefined properties, adjust cache debug logging, and improve field descriptions.
1 parent f3882f9 commit f5e16f6

4 files changed

Lines changed: 45 additions & 10 deletions

File tree

‎android/app/build.gradle‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ android {
1111
applicationId "com.compassconnections.app"
1212
minSdkVersion rootProject.ext.minSdkVersion
1313
targetSdkVersion rootProject.ext.targetSdkVersion
14-
versionCode 87
14+
versionCode 88
1515
versionName "1.19.0"
1616
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
1717
aaptOptions {

‎backend/api/package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@compass/api",
3-
"version": "1.34.0",
3+
"version": "1.34.1",
44
"private": true,
55
"description": "Backend API endpoints",
66
"main": "src/serve.ts",

‎backend/api/src/llm-extract-profile.ts‎

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,9 @@ async function validateProfileFields(
5757
llmProfile: Partial<ProfileWithoutUser>,
5858
validChoices: Record<string, string[]>,
5959
): Promise<Partial<ProfileWithoutUser>> {
60-
const result: Partial<Record<keyof ProfileWithoutUser, any>> = {...llmProfile}
60+
const result: Partial<Record<keyof ProfileWithoutUser, any>> = {
61+
...removeNullOrUndefinedProps(llmProfile),
62+
}
6163

6264
const toArray: (keyof ProfileWithoutUser)[] = [
6365
'diet',
@@ -188,6 +190,35 @@ async function validateProfileFields(
188190
)
189191
}
190192

193+
// Validate age preferences
194+
if (result.pref_age_min !== undefined) {
195+
if (
196+
!Number.isFinite(result.pref_age_min) ||
197+
result.pref_age_min < 18 ||
198+
result.pref_age_min > 100
199+
) {
200+
result.pref_age_min = undefined
201+
}
202+
}
203+
204+
if (result.pref_age_max !== undefined) {
205+
if (
206+
!Number.isFinite(result.pref_age_max) ||
207+
result.pref_age_max < 18 ||
208+
result.pref_age_max > 100
209+
) {
210+
result.pref_age_max = undefined
211+
}
212+
}
213+
214+
// Ensure pref_age_max > pref_age_min when both are defined
215+
if (result.pref_age_min !== undefined && result.pref_age_max !== undefined) {
216+
if (result.pref_age_max <= result.pref_age_min) {
217+
result.pref_age_max = undefined
218+
result.pref_age_min = undefined
219+
}
220+
}
221+
191222
return result
192223
}
193224

@@ -215,7 +246,7 @@ async function setCachedResult(cacheKey: string, result: any): Promise<void> {
215246
await fs.mkdir(CACHE_DIR, {recursive: true})
216247
const cacheFile = join(CACHE_DIR, `${cacheKey}.json`)
217248
await fs.writeFile(cacheFile, JSON.stringify(result), 'utf-8')
218-
debug('Cached LLM result', {cacheKey: cacheKey.substring(0, 8)})
249+
debug('Cached LLM result', {cacheKey: cacheKey.substring(0, 8), result})
219250
} catch (error) {
220251
log('Failed to write cache', {cacheKey, error})
221252
// Don't throw - caching failure shouldn't break the main flow
@@ -307,6 +338,7 @@ async function callGemini(text: string) {
307338
]
308339

309340
for (const model of models) {
341+
debug(`Calling Gemini ${model}...`)
310342
const response = await fetch(
311343
`https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${apiKey}`,
312344
{
@@ -423,7 +455,7 @@ export async function callLLM(
423455

424456
const PROFILE_FIELDS: Partial<Record<keyof ProfileWithoutUser, any>> = {
425457
// Basic info
426-
age: 'Number. Age in years.',
458+
age: 'Number. Age in years (between 18 and 100).',
427459
gender: `String. One of: ${validChoices.pref_gender?.join(', ')}. If multiple mentioned, use the most likely one. Infer if you have enough evidence`,
428460
height_in_inches: 'Number. Height converted to inches.',
429461
city: 'String. Current city of residence (English spelling).',
@@ -475,8 +507,10 @@ export async function callLLM(
475507
'String. Free-form elaboration on political views, only if explicitly stated.',
476508

477509
// Preferences
478-
pref_age_min: 'Number. Minimum preferred age of match.',
479-
pref_age_max: 'Number. Maximum preferred age of match.',
510+
pref_age_min:
511+
'Number. Minimum preferred age of match (higher than 18, only if mentioned, do NOT infer).',
512+
pref_age_max:
513+
'Number. Maximum preferred age of match (lower than 100, only if mentioned, do NOT infer).',
480514
pref_gender: `Array. Any of: ${validChoices.pref_gender?.join(', ')}`,
481515
pref_relation_styles: `Array. Any of: ${validChoices.pref_relation_styles?.join(', ')}`,
482516
pref_romantic_styles: `Array. Any of: ${validChoices.pref_romantic_styles?.join(', ')}`,
@@ -520,6 +554,7 @@ TEXT TO ANALYZE:
520554
debug({text})
521555

522556
const outputText = await callGemini(text)
557+
// const outputText = {pref_age_min: 0, pref_age_max: 120}
523558

524559
if (!outputText) {
525560
throw APIErrors.internalServerError('Failed to parse LLM response')

‎backend/shared/src/parse.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -523,9 +523,9 @@ function cleanHref(href: string): string {
523523

524524
export function extractGoogleDocId(url: string) {
525525
const patterns = [
526-
/\/document\/d\/([a-zA-Z0-9-_]+)/, // standard /d/{id}/ format
527-
/id=([a-zA-Z0-9-_]+)/, // ?id= query param format
528-
/^([a-zA-Z0-9-_]+)$/, // raw ID passed directly
526+
/\/document\/d\/([a-zA-Z0-9-_]+)\/edit/, // standard /d/{id}/edit format
527+
// /id=([a-zA-Z0-9-_]+)/, // ?id= query param format (catches false negatives)
528+
// /^([a-zA-Z0-9-_]+)$/, // raw ID passed directly (catches false negatives)
529529
]
530530

531531
for (const pattern of patterns) {

0 commit comments

Comments
 (0)