@websolutespa/bom-llm 0.0.5 → 0.0.6

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/CHANGELOG.md CHANGED
@@ -1,33 +1,40 @@
1
- # @websolutespa/bom-llm
2
-
3
- ## 0.0.5
4
-
5
- ### Patch Changes
6
-
7
- - Added: declarations
8
- - Modified: FormRecap, QuickLinks
9
-
10
- ## 0.0.4
11
-
12
- ### Patch Changes
13
-
14
- - Modified: decorateUrl async behaviour
15
-
16
- ## 0.0.3
17
-
18
- ### Patch Changes
19
-
20
- - Added: markdown support
21
-
22
- ## 0.0.2
23
-
24
- ### Patch Changes
25
-
26
- - Added: abort stream
27
- - Modified: speech, useLlm, message service, canvas, icons
28
-
29
- ## 0.0.1
30
-
31
- ### Patch Changes
32
-
33
- - Added: first release.
1
+ # @websolutespa/bom-llm
2
+
3
+ ## 0.0.6
4
+
5
+ ### Patch Changes
6
+
7
+ - Fixing: threads
8
+ - Modified: MessageService, FormRecap, useLlm
9
+
10
+ ## 0.0.5
11
+
12
+ ### Patch Changes
13
+
14
+ - Added: declarations
15
+ - Modified: FormRecap, QuickLinks
16
+
17
+ ## 0.0.4
18
+
19
+ ### Patch Changes
20
+
21
+ - Modified: decorateUrl async behaviour
22
+
23
+ ## 0.0.3
24
+
25
+ ### Patch Changes
26
+
27
+ - Added: markdown support
28
+
29
+ ## 0.0.2
30
+
31
+ ### Patch Changes
32
+
33
+ - Added: abort stream
34
+ - Modified: speech, useLlm, message service, canvas, icons
35
+
36
+ ## 0.0.1
37
+
38
+ ### Patch Changes
39
+
40
+ - Added: first release.
@@ -1765,7 +1765,12 @@
1765
1765
  }
1766
1766
  .llm .llm__message--assistant .llm__inner--string:not(:first-child) .llm__text .llm__text-body ol,
1767
1767
  .llm .llm__message--assistant .llm__inner--string:not(:first-child) .llm__text .llm__text-body ul {
1768
- margin-left: 0.9em;
1768
+ display: flex;
1769
+ flex-direction: column;
1770
+ gap: clamp(24px,
1771
+ calc(24px + (100vw - 375px) / (1920 - 375) * (8)),
1772
+ 32px);
1773
+ margin-left: 1em;
1769
1774
  }
1770
1775
  .llm .llm__message--assistant .llm__inner--string:not(:first-child) .llm__text .llm__text-body ul {
1771
1776
  list-style: disc;
package/dist/umd/index.js CHANGED
@@ -22873,8 +22873,18 @@
22873
22873
  let decodedChunks = [];
22874
22874
  try {
22875
22875
  // const replacedText = decodedText.replace(/(^\[)|(,$)|(\]$)/g, '');
22876
- const replacedText = decodedText.replace(/(,$)/g, '');
22877
- // console.log('textToChunks', `[${replacedText}]`);
22876
+ let replacedText = decodedText;
22877
+ // replacedText = replacedText.replace(/(^,")/, '",');
22878
+ replacedText = replacedText.replace(/(,$)/, '');
22879
+ // replacedText = replacedText.replace(/}\s{/g, '},{');
22880
+ /*
22881
+ replacedText = replacedText.split(',').map(x => {
22882
+ return x.replace(/^"([^{]*)"$/m, (m, g) => {
22883
+ return '"' + g.replace('"', '\\"') + '"';
22884
+ });
22885
+ }).join(',');
22886
+ */
22887
+ // console.log('textToChunks.replacedText', `[${replacedText}]`);
22878
22888
  const chunks = JSON.parse(`[${replacedText}]`);
22879
22889
  // console.log('chunks', chunks);
22880
22890
  /*
@@ -22959,19 +22969,24 @@
22959
22969
  chunks.push(x);
22960
22970
  }
22961
22971
  } else if (typeof x === 'string') {
22962
- if (lastMessage && lastMessage.type === 'string') {
22963
- const content = lastMessage.content + x;
22964
- const contents = content.split('\n');
22965
- contents.forEach((content, i) => {
22966
- if (i === 0) {
22967
- lastMessage.content = content;
22968
- } else if (content.length > 0 || i === contents.length - 1) {
22969
- chunks.push({
22970
- type: 'string',
22971
- content
22972
- });
22973
- }
22974
- });
22972
+ // console.warn('chunksToChunkItems typeof string');
22973
+ if (lastMessage && lastMessage.type === 'string' && !lastMessage.content.includes('\n')) {
22974
+ if (x.includes('\n')) {
22975
+ const contents = x.split('\n');
22976
+ contents.forEach((content, i) => {
22977
+ const lastChar = contents.length > i + 1 ? '\n' : '';
22978
+ if (i === 0) {
22979
+ lastMessage.content += content + lastChar;
22980
+ } else if (content.length > 0) {
22981
+ chunks.push({
22982
+ type: 'string',
22983
+ content: content + lastChar
22984
+ });
22985
+ }
22986
+ });
22987
+ } else {
22988
+ lastMessage.content += x;
22989
+ }
22975
22990
  } else {
22976
22991
  chunks.push({
22977
22992
  type: 'string',
@@ -22983,19 +22998,39 @@
22983
22998
  return chunks;
22984
22999
  }
22985
23000
  function decodeMessages(messages) {
22986
- return messages.map(x => ({
22987
- ...x,
22988
- chunks: chunksToChunkItems(textToChunks(x.content.split('\r\n').map(x => {
22989
- if (['{', '['].includes(x.substring(0, 1))) {
22990
- // console.log('obj', x);
22991
- return x;
22992
- } else {
22993
- // console.log('str', `"${x.replace(/\n/g, '\\n')}"`);
22994
- return `"${x.replace(/\n/g, '\\n')}"`;
22995
- }
22996
- }).join(',')))
22997
- }));
23001
+ return messages.map(x => {
23002
+ if (x.role === 'user') {
23003
+ return {
23004
+ ...x,
23005
+ chunks: [{
23006
+ type: 'string',
23007
+ content: x.content
23008
+ }]
23009
+ };
23010
+ }
23011
+ return {
23012
+ ...x,
23013
+ chunks: chunksToChunkItems(textToChunks(x.content))
23014
+ /*
23015
+ chunks: chunksToChunkItems(textToChunks(
23016
+ x.content
23017
+ .split('\r\n')
23018
+ .map(x => {
23019
+ if (['{', '['].includes(x.substring(0, 1))) {
23020
+ // console.log('obj', x);
23021
+ return x;
23022
+ } else {
23023
+ // console.log('str', `"${x.replace(/\n/g, '\\n')}"`);
23024
+ return `"${x.replace(/\n/g, '\\n')}"`;
23025
+ }
23026
+ })
23027
+ .join(',')
23028
+ )),
23029
+ */
23030
+ };
23031
+ });
22998
23032
  }
23033
+
22999
23034
  function shouldAddFormRequest(messages) {
23000
23035
  const hasFormRequest = messages.find(x => x.chunks.find(x => x.type === 'formRequest') !== undefined);
23001
23036
  const importantMessages = messages.filter(x => x.chunks.find(x => ['event', 'eventItem', 'eventGroup', 'poi', 'poiItem', 'poiGroup', 'tripadvisor', 'tripadvisorItem', 'tripadvisorGroup'].includes(x.type)) !== undefined);
@@ -23752,7 +23787,11 @@
23752
23787
  label
23753
23788
  } = _ref;
23754
23789
  /*
23755
- endpoint = endpoint || 'http://localhost:4000/bowl';
23790
+ // endpoint = 'https://platform.websolute.ai';
23791
+ endpoint = 'http://localhost:4000/bowl';
23792
+ appKey = 'app-pesaro2024';
23793
+ apiKey = 'b2c5912a-7b26-4c0c-8fd4-d046182c037c';
23794
+ threadId = '42616b78-2a0d-4ff7-9066-7e230985a4cb';
23756
23795
  test = false;
23757
23796
  */
23758
23797
 
@@ -23765,6 +23804,8 @@
23765
23804
  opened: false,
23766
23805
  hidden: false,
23767
23806
  fixed: false,
23807
+ idle: true,
23808
+ direction: 0,
23768
23809
  speakEnabled: false
23769
23810
  };
23770
23811
  let messageService = undefined;
@@ -23783,35 +23824,49 @@
23783
23824
  const baseUrl = `${origin}/api/llm`;
23784
23825
  return {
23785
23826
  get: async pathname => {
23786
- const response = await fetch(`${baseUrl}${pathname}${pathname.indexOf('?') !== -1 ? '&' : '?'}locale=${options.locale}`, {
23787
- method: 'GET',
23788
- headers: {
23789
- 'Content-Type': 'application/json'
23827
+ const url = `${baseUrl}${pathname}${pathname.indexOf('?') !== -1 ? '&' : '?'}locale=${options.locale}`;
23828
+ try {
23829
+ const response = await fetch(url, {
23830
+ method: 'GET',
23831
+ headers: {
23832
+ 'Content-Type': 'application/json'
23833
+ }
23834
+ });
23835
+ if (response.ok) {
23836
+ const data = await response.json();
23837
+ return data;
23838
+ } else {
23839
+ console.error('useLlm.api.get', url, response);
23840
+ return undefined;
23790
23841
  }
23791
- });
23792
- if (response.ok) {
23793
- const data = await response.json();
23794
- return data;
23795
- } else {
23796
- throw response;
23842
+ } catch (error) {
23843
+ console.error('useLlm.api.get', url, error);
23844
+ return undefined;
23797
23845
  }
23798
23846
  },
23799
23847
  post: async (pathname, payload) => {
23800
- const response = await fetch(`${baseUrl}${pathname}${pathname.indexOf('?') !== -1 ? '&' : '?'}locale=${options.locale}`, {
23801
- method: 'POST',
23802
- body: JSON.stringify({
23803
- ...options,
23804
- ...payload
23805
- }),
23806
- headers: {
23807
- 'Content-Type': 'application/json'
23848
+ const url = `${baseUrl}${pathname}${pathname.indexOf('?') !== -1 ? '&' : '?'}locale=${options.locale}`;
23849
+ try {
23850
+ const response = await fetch(url, {
23851
+ method: 'POST',
23852
+ body: JSON.stringify({
23853
+ ...options,
23854
+ ...payload
23855
+ }),
23856
+ headers: {
23857
+ 'Content-Type': 'application/json'
23858
+ }
23859
+ });
23860
+ if (response.ok) {
23861
+ const data = await response.json();
23862
+ return data;
23863
+ } else {
23864
+ console.error('useLlm.api.post', response, url);
23865
+ return undefined;
23808
23866
  }
23809
- });
23810
- if (response.ok) {
23811
- const data = await response.json();
23812
- return data;
23813
- } else {
23814
- throw response;
23867
+ } catch (error) {
23868
+ console.error('useLlm.api.post', error, url);
23869
+ return undefined;
23815
23870
  }
23816
23871
  }
23817
23872
  };
@@ -23834,21 +23889,19 @@
23834
23889
  },
23835
23890
  init: async locale => {
23836
23891
  const fetchApp = async () => {
23837
- try {
23838
- const api = getApi({
23839
- locale,
23840
- appKey,
23841
- apiKey,
23842
- threadId
23843
- });
23844
- const app = await api.post('/info');
23845
- return app;
23846
- } catch (error) {
23847
- console.log('useLlm.init.error', error);
23848
- throw error;
23849
- }
23892
+ const api = getApi({
23893
+ locale,
23894
+ appKey,
23895
+ apiKey,
23896
+ threadId
23897
+ });
23898
+ const app = await api.post('/info');
23899
+ return app;
23850
23900
  };
23851
23901
  const app = await fetchApp();
23902
+ if (!app) {
23903
+ return;
23904
+ }
23852
23905
  const state = get();
23853
23906
  speech.lang = locale;
23854
23907
  speech.enabled = state.speakEnabled;
@@ -23862,12 +23915,49 @@
23862
23915
  } : undefined;
23863
23916
  };
23864
23917
  const thread = decodeThread(app.thread);
23865
- // console.log('thread', thread);
23918
+ console.log('thread', thread);
23866
23919
  set(() => ({
23867
23920
  app,
23868
23921
  locale,
23869
23922
  ...thread
23870
23923
  }));
23924
+ // handle idle times
23925
+ const setIdleTimeout = () => {
23926
+ return setTimeout(() => {
23927
+ set(() => ({
23928
+ idle: true
23929
+ }));
23930
+ }, 6000);
23931
+ };
23932
+ const handleIdleTimes = () => {
23933
+ let to = setIdleTimeout();
23934
+ let lastScrollTop = 0;
23935
+ window.addEventListener('scroll', () => {
23936
+ const st = window.scrollY || document.documentElement.scrollTop;
23937
+ let direction = 0;
23938
+ if (st > lastScrollTop) {
23939
+ direction = 1;
23940
+ } else if (st < lastScrollTop) {
23941
+ direction = -1;
23942
+ }
23943
+ lastScrollTop = st <= 0 ? 0 : st;
23944
+ if (direction === 1) {
23945
+ if (to) {
23946
+ clearTimeout(to);
23947
+ }
23948
+ set(() => ({
23949
+ idle: false
23950
+ }));
23951
+ to = setIdleTimeout();
23952
+ }
23953
+ });
23954
+ };
23955
+ setTimeout(() => {
23956
+ set(() => ({
23957
+ idle: false
23958
+ }));
23959
+ handleIdleTimes();
23960
+ }, 2000);
23871
23961
  },
23872
23962
  send: async (prompt, onChunk, onEnd) => {
23873
23963
  if (test) {
@@ -23918,7 +24008,7 @@
23918
24008
  await messageService.sendMessage(request,
23919
24009
  // onMessage
23920
24010
  response => {
23921
- // console.log('response.chunks', response.chunks);
24011
+ // console.log('messageService.sendMessage.onMessage', response.chunks);
23922
24012
  set(state => ({
23923
24013
  chunks: response.chunks
23924
24014
  }));
@@ -23929,7 +24019,7 @@
23929
24019
  },
23930
24020
  // onEnd
23931
24021
  response => {
23932
- // console.log('response.chunks', response.chunks);
24022
+ // console.log('messageService.sendMessage.onEnd', response.chunks);
23933
24023
  const chunks = [...response.chunks];
23934
24024
  const assistantMessage = {
23935
24025
  chunks,
@@ -23942,17 +24032,22 @@
23942
24032
  type: 'formRequest'
23943
24033
  });
23944
24034
  }
23945
- assistantMessage.content = chunks.filter(x => !['info', 'end', 'formRequest', 'formRecap', 'formRecapSuccess', 'formRecapError'].includes(x.type)).map(x => {
23946
- let text = '';
23947
- switch (x.type) {
23948
- case 'string':
23949
- text += x.content;
23950
- break;
23951
- default:
23952
- text += JSON.stringify(x);
24035
+ // filtering history
24036
+ const validChunks = chunks.filter(x => !['info', 'end', 'formRequest', 'formRecap', 'formRecapSuccess', 'formRecapError'].includes(x.type));
24037
+ const parsedChunks = [];
24038
+ validChunks.reduce((p, c) => {
24039
+ const firstChunk = p.length > 1 && p[p.length - 2];
24040
+ const secondChunk = p.length > 1 && p[p.length - 1];
24041
+ if (firstChunk && secondChunk && c.type === 'string' && firstChunk.type === 'string' && secondChunk.type === 'string') {
24042
+ secondChunk.content += c.content;
24043
+ } else {
24044
+ p.push({
24045
+ ...c
24046
+ });
23953
24047
  }
23954
- return text;
23955
- }).join('\r\n');
24048
+ return p;
24049
+ }, parsedChunks);
24050
+ assistantMessage.content = parsedChunks.map(x => JSON.stringify(x)).join(',') + ',';
23956
24051
  set(state => ({
23957
24052
  chunks: undefined,
23958
24053
  messages,
@@ -24029,7 +24124,9 @@
24029
24124
  }));
24030
24125
  },
24031
24126
  formRecap: error => {
24032
- console.log('useLlm.formRecap', error);
24127
+ if (error) {
24128
+ console.warn('useLlm.formRecap', error);
24129
+ }
24033
24130
  const messages = [];
24034
24131
  const assistantMessage = {
24035
24132
  chunks: [{
@@ -24074,10 +24171,14 @@
24074
24171
  const scrolled = targetScroll > 100;
24075
24172
  const fixed = direction == -1 && scrolled && !autoScroll;
24076
24173
  const hidden = autoScroll || direction == 1 && scrolled;
24077
- set(state => ({
24078
- hidden,
24079
- fixed
24080
- }));
24174
+ const state = get();
24175
+ if (state.hidden !== hidden || state.fixed !== fixed || state.direction !== direction) {
24176
+ set(state => ({
24177
+ hidden,
24178
+ fixed,
24179
+ direction
24180
+ }));
24181
+ }
24081
24182
  });
24082
24183
  }
24083
24184
  }
@@ -24106,16 +24207,20 @@
24106
24207
  */
24107
24208
  currentState.hydrated = true;
24108
24209
  return currentState;
24109
- }
24210
+ },
24211
+ partialize: state => Object.fromEntries(Object.entries(state).filter(_ref2 => {
24212
+ let [key] = _ref2;
24213
+ return ['app', 'locale', 'speakEnabled'].includes(key);
24214
+ }))
24110
24215
  }));
24111
24216
  return useStore;
24112
24217
  };
24113
24218
  const LlmContext = /*#__PURE__*/reactExports.createContext(null);
24114
- function LlmProvider(_ref2) {
24219
+ function LlmProvider(_ref3) {
24115
24220
  let {
24116
24221
  children,
24117
24222
  ...props
24118
- } = _ref2;
24223
+ } = _ref3;
24119
24224
  const label = useLabel();
24120
24225
  const storeRef = reactExports.useRef();
24121
24226
  if (!storeRef.current) {
@@ -25654,6 +25759,7 @@ void main(void) {
25654
25759
 
25655
25760
  const FormRecap = () => {
25656
25761
  const label = useLabel();
25762
+ const app = useLlm(state => state.app);
25657
25763
  const threadId = useLlm(state => state.threadId);
25658
25764
  const {
25659
25765
  formRecap,
@@ -25670,12 +25776,19 @@ void main(void) {
25670
25776
  data.threadId = threadId;
25671
25777
  const payload = {
25672
25778
  ...data,
25673
- html: getEmailHtml(data)
25779
+ html: getEmailHtml(data, app)
25674
25780
  };
25675
25781
  const api = getApi();
25676
25782
  const response = await api.post('/summary', payload);
25677
- console.warn('FormRecap.onSubmit.success', response, payload);
25678
- formRecap();
25783
+ if (response) {
25784
+ console.warn('FormRecap.onSubmit.success', response, payload);
25785
+ formRecap();
25786
+ } else {
25787
+ console.warn('FormRecap.onSubmit.error');
25788
+ formRecap({
25789
+ message: 'unknown error'
25790
+ });
25791
+ }
25679
25792
  } catch (error) {
25680
25793
  console.warn('FormRecap.onSubmit.error', error);
25681
25794
  formRecap(error);
@@ -25731,12 +25844,13 @@ void main(void) {
25731
25844
  })
25732
25845
  });
25733
25846
  };
25734
- function getEmailHtml(data) {
25847
+ function getEmailHtml(data, app) {
25735
25848
  const firstName = data.fullName ? data.fullName.split(' ')[0] : '';
25849
+ const name = app?.contents?.shortWelcomeText || 'PlatformAI';
25736
25850
  const title = `Ciao ${firstName}`;
25737
25851
  const paragraphs = `<p>${['Ecco il tuo promemoria,', 'per qualunque altra cosa sai dove potermi trovare, sarò sempre lieto di parlare con te. 👋'].join('</p><p>')}</p>`;
25738
25852
  const colorAccent = '#00aeff';
25739
- const threadUrl = window.location.href + `${window.location.search ? '&' : '?'}threadId=${data.threadId}`;
25853
+ const threadUrl = window.location.href + `${window.location.search ? '&' : '?'}llmThreadId=${data.threadId}`;
25740
25854
  return `
25741
25855
  <!doctype html>
25742
25856
  <html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
@@ -25834,7 +25948,7 @@ void main(void) {
25834
25948
  <tbody>
25835
25949
  <tr>
25836
25950
  <td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
25837
- <div style="font-family:Inter;font-size:20px;font-weight:600;line-height:24px;text-align:left;color:#3b3b3b;">platform@websolute.ai</div>
25951
+ <div style="font-family:Inter;font-size:20px;font-weight:600;line-height:24px;text-align:left;color:#3b3b3b;">${name}</div>
25838
25952
  </td>
25839
25953
  </tr>
25840
25954
  <tr>
@@ -28678,8 +28792,17 @@ void main(void) {
28678
28792
  const app = useLlm(state => state.app);
28679
28793
  const label = useLabel();
28680
28794
  return /*#__PURE__*/jsxRuntimeExports.jsxs(motion.div, {
28795
+ initial: {
28796
+ y: '200%',
28797
+ opacity: 0
28798
+ },
28799
+ animate: {
28800
+ y: 0,
28801
+ opacity: 1
28802
+ },
28681
28803
  exit: {
28682
- y: '200%'
28804
+ y: '200%',
28805
+ opacity: 0
28683
28806
  },
28684
28807
  transition: {
28685
28808
  duration: .4
@@ -28722,6 +28845,7 @@ void main(void) {
28722
28845
  init
28723
28846
  } = useLlm(state => state.actions);
28724
28847
  const app = useLlm(state => state.app);
28848
+ const idle = useLlm(state => state.idle);
28725
28849
  const opened = useLlm(state => state.opened);
28726
28850
  reactExports.useEffect(() => {
28727
28851
  init(locale);
@@ -28735,14 +28859,14 @@ void main(void) {
28735
28859
  });
28736
28860
  if (mounted) {
28737
28861
  return /*#__PURE__*/jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, {
28738
- children: app && /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
28862
+ children: app && /*#__PURE__*/jsxRuntimeExports.jsx("div", {
28739
28863
  className: classNames,
28740
28864
  ...props,
28741
- children: [/*#__PURE__*/jsxRuntimeExports.jsx(AnimatePresence, {
28742
- children: !opened && /*#__PURE__*/jsxRuntimeExports.jsx(Trigger, {})
28743
- }), /*#__PURE__*/jsxRuntimeExports.jsx(AnimatePresence, {
28744
- children: opened && /*#__PURE__*/jsxRuntimeExports.jsx(Main, {})
28745
- })]
28865
+ children: /*#__PURE__*/jsxRuntimeExports.jsxs(AnimatePresence, {
28866
+ mode: "wait",
28867
+ initial: false,
28868
+ children: [!opened && !idle && /*#__PURE__*/jsxRuntimeExports.jsx(Trigger, {}), opened && /*#__PURE__*/jsxRuntimeExports.jsx(Main, {})]
28869
+ })
28746
28870
  })
28747
28871
  });
28748
28872
  } else {