agora-appbuilder-core 4.1.0-beta-4 → 4.1.0-beta-5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agora-appbuilder-core",
3
- "version": "4.1.0-beta-4",
3
+ "version": "4.1.0-beta-5",
4
4
  "description": "React Native template for RTE app builder",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -1,4 +1,10 @@
1
- import {UidType, useContent, useRoomInfo, Toast} from 'customization-api';
1
+ import {
2
+ UidType,
3
+ useContent,
4
+ useRoomInfo,
5
+ Toast,
6
+ useRtc,
7
+ } from 'customization-api';
2
8
  import React, {createContext, useContext, useEffect} from 'react';
3
9
  import {AgentContext} from './AgentContext';
4
10
  import {AgentState} from './const';
@@ -25,12 +31,125 @@ export const AgentConnectionProvider: React.FC<{children: React.ReactNode}> = ({
25
31
  agentId,
26
32
  setAgentUID,
27
33
  prompt,
34
+ isSubscribedForStreams,
35
+ setIsSubscribedForStreams,
36
+ addChatItem,
28
37
  } = useContext(AgentContext);
29
38
  const {
30
39
  data: {channel: channel_name, uid: localUid, agents},
31
40
  } = useRoomInfo();
32
41
  const {store} = useContext(StorageContext);
33
42
 
43
+ const {RtcEngineUnsafe} = useRtc();
44
+
45
+ const messageCache = {};
46
+ const TIMEOUT_MS = 5000; // Timeout for incomplete messages
47
+
48
+ React.useEffect(() => {
49
+ if (!isSubscribedForStreams) {
50
+ RtcEngineUnsafe.addListener(
51
+ 'onStreamMessage',
52
+ handleStreamMessageCallback,
53
+ );
54
+ setIsSubscribedForStreams(true);
55
+ }
56
+ }, []);
57
+
58
+ const handleStreamMessageCallback = (...args) => {
59
+ console.log('rec', args);
60
+ parseData(args[1]);
61
+ };
62
+
63
+ const parseData = data => {
64
+ let decoder = new TextDecoder('utf-8');
65
+ let decodedMessage = decoder.decode(data);
66
+ console.log('[test] textstream raw data', decodedMessage);
67
+ handleChunk(decodedMessage);
68
+ };
69
+ // Function to process received chunk via event emitter
70
+ const handleChunk = (formattedChunk: string) => {
71
+ try {
72
+ // Split the chunk by the delimiter "|"
73
+ const [message_id, partIndexStr, totalPartsStr, content] =
74
+ formattedChunk.split('|');
75
+
76
+ const part_index = parseInt(partIndexStr, 10);
77
+ const total_parts =
78
+ totalPartsStr === '???' ? -1 : parseInt(totalPartsStr, 10); // -1 means total parts unknown
79
+
80
+ // Ensure total_parts is known before processing further
81
+ if (total_parts === -1) {
82
+ console.warn(
83
+ `Total parts for message ${message_id} unknown, waiting for further parts.`,
84
+ );
85
+ return;
86
+ }
87
+
88
+ const chunkData = {
89
+ message_id,
90
+ part_index,
91
+ total_parts,
92
+ content,
93
+ };
94
+
95
+ // Check if we already have an entry for this message
96
+ if (!messageCache[message_id]) {
97
+ messageCache[message_id] = [];
98
+ // Set a timeout to discard incomplete messages
99
+ setTimeout(() => {
100
+ if (messageCache[message_id]?.length !== total_parts) {
101
+ console.warn(`Incomplete message with ID ${message_id} discarded`);
102
+ delete messageCache[message_id]; // Discard incomplete message
103
+ }
104
+ }, TIMEOUT_MS);
105
+ }
106
+
107
+ // Cache this chunk by message_id
108
+ messageCache[message_id].push(chunkData);
109
+
110
+ // If all parts are received, reconstruct the message
111
+ if (messageCache[message_id].length === total_parts) {
112
+ const completeMessage = reconstructMessage(messageCache[message_id]);
113
+ const data = atob(completeMessage);
114
+ const {stream_id, is_final, text, text_ts} = JSON.parse(data);
115
+ /** Data type of above object
116
+ * stream_id: number
117
+ * is_final: boolean
118
+ * text: string
119
+ * text_ts: number
120
+ */
121
+ const textItem = {
122
+ id: message_id,
123
+ uid: stream_id,
124
+ time: text_ts,
125
+ dataType: 'transcribe',
126
+ text: text,
127
+ isFinal: is_final,
128
+ isSelf: stream_id === 0 ? false : true,
129
+ };
130
+
131
+ if (text.trim().length > 0) {
132
+ //this.emit("textChanged", textItem);
133
+ console.warn('emit textChanged: ', textItem);
134
+ addChatItem(textItem);
135
+ }
136
+
137
+ // Clean up the cache
138
+ delete messageCache[message_id];
139
+ }
140
+ } catch (error) {
141
+ console.error('Error processing chunk:', error);
142
+ }
143
+ };
144
+
145
+ const reconstructMessage = chunks => {
146
+ // Sort chunks by their part index
147
+ chunks.sort((a, b) => a.part_index - b.part_index);
148
+
149
+ // Concatenate all chunks to form the full message
150
+ return chunks.map(chunk => chunk.content).join('');
151
+ };
152
+
34
153
  useEffect(() => {
35
154
  console.log('debugging users agent contrl', {users});
36
155
  // welcome agent
@@ -87,7 +87,7 @@ export const AgentControl: React.FC = () => {
87
87
  lineHeight: 18,
88
88
  fontWeight: '600',
89
89
  ...fontcolorStyle,
90
- }}>{`${AI_AGENT_STATE[agentConnectionState]}`}</Text>
90
+ }}>{` ${AI_AGENT_STATE[agentConnectionState]}`}</Text>
91
91
  ) : (
92
92
  <></>
93
93
  )}
@@ -1,122 +1,8 @@
1
1
  import {StyleSheet, View} from 'react-native';
2
- import React, {useContext} from 'react';
3
- import {useRtc} from 'customization-api';
4
- import {AgentContext} from './AgentControls/AgentContext';
2
+ import React from 'react';
5
3
  import ChatScreen from './agent-chat-panel/agent-chat-ui';
6
4
 
7
5
  const CustomSidePanel = () => {
8
- const {RtcEngineUnsafe} = useRtc();
9
- const {isSubscribedForStreams, setIsSubscribedForStreams, addChatItem} =
10
- useContext(AgentContext);
11
-
12
- const messageCache = {};
13
- const TIMEOUT_MS = 5000; // Timeout for incomplete messages
14
-
15
- React.useEffect(() => {
16
- if (!isSubscribedForStreams) {
17
- RtcEngineUnsafe.addListener(
18
- 'onStreamMessage',
19
- handleStreamMessageCallback,
20
- );
21
- setIsSubscribedForStreams(true);
22
- }
23
- }, []);
24
-
25
- const handleStreamMessageCallback = (...args) => {
26
- console.log('rec', args);
27
- parseData(args[1]);
28
- };
29
-
30
- const parseData = data => {
31
- let decoder = new TextDecoder('utf-8');
32
- let decodedMessage = decoder.decode(data);
33
- console.log('[test] textstream raw data', decodedMessage);
34
- handleChunk(decodedMessage);
35
- };
36
- // Function to process received chunk via event emitter
37
- const handleChunk = (formattedChunk: string) => {
38
- try {
39
- // Split the chunk by the delimiter "|"
40
- const [message_id, partIndexStr, totalPartsStr, content] =
41
- formattedChunk.split('|');
42
-
43
- const part_index = parseInt(partIndexStr, 10);
44
- const total_parts =
45
- totalPartsStr === '???' ? -1 : parseInt(totalPartsStr, 10); // -1 means total parts unknown
46
-
47
- // Ensure total_parts is known before processing further
48
- if (total_parts === -1) {
49
- console.warn(
50
- `Total parts for message ${message_id} unknown, waiting for further parts.`,
51
- );
52
- return;
53
- }
54
-
55
- const chunkData = {
56
- message_id,
57
- part_index,
58
- total_parts,
59
- content,
60
- };
61
-
62
- // Check if we already have an entry for this message
63
- if (!messageCache[message_id]) {
64
- messageCache[message_id] = [];
65
- // Set a timeout to discard incomplete messages
66
- setTimeout(() => {
67
- if (messageCache[message_id]?.length !== total_parts) {
68
- console.warn(`Incomplete message with ID ${message_id} discarded`);
69
- delete messageCache[message_id]; // Discard incomplete message
70
- }
71
- }, TIMEOUT_MS);
72
- }
73
-
74
- // Cache this chunk by message_id
75
- messageCache[message_id].push(chunkData);
76
-
77
- // If all parts are received, reconstruct the message
78
- if (messageCache[message_id].length === total_parts) {
79
- const completeMessage = reconstructMessage(messageCache[message_id]);
80
- const data = atob(completeMessage);
81
- const {stream_id, is_final, text, text_ts} = JSON.parse(data);
82
- /** Data type of above object
83
- * stream_id: number
84
- * is_final: boolean
85
- * text: string
86
- * text_ts: number
87
- */
88
- const textItem = {
89
- id: message_id,
90
- uid: stream_id,
91
- time: text_ts,
92
- dataType: 'transcribe',
93
- text: text,
94
- isFinal: is_final,
95
- isSelf: stream_id === 0 ? false : true,
96
- };
97
-
98
- if (text.trim().length > 0) {
99
- //this.emit("textChanged", textItem);
100
- console.warn('emit textChanged: ', textItem);
101
- addChatItem(textItem);
102
- }
103
-
104
- // Clean up the cache
105
- delete messageCache[message_id];
106
- }
107
- } catch (error) {
108
- console.error('Error processing chunk:', error);
109
- }
110
- };
111
-
112
- const reconstructMessage = chunks => {
113
- // Sort chunks by their part index
114
- chunks.sort((a, b) => a.part_index - b.part_index);
115
-
116
- // Concatenate all chunks to form the full message
117
- return chunks.map(chunk => chunk.content).join('');
118
- };
119
-
120
6
  return (
121
7
  <View style={styles.container}>
122
8
  <ChatScreen />
@@ -56,7 +56,7 @@ const CustomCreate = () => {
56
56
  };
57
57
  });
58
58
  // set default meeting name
59
- onChangeRoomTitle(generateChannelId);
59
+ onChangeRoomTitle('Conversational AI');
60
60
  }, []);
61
61
 
62
62
  const createRoomAndNavigateToShare = async (
@@ -1,10 +1,21 @@
1
- import React, {useContext} from 'react';
1
+ import React, {useContext, useEffect} from 'react';
2
2
  import {View, TextInput, StyleSheet, Text, Platform} from 'react-native';
3
3
  import ThemeConfig from '../../theme';
4
4
  import {AgentContext} from './AgentControls/AgentContext';
5
+ import {useRoomInfo} from 'customization-api';
5
6
 
6
7
  const UserPrompt = () => {
7
- const {prompt, setPrompt, agentConnectionState} = useContext(AgentContext);
8
+ const {prompt, setPrompt, agentConnectionState, agentId} =
9
+ useContext(AgentContext);
10
+ const {
11
+ data: {agents},
12
+ } = useRoomInfo();
13
+
14
+ useEffect(() => {
15
+ if (agentId) {
16
+ setPrompt(agents?.find(a => a?.id === agentId)?.config?.llm?.prompt);
17
+ }
18
+ }, [agentId, agents, setPrompt]);
8
19
  return (
9
20
  <>
10
21
  <Text style={styles.label}>Prompt</Text>
@@ -20,7 +31,7 @@ const UserPrompt = () => {
20
31
  value={prompt}
21
32
  onChangeText={setPrompt}
22
33
  placeholder="Customize Prompt"
23
- numberOfLines={5}
34
+ numberOfLines={10}
24
35
  multiline={true}
25
36
  />
26
37
  </View>
@@ -25,9 +25,7 @@ const ChatItemBubble = ({item}: {item: ChatItem}) => {
25
25
  paddingTop: 2,
26
26
  marginTop: 0,
27
27
  },
28
- bubbleStyleLayer2: {
29
- padding: 0,
30
- },
28
+ bubbleStyleLayer2: {},
31
29
  }}
32
30
  />
33
31
  );
@@ -74,6 +74,7 @@ export interface AIAgentInterface {
74
74
  llm: {
75
75
  agent_name: string;
76
76
  model: string;
77
+ prompt: string;
77
78
  };
78
79
  tts: {
79
80
  vendor: string;
@@ -52,6 +52,7 @@ const JOIN_CHANNEL_PHRASE_AND_GET_USER = gql`
52
52
  llm {
53
53
  agent_name
54
54
  model
55
+ prompt
55
56
  }
56
57
  tts {
57
58
  vendor
@@ -115,6 +116,7 @@ const JOIN_CHANNEL_PHRASE = gql`
115
116
  llm {
116
117
  agent_name
117
118
  model
119
+ prompt
118
120
  }
119
121
  tts {
120
122
  vendor