ultron-ai-sdk 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -16,32 +16,27 @@ npm install ultron-ai-sdk
16
16
 
17
17
  ```javascript
18
18
  // Import the SDK
19
- import {SceneCanvas, Character} from './dist/index.mjs';
19
+ import {SceneCanvas, Character} from './dist/index.mjs';
20
20
 
21
- let devices = await navigator.mediaDevices.enumerateDevices();
22
- console.log(devices)
23
- let sceneCanvas
24
- let character
25
-
26
- const init = async() => {
27
- sceneCanvas = new SceneCanvas('target-html-element')
28
- const initializationSetting= {
29
- avatarId: "AVATAR_ID/REQUEST_ID",
30
- config:{
31
- accessToken : "ACCESS_TOKEN",
32
- refreshToken : "REFRESH_TOKEN",
33
- // sessionId : "426536db-25a4-4682-9bb4-4e93530f84a0",
34
- apiKey: "YOUR_ULTRON_API_KEY"
35
- },
36
- options:{
37
- alwaysListen: false // For Push to talk conversation
38
- }
21
+ let sceneCanvas
22
+ let character
23
+
24
+ const init = async() => {
25
+ sceneCanvas = new SceneCanvas('target-html-element')
26
+ const initializationSetting= {
27
+ avatarId: "AVATAR_ID", // AvatarId and Request Id are same
28
+ config:{
29
+ apiKey: "YOUR_ULTRON_API_KEY"
30
+ },
31
+ options:{
32
+ alwaysListen: false // For Push to talk conversation
39
33
  }
40
- await sceneCanvas.init(initializationSetting)
41
- character = sceneCanvas.character
42
-
43
34
  }
44
- init()
35
+ await sceneCanvas.init(initializationSetting)
36
+ character = sceneCanvas.character
37
+
38
+ }
39
+ init()
45
40
 
46
41
  ```
47
42
 
@@ -61,8 +56,7 @@ import {SceneCanvas, Character} from './dist/index.mjs';
61
56
 
62
57
  ```javascript
63
58
  const sceneCanvas = new SceneCanvas('target-html-element')
64
-
65
- ultronSDK.init(config)
59
+ sceneCanvas.init(config)
66
60
  ```
67
61
 
68
62
  ---
@@ -71,11 +65,26 @@ ultronSDK.init(config)
71
65
 
72
66
  | Option | Description |
73
67
  |-------------|--------------|
74
- | `accessToken` | Token recieved on successfull authentication |
75
- | `refreshToken` |Token recieved on successfull refreshing of existing access token |
76
68
  | `sessionId` (optional) | Session Id obtained using API key |
77
69
  | `apiKey` | You ultron key which can be found in your profile in Ultron App |
78
70
 
71
+ #### API key (apiKey)
72
+
73
+ To get API key of your ultron account follow the steps below
74
+
75
+ ### STEP 1: Click on account at top right corner
76
+
77
+ ![Avatar ID step 1](https://media.ultronai.me/Images/website/apikeysh1.png)
78
+
79
+ ### STEP 2: Select API key from dropdown
80
+
81
+ ![Avatar ID step 1](https://media.ultronai.me/Images/website/apikey2.png)
82
+
83
+ ### STEP 3: Copy your API key
84
+
85
+ ![Avatar ID step 1](https://media.ultronai.me/Images/website/apishe3.png)
86
+
87
+
79
88
  ---
80
89
 
81
90
  ## Core Methods
@@ -86,8 +95,24 @@ Loads a specific avatar into the container.
86
95
 
87
96
  - `avatarId`: **String** - The unique identifier for the avatar
88
97
 
89
- ---
90
98
 
99
+ ### AvatarId
100
+
101
+ To get avatarId follow the steps below
102
+
103
+ ### Step 1: Open the desired avatar in ultron app (app.ultronai.me)
104
+
105
+ Click share on top right corner
106
+
107
+ ![Avatar ID step 1](https://media.ultronai.me/Images/website/avateridshar1.png)
108
+
109
+ ### Step 1: Open the desired avatar in ultron app (app.ultronai.me)
110
+
111
+ Step 2: Select the avatar id value as from share url
112
+
113
+ ![Avatar ID step 2](https://media.ultronai.me/Images/website/avartaridshare2.png)
114
+
115
+ ---
91
116
 
92
117
  ## Audio Input Device Settings
93
118
 
@@ -142,25 +167,27 @@ ultronSDK.setAudioInputDevice(myDevice.deviceId)
142
167
  ### Basic Implementation
143
168
 
144
169
  ```javascript
145
- import CharacterCompanionSDK from './dist/index.mjs';
146
-
147
- init=()=>{
148
- let sdk = new CharacterCompanionSDK('ultron-model')
149
- ultronSDK.init({
150
- accessToken : 'YOUR_ACCESS_TOKEN',
151
- refreshToken : 'YOUR_REFRESH_TOKEN',
152
- sessionId : "SESSIOON_ID", // If you have backend or it will create session from apiKey
153
- apiKey: "YOUR_ULTRON_API_KEY"
154
- })
155
- const avatarId = 'AVATAR_ID/REQUEST_ID'
156
- await ultronSDK.loadAvatarById(avatarId)
157
- ultronSDK.initAudioListener()
158
-
159
- // Load an avatar
160
- await ultron.loadAvatar('avatar-id');
161
- }
162
-
163
- init()
170
+ import {SceneCanvas, Character} from './dist/index.mjs';
171
+
172
+ let sceneCanvas
173
+ let character
174
+
175
+ const init = async() => {
176
+ sceneCanvas = new SceneCanvas('target-html-element')
177
+ const initializationSetting= {
178
+ avatarId: "AVATAR_ID/REQUEST_ID",
179
+ config:{
180
+ apiKey: "YOUR_ULTRON_API_KEY"
181
+ },
182
+ options:{
183
+ alwaysListen: false // For Push to talk conversation
184
+ }
185
+ }
186
+ await sceneCanvas.init(initializationSetting)
187
+ character = sceneCanvas.character
188
+
189
+ }
190
+ init()
164
191
  ```
165
192
 
166
193
  ---
@@ -168,7 +195,9 @@ init()
168
195
  ### Chat with character using AI
169
196
 
170
197
  ```javascript
171
- ultronSDK.chat("your text query to AI")
198
+ // once you have the "character" object from sceneCanvas after init() you can use it to chat
199
+
200
+ character.chat("your text query to AI")
172
201
 
173
202
  //This will generate a response from AI as per Avatar backstory and character will speak the response
174
203
 
@@ -178,7 +207,8 @@ ultronSDK.chat("your text query to AI")
178
207
  ### Make the character say
179
208
 
180
209
  ```javascript
181
- ultronSDK.say("your text that character will speak")
210
+
211
+ character.say("your text that character will speak")
182
212
 
183
213
  // This will simply make the character speak the text you provide
184
214
 
@@ -189,11 +219,11 @@ ultronSDK.say("your text that character will speak")
189
219
  ```javascript
190
220
  //Switch camera to potrait (closer to face)
191
221
 
192
- ultronSDK.switchCameraToPotrait()
222
+ sceneCanvas.switchCameraToPotrait()
193
223
 
194
224
  //Switch camera to normal position (full body view)
195
225
 
196
- ultronSDK.switchCameraToNormal()
226
+ sceneCanvas.switchCameraToNormal()
197
227
 
198
228
 
199
229
 
package/dist/index.cjs CHANGED
@@ -43655,6 +43655,7 @@ class AudioListener {
43655
43655
  stopListening() {
43656
43656
  if (this.mediaRecorder && this.mediaRecorder.state === "recording") {
43657
43657
  this.mediaRecorder.stop();
43658
+
43658
43659
  this.stream.getTracks().forEach(track => {
43659
43660
  track.stop();
43660
43661
 
@@ -43693,10 +43694,13 @@ class AudioListener {
43693
43694
 
43694
43695
  }
43695
43696
 
43696
- detectSilence(silenceThreshold = -50, silenceDuration = 2000) {
43697
+ detectSilence(silenceThreshold = -40, silenceDuration = 700, maxListenDuration = 10) {
43697
43698
  const bufferLength = this.analyser.frequencyBinCount;
43698
43699
  const dataArray = new Uint8Array(bufferLength);
43699
-
43700
+ this.maxkimitTimeout = setTimeout(()=>{
43701
+ console.log("Max time limite reached, stopping recording...");
43702
+ this.stopListening();
43703
+ },maxListenDuration*1000);
43700
43704
  const checkSilence = () => {
43701
43705
  if (!this.mediaRecorder || this.mediaRecorder.state !== "recording") return;
43702
43706
 
@@ -43928,6 +43932,7 @@ class SceneCanvas{
43928
43932
 
43929
43933
  addCharacter=(character)=>{
43930
43934
  this.character = character;
43935
+ this.character.sceneCanvasRef = this;
43931
43936
  this.scene.add(this.character.model);
43932
43937
  }
43933
43938
 
@@ -43959,23 +43964,31 @@ class SceneCanvas{
43959
43964
 
43960
43965
  console.log('adding mic button');
43961
43966
  // Create button element
43967
+ this.voiceElementBlock = document.createElement('div');
43968
+
43969
+ this.voiceElementBlock.style.position = 'absolute';
43970
+ this.voiceElementBlock.style.bottom = '20px';
43971
+ this.voiceElementBlock.style.marginLeft = '50%';
43972
+ this.voiceElementBlock.style.transition = 'background-color 0.2s';
43973
+ this.voiceElementBlock.style.transform = 'translate(-50%, 0%)';
43974
+
43962
43975
  const micButton = document.createElement('button');
43976
+ this.micButton = micButton;
43963
43977
  micButton.id = 'mic-button';
43964
43978
  // Mic emoji (you can replace with SVG if needed)
43965
43979
 
43966
43980
  // Apply styles (round, centered icon, etc.)
43967
- micButton.style.width = '64px';
43968
- micButton.style.height = '64px';
43981
+ micButton.style.width = '48px';
43982
+ micButton.style.height = '48px';
43969
43983
  micButton.style.borderRadius = '50%';
43970
43984
  micButton.style.backgroundColor = '#f1f1f1';
43971
- micButton.style.position = 'absolute';
43972
- micButton.style.bottom = '20px';
43973
- micButton.style.marginLeft = '50%';
43985
+
43986
+
43974
43987
 
43975
43988
  micButton.style.display = 'flex';
43976
43989
  micButton.style.alignItems = 'center';
43977
43990
  micButton.style.justifyContent = 'center';
43978
- micButton.style.boxShadow = '0 4px 8px rgba(0,0,0,0.2)';
43991
+ micButton.style.boxShadow = '0 4px 8px rgba(0,0,0,0.3)';
43979
43992
  micButton.style.cursor = 'pointer';
43980
43993
  micButton.style.border = 'none';
43981
43994
  micButton.style.fontSize = '24px';
@@ -43987,9 +44000,18 @@ class SceneCanvas{
43987
44000
  const micIcon = document.createElement('img');
43988
44001
  micIcon.src = micUrl;
43989
44002
  micIcon.alt = 'Mic Icon';
43990
- micIcon.style.width = '36px';
43991
- micIcon.style.height = '36px';
44003
+ micIcon.style.width = '26px';
44004
+ micIcon.style.height = '26px';
43992
44005
 
44006
+ this.voiceUIText = document.createElement('div');
44007
+ this.voiceUIText.style.display = 'none';
44008
+ this.voiceUIText.style.fontFamily = '"Inter", sans-serif';
44009
+ this.voiceUIText.style.fontSize = '20px';
44010
+ this.voiceUIText.style.color = "white";
44011
+ this.voiceUIText.style.backgroundColor = "#00000030";
44012
+ this.voiceUIText.style.padding = "4px";
44013
+
44014
+ this.voiceUIText.innerHTML = "Listening...";
43993
44015
  // Hover effect
43994
44016
  micButton.onmouseover = () => {
43995
44017
  micButton.style.backgroundColor = '#e5e5e5';
@@ -44006,7 +44028,10 @@ class SceneCanvas{
44006
44028
 
44007
44029
  // Append to target div
44008
44030
  micButton.appendChild(micIcon);
44009
- this.container.appendChild(micButton);
44031
+ this.voiceElementBlock.append(this.micButton);
44032
+ this.voiceElementBlock.append(this.voiceUIText);
44033
+
44034
+ this.container.appendChild(this.voiceElementBlock);
44010
44035
  }
44011
44036
  }
44012
44037
 
@@ -44052,10 +44077,23 @@ class Character {
44052
44077
  console.log('initializing audio listener');
44053
44078
  this.continuousConversation = alwaysListen;
44054
44079
  this.audioListener = new AudioListener();
44055
- this.audioListener.onSpeechStart = () => {console.log('Listening...'); };
44080
+ this.audioListener.onSpeechStart = () => {
44081
+ console.log('Listening...');
44082
+ if(this.sceneCanvasRef?.micButton){
44083
+ this.sceneCanvasRef.micButton.style.display = 'none';
44084
+ }
44085
+ if(this.sceneCanvasRef?.voiceUIText){
44086
+ this.sceneCanvasRef.voiceUIText.style.display = 'block';
44087
+ this.sceneCanvasRef.voiceUIText.innerHTML = "Listening...";
44088
+ }
44089
+
44090
+ };
44056
44091
  this.audioListener.onSpeechEnd = (audio) => {
44057
44092
  console.log("audio ended", audio);
44058
- this.AIServices.currentAudioChunks = [audio];
44093
+ this.AIServices.currentAudioChunks = [audio];
44094
+ if(this.sceneCanvasRef?.voiceUIText){
44095
+ this.sceneCanvasRef.voiceUIText.innerHTML = "Thinking...";
44096
+ }
44059
44097
  this.handleCurrentAudioMessage();
44060
44098
  };
44061
44099
  console.log(this.audioListener);
@@ -44093,6 +44131,7 @@ class Character {
44093
44131
  formData.append("lipSync", false);
44094
44132
 
44095
44133
  this.chatHistory.push({ text: 'audio', role: 'user' });
44134
+ // this.playAnimation('listening')
44096
44135
  await this.chat('audio',formData);
44097
44136
  // this.chatHistory.push({ text: response.text, role: 'assistant' });
44098
44137
  }
@@ -44240,14 +44279,27 @@ class Character {
44240
44279
  }, (duration - 0.5)*1000);
44241
44280
  }
44242
44281
  }
44282
+ if(this.sceneCanvasRef?.voiceUIText){
44283
+ this.sceneCanvasRef.voiceUIText.innerHTML = "Speaking...";
44284
+
44285
+ }
44243
44286
 
44244
44287
  }
44245
44288
 
44246
44289
  onSpeakComplete=()=>{
44247
- if(this.continuousConversation)
44290
+ if(this.continuousConversation){
44248
44291
  this.startListening();
44249
- else
44250
- this.playAnimation('idle');
44292
+ }else {
44293
+ if(this.sceneCanvasRef?.micButton){
44294
+ this.sceneCanvasRef.micButton.style.display = 'flex';
44295
+ }
44296
+ if(this.sceneCanvasRef?.voiceUIText){
44297
+ this.sceneCanvasRef.voiceUIText.style.display = 'none';
44298
+ this.sceneCanvasRef.voiceUIText.innerHTML = "";
44299
+ }
44300
+
44301
+ this.playAnimation('idle');
44302
+ }
44251
44303
  }
44252
44304
 
44253
44305
  processLipSync=(lipSyncData)=>{
package/dist/index.mjs CHANGED
@@ -43653,6 +43653,7 @@ class AudioListener {
43653
43653
  stopListening() {
43654
43654
  if (this.mediaRecorder && this.mediaRecorder.state === "recording") {
43655
43655
  this.mediaRecorder.stop();
43656
+
43656
43657
  this.stream.getTracks().forEach(track => {
43657
43658
  track.stop();
43658
43659
 
@@ -43691,10 +43692,13 @@ class AudioListener {
43691
43692
 
43692
43693
  }
43693
43694
 
43694
- detectSilence(silenceThreshold = -50, silenceDuration = 2000) {
43695
+ detectSilence(silenceThreshold = -40, silenceDuration = 700, maxListenDuration = 10) {
43695
43696
  const bufferLength = this.analyser.frequencyBinCount;
43696
43697
  const dataArray = new Uint8Array(bufferLength);
43697
-
43698
+ this.maxkimitTimeout = setTimeout(()=>{
43699
+ console.log("Max time limite reached, stopping recording...");
43700
+ this.stopListening();
43701
+ },maxListenDuration*1000);
43698
43702
  const checkSilence = () => {
43699
43703
  if (!this.mediaRecorder || this.mediaRecorder.state !== "recording") return;
43700
43704
 
@@ -43926,6 +43930,7 @@ class SceneCanvas{
43926
43930
 
43927
43931
  addCharacter=(character)=>{
43928
43932
  this.character = character;
43933
+ this.character.sceneCanvasRef = this;
43929
43934
  this.scene.add(this.character.model);
43930
43935
  }
43931
43936
 
@@ -43957,23 +43962,31 @@ class SceneCanvas{
43957
43962
 
43958
43963
  console.log('adding mic button');
43959
43964
  // Create button element
43965
+ this.voiceElementBlock = document.createElement('div');
43966
+
43967
+ this.voiceElementBlock.style.position = 'absolute';
43968
+ this.voiceElementBlock.style.bottom = '20px';
43969
+ this.voiceElementBlock.style.marginLeft = '50%';
43970
+ this.voiceElementBlock.style.transition = 'background-color 0.2s';
43971
+ this.voiceElementBlock.style.transform = 'translate(-50%, 0%)';
43972
+
43960
43973
  const micButton = document.createElement('button');
43974
+ this.micButton = micButton;
43961
43975
  micButton.id = 'mic-button';
43962
43976
  // Mic emoji (you can replace with SVG if needed)
43963
43977
 
43964
43978
  // Apply styles (round, centered icon, etc.)
43965
- micButton.style.width = '64px';
43966
- micButton.style.height = '64px';
43979
+ micButton.style.width = '48px';
43980
+ micButton.style.height = '48px';
43967
43981
  micButton.style.borderRadius = '50%';
43968
43982
  micButton.style.backgroundColor = '#f1f1f1';
43969
- micButton.style.position = 'absolute';
43970
- micButton.style.bottom = '20px';
43971
- micButton.style.marginLeft = '50%';
43983
+
43984
+
43972
43985
 
43973
43986
  micButton.style.display = 'flex';
43974
43987
  micButton.style.alignItems = 'center';
43975
43988
  micButton.style.justifyContent = 'center';
43976
- micButton.style.boxShadow = '0 4px 8px rgba(0,0,0,0.2)';
43989
+ micButton.style.boxShadow = '0 4px 8px rgba(0,0,0,0.3)';
43977
43990
  micButton.style.cursor = 'pointer';
43978
43991
  micButton.style.border = 'none';
43979
43992
  micButton.style.fontSize = '24px';
@@ -43985,9 +43998,18 @@ class SceneCanvas{
43985
43998
  const micIcon = document.createElement('img');
43986
43999
  micIcon.src = micUrl;
43987
44000
  micIcon.alt = 'Mic Icon';
43988
- micIcon.style.width = '36px';
43989
- micIcon.style.height = '36px';
44001
+ micIcon.style.width = '26px';
44002
+ micIcon.style.height = '26px';
43990
44003
 
44004
+ this.voiceUIText = document.createElement('div');
44005
+ this.voiceUIText.style.display = 'none';
44006
+ this.voiceUIText.style.fontFamily = '"Inter", sans-serif';
44007
+ this.voiceUIText.style.fontSize = '20px';
44008
+ this.voiceUIText.style.color = "white";
44009
+ this.voiceUIText.style.backgroundColor = "#00000030";
44010
+ this.voiceUIText.style.padding = "4px";
44011
+
44012
+ this.voiceUIText.innerHTML = "Listening...";
43991
44013
  // Hover effect
43992
44014
  micButton.onmouseover = () => {
43993
44015
  micButton.style.backgroundColor = '#e5e5e5';
@@ -44004,7 +44026,10 @@ class SceneCanvas{
44004
44026
 
44005
44027
  // Append to target div
44006
44028
  micButton.appendChild(micIcon);
44007
- this.container.appendChild(micButton);
44029
+ this.voiceElementBlock.append(this.micButton);
44030
+ this.voiceElementBlock.append(this.voiceUIText);
44031
+
44032
+ this.container.appendChild(this.voiceElementBlock);
44008
44033
  }
44009
44034
  }
44010
44035
 
@@ -44050,10 +44075,23 @@ class Character {
44050
44075
  console.log('initializing audio listener');
44051
44076
  this.continuousConversation = alwaysListen;
44052
44077
  this.audioListener = new AudioListener();
44053
- this.audioListener.onSpeechStart = () => {console.log('Listening...'); };
44078
+ this.audioListener.onSpeechStart = () => {
44079
+ console.log('Listening...');
44080
+ if(this.sceneCanvasRef?.micButton){
44081
+ this.sceneCanvasRef.micButton.style.display = 'none';
44082
+ }
44083
+ if(this.sceneCanvasRef?.voiceUIText){
44084
+ this.sceneCanvasRef.voiceUIText.style.display = 'block';
44085
+ this.sceneCanvasRef.voiceUIText.innerHTML = "Listening...";
44086
+ }
44087
+
44088
+ };
44054
44089
  this.audioListener.onSpeechEnd = (audio) => {
44055
44090
  console.log("audio ended", audio);
44056
- this.AIServices.currentAudioChunks = [audio];
44091
+ this.AIServices.currentAudioChunks = [audio];
44092
+ if(this.sceneCanvasRef?.voiceUIText){
44093
+ this.sceneCanvasRef.voiceUIText.innerHTML = "Thinking...";
44094
+ }
44057
44095
  this.handleCurrentAudioMessage();
44058
44096
  };
44059
44097
  console.log(this.audioListener);
@@ -44091,6 +44129,7 @@ class Character {
44091
44129
  formData.append("lipSync", false);
44092
44130
 
44093
44131
  this.chatHistory.push({ text: 'audio', role: 'user' });
44132
+ // this.playAnimation('listening')
44094
44133
  await this.chat('audio',formData);
44095
44134
  // this.chatHistory.push({ text: response.text, role: 'assistant' });
44096
44135
  }
@@ -44238,14 +44277,27 @@ class Character {
44238
44277
  }, (duration - 0.5)*1000);
44239
44278
  }
44240
44279
  }
44280
+ if(this.sceneCanvasRef?.voiceUIText){
44281
+ this.sceneCanvasRef.voiceUIText.innerHTML = "Speaking...";
44282
+
44283
+ }
44241
44284
 
44242
44285
  }
44243
44286
 
44244
44287
  onSpeakComplete=()=>{
44245
- if(this.continuousConversation)
44288
+ if(this.continuousConversation){
44246
44289
  this.startListening();
44247
- else
44248
- this.playAnimation('idle');
44290
+ }else {
44291
+ if(this.sceneCanvasRef?.micButton){
44292
+ this.sceneCanvasRef.micButton.style.display = 'flex';
44293
+ }
44294
+ if(this.sceneCanvasRef?.voiceUIText){
44295
+ this.sceneCanvasRef.voiceUIText.style.display = 'none';
44296
+ this.sceneCanvasRef.voiceUIText.innerHTML = "";
44297
+ }
44298
+
44299
+ this.playAnimation('idle');
44300
+ }
44249
44301
  }
44250
44302
 
44251
44303
  processLipSync=(lipSyncData)=>{
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ultron-ai-sdk",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "This package is for integrating Ultron AI Characters as website Companions on a website",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.mjs",