Update AI planner integration, docs, and config

This commit is contained in:
周瑞哲
2026-07-30 16:33:39 +08:00
parent 33c14eec86
commit ac4179086c
13 changed files with 192 additions and 29 deletions
+72
View File
@@ -4,6 +4,7 @@ import {
adjustLocalPlan,
classifyDurationFit,
createLocalPlan,
createRecommendedPlan,
hasSignificantDurationGap,
LEGACY_PLACE_ID_TO_POI_ID,
normalizePlanningRequest,
@@ -17,10 +18,13 @@ import {
import {
createPlan,
loadPlan,
loadPlanningRequest,
loadPreferences,
PLAN_STORAGE_KEY,
PLANNING_REQUEST_STORAGE_KEY,
PREFERENCES_STORAGE_KEY,
savePlan,
savePlanningRequest,
savePreferences,
} from '../src/services/travel-assistant'
@@ -354,6 +358,56 @@ describe('deterministic local POC planner', () => {
})
})
describe('reviewed AI recommendations', () => {
const repository = getPoiRepository()
const selectedPoiIds = repository.getPublishedPois().slice(0, 3).map(poi => poi.id)
const request: PlanningRequest = {
mode: 'custom',
preferences: preferences(),
durationMinutes: 120,
selectedPoiIds,
origin: { longitude: 113.94, latitude: 22.76, coordinateSystem: 'GCJ02' },
}
const recommendations = selectedPoiIds.map((poiId, index) => ({
poiId,
reason: `AI 白名单推荐理由 ${index + 1}`,
}))
it('keeps all custom POIs, AI reasons and local-only location data', () => {
const plan = createRecommendedPlan(request, recommendations, repository, '真实模型推荐完成', 'remote_ai')
expect(plan.source).toBe('remote_ai')
expect(new Set(plan.itinerary.items.map(item => item.placeId))).toEqual(new Set(selectedPoiIds))
expect(plan.itinerary.items.every(item => item.reason.includes('AI 白名单推荐理由'))).toBe(true)
expect(plan.itinerary.durationFitStatus).toBe('overflow')
expect(JSON.stringify(plan)).not.toContain('113.94')
expect(JSON.stringify(plan)).not.toContain('22.76')
})
it('uses current location to optimize a quick AI recommendation and still returns an overflow route', () => {
const quickRequest: PlanningRequest = {
...request,
mode: 'quick',
selectedPoiIds: [],
durationMinutes: 120,
origin: { longitude: 0, latitude: 0, coordinateSystem: 'GCJ02' },
}
const plan = createRecommendedPlan(quickRequest, recommendations, repository, '推荐完成', 'remote_ai')
expect(plan.itinerary.items).toHaveLength(1)
expect(plan.itinerary.durationFitStatus).toBe('overflow')
expect(plan.itinerary.startsFromCurrentLocation).toBe(true)
})
it('labels mock recommendations honestly and rejects an incomplete custom set', () => {
const mockPlan = createRecommendedPlan(request, recommendations, repository, '演示推荐完成', 'remote_mock')
expect(mockPlan.source).toBe('remote_mock')
expect(mockPlan.itinerary.title).not.toContain('AI')
expect(() => createRecommendedPlan(request, recommendations.slice(0, 2), repository, '', 'remote_ai'))
.toThrow('未完整保留')
})
})
describe('travel storage', () => {
const values = new Map<string, unknown>()
@@ -382,6 +436,24 @@ describe('travel storage', () => {
expect(values.has(PLAN_STORAGE_KEY)).toBe(true)
})
it('round-trips custom planning inputs without persisting an exact origin', () => {
const selectedPoiIds = getPoiRepository().getPublishedPois().slice(0, 4).map(poi => poi.id)
const request: PlanningRequest = {
mode: 'custom',
preferences: preferences(),
durationMinutes: 330,
selectedPoiIds,
origin: { longitude: 113.94, latitude: 22.76, coordinateSystem: 'GCJ02' },
}
savePlanningRequest(request)
const loaded = loadPlanningRequest()!
expect(loaded).toEqual({ ...request, origin: undefined })
expect(loaded).not.toHaveProperty('origin')
expect(JSON.stringify(values.get(PLANNING_REQUEST_STORAGE_KEY))).not.toContain('113.94')
expect(JSON.stringify(values.get(PLANNING_REQUEST_STORAGE_KEY))).not.toContain('22.76')
})
it('never persists planning-origin coordinates with a plan', () => {
const sourcePlan = createLocalPlan(
preferences(),