feat: Add FaceAI integration with handoff and return functionality
- Introduced a new workspace for FaceAI in package.json. - Implemented FaceAI handoff logic in faceai_handoff.php, including identity verification and token signing. - Created faceai_return.php to handle return requests from FaceAI, validating tokens and forwarding results. - Developed faceai_simulator.php and faceai_simulator_view.php for simulating the FaceAI interface with demo photos. - Enhanced rus-ecom-240621.js to support new FaceAI features, including dynamic URL building and button integration. - Added faceai_config.php for configuration management, including environment variable handling and utility functions. - Updated HTML structure and styles in simulator view for better user experience.
This commit is contained in:
parent
f65a85dcc9
commit
da362c201f
31 changed files with 4511 additions and 60 deletions
110
faceai/apps/backend/src/store.js
Normal file
110
faceai/apps/backend/src/store.js
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
import { randomId } from './auth.js';
|
||||
|
||||
export const mockCatalog = {
|
||||
'101': {
|
||||
id: '101',
|
||||
slug: 'mezza-di-firenze',
|
||||
name: 'Mezza di Firenze',
|
||||
photos: [
|
||||
{ id: 'f101-001', label: 'Arrivo 001', bib: '245', checkpoint: 'Arrivo', thumb: 'thumb-arrivo-001.jpg' },
|
||||
{ id: 'f101-002', label: 'Arrivo 002', bib: '245', checkpoint: 'Arrivo', thumb: 'thumb-arrivo-002.jpg' },
|
||||
{ id: 'f101-003', label: 'Ponte 003', bib: '245', checkpoint: 'Ponte', thumb: 'thumb-ponte-003.jpg' },
|
||||
{ id: 'f101-004', label: 'Centro 004', bib: '245', checkpoint: 'Centro', thumb: 'thumb-centro-004.jpg' },
|
||||
{ id: 'f101-005', label: 'Centro 005', bib: '812', checkpoint: 'Centro', thumb: 'thumb-centro-005.jpg' },
|
||||
{ id: 'f101-006', label: 'Arrivo 006', bib: '812', checkpoint: 'Arrivo', thumb: 'thumb-arrivo-006.jpg' },
|
||||
{ id: 'f101-007', label: 'Ponte 007', bib: '391', checkpoint: 'Ponte', thumb: 'thumb-ponte-007.jpg' },
|
||||
{ id: 'f101-008', label: 'Centro 008', bib: '391', checkpoint: 'Centro', thumb: 'thumb-centro-008.jpg' },
|
||||
{ id: 'f101-009', label: 'Arrivo 009', bib: '128', checkpoint: 'Arrivo', thumb: 'thumb-arrivo-009.jpg' },
|
||||
{ id: 'f101-010', label: 'Lungarno 010', bib: '128', checkpoint: 'Lungarno', thumb: 'thumb-lungarno-010.jpg' },
|
||||
{ id: 'f101-011', label: 'Piazza 011', bib: '560', checkpoint: 'Piazza', thumb: 'thumb-piazza-011.jpg' },
|
||||
{ id: 'f101-012', label: 'Arrivo 012', bib: '560', checkpoint: 'Arrivo', thumb: 'thumb-arrivo-012.jpg' }
|
||||
]
|
||||
},
|
||||
'202': {
|
||||
id: '202',
|
||||
slug: 'trail-del-chianti',
|
||||
name: 'Trail del Chianti',
|
||||
photos: [
|
||||
{ id: 'f202-001', label: 'Bosco 001', bib: '77', checkpoint: 'Bosco', thumb: 'thumb-bosco-001.jpg' },
|
||||
{ id: 'f202-002', label: 'Salita 002', bib: '77', checkpoint: 'Salita', thumb: 'thumb-salita-002.jpg' },
|
||||
{ id: 'f202-003', label: 'Arrivo 003', bib: '77', checkpoint: 'Arrivo', thumb: 'thumb-arrivo-003.jpg' },
|
||||
{ id: 'f202-004', label: 'Bosco 004', bib: '19', checkpoint: 'Bosco', thumb: 'thumb-bosco-004.jpg' }
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
const sessions = new Map();
|
||||
const searches = new Map();
|
||||
const results = new Map();
|
||||
|
||||
export function createSession(session) {
|
||||
const sessionId = randomId('sess');
|
||||
sessions.set(sessionId, {
|
||||
...session,
|
||||
createdAt: Date.now()
|
||||
});
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
export function getSession(sessionId) {
|
||||
return sessions.get(sessionId) || null;
|
||||
}
|
||||
|
||||
export function createSearch({ raceId, user, selfieName, returnUrl, lang }) {
|
||||
const searchId = randomId('search');
|
||||
searches.set(searchId, {
|
||||
id: searchId,
|
||||
raceId,
|
||||
user,
|
||||
selfieName,
|
||||
returnUrl,
|
||||
lang,
|
||||
status: 'processing',
|
||||
createdAt: Date.now(),
|
||||
completedAt: null,
|
||||
resultId: null,
|
||||
matches: []
|
||||
});
|
||||
return searches.get(searchId);
|
||||
}
|
||||
|
||||
export function getSearch(searchId) {
|
||||
return searches.get(searchId) || null;
|
||||
}
|
||||
|
||||
export function completeSearch(searchId) {
|
||||
const search = searches.get(searchId);
|
||||
if (!search) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const race = mockCatalog[search.raceId];
|
||||
const matches = (race?.photos || []).slice(0, Math.min(4, race?.photos?.length || 0));
|
||||
const resultId = randomId('result');
|
||||
|
||||
results.set(resultId, {
|
||||
id: resultId,
|
||||
raceId: search.raceId,
|
||||
raceName: race?.name || search.raceId,
|
||||
userId: search.user.id,
|
||||
returnUrl: search.returnUrl,
|
||||
lang: search.lang,
|
||||
matches,
|
||||
createdAt: Date.now()
|
||||
});
|
||||
|
||||
const completed = {
|
||||
...search,
|
||||
status: 'completed',
|
||||
completedAt: Date.now(),
|
||||
resultId,
|
||||
matches
|
||||
};
|
||||
|
||||
searches.set(searchId, completed);
|
||||
return completed;
|
||||
}
|
||||
|
||||
export function getResult(resultId) {
|
||||
return results.get(resultId) || null;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue