cozy-viewer 26.2.2 → 26.3.0

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
@@ -3,6 +3,23 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [26.3.0](https://github.com/cozy/cozy-libs/compare/cozy-viewer@26.2.3...cozy-viewer@26.3.0) (2025-12-23)
7
+
8
+ ### Bug Fixes
9
+
10
+ - Handle Windows CRLF line endings :bug: ([e415041](https://github.com/cozy/cozy-libs/commit/e41504102b12b0d51a63db368c4c028c5d1e18c3))
11
+ - Resolve failed test cases :bug: ([8a7bc67](https://github.com/cozy/cozy-libs/commit/8a7bc67aa3856b4707b69bd8e2deafc21a9d4827))
12
+
13
+ ### Features
14
+
15
+ - Sanitize text content for AI ([6a4dc7b](https://github.com/cozy/cozy-libs/commit/6a4dc7bc52126a39fd89284cfd3c7b142699c5eb))
16
+
17
+ ## [26.2.3](https://github.com/cozy/cozy-libs/compare/cozy-viewer@26.2.2...cozy-viewer@26.2.3) (2025-12-20)
18
+
19
+ ### Bug Fixes
20
+
21
+ - **cozy-viewer:** Reduce the default height of the bottom sheet ([808bddd](https://github.com/cozy/cozy-libs/commit/808bdddaf6675e73e5b1d87ec8d4dfe26e9f32a7))
22
+
6
23
  ## [26.2.2](https://github.com/cozy/cozy-libs/compare/cozy-viewer@26.2.1...cozy-viewer@26.2.2) (2025-12-16)
7
24
 
8
25
  ### Bug Fixes
@@ -67,7 +67,7 @@ var FooterContent = function FooterContent(_ref) {
67
67
  });
68
68
  var bottomSheetSettings = {
69
69
  isOpenMin: true,
70
- mediumHeightRatio: isPublic ? undefined : 0.5
70
+ mediumHeightRatio: isPublic ? undefined : 0.2
71
71
  };
72
72
  return /*#__PURE__*/_react.default.createElement(_BottomSheet.default, {
73
73
  toolbarProps: toolbarProps,
@@ -146,7 +146,7 @@ var AIAssistantPanel = function AIAssistantPanel(_ref) {
146
146
 
147
147
  case 7:
148
148
  rawTextContent = _context.sent;
149
- textContent = rawTextContent ? JSON.stringify(rawTextContent) : '';
149
+ textContent = rawTextContent ? (0, _helpers.sanitizeText)(JSON.stringify(rawTextContent)) : '';
150
150
  summaryConfig = (0, _cozyFlags.default)('drive.summary');
151
151
 
152
152
  if (!(summaryConfig !== null && summaryConfig !== void 0 && summaryConfig.maxTokens && (0, _helpers.roughTokensEstimation)(textContent) > summaryConfig.maxTokens)) {
package/dist/helpers.d.ts CHANGED
@@ -13,6 +13,7 @@ export function makeWebLink({ client, slug, path }: {
13
13
  }): string;
14
14
  export function removeFilenameFromPath(path: string): string;
15
15
  export function roughTokensEstimation(text: string): number;
16
+ export function sanitizeText(text: string): string;
16
17
  export function isFileSummaryCompatible(file: object, options?: {
17
18
  pageCount: number;
18
19
  }): boolean;
package/dist/helpers.js CHANGED
@@ -5,7 +5,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
5
5
  Object.defineProperty(exports, "__esModule", {
6
6
  value: true
7
7
  });
8
- exports.roughTokensEstimation = exports.removeFilenameFromPath = exports.normalizeAndSpreadAttributes = exports.makeWebLink = exports.isFileSummaryCompatible = exports.isFileEncrypted = exports.isEditableAttribute = exports.formatDate = void 0;
8
+ exports.sanitizeText = exports.roughTokensEstimation = exports.removeFilenameFromPath = exports.normalizeAndSpreadAttributes = exports.makeWebLink = exports.isFileSummaryCompatible = exports.isFileEncrypted = exports.isEditableAttribute = exports.formatDate = void 0;
9
9
 
10
10
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
11
11
 
@@ -115,6 +115,24 @@ exports.removeFilenameFromPath = removeFilenameFromPath;
115
115
  var roughTokensEstimation = function roughTokensEstimation(text) {
116
116
  return Math.ceil(text.length / 4);
117
117
  };
118
+ /**
119
+ * Sanitize text, typically from after file text extraction
120
+ * @param {string} text - The text to sanitize
121
+ * @returns {string} The sanitized text
122
+ */
123
+
124
+
125
+ exports.roughTokensEstimation = roughTokensEstimation;
126
+
127
+ var sanitizeText = function sanitizeText(text) {
128
+ if (!text) return '';
129
+ return text.replace(/\r\n?/g, '\n') // Normalize line endings
130
+ .replace(/[^\S\r\n]{4,}/g, ' ') // Compress spaces
131
+ .replace(/\n{2,}/g, '\n') // Remove empty lines
132
+ // eslint-disable-next-line no-control-regex
133
+ .replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, '') // Remove control chars
134
+ ;
135
+ };
118
136
  /**
119
137
  * Check if a file is compatible with AI summary feature
120
138
  * Compatible file types are defined in the drive.summary flag
@@ -126,7 +144,7 @@ var roughTokensEstimation = function roughTokensEstimation(text) {
126
144
  */
127
145
 
128
146
 
129
- exports.roughTokensEstimation = roughTokensEstimation;
147
+ exports.sanitizeText = sanitizeText;
130
148
 
131
149
  var isFileSummaryCompatible = function isFileSummaryCompatible(file) {
132
150
  var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cozy-viewer",
3
- "version": "26.2.2",
3
+ "version": "26.3.0",
4
4
  "description": "Cozy-Viewer provides a component to show files in a viewer.",
5
5
  "main": "dist/index.js",
6
6
  "license": "MIT",
@@ -31,7 +31,7 @@
31
31
  "babel-preset-cozy-app": "^2.8.2",
32
32
  "cozy-client": "^60.20.0",
33
33
  "cozy-device-helper": "2.0.0",
34
- "cozy-harvest-lib": "^36.0.11",
34
+ "cozy-harvest-lib": "^36.0.13",
35
35
  "cozy-intent": "^2.30.1",
36
36
  "cozy-logger": "^1.17.0",
37
37
  "cozy-sharing": "^28.1.2",
@@ -70,5 +70,5 @@
70
70
  "react-router-dom": ">=6.14.2",
71
71
  "twake-i18n": ">=0.3.0"
72
72
  },
73
- "gitHead": "f66279b4f43a3c1abdc05ebceab759065ec888de"
73
+ "gitHead": "6b0e77a72b8e001001efccbee4a99bc03aa3563d"
74
74
  }
@@ -41,7 +41,7 @@ const FooterContent = ({ toolbarRef, children, isDisplayChildrenDirectly }) => {
41
41
 
42
42
  const bottomSheetSettings = {
43
43
  isOpenMin: true,
44
- mediumHeightRatio: isPublic ? undefined : 0.5
44
+ mediumHeightRatio: isPublic ? undefined : 0.2
45
45
  }
46
46
 
47
47
  return (
@@ -23,7 +23,7 @@ import { useAlert } from 'cozy-ui/transpiled/react/providers/Alert'
23
23
 
24
24
  import { SUMMARY_SYSTEM_PROMPT, getSummaryUserPrompt } from './prompts'
25
25
  import styles from './styles.styl'
26
- import { roughTokensEstimation } from '../../helpers'
26
+ import { roughTokensEstimation, sanitizeText } from '../../helpers'
27
27
  import { useViewer } from '../../providers/ViewerProvider'
28
28
 
29
29
  const AIAssistantPanel = ({ className }) => {
@@ -57,7 +57,9 @@ const AIAssistantPanel = ({ className }) => {
57
57
  name: file.name,
58
58
  mime: file.mime
59
59
  })
60
- const textContent = rawTextContent ? JSON.stringify(rawTextContent) : ''
60
+ const textContent = rawTextContent
61
+ ? sanitizeText(JSON.stringify(rawTextContent))
62
+ : ''
61
63
 
62
64
  const summaryConfig = flag('drive.summary')
63
65
  if (
package/src/helpers.js CHANGED
@@ -84,6 +84,23 @@ export const roughTokensEstimation = text => {
84
84
  return Math.ceil(text.length / 4)
85
85
  }
86
86
 
87
+ /**
88
+ * Sanitize text, typically from after file text extraction
89
+ * @param {string} text - The text to sanitize
90
+ * @returns {string} The sanitized text
91
+ */
92
+ export const sanitizeText = text => {
93
+ if (!text) return ''
94
+ return (
95
+ text
96
+ .replace(/\r\n?/g, '\n') // Normalize line endings
97
+ .replace(/[^\S\r\n]{4,}/g, ' ') // Compress spaces
98
+ .replace(/\n{2,}/g, '\n') // Remove empty lines
99
+ // eslint-disable-next-line no-control-regex
100
+ .replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, '') // Remove control chars
101
+ )
102
+ }
103
+
87
104
  /**
88
105
  * Check if a file is compatible with AI summary feature
89
106
  * Compatible file types are defined in the drive.summary flag
@@ -3,7 +3,8 @@ import flag from 'cozy-flags'
3
3
  import {
4
4
  isEditableAttribute,
5
5
  removeFilenameFromPath,
6
- isFileSummaryCompatible
6
+ isFileSummaryCompatible,
7
+ sanitizeText
7
8
  } from './helpers'
8
9
 
9
10
  jest.mock('cozy-flags')
@@ -193,4 +194,36 @@ describe('helpers', () => {
193
194
  expect(isFileSummaryCompatible({ mime: 'application/pdf' })).toBe(true)
194
195
  })
195
196
  })
197
+
198
+ describe('sanitizeText', () => {
199
+ it('compresses 4+ consecutive spaces into a single space', () => {
200
+ const input = 'Hello world !'
201
+ const output = sanitizeText(input)
202
+ expect(output).toBe('Hello world !')
203
+ })
204
+
205
+ it('does not modify sequences of less than 4 spaces', () => {
206
+ const input = 'a b c d'
207
+ const output = sanitizeText(input)
208
+ expect(output).toBe('a b c d')
209
+ })
210
+
211
+ it('collapses multiple empty lines into a single newline', () => {
212
+ const input = 'line 1\n\n\nline 2\nline 3'
213
+ const output = sanitizeText(input)
214
+ expect(output).toBe('line 1\nline 2\nline 3')
215
+ })
216
+
217
+ it('removes ASCII control characters but keeps accents and punctuation', () => {
218
+ const input = 'A\u0001B\u001F C éàç €'
219
+ const output = sanitizeText(input)
220
+ expect(output).toBe('AB C éàç €')
221
+ })
222
+
223
+ it('handles a mix of spaces, newlines and control characters', () => {
224
+ const input = 'Foo \n\n\nbar\u0003 baz'
225
+ const output = sanitizeText(input)
226
+ expect(output).toBe('Foo \nbar baz')
227
+ })
228
+ })
196
229
  })