Это еще один bash
& amp; python
гибридный ответ. Я опубликовал этот ответ, потому что хотел обработать более сложный вывод JSON, но, уменьшив сложность моего приложения bash. Я хочу открыть следующий объект JSON из http://www.arcgis.com/sharing/rest/info?f=json в bash
:
{
"owningSystemUrl": "http://www.arcgis.com",
"authInfo": {
"tokenServicesUrl": "https://www.arcgis.com/sharing/rest/generateToken",
"isTokenBasedSecurity": true
}
}
Несмотря на то, что этот подход увеличивает сложность функции Python, использование bash упрощается:
function jsonGet {
python -c 'import json,sys
o=json.load(sys.stdin)
k="'$1'"
if k != "":
for a in k.split("."):
if isinstance(o, dict):
o=o[a] if a in o else ""
elif isinstance(o, list):
if a == "length":
o=str(len(o))
elif a == "join":
o=",".join(o)
else:
o=o[int(a)]
else:
o=""
if isinstance(o, str) or isinstance(o, unicode):
print o
else:
print json.dumps(o)
'
}
curl -s http://www.arcgis.com/sharing/rest/info?f=json | jsonGet
curl -s http://www.arcgis.com/sharing/rest/info?f=json | jsonGet authInfo
curl -s http://www.arcgis.com/sharing/rest/info?f=json | jsonGet authInfo.tokenServicesUrl
Вывод вышеупомянутого скрипта:
Я добавил поддержку массивов, поэтому вы можете использовать .length
, и если источник представляет собой строковый массив, вы можете использовать .join
:
curl -s http://www.arcgis.com/sharing/rest/portals/self?f=pjson | jsonGet defaultBasemap.baseMapLayers.length
curl -s http://www.arcgis.com/sharing/rest/portals/self?f=pjson | jsonGet defaultBasemap.baseMapLayers.0.resourceInfo.tileInfo.lods
curl -s http://www.arcgis.com/sharing/rest/portals/self?f=pjson | jsonGet defaultBasemap.baseMapLayers.0.resourceInfo.tileInfo.lods.length
curl -s http://www.arcgis.com/sharing/rest/portals/self?f=pjson | jsonGet defaultBasemap.baseMapLayers.0.resourceInfo.tileInfo.lods.23
Какие выходы:
Вам необходимо предоставить специальный валидатор, если вы хотите захватить местоположение пользователя с помощью быстрого ответа о местоположении Facebook Messenger в текстовом или вложенном приглашении - я бы рекомендовал использовать текстовое приглашение.
Конструктор
Создайте свой водопад и добавьте свои подсказки в стек диалогов в вашем конструкторе. Не забудьте добавить пользовательский валидатор в текстовое приглашение; в противном случае бот будет неоднократно запрашивать у пользователя его местоположение, так как он ожидает текстовое значение, которое быстрый ответ не предоставляет.
public MultiTurnPromptsBot(MultiTurnPromptsBotAccessors accessors)
{
...
// This array defines how the Waterfall will execute.
var waterfallSteps = new WaterfallStep[]
{
PromptForLocation,
CaptureLocation,
};
...
// Add named dialogs to the DialogSet. These names are saved in the dialog state.
_dialogs.Add(new WaterfallDialog("details", waterfallSteps));
_dialogs.Add(new TextPrompt("location", LocationPromptValidatorAsync));
}
Валидатор местоположения
В пользовательском валидаторе вы можете проверить входящее действие для объекта местоположения, который находится в свойстве сущностей действия. Если у действия нет местоположения, вы можете вернуть false, и в запросе у пользователя снова будет указано его местоположение; в противном случае он перейдет к следующему шагу.
public Task<bool> LocationPromptValidatorAsync(PromptValidatorContext<string> promptContext, CancellationToken cancellationToken)
{
var activity = promptContext.Context.Activity;
var location = activity.Entities?.FirstOrDefault(e => e.Type == "Place");
if (location != null) {
return Task.FromResult(true);
}
return Task.FromResult(false);
}
Запрос местоположения
Как и в приведенном выше фрагменте кода, вы можете добавить быстрый ответ Facebook Messenger к данным канала ответа.
private static async Task<DialogTurnResult> PromptForLocation(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
Activity reply = stepContext.Context.Activity.CreateReply();
reply.Text = "What is your location?";
reply.ChannelData = JObject.FromObject( new {
quick_replies = new object[]
{
new
{
content_type = "location",
},
},
});
return await stepContext.PromptAsync("location", new PromptOptions { Prompt = reply }, cancellationToken);
}
Местоположение захвата
Здесь вы можете захватить местоположение пользователя, чтобы использовать его как угодно.
private async Task<DialogTurnResult> CaptureLocation(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
var activity = stepContext.Context.Activity;
var location = activity.Entities?.FirstOrDefault(e => e.Type == "Place");
if (location != null) {
var latitude = location.Properties["geo"]?["latitude"].ToString();
var longitude = location.Properties["geo"]?["longitude"].ToString();
await stepContext.Context.SendActivityAsync($"Latitude: {latitude} Longitude: {longitude}");
}
// WaterfallStep always finishes with the end of the Waterfall or with another dialog, here it is the end.
return await stepContext.EndDialogAsync(cancellationToken: cancellationToken);
}
Надеюсь, это поможет!