updates on the issue and the another thing updates on the ai optimization

This commit is contained in:
2026-09-23 11:58:24 +05:30
parent c6dfa3cb8f
commit 7544a07066
17 changed files with 622 additions and 104 deletions

View File

@@ -74,7 +74,14 @@ export const answerFlowStep = async (steps, flow, raw, option) => {
let value = raw;
if (s.resolve) {
const resolved = await s.resolve(raw);
// `option` as well as `raw`, so a step whose UI already resolved the
// answer can say so. The address step picks a place from a suggestion
// list that has already returned coordinates — re-geocoding the label it
// just handed us is a round trip that can also come back with a DIFFERENT
// place than the one the operator chose.
//
// Every existing resolve ignores the second argument, so this is additive.
const resolved = await s.resolve(raw, option);
if (resolved.error) return { flow, step: s, ask: resolved.error, done: false, retry: true };
value = resolved.value;
}

View File

@@ -2090,6 +2090,30 @@ const INTENTS = [
const INTENTS_BY_ID = Object.fromEntries(INTENTS.map((i) => [i.id, i]));
// Which intent the ordered catalog reaches for a question, WITHOUT running it.
//
// Exported for the page-suggestion test. The catalog is ordered and the first
// match wins, so "something matches this chip" and "the right thing matches
// this chip" are different questions — ROADMAP.md B1/B2 are two shipped cases
// where they had different answers.
//
// Covers the deterministic pass only. answerQuestion tries semantic routing
// and the multi-part splitter ahead of this, both of which are additive: they
// can route a question the catalog would miss, never away from one it hits.
export const resolveIntentId = (text) => {
const normalized = correctTypos(text);
for (const intent of INTENTS) {
let params = null;
try {
params = intent.match(normalized);
} catch {
params = null;
}
if (params) return intent.id;
}
return null;
};
export const SUPPORTED_QUESTIONS = INTENTS.map((i) => i.label);
// Clean, directly-askable example phrasings — for "recommended question"

View File

@@ -127,26 +127,60 @@ export const ORDER_STEPS = [
},
{
id: 'deliveryaddress',
type: 'text',
ask: 'Where is it being delivered? Give the full address.',
// `address` renders a real search field with live suggestions instead of
// leaving the operator to type a full address into the chat box and hope
// the geocoder finds it. Typing still works — the resolve below falls back
// to geocoding free text — so this step degrades to its old behaviour
// wherever the field is not rendered.
type: 'address',
ask: 'Where is it being delivered? Start typing the area, street or pincode.',
// Geocoded on the way in: the dispatch optimiser routes on coordinates, so
// an address that can't be located is refused here rather than becoming a
// booking nothing can dispatch.
resolve: async (t) => {
const place = await geocodeAddress(String(t).trim()).catch(() => null);
resolve: async (t, option) => {
// A place picked from the suggestion list is already resolved, with the
// coordinates the operator actually chose. Geocoding its label again
// can return a different place entirely.
const place = option?.place || (await geocodeAddress(String(t).trim()).catch(() => null));
if (!place) return { error: 'I couldn’t find that address. Try adding the area or pincode.' };
const parts = { deliveryaddress: place.formatted_address || String(t).trim() };
(place.address_components || []).forEach((c) => {
if ((c.types || []).includes('locality')) parts.deliverycity = c.long_name;
if ((c.types || []).includes('postal_code')) parts.deliverypincode = c.long_name;
});
return {
value: {
...parts,
deliverylatitude: place.geometry?.location?.lat?.(),
deliverylongitude: place.geometry?.location?.lng?.()
}
};
// geocodingService.standardizePlace returns a FLAT place — formatted_address,
// city, postcode, latitude, longitude. This used to read Google's raw
// shape instead (`address_components`, `geometry.location.lat()`), and
// neither exists on what geocodeAddress actually returns: the forEach
// never ran and both coordinates came back undefined. Every order created
// through this flow was therefore missing its delivery coordinates — the
// exact thing the comment above says the optimiser routes on — and the
// pincode step below fired every time because nothing ever set it.
//
// The Google shape is still read as a fallback so a caller that hands in
// a raw Places result keeps working.
const num = (v) => (Number.isFinite(Number(v)) ? Number(v) : undefined);
let lat = num(place.latitude);
let lng = num(place.longitude);
let city = place.city || '';
let pincode = place.postcode || '';
if (lat === undefined && place.geometry?.location) {
const loc = place.geometry.location;
lat = num(typeof loc.lat === 'function' ? loc.lat() : loc.lat);
lng = num(typeof loc.lng === 'function' ? loc.lng() : loc.lng);
}
if (!city || !pincode) {
(place.address_components || []).forEach((c) => {
if (!city && (c.types || []).includes('locality')) city = c.long_name;
if (!pincode && (c.types || []).includes('postal_code')) pincode = c.long_name;
});
}
const value = { deliveryaddress: place.formatted_address || place.name || String(t).trim() };
if (city) value.deliverycity = city;
if (pincode) value.deliverypincode = pincode;
if (lat !== undefined && lng !== undefined) {
value.deliverylatitude = lat;
value.deliverylongitude = lng;
}
return { value };
},
apply: (d, v) => ({ ...d, ...v })
},