takataka430’s blog

.NET系を中心に勉強したことのまとめを書きます

Azure Functions(Node.js)がStreamに対応したのでOpenAIのStreamと組み合わせてみた

少し前ですが、Azure FunctionsのNode.jsでstream対応になりました。

techcommunity.microsoft.com

stream対応したということは、OpenAIのstreamの返信をFunctions経由で返すことができるということなので、このブログで検証しようと思います。

※OpenAIのAPIを使います。AzureOpenAIではないです。

環境

@azure/functions 4.0.0
openai 4.38.1
FunctionsはHTTPトリガーを使用

Functions実装

最初に環境変数を設定します。
名前:"OpenAIApiKey"
値:OpenAIのAPIキー
local.setting.jsonに記載する場合は以下のようになります。

{
  "Values": {
      "OpenAIApiKey": "[OpenAIのAPIキー]"
  }
}

ソースコードを書いていきます。
まずOpenAIのパッケージをインストールします。

npm install openai

コードを書いていきます。
まず以下でFunctionsのstreamを有効にします。

app.setup({ enableHttpStream: true });

APIキーを環境変数から取得してOpenAIのクライアントを作成します。

const apiKey = process.env["OpenAIApiKey"];
const openai = new OpenAI({ apiKey: apiKey});

HTTPリクエストを受けてreturnする関数は以下のようにします。

async function httpTrigger1(req: HttpRequest){
    //本文から値を取得
    //想定しているJSONは以下の通り
    //{"prompt": "Hello, World!"}
    const prompt = req.params['prompt'];

    //OpenAIのAPIを呼び出す
    const completion = await openai.chat.completions.create({
        messages: [{ role: "user", content: prompt }],
        model: "gpt-3.5-turbo",
        stream: true
    });

    //streamを生成するgenerator
    const generator = async function* () {
        for await (const chunk of completion) {
            if(chunk.choices[0].finish_reason === "stop"){
                break;
            }
            yield chunk.choices[0].delta.content + '\n';
        }
    };

    //streamを取得
    const stream = Readable.from(generator());
    
    //streamを返す
    return {
        body: stream,
        headers: {
            'Content-Type': 'text/event-stream',
            'Cache-Control': 'no-store'
        }
    };
};

ポイントとしては以下の通りです。

  • OpenAIにリクエストを送るときはstream: trueにします
  • レスポンスのヘッダーに'Content-Type': 'text/event-stream','Cache-Control': 'no-store'を設定します
    参考: developer.mozilla.org

  • generatorのあたりはあまりよくわかっていませんが、見よう見まねで実装しました

全体のコードは以下のようになります。

import { app, HttpRequest } from "@azure/functions";
import OpenAI from "openai";
import { Readable } from "stream";

//streamを使うために必要
app.setup({ enableHttpStream: true });

// APIキーを環境変数から取得
const apiKey = process.env["OpenAIApiKey"];
const openai = new OpenAI({ apiKey: apiKey});

async function httpTrigger1(req: HttpRequest){
    //本文から値を取得
    //想定しているJSONは以下の通り
    //{"prompt": "Hello, World!"}
    const prompt = req.params['prompt'];

    //OpenAIのAPIを呼び出す
    const completion = await openai.chat.completions.create({
        messages: [{ role: "user", content: prompt }],
        model: "gpt-3.5-turbo",
        stream: true
    });

    //streamを生成するgenerator
    const generator = async function* () {
        for await (const chunk of completion) {
            if(chunk.choices[0].finish_reason === "stop"){
                break;
            }
            yield chunk.choices[0].delta.content + '\n';
        }
    };

    //streamを取得
    const stream = Readable.from(generator());
    
    //streamを返す
    return {
        body: stream,
        headers: {
            'Content-Type': 'text/event-stream',
            'Cache-Control': 'no-store'
        }
    };
};

app.http('httpTrigger1', {
    methods: ['POST'],
    authLevel: 'function',
    handler: httpTrigger1
});

Functions側はこれで完了です。

クライアントの実装

次にFunctionsにアクセスするクライアントをC#のコンソールアプリで実装します。

using System.Text;
using System.Text.Json;

var endpointUrl = "[FunctionsのURL]";
var promptString = "[OpenAIに送信するプロンプト]";

//HttpClientの作成
var client = new HttpClient();

//HTTPリクエストの作成
var request = new HttpRequestMessage(HttpMethod.Post, endpointUrl);

//JSON形式でデータを送信
using StringContent jsonContent = new(
        JsonSerializer.Serialize(new
        {
            prompt = promptString
        }),
        Encoding.UTF8,
        "application/json");
request.Content = jsonContent;

//リクエストの送信
var response = await client.SendAsync(request,HttpCompletionOption.ResponseHeadersRead);

//レスポンスの読み取って表示
using var stream = await response.Content.ReadAsStreamAsync();
using var streamReader = new StreamReader(stream);
while (!streamReader.EndOfStream)
{
    var line = await streamReader.ReadLineAsync();
    if (string.IsNullOrEmpty(line))
        continue;
    Console.Write(line);
}

promptStringにこんにちは。お元気ですか?と設定してプログラムを実行すると以下のようになります。

想定通り少しずつ回答を取得して表示していますね!

参考URL

Azure Functions の Node.js v4 に追加された HTTP Streaming サポートを深掘りする - しばやん雑記

https://platform.openai.com/docs/api-reference/chat/create?lang=node.js

Stream | Node.js v21.7.3 Documentation

Azure OpenAIのC# SDKを使ってOpenAI(Azureではない)にリクエストを投げる

環境

Azure.AI.OpenAI 1.0.0-beta.15
コンソールアプリ(.NET 6)

実装

まずはクライアントを作成します。

string key = "[OpenAIのAPIキー]";

OpenAIClient client = new(key);

次にモデルの指定やプロンプトの設定を行います。

string modelName = "[モデル名]";

var chatCompletionOptions = new ChatCompletionsOptions()
{
    Messages =
    {
        new ChatRequestSystemMessage("You are a helpful assistant."),
        new ChatRequestUserMessage("Hello")
    },
    DeploymentName = modelName, //デプロイ名っぽいプロパティですが、OpenAIの場合はモデル名を指定します。
};

Messagesには上記のコードに直接List型のオブジェクトを設定することはできません。その代わりに以下のように実装できます。

IList<ChatRequestMessage> messageList = new List<ChatRequestMessage>
{
    new ChatRequestSystemMessage("You are a helpful assistant."),
    new ChatRequestUserMessage("Hello")
};

foreach (var message in messageList)
{
    chatCompletionOptions.Messages.Add(message);
}

こちらのほうが使い勝手がよさそうですね。

最後にOpenAIにリクエストを送って結果を表示します。

var completionsResponse = await client.GetChatCompletionsAsync(chatCompletionOptions);
string completion = completionsResponse.Value.Choices[0].Message.Content;
Console.WriteLine($"Chatbot: {completion}");

全体のコードは以下のようになります。

using Azure.AI.OpenAI;

string key = "[OpenAIのAPIキー]";
string modelName = "[モデル名]";

OpenAIClient client = new(key);


var chatCompletionOptions = new ChatCompletionsOptions()
{
    DeploymentName = modelName,
};

IList<ChatRequestMessage> messageList = new List<ChatRequestMessage>
{
    new ChatRequestSystemMessage("You are a helpful assistant."),
    new ChatRequestUserMessage("Hello")
};

foreach (var message in messageList)
{
    chatCompletionOptions.Messages.Add(message);
}

var completionsResponse = await client.GetChatCompletionsAsync(chatCompletionOptions);
string completion = completionsResponse.Value.Choices[0].Message.Content;
Console.WriteLine($"Chatbot: {completion}");

実行すると以下の結果が得られます。

Chatbot: Hello! How can I assist you today?

参考URL

learn.microsoft.com

C#のコンソールでChatGPTと英会話するアプリを作ってみた

はじめに

最近ChatGPTを英語の勉強のために英語で質問するようにしているのですが、「これって会話できないかな?」というのが気になったので作ってみました。

環境

.NET6 コンソールアプリ
Microsoft.CognitiveServices.Speech 1.26.0

コード

OpenAIに質問を投げる

以下のようになります。

static async Task<string> AnswerQuestionAsync(string question, HttpClient client, string openai_api_key)
{
    //OpenAIのエンドポイントを入力
    string endpoint = "https://api.openai.com/v1/chat/completions";

    //OpenAIのエンドポイントに送るリクエスト本文を作成
    var content = JsonContent.Create(new
    {
        model = "gpt-3.5-turbo",
        messages = new List<Message> { new Message("user", question) },
        stream = true
    });

    //リクエストを送る
    HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Post, endpoint);
    requestMessage.Content = content;// new StringContent(request, Encoding.UTF8, "application/json");
    requestMessage.Headers.Add("Authorization", "Bearer " + openai_api_key);

    Console.Write("");
    
    HttpResponseMessage response = await client.SendAsync(requestMessage);

    if(response.IsSuccessStatusCode)
    {
        //Choicesの中のcontenを取得
        var resultContent = await response.Content.ReadAsStringAsync();

        var obj = JsonNode.Parse(resultContent)!["choices"]![0]!["message"]!["content"];
        if (obj != null)
        {
            var answer = obj.ToString().Replace("\n", "");
            return answer;
        }
        else
        {
            return "Can not get an answer.";
        }
    }
    else
    {
        return "An error has occurred.";
    }

}

本文のJSONを作成するためのクラスを作っておきます。

class message
{
    public message(string _role, string _content)
    {
        role = _role;
        content = _content;
    }
    public string role { get; set; }
    public string content { get; set; }
}

音声を文字に変換

static async Task<string> OutputSpeechRecognitionResultAsync(string speechKey, string speechRegion)
{
    var speechConfig = SpeechConfig.FromSubscription(speechKey, speechRegion);
    speechConfig.SpeechRecognitionLanguage = "en-US";

    using var audioConfig = AudioConfig.FromDefaultMicrophoneInput();
    using var speechRecognizer = new SpeechRecognizer(speechConfig, audioConfig);

    Console.WriteLine("マイクに向けて話してください。");
    var speechRecognitionResult = await speechRecognizer.RecognizeOnceAsync();

    string answer = "";

    switch (speechRecognitionResult.Reason)
    {
        case ResultReason.RecognizedSpeech:
            Console.WriteLine($"RECOGNIZED: Text={speechRecognitionResult.Text}");
            answer = speechRecognitionResult.Text;
            break;
        case ResultReason.NoMatch:
            Console.WriteLine($"NOMATCH: Speech could not be recognized.");
            break;
        case ResultReason.Canceled:
            var cancellation = CancellationDetails.FromResult(speechRecognitionResult);
            Console.WriteLine($"CANCELED: Reason={cancellation.Reason}");

            if (cancellation.Reason == CancellationReason.Error)
            {
                Console.WriteLine($"CANCELED: ErrorCode={cancellation.ErrorCode}");
                Console.WriteLine($"CANCELED: ErrorDetails={cancellation.ErrorDetails}");
                Console.WriteLine($"CANCELED: Did you set the speech resource key and region values?");
            }
            break;
    }
    return answer;
}

以下のページのコードを参考にしました。

音声テキスト変換クイックスタート - Speech サービス - Azure Cognitive Services | Microsoft Learn

文字を音声に変換

static async Task OutputSpeechSynthesisResultAsync(string text, string speechKey, string speechRegion)
{
    var speechConfig = SpeechConfig.FromSubscription(speechKey, speechRegion);

    speechConfig.SpeechSynthesisVoiceName = "en-US-JennyNeural";

    using (var speechSynthesizer = new SpeechSynthesizer(speechConfig))
    {
        var speechSynthesisResult = await speechSynthesizer.SpeakTextAsync(text);          

        switch (speechSynthesisResult.Reason)
        {
            case ResultReason.SynthesizingAudioCompleted:
                Console.WriteLine($"Speech synthesized for text: [{text}]");
                break;
            case ResultReason.Canceled:
                var cancellation = SpeechSynthesisCancellationDetails.FromResult(speechSynthesisResult);
                Console.WriteLine($"CANCELED: Reason={cancellation.Reason}");

                if (cancellation.Reason == CancellationReason.Error)
                {
                    Console.WriteLine($"CANCELED: ErrorCode={cancellation.ErrorCode}");
                    Console.WriteLine($"CANCELED: ErrorDetails=[{cancellation.ErrorDetails}]");
                    Console.WriteLine($"CANCELED: Did you set the speech resource key and region values?");
                }
                break;
            default:
                break;
        }
    }
}

以下のページを参考にしました。

テキスト読み上げクイックスタート - Speech サービス - Azure Cognitive Services | Microsoft Learn

全体のコード

コード全体は以下のようになります。

using System.Net.Http.Json;
using System.Text.Json.Nodes;
using Microsoft.CognitiveServices.Speech;
using Microsoft.CognitiveServices.Speech.Audio;

class Program
{
    async static Task Main(string[] args)
    {
        // Azure Speech Serviceの "SPEECH_KEY" と "SPEECH_REGION"を入力
        string speechKey = "[Azure Speech Serviceのキー]";
        string speechRegion = "[Azure Speech Serviceのリージョン]";

        //OpenAIのAPIキーを入力
        string openai_api_key = "[OpenAIのAPIキー]";

        HttpClient client = new HttpClient();


        var inProcess = true;

        while(inProcess)
        {
            //話した内容を文字として取得
            var questionText = await OutputSpeechRecognitionResultAsync(speechKey, speechRegion);

            //Byeと言われたら終了
            if (questionText.ToLower().Contains("bye"))
            {
                inProcess = false;
            }

            //OpenAIに質問を投げる
            var answer = await AnswerQuestionAsync(questionText, client,openai_api_key);
            
            //答えを話してもらう
            await OutputSpeechSynthesisResultAsync(answer, speechKey, speechRegion);
            
        }
    }


    static async Task<string> AnswerQuestionAsync(string question, HttpClient client, string openai_api_key)
    {
        //OpenAIのエンドポイントを入力
        string endpoint = "https://api.openai.com/v1/chat/completions";

        //OpenAIのエンドポイントに送るリクエスト本文を作成
        var content = JsonContent.Create(new
        {
            model = "gpt-3.5-turbo",
            messages = new List<Message> { new Message("user", question) },
            stream = true
        });

        //リクエストを送る
        HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Post, endpoint);
        requestMessage.Content = content;// new StringContent(request, Encoding.UTF8, "application/json");
        requestMessage.Headers.Add("Authorization", "Bearer " + openai_api_key);

        Console.Write("");
        
        HttpResponseMessage response = await client.SendAsync(requestMessage);

        if(response.IsSuccessStatusCode)
        {
            //Choicesの中のcontenを取得
            var resultContent = await response.Content.ReadAsStringAsync();

            var obj = JsonNode.Parse(resultContent)!["choices"]![0]!["message"]!["content"];
            if (obj != null)
            {
                var answer = obj.ToString().Replace("\n", "");
                return answer;
            }
            else
            {
                return "Can not get an answer.";
            }
        }
        else
        {
            return "An error has occurred.";
        }

    }


    static async Task<string> OutputSpeechRecognitionResultAsync(string speechKey, string speechRegion)
    {
        var speechConfig = SpeechConfig.FromSubscription(speechKey, speechRegion);
        speechConfig.SpeechRecognitionLanguage = "en-US";

        using var audioConfig = AudioConfig.FromDefaultMicrophoneInput();
        using var speechRecognizer = new SpeechRecognizer(speechConfig, audioConfig);

        Console.WriteLine("マイクに向けて話してください。");
        var speechRecognitionResult = await speechRecognizer.RecognizeOnceAsync();

        string answer = "";

        switch (speechRecognitionResult.Reason)
        {
            case ResultReason.RecognizedSpeech:
                Console.WriteLine($"RECOGNIZED: Text={speechRecognitionResult.Text}");
                answer = speechRecognitionResult.Text;
                break;
            case ResultReason.NoMatch:
                Console.WriteLine($"NOMATCH: Speech could not be recognized.");
                break;
            case ResultReason.Canceled:
                var cancellation = CancellationDetails.FromResult(speechRecognitionResult);
                Console.WriteLine($"CANCELED: Reason={cancellation.Reason}");

                if (cancellation.Reason == CancellationReason.Error)
                {
                    Console.WriteLine($"CANCELED: ErrorCode={cancellation.ErrorCode}");
                    Console.WriteLine($"CANCELED: ErrorDetails={cancellation.ErrorDetails}");
                    Console.WriteLine($"CANCELED: Did you set the speech resource key and region values?");
                }
                break;
        }
        return answer;
    }

    

    static async Task OutputSpeechSynthesisResultAsync(string text, string speechKey, string speechRegion)
    {
        var speechConfig = SpeechConfig.FromSubscription(speechKey, speechRegion);

        speechConfig.SpeechSynthesisVoiceName = "en-US-JennyNeural";

        using (var speechSynthesizer = new SpeechSynthesizer(speechConfig))
        {
            var speechSynthesisResult = await speechSynthesizer.SpeakTextAsync(text);          

            switch (speechSynthesisResult.Reason)
            {
                case ResultReason.SynthesizingAudioCompleted:
                    Console.WriteLine($"Speech synthesized for text: [{text}]");
                    break;
                case ResultReason.Canceled:
                    var cancellation = SpeechSynthesisCancellationDetails.FromResult(speechSynthesisResult);
                    Console.WriteLine($"CANCELED: Reason={cancellation.Reason}");

                    if (cancellation.Reason == CancellationReason.Error)
                    {
                        Console.WriteLine($"CANCELED: ErrorCode={cancellation.ErrorCode}");
                        Console.WriteLine($"CANCELED: ErrorDetails=[{cancellation.ErrorDetails}]");
                        Console.WriteLine($"CANCELED: Did you set the speech resource key and region values?");
                    }
                    break;
                default:
                    break;
            }
        }
    }
}

//JSON作成用のクラス
class Message
{
    public Message(string _role, string _content)
    {
        role = _role;
        content = _content;
    }
    public string role { get; set; }
    public string content { get; set; }
}

「Bye」という単語が含まれるまで繰り返し会話ができます。ぜひ試してみてください。

C#を使ってOpenAIのAPIからの結果をChatGPTのように順次表示する方法

はじめに

ChatGPTは回答が一気に表示されるのではなく、少しずつ表示されます。これができたらユーザーは待機時間が短く感じらますよね。
今回はChatGPTのAPIを利用してどのように実装するのかを調査してみました。

環境

.NET 6 コンソールアプリ
OpenAIのモデル:gpt-3.5-turbo

ポイント

結果を順次受け取るようにする際のポイントをまとめました。

streamパラメータの設定

以下記事の通り、APIにリクエストを送る際のパラメータでstreamをtrueにする必要があります。

https://platform.openai.com/docs/api-reference/chat/create#chat/create-stream

結果の受け取り

上記のようにstreamを有効にした場合、結果は以下のようなJSONになります。

data: {
    "id": "...",
    "object": "...",
    "created": ...,
    "model": "gpt-3.5-turbo-0301",
    "choices": [
        {
            "delta": {
                "content": "..."
            },
            "index": 0,
            "finish_reason": null
        }
    ]
}

data: {
    "id": "...",
    "object": "...",
    "created": ...,
    "model": "gpt-3.5-turbo-0301",
    "choices": [
        {
            "delta": {
                "content": "..."
            },
            "index": 0,
            "finish_reason": null
        }
    ]
}

(省略)

data: [DONE
]

上記はすべての結果をまとめて表示していますが、コードを実行した際にはdata:[JSON形式のデータ]という結果を繰り返し取得できます。このままではJSONに変換しにくいので「data:」の部分は削除すると扱いやすいです。
また、回答はcontentの中にあるのでJSONの解析でこの値を取得するといいでしょう。

コード

では実際にコードを見てみましょう。C#のコンソールアプリでの例です。

using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Net.Http.Json;
using System.Text.Json.Nodes;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        string key = "[OpenAIのAPIキー]";

        Console.WriteLine("質問を入力してください。");
        string question = Console.ReadLine();
        
        Console.WriteLine("--------------------------------------");

        var client = new HttpClient();
        var request = new HttpRequestMessage(HttpMethod.Post, "https://api.openai.com/v1/chat/completions");
        request.Headers.Add("Authorization", $"Bearer {key}");

        var content = JsonContent.Create(new
        {
            model = "gpt-3.5-turbo",
            messages= new List<message> { new message("user", question) },
            stream = true
        });

        request.Content = content;

        var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
        using var streamReader = new StreamReader(await response.Content.ReadAsStreamAsync());

        while (!streamReader.EndOfStream)
        {
            var line = await streamReader.ReadLineAsync();
            if (string.IsNullOrEmpty(line))
                continue;

            //冒頭の[data]を削除
            line = line.Remove(0, 6);
            
            //[DONE]の場合は終了
            if (line == "[DONE]")
                continue;

            var resultContent = JsonNode.Parse(line)?["choices"]?[0]?["delta"]?["content"]?.ToString();
            if(resultContent != null)
                Console.Write(resultContent);  //結果をコンソールに表示
        }
    }
}

class message
{
    public message(string _role, string _content)
    {
        role = _role;
        content = _content;
    }
    public string role { get; set; }
    public string content { get; set; }
}

実行結果

以下のように結果が順次表示されました。

youtu.be

OpenAIを使ってみた

最近よく聞くOpenAIのAPIを使ってみました。

環境

Python 3.9.13
Visual Studio Code 1.75.0

手順

APIキーの取得

以下のページからログインします。(利用にはサインアップが必要です)
https://beta.openai.com/

ログインしたら以下のページからAPIキーを取得できます。
https://platform.openai.com/account/api-keys

コードを書く

今回はPythonのライブラリを使うので以下のコマンドでインストールします。

pip install openai

これでライブラリを使う準備は完了です。
OpenAIでできることは以下のページにまとめられています。

https://platform.openai.com/examples

今回はQ&Aのサンプルコードを少し修正して使います。

import openai

question = "Where is the Valley of Kings?"

# 本来APIキーはソースコードに含めてはいけないのですが、今回は動作確認なのでここで設定します
openai.api_key = "[OpenAIのAPIキー]"

response = openai.Completion.create(
  model="text-davinci-003",
  prompt="I am a highly intelligent question answering bot. If you ask me a question that is rooted in truth, I will give you the answer. If you ask me a question that is nonsense, trickery, or has no clear answer, I will respond with ""Unknown"". Q: " + question  + " A:",
  temperature=0,
  max_tokens=300,
  top_p=1,
  frequency_penalty=0.0,
  presence_penalty=0.0,
  stop=["\n"]
)

# 翻訳結果の表示
print(response["choices"][0]["text"])

結果は以下のようになりました。

 The Valley of the Kings is located in Egypt, on the west bank of the Nile River in Luxor.

ソースコードquestionを変更すると色々質問することができます。是非皆さんも使ってみてください!

スクリプトから3Dモデルを読み込む【MRTK】

はじめに

Unityで3Dオブジェクトを読み込むためにはUnityのプロジェクトにドラッグアンドドロップでインポートする方法があると思います。今回はその方法とは別に、スクリプトから3Dオブジェクトを読み込む方法を調べてみました。

環境

MRTK 2.8.2
Unity 2020.3.27f1

手順

基本的な使い方はMixed Reality Toolkit ExamplesのDemos - Gltfを見ていただければわかると思います。

以下のような方法でgltfまたはglb形式の3Dモデルを読み込みGameObjectとして扱うことができます。

名前空間Microsoft.MixedReality.Toolkit.Utilities.Gltf.Serialization

//gltfから読み込む場合
string path = "[ファイルパス]";
var gltf = await GltfUtility.ImportGltfObjectFromPathAsync(path);
GameObject gltfobj = gltf.GameObjectReference;

//glbから読み込む場合
byte[] glbbytearray = ~~~; //何らかの形でglb形式の3Dモデルをバイト配列で取得
var gltfObject = GltfUtility.GetGltfObjectFromGlb(glbbytearray);
GameObject gltfobj = await gltfObject.ConstructAsync();

上記のどちらを使う場合でも、異なる形式の3Dモデルを読み込もうとすると例外になるので例外処理をする必要があると思います。

この方法を使えばクラウドのストレージから呼び出すなんてこともできるので応用が利きそうですね。

model-viewerを使ってWEBで3Dモデルを表示してみた

はじめに

3DモデルをWEB上で表示したいと思ってツールを探してみたらmodel-viewerというものを見つけました。

modelviewer.dev

これを利用すれば簡単に3Dモデルを表示することができそうなので、さっそく使ってみました。

環境

Visual Studio Code 1.72.2
Live Server v5.7.9 (Visual Studio Code拡張機能

Live Serverについては以下をご覧ください。 marketplace.visualstudio.com

利用手順

まずはhtmlファイル(index.html)と3Dモデル(TestObject.glb)を用意し、同じ場所に配置します。

index.htmlは以下のように記載しました。

<!DOCTYPE html>
<html>
<body>
<model-viewer 
    src="TestObject.glb" 
    camera-controls
    style="width: 1000px; height: 800px;">
</model-viewer>

<script type="module" src="https://unpkg.com/@google/model-viewer/dist/model-viewer.min.js"></script>

</body>
</html>

とりあえずさっと動かすだけならこれでOKです。
あとはWEBブラウザ経由でindex.htmlにアクセスすればいいのですが、そのまま開くと3Dモデルへアクセスする際にCORSのエラーが発生します。そのためLive Serverを使用して開きます。

実際に動かしてみると以下のようになります。

3Dモデルが表示されて、マウスで操作することもできていますね。