HoloLens(1세대) 및 Azure 303: LUIS(자연어 이해)


참고

Mixed Reality 아카데미 자습서는 HoloLens(1세대) 및 Mixed Reality 몰입형 헤드셋을 염두에 두고 설계되었습니다. 따라서 이러한 디바이스 개발에 대한 지침을 계속 찾고 있는 개발자를 위해 이러한 자습서를 그대로 두는 것이 중요합니다. 이러한 자습서는 HoloLens 2에 사용되는 최신 도구 집합 또는 상호 작용으로 업데이트되지 않습니다. 대신 지원되는 디바이스에서 계속 작동하도록 유지 관리됩니다. HoloLens 2 위해 개발하는 방법을 보여 줄 새로운 자습서 시리즈가 미래에 게시될 예정입니다. 이 알림은 해당 자습서가 게시될 때 해당 자습서에 대한 링크로 업데이트됩니다.


이 과정에서는 Language Understanding API와 함께 Azure Cognitive Services를 사용하여 혼합 현실 애플리케이션에 Language Understanding 통합하는 방법을 알아봅니다.

랩 결과

LUIS(Language Understanding)는 사용자가 원하는 것을 자신의 말로 추출하는 것과 같이 사용자 입력에서 의미를 만들 수 있는 기능을 애플리케이션에 제공하는 Microsoft Azure 서비스입니다. 이는 입력 정보를 이해하고 학습한 다음 자세한 관련 정보로 회신할 수 있는 기계 학습을 통해 수행됩니다. 자세한 내용은 AZURE Language Understanding(LUIS) 페이지를 참조하세요.

이 과정을 완료하면 다음을 수행할 수 있는 혼합 현실 몰입형 헤드셋 애플리케이션이 제공됩니다.

  1. 몰입형 헤드셋에 연결된 마이크를 사용하여 사용자 입력 음성을 캡처합니다.
  2. 캡처된 받아쓰기를 Azure Language Understanding LUIS(Intelligent Service)로 보냅니다.
  3. LUIS가 분석될 전송 정보에서 의미를 추출하도록 하고 사용자의 요청 의도를 확인하려고 시도합니다.

개발에는 사용자가 음성 및/또는 응시를 사용하여 장면에 있는 개체의 크기와 색을 변경할 수 있는 앱 만들기가 포함됩니다. 모션 컨트롤러의 사용은 적용되지 않습니다.

애플리케이션에서 결과를 디자인과 통합하는 방법은 사용자에게 달려 있습니다. 이 과정은 Unity 프로젝트와 Azure 서비스를 통합하는 방법을 교육하기 위해 고안되었습니다. 혼합 현실 애플리케이션을 향상시키기 위해 이 과정에서 얻은 지식을 사용하는 것이 여러분의 임무입니다.

12장에서 다루는 LUIS 학습을 여러 번 준비합니다. LUIS가 학습된 시간이 많을수록 더 나은 결과를 얻을 수 있습니다.

디바이스 지원

과정 HoloLens 몰입형 헤드셋
MR 및 Azure 303: LUIS(자연어 이해) ✔️ ✔️

참고

이 과정은 주로 Windows Mixed Reality 몰입형(VR) 헤드셋에 중점을 두지만, 이 과정에서 배운 내용을 Microsoft HoloLens 적용할 수도 있습니다. 과정을 따라가면 HoloLens를 지원하기 위해 사용해야 할 수 있는 변경 내용에 대한 메모가 표시됩니다. HoloLens를 사용하는 경우 음성 캡처 중에 약간의 에코가 나타날 수 있습니다.

사전 요구 사항

참고

이 자습서는 Unity 및 C#에 대한 기본 경험이 있는 개발자를 위해 설계되었습니다. 또한 이 문서의 필수 구성 요소 및 서면 지침은 작성 당시 테스트 및 확인된 내용(2018년 5월)을 나타냅니다. 이 과정의 정보가 아래에 나열된 것보다 최신 소프트웨어에서 찾을 수 있는 내용과 완벽하게 일치한다고 가정해서는 안 되지만 도구 설치 문서에 나열된 대로 최신 소프트웨어를 자유롭게 사용할 수 있습니다.

이 과정에서는 다음 하드웨어 및 소프트웨어를 사용하는 것이 좋습니다.

시작하기 전에

  1. 이 프로젝트를 빌드하는 데 문제가 발생하지 않도록 이 자습서에서 언급한 프로젝트를 루트 또는 루트에 가까운 폴더에 만드는 것이 좋습니다(긴 폴더 경로는 빌드 시 문제를 일으킬 수 있음).

  2. 컴퓨터가 받아쓰기를 사용하도록 허용하려면 Windows 설정 > 개인 정보 보호 > 음성, 수동 입력 & 입력 입력으로 이동하여 음성 서비스 켜기 및 제안 입력 단추를 누릅니다.

  3. 이 자습서의 코드를 사용하면 컴퓨터의 기본 마이크 디바이스 집합에서 녹음할 수 있습니다. 기본 마이크 디바이스가 음성을 캡처하는 데 사용하려는 디바이스로 설정되어 있는지 확인합니다.

  4. 헤드셋에 기본 제공 마이크가 있는 경우 Mixed Reality 포털 설정에서 "헤드셋을 착용할 때 헤드셋 마이크로 전환" 옵션이 켜져 있는지 확인합니다.

    몰입형 헤드셋 설정

1장 - Azure Portal 설정

Azure에서 Language Understanding 서비스를 사용하려면 애플리케이션에서 사용할 수 있도록 서비스의 instance 구성해야 합니다.

  1. Azure Portal에 로그인합니다.

    참고

    Azure 계정이 아직 없는 경우 계정을 만들어야 합니다. 강의실 또는 랩 상황에서 이 자습서를 따르는 경우 강사 또는 감독자 중 한 명에게 새 계정 설정에 대한 도움을 요청하세요.

  2. 로그인한 후 왼쪽 위 모서리에서 새로 만들기를 클릭하고 Language Understanding 검색한 다음 Enter 키를 클릭합니다.

    LUIS 리소스 만들기

    참고

    New라는 단어가 최신 포털에서 리소스 만들기로 대체되었을 수 있습니다.

  3. 오른쪽의 새 페이지에서는 Language Understanding 서비스에 대한 설명을 제공합니다. 이 페이지의 왼쪽 아래에서 만들기 단추를 선택하여 이 서비스의 instance 만듭니다.

    LUIS 서비스 만들기 - 법적 통지

  4. 만들기를 클릭한 후에는 다음을 수행합니다.

    1. 이 서비스 instance 원하는 이름을 삽입합니다.

    2. 구독을 선택합니다.

    3. LUIS 서비스를 처음 만드는 경우 F0이라는 무료 계층을 사용할 수 있어야 하는 경우 적절한 가격 책정 계층을 선택합니다. 무료 할당은 이 과정에 충분해야 합니다.

    4. 리소스 그룹을 선택하거나 새 그룹을 만듭니다. 리소스 그룹은 Azure 자산 컬렉션에 대한 액세스를 모니터링, 제어, 프로비전 및 관리하는 방법을 제공합니다. 단일 프로젝트(예: 이러한 과정)와 연결된 모든 Azure 서비스를 공통 리소스 그룹 아래에 유지하는 것이 좋습니다.

      Azure 리소스 그룹에 대해 자세히 알아보려면 리소스 그룹 문서를 방문하세요.

    5. 리소스 그룹의 위치를 결정합니다(새 리소스 그룹을 만드는 경우). 위치는 애플리케이션이 실행되는 지역에 있는 것이 가장 좋습니다. 일부 Azure 자산은 특정 지역에서만 사용할 수 있습니다.

    6. 또한 이 서비스에 적용된 사용 약관을 이해했음을 확인해야 합니다.

    7. 만들기를 선택합니다.

      LUIS 서비스 만들기 - 사용자 입력

  5. 만들기를 클릭하면 서비스가 생성될 때까지 기다려야 합니다. 이 작업은 1분 정도 걸릴 수 있습니다.

  6. 서비스 instance 만들어지면 포털에 알림이 표시됩니다.

    새 Azure 알림 이미지

  7. 알림을 클릭하여 새 서비스 instance 탐색합니다.

    리소스 만들기 알림 성공

  8. 알림에서 리소스로 이동 단추를 클릭하여 새 서비스 instance 탐색합니다. 새 LUIS 서비스 instance 이동합니다.

    LUIS 키 액세스

  9. 이 자습서 내에서 애플리케이션은 서비스의 구독 키를 사용하여 수행되는 서비스를 호출해야 합니다.

  10. LUIS API 서비스의 빠른 시작 페이지에서 첫 번째 단계인 키 가져오기로 이동하고 키를 클릭합니다(키 아이콘으로 표시된 서비스 탐색 메뉴에 있는 파란색 하이퍼링크 키를 클릭하여 이 작업을 수행할 수도 있음). 그러면 서비스 키가 표시됩니다.

  11. 나중에 프로젝트에서 필요하므로 표시된 키 중 하나의 복사본을 가져옵니다.

  12. 서비스 페이지에서 Language Understanding 포털을 클릭하여 LUIS 앱 내에서 새 서비스를 만드는 데 사용할 웹 페이지로 리디렉션됩니다.

2장 - Language Understanding 포털

이 섹션에서는 LUIS 포털에서 LUIS 앱을 만드는 방법을 알아봅니다.

중요

이 챕 터 내에서 엔터티, 의도발화를 설정하는 것은 LUIS 서비스를 빌드하는 첫 번째 단계일 뿐입니다. 더 정확하게 하기 위해 서비스를 여러 번 다시 학습해야 합니다. 서비스 재학습은 이 과정의 마지막 챕터 에서 다루므로 완료해야 합니다.

  1. Language Understanding Portal에 도달하면 아직 로그인하지 않은 경우 Azure Portal 동일한 자격 증명으로 로그인해야 할 수 있습니다.

    LUIS 로그인 페이지

  2. LUIS를 처음 사용하는 경우 시작 페이지 아래쪽으로 스크롤하여 LUIS 앱 만들기 단추를 찾아 클릭해야 합니다.

    LUIS 앱 만들기 페이지

  3. 로그인한 후 내 앱을 클릭합니다(현재 해당 섹션에 없는 경우). 그런 다음 새 앱 만들기를 클릭할 수 있습니다.

    LUIS - 내 앱 이미지

  4. 앱에 이름을 지정합니다.

  5. 앱이 영어와 다른 언어를 이해해야 하는 경우 Culture 를 적절한 언어로 변경해야 합니다.

  6. 여기에서 새 LUIS 앱에 대한 설명을 추가할 수도 있습니다.

    LUIS - 새 앱 만들기

  7. 완료를 누르면 새 LUIS 애플리케이션의 빌드 페이지가 입력됩니다.

  8. 여기서 이해해야 할 몇 가지 중요한 개념이 있습니다.

    • 의도는 사용자의 쿼리에 따라 호출되는 메서드를 나타냅니다. 의도에는 하나 이상의 엔터티가 있을 수 있습니다.
    • EntityINTENT와 관련된 정보를 설명하는 쿼리의 구성 요소입니다.
    • 발화는 LUIS가 자체 학습에 사용하는 개발자가 제공하는 쿼리의 예입니다.

이러한 개념이 완벽하게 명확하지 않은 경우 이 과정에서 이 챕터에서 자세히 설명하므로 걱정하지 마세요.

먼저 이 과정을 빌드하는 데 필요한 엔터티 를 만듭니다.

  1. 페이지 왼쪽에서 엔터티를 클릭한 다음 새 엔터티 만들기를 클릭합니다.

    새 엔터티 만들기

  2. 새 엔터티 을 호출하고 해당 형식을 단순으로 설정한 다음 완료를 누릅니다.

    단순 엔터티 만들기 - 색

  3. 이 프로세스를 반복하여 다음과 같은 세 개의 간단한 엔터티를 만듭니다.

    • 업사이징할
    • 줄여야
    • 대상

결과는 아래 이미지와 같아야 합니다.

엔터티 만들기 결과

이 시점에서 의도 만들기를 시작할 수 있습니다.

경고

None 의도는 삭제하지 마세요.

  1. 페이지 왼쪽에서 의도를 클릭한 다음 새 의도 만들기를 클릭합니다.

    새 의도 만들기

  2. 의도ChangeObjectColor를 호출합니다.

    중요

    의도 이름은 이 과정의 뒷부분에서 코드 내에서 사용되므로 최상의 결과를 위해 제공된 대로 이 이름을 정확하게 사용합니다.

이름을 확인하면 의도 페이지로 이동됩니다.

LUIS - 의도 페이지

5개 이상의 다른 발화를 입력하라는 텍스트 상자 가 있습니다.

참고

LUIS는 모든 발화를 소문자로 변환합니다.

  1. 위쪽 텍스트 상자에 다음 발화를 삽입하고(현재 형식 약 5 예제... ) 텍스트가 있는 다음 발화를 삽입하고 Enter 키를 누릅니다.
The color of the cylinder must be red

발화 가 아래 목록에 표시됩니다.

동일한 프로세스에 따라 다음 6개의 발화를 삽입합니다.

make the cube black

make the cylinder color white

change the sphere to red

change it to green

make this yellow

change the color of this object to blue

만든 각 발화에 대해 LUIS에서 엔터티로 사용해야 하는 단어를 식별해야 합니다. 이 예제에서는 모든 색에 엔터티로 레이블을 지정하고 대상에 대한 가능한 모든 참조를 대상 엔터티로 지정해야 합니다.

  1. 이렇게 하려면 첫 번째 발화에서 원통 이라는 단어를 클릭하고 대상을 선택합니다.

    발화 대상 식별

  2. 이제 첫 번째 발화에서 빨간색 단어를 클릭하고 을 선택합니다.

    발화 엔터티 식별

  3. 큐브가 대상이어야 하고검은색이어야 하는 다음 줄에도 레이블을 지정합니다. 또한 특정이 아닌 대상 형식을 사용할 수 있도록 제공하는 'this', 'it', 'this object'라는 단어도 사용합니다.

  4. 모든 발화에 엔터티 레이블이 지정될 때까지 위의 프로세스를 반복합니다. 도움이 필요한 경우 아래 이미지를 참조하세요.

    엔터티로 레이블을 지정할 단어를 선택할 경우 다음을 수행합니다.

    • 한 단어의 경우 클릭하기만 하면 됩니다.
    • 두 개 이상의 단어 집합에 대해 시작 부분을 클릭한 다음 집합의 끝을 클릭합니다.

    참고

    토큰 보기 토글 단추를 사용하여 엔터티/토큰 보기 간에 전환할 수 있습니다.

  5. 결과는 아래 이미지와 같이 엔터티/토큰 보기를 보여 줍니다.

    토큰 & 엔터티 뷰

  6. 이때 페이지 오른쪽 위에 있는 학습 단추를 누르고 작은 둥근 표시기가 녹색으로 변할 때까지 기다립니다. 이는 LUIS가 이 의도를 인식하도록 성공적으로 학습되었음을 나타냅니다.

    LUIS 학습

  7. 연습으로 엔터티 대상, 업사이즈 및다운사이즈를 사용하여 ChangeObjectSize라는 새 의도를 만듭니다.

  8. 이전 의도와 동일한 프로세스에 따라 크기 변경에 대한 다음 8개 발화를 삽입합니다.

    increase the dimensions of that
    
    reduce the size of this
    
    i want the sphere smaller
    
    make the cylinder bigger
    
    size down the sphere
    
    size up the cube
    
    decrease the size of that object
    
    increase the size of this object
    
  9. 결과는 아래 이미지의 결과와 같아야 합니다.

    ChangeObjectSize 토큰/엔터티 설정

  10. 의도, ChangeObjectColorChangeObjectSize가 모두 만들어지고 학습되면 페이지 맨 위에 있는 게시 단추를 클릭합니다.

    LUIS 서비스 게시

  11. 게시 페이지에서 LUIS 앱을 완료하고 게시하여 코드에서 액세스할 수 있도록 합니다.

    1. 게시할 드롭다운 프로덕션으로 설정합니다.

    2. 표준 시간대를 표준 시간대로 설정합니다.

    3. 예측된 모든 의도 점수 포함 확인란을 선택합니다.

    4. 프로덕션 슬롯에 게시를 클릭합니다.

      게시 설정

  12. 리소스 및 키 섹션에서 다음을 수행합니다.

    1. Azure Portal에서 서비스 instance 대해 설정한 지역을 선택합니다.
    2. 아래 의 Starter_Key 요소를 알아차리고 무시합니다.
    3. 키 추가를 클릭하고 서비스 instance 만들 때 Azure Portal에서 가져온 키를 삽입합니다. Azure와 LUIS 포털이 동일한 사용자에 로그인된 경우 테넌트 이름, 구독 이름 및 사용하려는 에 대한 드롭다운 메뉴가 제공됩니다(Azure Portal에서 이전에 제공한 것과 동일한 이름을 갖습니다.)

    중요

    엔드포인트 아래에서 삽입한 키에 해당하는 엔드포인트의 복사본을 가져와 코드에서 곧 사용할 것입니다.

3장 - Unity 프로젝트 설정

다음은 혼합 현실로 개발하기 위한 일반적인 설정이며, 따라서 다른 프로젝트에 적합한 템플릿입니다.

  1. Unity를 열고 새로 만들기를 클릭합니다.

    새 Unity 프로젝트를 시작합니다.

  2. 이제 Unity 프로젝트 이름을 제공하고 MR_LUIS 삽입해야 합니다. 프로젝트 형식이 3D로 설정되어 있는지 확인합니다. 위치를 적절한 위치로 설정합니다(루트 디렉터리에 더 가까울수록 좋습니다). 그런 다음 프로젝트 만들기를 클릭합니다.

    새 Unity 프로젝트에 대한 세부 정보를 제공합니다.

  3. Unity를 열면 기본 스크립트 편집 기가 Visual Studio로 설정되어 있는지 확인할 필요가 있습니다. 기본 설정 편집 > 으로 이동한 다음 새 창에서 외부 도구로 이동합니다. 외부 스크립트 편집기를 Visual Studio 2017로 변경합니다. 기본 설정 창을 닫습니다.

    스크립트 편집기 기본 설정을 업데이트합니다.

  4. 다음으로, 파일 > 빌드 설정으로 이동하여 플랫폼 전환 단추를 클릭하여 플랫폼을 유니버설 Windows 플랫폼전환합니다.

    빌드 설정 창에서 플랫폼을 UWP로 전환합니다.

  5. 파일 > 빌드 설정으로 이동하여 다음을 확인합니다.

    1. 대상 디바이스모든 디바이스로 설정됩니다.

      Microsoft HoloLens 대상 디바이스HoloLens로 설정합니다.

    2. 빌드 유형D3D로 설정됨

    3. SDK최신 설치됨으로 설정됨

    4. Visual Studio 버전최신 설치됨으로 설정됨

    5. 빌드 및 실행로컬 컴퓨터로 설정됩니다.

    6. 장면을 저장하고 빌드에 추가합니다.

      1. 열린 장면 추가를 선택하여 이 작업을 수행합니다. 저장 창이 나타납니다.

        열린 장면 추가 단추를 클릭합니다.

      2. 이에 대한 새 폴더를 만들고 이후의 장면에 대해 새 폴더 를 만든 다음 새 폴더 단추를 선택하여 새 폴더를 만들고 이름을 Scenes로 지정 합니다.

        새 스크립트 폴더 만들기

      3. 새로 만든 Scenes 폴더를 연 다음 파일 이름: 텍스트 필드에 MR_LuisScene 입력한 다음 저장을 누릅니다.

        새 장면에 이름을 지정합니다.

    7. 빌드 설정의 나머지 설정은 현재 기본값으로 남아 있어야 합니다.

  6. 빌드 설정 창에서 플레이어 설정 단추를 클릭하면 Inspector가 있는 공간에서 관련 패널이 열립니다.

    플레이어 설정을 엽니다.

  7. 이 패널에서 몇 가지 설정을 확인해야 합니다.

    1. 기타 설정 탭에서 다음을 수행합니다.

      1. 런타임 버전 스크립팅안정적 이어야 합니다(.NET 3.5 등가).

      2. 백 엔드 스크립팅.NET이어야 합니다.

      3. API 호환성 수준은.NET 4.6이어야 합니다.

        다른 설정을 업데이트합니다.

    2. 게시 설정 탭의 기능에서 다음을 검사.

      1. InternetClient

      2. 마이크

        게시 설정을 업데이트합니다.

    3. 패널 아래쪽의 XR 설정(게시 설정 아래에 있음)에서 Virtual Reality Supported를 체크하고 Windows Mixed Reality SDK가 추가되었는지 확인합니다.

      X R 설정을 업데이트합니다.

  8. 빌드 설정으로 돌아가서 Unity C# 프로젝트는 더 이상 회색으로 표시되지 않습니다. 이 옆에 있는 확인란을 선택합니다.

  9. 빌드 설정 창을 닫습니다.

  10. 장면 및 프로젝트를 저장합니다(파일 > 저장 장면/파일 > 저장 프로젝트).

4장 - 장면 만들기

중요

이 과정의 Unity 설정 구성 요소를 건너뛰고 코드를 계속 진행하려면 이 .unitypackage를 자유롭게 다운로드하고 프로젝트에 사용자 지정 패키지로 가져온 다음 5장에서 계속 진행하세요.

  1. 계층 패널의 빈 영역을 마우스 오른쪽 단추로 클릭하고 3D 개체 아래에서 평면을 추가합니다.

    평면을 만듭니다.

  2. 계층 구조 내에서 마우스 오른쪽 단추로 클릭하여 더 많은 개체를 만들 때 마지막 개체가 선택된 경우 선택한 개체가 새 개체의 부모가 됩니다. 계층 내의 빈 공간에서 이 왼쪽 단추를 클릭한 다음 마우스 오른쪽 단추를 클릭하지 마세요.

  3. 위의 절차를 반복하여 다음 개체를 추가합니다.

    1. Sphere
    2. 실린더
    3. Cube
    4. 3D 텍스트
  4. 결과 장면 계층 구조 는 아래 이미지에 있는 것과 같아야 합니다.

    장면 계층 설정.

  5. 주 카메라를 마우스 왼쪽 단추로 클릭하여 선택하고 검사기 패널을 보면 모든 구성 요소가 있는 카메라 개체가 표시됩니다.

  6. 검사기 패널의 맨 아래에 있는 구성 요소 추가 단추를 클릭합니다.

    오디오 원본 추가

  7. 위에 표시된 대로 오디오 원본이라는 구성 요소를 검색합니다.

  8. 또한 주 카메라의 변환 구성 요소가 (0,0,0)로 설정되어 있는지 확인합니다. 카메라의 변환 구성 요소 옆에 있는 기어 아이콘을 누르고 다시 설정을 선택하여 이 작업을 수행할 수 있습니다. 그런 다음 변환 구성 요소는 다음과 같이 표시됩니다.

    1. 위치0, 0, 0으로 설정됩니다.
    2. 회전0, 0, 0으로 설정됩니다.

    참고

    Microsoft HoloLens 경우 기본 카메라에 있는 카메라 구성 요소의 일부인 다음도 변경해야 합니다.

    • 플래그 지우기: 단색.
    • 배경 'Black, Alpha 0' – 16진수 색: #00000000.
  9. 평면을 마우스 왼쪽 단추로 클릭하여 선택합니다. 검사기 패널에서 Transform 구성 요소를 다음 값으로 설정합니다.

    X축 Y축 Z 축
    0 -1 0
  10. Sphere를 마우스 왼쪽 단추 로 클릭하여 선택합니다. 검사기 패널에서 Transform 구성 요소를 다음 값으로 설정합니다.

    X축 Y축 Z 축
    2 1 2
  11. 원통을 마우스 왼쪽 단추로 클릭하여 선택합니다. 검사기 패널에서 Transform 구성 요소를 다음 값으로 설정합니다.

    X축 Y축 Z 축
    -2 1 2
  12. 큐브를 마우스 왼쪽 단추로 클릭하여 선택합니다. 검사기 패널에서 Transform 구성 요소를 다음 값으로 설정합니다.

변환 - 위치

X Z
0 1 4

변환 - 회전

X Z
45 45 0
  1. 새 텍스트 개체를 마우스 왼쪽 단추로 클릭하여 선택합니다. 검사기 패널에서 변환 구성 요소를 다음 값으로 설정합니다.

변환 - 위치

X Z
-2 6 9

변환 - 크기 조정

X Z
0.1 0.1 0.1
  1. 텍스트 메시 구성 요소의 글꼴 크기를50으로 변경합니다.

  2. Text Mesh 개체의 이름을받아쓰기 텍스트로 변경합니다.

    3D Text 개체 만들기

  3. 계층 구조 패널 구조는 이제 다음과 같이 표시됩니다.

    장면 보기의 텍스트 메시

  4. 마지막 장면은 아래 이미지와 같아야 합니다.

    장면 보기입니다.

5장 – MicrophoneManager 클래스 만들기

만들려는 첫 번째 스크립트는 MicrophoneManager 클래스입니다. 그런 다음 LuisManager, Behaviours 클래스 및 마지막으로 Gaze 클래스를 만듭니다(각 챕터에 도달할 때 다루어지더라도 지금 이 모든 것을 자유롭게 만들 수 있음).

MicrophoneManager 클래스는 다음을 담당합니다.

  • 헤드셋 또는 컴퓨터에 연결된 녹음/녹화 장치 감지(기본값 중 하나임).
  • 오디오(음성)를 캡처하고 받아쓰기를 사용하여 문자열로 저장합니다.
  • 음성이 일시 중지되면 LuisManager 클래스에 받아쓰기를 제출합니다.

이 클래스를 만들려면 다음을 수행합니다.

  1. 프로젝트 패널 폴더 만들기를 마우스 오른쪽 단추로 >클릭합니다. 스크립트 폴더 를 호출합니다.

    스크립트 폴더를 만듭니다.

  2. Scripts 폴더를 만든 상태에서 두 번 클릭하여 엽니다. 그런 다음 해당 폴더 내에서 C# 스크립트 만들기를 마우스 오른쪽 단추로 >클릭합니다. 스크립트 이름을 MicrophoneManager로 지정합니다.

  3. MicrophoneManager를 두 번 클릭하여 Visual Studio에서 엽니다.

  4. 파일 맨 위에 다음 네임스페이스를 추가합니다.

        using UnityEngine;
        using UnityEngine.Windows.Speech;
    
  5. 그런 다음 , MicrophoneManager 클래스 내에 다음 변수를 추가합니다.

        public static MicrophoneManager instance; //help to access instance of this object
        private DictationRecognizer dictationRecognizer;  //Component converting speech to text
        public TextMesh dictationText; //a UI object used to debug dictation result
    
  6. 이제 Awake()Start() 메서드에 대한 코드를 추가해야 합니다. 클래스가 초기화될 때 호출됩니다.

        private void Awake()
        {
            // allows this class instance to behave like a singleton
            instance = this;
        }
    
        void Start()
        {
            if (Microphone.devices.Length > 0)
            {
                StartCapturingAudio();
                Debug.Log("Mic Detected");
            }
        }
    
  7. 이제 앱이 음성 캡처를 시작 및 중지하고 LuisManager 클래스에 전달하는 데 사용하는 메서드가 필요합니다. 이 메서드는 곧 빌드됩니다.

        /// <summary>
        /// Start microphone capture, by providing the microphone as a continual audio source (looping),
        /// then initialise the DictationRecognizer, which will capture spoken words
        /// </summary>
        public void StartCapturingAudio()
        {
            if (dictationRecognizer == null)
            {
                dictationRecognizer = new DictationRecognizer
                {
                    InitialSilenceTimeoutSeconds = 60,
                    AutoSilenceTimeoutSeconds = 5
                };
    
                dictationRecognizer.DictationResult += DictationRecognizer_DictationResult;
                dictationRecognizer.DictationError += DictationRecognizer_DictationError;
            }
            dictationRecognizer.Start();
            Debug.Log("Capturing Audio...");
        }
    
        /// <summary>
        /// Stop microphone capture
        /// </summary>
        public void StopCapturingAudio()
        {
            dictationRecognizer.Stop();
            Debug.Log("Stop Capturing Audio...");
        }
    
  8. 음성이 일시 중지될 때 호출될 받아쓰기 처리기를 추가합니다. 이 메서드는 받아쓰기 텍스트를 LuisManager 클래스에 전달합니다.

        /// <summary>
        /// This handler is called every time the Dictation detects a pause in the speech. 
        /// This method will stop listening for audio, send a request to the LUIS service 
        /// and then start listening again.
        /// </summary>
        private void DictationRecognizer_DictationResult(string dictationCaptured, ConfidenceLevel confidence)
        {
            StopCapturingAudio();
            StartCoroutine(LuisManager.instance.SubmitRequestToLuis(dictationCaptured, StartCapturingAudio));
            Debug.Log("Dictation: " + dictationCaptured);
            dictationText.text = dictationCaptured;
        }
    
        private void DictationRecognizer_DictationError(string error, int hresult)
        {
            Debug.Log("Dictation exception: " + error);
        }
    

    중요

    이 클래스는 이 메서드를 사용하지 않으므로 Update() 메서드를 삭제합니다.

  9. Unity로 돌아가기 전에 Visual Studio 에서 변경 내용을 저장해야 합니다.

    참고

    이때 Unity 편집기 콘솔 패널에 오류가 표시됩니다. 코드가 다음 챕터에서 만들 LuisManager 클래스를 참조하기 때문입니다.

6장 - LUISManager 클래스 만들기

Azure LUIS 서비스를 호출할 LuisManager 클래스를 만들어야 합니다.

이 클래스의 목적은 MicrophoneManager 클래스에서 받아쓰기 텍스트를 수신하고 분석할 Azure Language Understanding API로 보내는 것입니다.

이 클래스는 JSON 응답을 역직렬화하고 Actions 클래스의 적절한 메서드를 호출하여 작업을 트리거합니다.

이 클래스를 만들려면 다음을 수행합니다.

  1. Scripts 폴더를 두 번 클릭하여 엽니다.

  2. Scripts 폴더 내부를 마우스 오른쪽 단추로 클릭하고 C# 스크립트 만들기>를 클릭합니다. 스크립트 이름을 LuisManager로 지정합니다.

  3. 스크립트를 두 번 클릭하여 Visual Studio에서 엽니다.

  4. 파일 맨 위에 다음 네임스페이스를 추가합니다.

        using System;
        using System.Collections;
        using System.Collections.Generic;
        using System.IO;
        using UnityEngine;
        using UnityEngine.Networking;
    
  5. 먼저 Azure 의 역 직렬화된 JSON 응답을 나타내는 LuisManager 클래스(Start () 메서드 위의 동일한 스크립트 파일 내에서 세 개의 클래스를 만듭니다.

        [Serializable] //this class represents the LUIS response
        public class AnalysedQuery
        {
            public TopScoringIntentData topScoringIntent;
            public EntityData[] entities;
            public string query;
        }
    
        // This class contains the Intent LUIS determines 
        // to be the most likely
        [Serializable]
        public class TopScoringIntentData
        {
            public string intent;
            public float score;
        }
    
        // This class contains data for an Entity
        [Serializable]
        public class EntityData
        {
            public string entity;
            public string type;
            public int startIndex;
            public int endIndex;
            public float score;
        }
    
  6. 다음으로 LuisManager 클래스 내에 다음 변수를 추가합니다.

        public static LuisManager instance;
    
        //Substitute the value of luis Endpoint with your own End Point
        string luisEndpoint = "https://westus.api.cognitive... add your endpoint from the Luis Portal";
    
  7. LUIS 포털에서 사용할 LUIS 엔드포인트를 지금 에 배치해야 합니다.

  8. 이제 Awake() 메서드에 대한 코드를 추가해야 합니다. 이 메서드는 클래스가 초기화될 때 호출됩니다.

        private void Awake()
        {
            // allows this class instance to behave like a singleton
            instance = this;
        }
    
  9. 이제 이 애플리케이션이 MicrophoneManager 클래스에서 받은 받아쓰기를 LUIS로 보낸 다음 응답을 받고 역직렬화하는 데 사용하는 메서드가 필요합니다.

  10. 의도 및 관련 엔터티의 값이 결정되면 의도된 작업을 트리거하기 위해 Behaviours 클래스의 instance 전달됩니다.

        /// <summary>
        /// Call LUIS to submit a dictation result.
        /// The done Action is called at the completion of the method.
        /// </summary>
        public IEnumerator SubmitRequestToLuis(string dictationResult, Action done)
        {
            string queryString = string.Concat(Uri.EscapeDataString(dictationResult));
    
            using (UnityWebRequest unityWebRequest = UnityWebRequest.Get(luisEndpoint + queryString))
            {
                yield return unityWebRequest.SendWebRequest();
    
                if (unityWebRequest.isNetworkError || unityWebRequest.isHttpError)
                {
                    Debug.Log(unityWebRequest.error);
                }
                else
                {
                    try
                    {
                        AnalysedQuery analysedQuery = JsonUtility.FromJson<AnalysedQuery>(unityWebRequest.downloadHandler.text);
    
                        //analyse the elements of the response 
                        AnalyseResponseElements(analysedQuery);
                    }
                    catch (Exception exception)
                    {
                        Debug.Log("Luis Request Exception Message: " + exception.Message);
                    }
                }
    
                done();
                yield return null;
            }
        }
    
  11. 결과 분석Query를 읽고 엔터티를 결정하는 AnalyseResponseElements()라는 새 메서드를 만듭니다. 이러한 엔터티가 결정되면 동작에 사용할 Actionss 클래스의 instance 전달됩니다.

        private void AnalyseResponseElements(AnalysedQuery aQuery)
        {
            string topIntent = aQuery.topScoringIntent.intent;
    
            // Create a dictionary of entities associated with their type
            Dictionary<string, string> entityDic = new Dictionary<string, string>();
    
            foreach (EntityData ed in aQuery.entities)
            {
                entityDic.Add(ed.type, ed.entity);
            }
    
            // Depending on the topmost recognized intent, read the entities name
            switch (aQuery.topScoringIntent.intent)
            {
                case "ChangeObjectColor":
                    string targetForColor = null;
                    string color = null;
    
                    foreach (var pair in entityDic)
                    {
                        if (pair.Key == "target")
                        {
                            targetForColor = pair.Value;
                        }
                        else if (pair.Key == "color")
                        {
                            color = pair.Value;
                        }
                    }
    
                    Behaviours.instance.ChangeTargetColor(targetForColor, color);
                    break;
    
                case "ChangeObjectSize":
                    string targetForSize = null;
                    foreach (var pair in entityDic)
                    {
                        if (pair.Key == "target")
                        {
                            targetForSize = pair.Value;
                        }
                    }
    
                    if (entityDic.ContainsKey("upsize") == true)
                    {
                        Behaviours.instance.UpSizeTarget(targetForSize);
                    }
                    else if (entityDic.ContainsKey("downsize") == true)
                    {
                        Behaviours.instance.DownSizeTarget(targetForSize);
                    }
                    break;
            }
        }
    

    중요

    이 클래스는 사용하지 않으므로 Start()Update() 메서드를 삭제합니다.

  12. Unity로 돌아가기 전에 Visual Studio 에서 변경 내용을 저장해야 합니다.

참고

이때 Unity 편집기 콘솔 패널에 몇 가지 오류가 표시됩니다. 코드가 다음 챕터에서 만들 Behaviours 클래스를 참조하기 때문입니다.

7장 - Behaviours 클래스 만들기

Behaviours 클래스는 LuisManager 클래스에서 제공하는 엔터티를 사용하여 작업을 트리거합니다.

이 클래스를 만들려면 다음을 수행합니다.

  1. Scripts 폴더를 두 번 클릭하여 엽니다.

  2. Scripts 폴더 내부를 마우스 오른쪽 단추로 클릭하고 C# 스크립트 만들기>를 클릭합니다. 스크립트 이름을 동작으로 지정합니다.

  3. 스크립트를 두 번 클릭하여 Visual Studio에서 엽니다.

  4. 그런 다음 , Behaviours 클래스 내에 다음 변수를 추가합니다.

        public static Behaviours instance;
    
        // the following variables are references to possible targets
        public GameObject sphere;
        public GameObject cylinder;
        public GameObject cube;
        internal GameObject gazedTarget;
    
  5. Awake() 메서드 코드를 추가합니다. 이 메서드는 클래스가 초기화될 때 호출됩니다.

        void Awake()
        {
            // allows this class instance to behave like a singleton
            instance = this;
        }
    
  6. 다음 메서드는 LuisManager 클래스(이전에 만든)에 의해 호출되어 쿼리의 대상이 되는 개체를 확인한 다음 적절한 작업을 트리거합니다.

        /// <summary>
        /// Changes the color of the target GameObject by providing the name of the object
        /// and the name of the color
        /// </summary>
        public void ChangeTargetColor(string targetName, string colorName)
        {
            GameObject foundTarget = FindTarget(targetName);
            if (foundTarget != null)
            {
                Debug.Log("Changing color " + colorName + " to target: " + foundTarget.name);
    
                switch (colorName)
                {
                    case "blue":
                        foundTarget.GetComponent<Renderer>().material.color = Color.blue;
                        break;
    
                    case "red":
                        foundTarget.GetComponent<Renderer>().material.color = Color.red;
                        break;
    
                    case "yellow":
                        foundTarget.GetComponent<Renderer>().material.color = Color.yellow;
                        break;
    
                    case "green":
                        foundTarget.GetComponent<Renderer>().material.color = Color.green;
                        break;
    
                    case "white":
                        foundTarget.GetComponent<Renderer>().material.color = Color.white;
                        break;
    
                    case "black":
                        foundTarget.GetComponent<Renderer>().material.color = Color.black;
                        break;
                }          
            }
        }
    
        /// <summary>
        /// Reduces the size of the target GameObject by providing its name
        /// </summary>
        public void DownSizeTarget(string targetName)
        {
            GameObject foundTarget = FindTarget(targetName);
            foundTarget.transform.localScale -= new Vector3(0.5F, 0.5F, 0.5F);
        }
    
        /// <summary>
        /// Increases the size of the target GameObject by providing its name
        /// </summary>
        public void UpSizeTarget(string targetName)
        {
            GameObject foundTarget = FindTarget(targetName);
            foundTarget.transform.localScale += new Vector3(0.5F, 0.5F, 0.5F);
        }
    
  7. FindTarget() 메서드를 추가하여 현재 의도의 대상인 GameObjects를 확인합니다. 이 메서드는 엔터티에 명시적 대상이 정의되지 않은 경우 기본적으로 대상을 "응시"하는 GameObject 로 설정합니다.

        /// <summary>
        /// Determines which object reference is the target GameObject by providing its name
        /// </summary>
        private GameObject FindTarget(string name)
        {
            GameObject targetAsGO = null;
    
            switch (name)
            {
                case "sphere":
                    targetAsGO = sphere;
                    break;
    
                case "cylinder":
                    targetAsGO = cylinder;
                    break;
    
                case "cube":
                    targetAsGO = cube;
                    break;
    
                case "this": // as an example of target words that the user may use when looking at an object
                case "it":  // as this is the default, these are not actually needed in this example
                case "that":
                default: // if the target name is none of those above, check if the user is looking at something
                    if (gazedTarget != null) 
                    {
                        targetAsGO = gazedTarget;
                    }
                    break;
            }
            return targetAsGO;
        }
    

    중요

    이 클래스는 사용하지 않으므로 Start()Update() 메서드를 삭제합니다.

  8. Unity로 돌아가기 전에 Visual Studio 에서 변경 내용을 저장해야 합니다.

8장 - 응시 클래스 만들기

이 앱을 완료하는 데 필요한 마지막 클래스는 Gaze 클래스입니다. 이 클래스는 현재 사용자의 시각적 포커스에 있는 GameObject 에 대한 참조를 업데이트합니다.

이 클래스를 만들려면 다음을 수행합니다.

  1. Scripts 폴더를 두 번 클릭하여 엽니다.

  2. Scripts 폴더 내부를 마우스 오른쪽 단추로 클릭하고 C# 스크립트 만들기>를 클릭합니다. 스크립트 이름을 응시로 지정 합니다.

  3. 스크립트를 두 번 클릭하여 Visual Studio에서 엽니다.

  4. 이 클래스에 대해 다음 코드를 삽입합니다.

        using UnityEngine;
    
        public class Gaze : MonoBehaviour
        {        
            internal GameObject gazedObject;
            public float gazeMaxDistance = 300;
    
            void Update()
            {
                // Uses a raycast from the Main Camera to determine which object is gazed upon.
                Vector3 fwd = gameObject.transform.TransformDirection(Vector3.forward);
                Ray ray = new Ray(Camera.main.transform.position, fwd);
                RaycastHit hit;
                Debug.DrawRay(Camera.main.transform.position, fwd);
    
                if (Physics.Raycast(ray, out hit, gazeMaxDistance) && hit.collider != null)
                {
                    if (gazedObject == null)
                    {
                        gazedObject = hit.transform.gameObject;
    
                        // Set the gazedTarget in the Behaviours class
                        Behaviours.instance.gazedTarget = gazedObject;
                    }
                }
                else
                {
                    ResetGaze();
                }         
            }
    
            // Turn the gaze off, reset the gazeObject in the Behaviours class.
            public void ResetGaze()
            {
                if (gazedObject != null)
                {
                    Behaviours.instance.gazedTarget = null;
                    gazedObject = null;
                }
            }
        }
    
  5. Unity로 돌아가기 전에 Visual Studio 에서 변경 내용을 저장해야 합니다.

9장 – 장면 설정 완료

  1. 장면 설정을 완료하려면 스크립트 폴더에서 만든 각 스크립트를 계층 구조 패널기본 카메라 개체로 끌어옵니다.

  2. 주 카메라를 선택하고 검사기 패널을 보면 연결한 각 스크립트를 볼 수 있어야 하며, 아직 설정되지 않은 각 스크립트에 매개 변수가 있음을 알 수 있습니다.

    카메라 참조 대상 설정

  3. 이러한 매개 변수를 올바르게 설정하려면 다음 지침을 따릅니다.

    1. MicrophoneManager:

      • 계층 패널에서 받아쓰기 텍스트 개체를 받아쓰기 텍스트 매개 변수 값 상자로 끕니다.
    2. 계층 구조 패널동작:

      • Sphere 개체를 Sphere 참조 대상 상자로 끌어 옵니다.
      • 실린더실린더 참조 대상 상자로 끌어옵니다.
      • 큐브큐브 참조 대상 상자로 끌어옵니다.
    3. 응시:

      • 응시 최대 거리를300으로 설정합니다(아직 없는 경우).
  4. 결과는 아래 이미지와 같아야 합니다.

    이제 설정된 카메라 참조 대상을 표시합니다.

10장 – Unity 편집기에서 테스트

장면 설정이 제대로 구현되었는지 테스트합니다.

다음 사항을 확인합니다.

  • 모든 스크립트는 Main Camera 개체에 연결됩니다.
  • 주 카메라 검사기 패널의 모든 필드가 제대로 할당됩니다.
  1. Unity 편집기에서 재생 단추를 누릅니다. 앱은 연결된 몰입형 헤드셋 내에서 실행되어야 합니다.

  2. 다음과 같은 몇 가지 발언을 시도해 보세요.

    make the cylinder red
    
    change the cube to yellow
    
    I want the sphere blue
    
    make this to green
    
    change it to white
    

    참고

    Unity 콘솔에서 기본 오디오 디바이스 변경에 대한 오류가 표시되면 장면이 예상대로 작동하지 않을 수 있습니다. 이는 혼합 현실 포털이 헤드셋이 있는 헤드셋용 기본 제공 마이크를 처리하는 방식 때문입니다. 이 오류가 표시되면 장면을 중지하고 다시 시작하면 예상대로 작동합니다.

11장 - UWP 솔루션 빌드 및 테스트용 로드

애플리케이션이 Unity 편집기에서 작동하는지 확인했으면 빌드 및 배포할 준비가 된 것입니다.

빌드하려면 다음을 수행합니다.

  1. 파일 > 저장을 클릭하여 현재 장면을 저장합니다.

  2. 파일 > 빌드 설정으로 이동합니다.

  3. Unity C# 프로젝트라는 상자를 선택합니다(UWP 프로젝트가 만들어지면 코드를 보고 디버깅하는 데 유용합니다.

  4. 열린 장면 추가를 클릭한 다음 빌드를 클릭합니다.

    빌드 설정 창

  5. 솔루션을 빌드할 폴더를 선택하라는 메시지가 표시됩니다.

  6. BUILDS 폴더를 만들고 해당 폴더 내에서 원하는 적절한 이름으로 다른 폴더를 만듭니다.

  7. 폴더 선택을 클릭하여 해당 위치에서 빌드를 시작합니다.

    빌드 폴더 만들기빌드 폴더 선택

  8. Unity가 빌드를 완료하면(다소 시간이 걸릴 수 있음) 빌드 위치에 파일 탐색기 창이 열립니다.

로컬 컴퓨터에 배포하려면 다음을 수행합니다.

  1. Visual Studio에서 이전 챕터에서 만든 솔루션 파일을 엽니다.

  2. 솔루션 플랫폼에서x86, 로컬 머신을 선택합니다.

  3. 솔루션 구성에서 디버그를 선택합니다.

    Microsoft HoloLens 컴퓨터에 연결되지 않도록 원격 컴퓨터로 설정하는 것이 더 쉬울 수 있습니다. 하지만 다음을 수행해야 합니다.

    • 설정 > 네트워크 & 인터넷 >> Wi-Fi 고급 옵션 내에서 찾을 수 있는 HoloLens의 IP 주소를 알고 있습니다. IPv4는 사용해야 하는 주소입니다.
    • 개발자 모드가 켜지도록 합니다.개발자를 위한 설정 > 업데이트 & 보안 > 에서 찾을 수 있습니다.

    앱 배포

  4. 빌드 메뉴로 이동하여 솔루션 배포를 클릭하여 애플리케이션을 컴퓨터에 테스트용으로 로드합니다.

  5. 이제 앱이 설치된 앱 목록에 표시되고 시작할 준비가 되었습니다.

  6. 시작되면 앱에서 마이크에 대한 액세스 권한을 부여하라는 메시지를 표시합니다. 동작 컨트롤러 또는 음성 입력 또는 키보드를 사용하여 YES 단추를 누릅니다.

12장 - LUIS 서비스 개선

중요

이 챕터는 매우 중요하며 LUIS 서비스의 정확도를 개선하는 데 도움이 되므로 여러 번 반복해야 할 수 있습니다. 이 작업을 완료해야 합니다.

LUIS에서 제공하는 이해 수준을 개선하려면 새 발화를 캡처하고 이를 사용하여 LUIS 앱을 다시 학습시켜야 합니다.

예를 들어 LUIS에서 "증가" 및 "Upsize"를 이해하도록 학습했을 수 있지만 앱에서 "확대"와 같은 단어도 이해하지 못하게 하시겠습니까?

애플리케이션을 몇 번 사용한 후에는 사용자가 말한 모든 항목이 LUIS에서 수집되고 LUIS 포털에서 사용할 수 있습니다.

  1. LINK 및 로그인에 따라 포털 애플리케이션으로 이동합니다.

  2. MS 자격 증명으로 로그인한 후 앱 이름을 클릭합니다.

  3. 페이지 왼쪽에서 엔드포인트 발화 검토 단추를 클릭합니다.

    발화 검토

  4. 혼합 현실 애플리케이션에서 LUIS로 전송된 발화 목록이 표시됩니다.

    발화 목록

강조 표시된 엔 터티가 표시됩니다.

강조 표시된 각 단어를 마우스로 가리키면 각 발화를 검토하고 올바르게 인식된 엔터티, 잘못된 엔터티 및 누락된 엔터티를 확인할 수 있습니다.

위의 예제에서는 "spear"라는 단어가 대상으로 강조 표시되었으므로 마우스로 단어를 마우스로 가리키고 레이블 제거를 클릭하여 실수를 수정해야 합니다.

발화레이블 이미지 제거 확인

  1. 완전히 잘못된 발화가 발견되면 화면 오른쪽의 삭제 단추를 사용하여 삭제 할 수 있습니다.

    잘못된 발화 삭제

  2. 또는 LUIS가 발화를 올바르게 해석했다고 생각되면 맞춤 의도에 추가 단추를 사용하여 이해의 유효성을 검사할 수 있습니다.

    정렬된 의도에 추가

  3. 표시된 모든 발화를 정렬한 후 페이지를 다시 로드하여 더 많은 발화를 사용할 수 있는지 확인합니다.

  4. 애플리케이션 이해를 향상시키기 위해 이 프로세스를 가능한 한 여러 번 반복하는 것이 매우 중요합니다.

즐거운 시간 보내세요!

완성된 LUIS 통합 애플리케이션

축하합니다. Azure Language Understanding Intelligence Service를 활용하여 사용자가 말하는 내용을 이해하고 해당 정보에 대해 조치를 수행하는 혼합 현실 앱을 빌드했습니다.

랩 결과

보너스 연습

연습 1

이 응용 프로그램을 사용하는 동안 Floor 개체를 응시하고 색을 변경하도록 요청하는 경우 이를 확인할 수 있습니다. 응용 프로그램이 바닥 색을 변경하지 못하게 하는 방법을 알아낼 수 있나요?

연습 2

LUIS 및 앱 기능을 확장하고 장면의 개체에 대한 기능을 추가해 보세요. 예를 들어 사용자가 말하는 내용에 따라 응시 적중 지점에서 새 개체를 만든 다음, 기존 명령과 함께 현재 장면 개체와 함께 해당 개체를 사용할 수 있습니다.