using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Microsoft.Extensions.Configuration;
namespace HelloWorld
{
publicstaticclass HttpTrigger
{
[FunctionName("HttpTrigger")]
publicstatic async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req,
ExecutionContext context,
ILogger log)
{
var config = new ConfigurationBuilder()
.AddJsonFile("local.settings.json", true)
.AddEnvironmentVariables()
.Build();
returnnew OkObjectResult(config["secret"]);
}
}
}
using CoreFoundation;
using CoreImage;
using CoreML;
using Foundation;
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Vision;
using Xamarin.Forms;
[assembly: Dependency(typeof(AIApp.iOS.PhotoDetector))]
namespace AIApp.iOS
{
publicclass PhotoDetector : IPhotoDetector
{
privatereadonly MLModel _mlModel;
privatereadonly VNCoreMLModel _model;
public PhotoDetector()
{
var assetPath = NSBundle.MainBundle.GetUrlForResource("FriesOrNotFries", "mlmodelc");
_mlModel = MLModel.Create(assetPath, out var _);
_model = VNCoreMLModel.FromMLModel(_mlModel, out var __);
}
public Task<FriesOrNotFriesTag> DetectAsync(Stream photo)
{
var taskCompletionSource = new TaskCompletionSource<FriesOrNotFriesTag>();
void handleClassification(VNRequest request, NSError error)
{
var observations = request.GetResults<VNClassificationObservation>();
if (observations == null)
{
taskCompletionSource.SetException(new Exception("Unexpected result type from VNCoreMLRequest"));
return;
}
if (!observations.Any())
{
taskCompletionSource.SetResult(FriesOrNotFriesTag.None);
return;
}
var best = observations.First();
taskCompletionSource.SetResult((FriesOrNotFriesTag)Enum.Parse(typeof(FriesOrNotFriesTag), best.Identifier));
}
using (var data = NSData.FromStream(photo))
{
var ciImage = new CIImage(data);
var handler = new VNImageRequestHandler(ciImage, new VNImageOptions());
DispatchQueue.DefaultGlobalQueue.DispatchAsync(() =>
{
handler.Perform(new VNRequest[] { new VNCoreMLRequest(_model, handleClassification) }, out var _);
});
}
return taskCompletionSource.Task;
}
}
}
マークダウンの書き方見てねってなりますが、最初にいれた Paste Image 拡張機能のおかげでクリップボードに画像があれば画像を入れたい場所にフォーカスを持っていって Ctrl + Alt + V で画像を表示するためのマークダウンを入れてくれます。
Windows 10 は Win + Shift + D でデスクトップの矩形切り抜きができるので作業手順とかを作るときは便利です。
Ctrl + Alt + V をすると以下のように画像が自動的に追加されて表示するための記述が挿入されます。
教材によってはAzure CLIだけで完結する場合はターミナルが教材に表示されたり、あとは実際にAzureポータルにサインインするように案内されるものがあります。同じアカウントで複数のサブスクリプション(Azureでいう契約みたいなもんだと思ってもらえればいいです)持ってる場合はポータルの右上のアイコンからディレクトリの切り替えを押して Microsoft Learn Sandbox という名前のに切り替えれば OK です。
ということで、Microsoft Learn は実際にものを触りながら学習できるので個人的にはおすすめです。
Typoとかみつけたら reporting an issue を送ってあげると喜ばれるかもしれません。
using Microsoft.Bot.Builder.AI.Luis;
using Microsoft.Bot.Builder.AI.QnA;
using Microsoft.Bot.Configuration;
using System.Collections.Generic;
namespace HelloWorldBot
{
publicclass BotServices
{
public Dictionary<string, QnAMaker> QnAServices { get; } = new Dictionary<string, QnAMaker>();
public Dictionary<string, LuisRecognizer> LuisServices { get; } = new Dictionary<string, LuisRecognizer>();
public BotServices(BotConfiguration botConfiguration)
{
foreach (var service in botConfiguration.Services)
{
switch (service.Type)
{
case ServiceTypes.QnA:
{
var qna = (QnAMakerService)service;
// ここらへんで QnAMaker クラスの初期化と登録break;
}
case ServiceTypes.Luis:
{
var luis = (LuisService)service;
// ここらへんで LuisRecognizer の初期化と登録break;
}
}
}
}
}
}
LUIS や QnA Maker と連携したかったら、この BotServices クラスを DI して使ってねって感じです。サンプルでは Dictionary 型で定義されてることが多いけど、かちっとやるなら個別プロパティかなぁ?どっちがいいんだろう。個人的な感覚では Dictionary よりもきちんと個々のプロパティ定義する方が好みだけど。
$ vue create hello-world-ts
Vue CLI v3.4.0
? Please pick a preset: Manually select features
? Check the features needed for your project: TS, Linter
? Use class-style component syntax? Yes
? Use Babel alongside TypeScript for auto-detected polyfills? No
? Pick a linter / formatter config: TSLint
? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection)Lint on save
? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? No
実行が終わると、こんなファイルが生成されてる。
npm run serveで開発用サーバーを立てたり、npm run buildで本番向けビルドもできる。至れり尽くせり。
$ vue create vue-item
Vue CLI v3.4.0
? Please pick a preset: Manually select features
? Check the features needed for your project: TS
? Use class-style component syntax? Yes
? Use Babel alongside TypeScript for auto-detected polyfills? No
? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? No
出来上がったら public フォルダーにサイトの中身をごそっと入れます。
そして id が app の div タグを追加。
<!DOCTYPE html><htmllang="ja"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><metahttp-equiv="X-UA-Compatible"content="ie=edge"><title>Sample Web site</title><linkrel="stylesheet"type="text/css"href="css/site.css"><scripttype="text/javascript"src="scripts/index.js"></script></head><body><h1>ようこそ!!私のホームページへ!</h1><spanclass="welcome-message">Welcome!!</span><p>あなたは 201923 人目の訪問者です。</p><p>現在は <spanid="clock"></span>です。</p><divid="app"></div></body></html>
<!DOCTYPE html><htmllang="en"><head><metacharset="utf-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><metaname="viewport"content="width=device-width,initial-scale=1.0"><linkrel="icon"href="<%= BASE_URL %>favicon.ico"><title>ts-lab</title></head><body><noscript><strong>We're sorry but ts-lab doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><divid="app">{{ message }}</div><!-- built files will be auto injected --></body></html>
div の中に {{ message }}を足してます。そして src/main.tsを以下のように書き換え。
[Vue warn]: You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.
(found in <Root>)
ということで vue.config.jsをプロジェクトルートに作って中身を以下のようにします。
module.exports = {runtimeCompiler: true,}
そして、npm run serveとすれば開発サーバーが立ち上がってブラウザーで URL を開くと以下のように結果が確認できます。
ここで JavaScript の初見殺しだと思ってる this が状況によって変わる問題についての言及があった。
JavaScript は呼び出し側が this を指定することが出来るんだけど、どうも Vue.js は、これを使ってライフサイクルや $watch のコールバックの this を Vue のインスタンスにしてるみたいだけど、他の言語と同じように this が勝手に変わらないアロー関数(() => { ... })を使うと this が思ったのと違うのになってつらいということみたい。
<!DOCTYPE html><htmllang="en"><head><metacharset="utf-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><metaname="viewport"content="width=device-width,initial-scale=1.0"><linkrel="icon"href="<%= BASE_URL %>favicon.ico"><title>ts-lab</title></head><body><noscript><strong>We're sorry but ts-lab doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><divid="app" v-bind:title="tooltip">{{ text }}</div><!-- built files will be auto injected --></body></html>
VisualElement から派生したすべてのクラスで CommonStatus という Visual State Group で Normal, Disabled, Focused という Visual State があるので、これを設定することでいい感じに一般的な状態に対する見た目を個々に設定できる。今まではTriggerとか使ってやる感じだったけどわかりやすくなりましたね。