@arqel-dev/ai 0.8.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/LICENSE +21 -0
- package/README.md +24 -0
- package/SKILL.md +425 -0
- package/dist/index.d.ts +268 -0
- package/dist/index.js +1133 -0
- package/dist/index.js.map +1 -0
- package/dist/register.d.ts +2 -0
- package/dist/register.js +1342 -0
- package/dist/register.js.map +1 -0
- package/package.json +80 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import { ReactElement } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* `<AiExtractInput>` — apresentational React component for the PHP
|
|
5
|
+
* `Arqel\Ai\Fields\AiExtractField` (component string `AiExtractInput`).
|
|
6
|
+
*
|
|
7
|
+
* Render contract (AI-010):
|
|
8
|
+
* - Read-only label `Source: {sourceField}` indicando o campo do
|
|
9
|
+
* formulário de onde o texto-fonte é lido.
|
|
10
|
+
* - Botão `Extract with AI` (label vem de `props.buttonLabel`); em
|
|
11
|
+
* loading o botão fica `disabled` + spinner inline.
|
|
12
|
+
* - Empty state `No extraction yet — click button to start` antes da
|
|
13
|
+
* primeira extração.
|
|
14
|
+
* - Após sucesso: lista preview `<dl>` com cada `targetField:
|
|
15
|
+
* extractedValue`; cada entry tem botão `Apply` individual e o
|
|
16
|
+
* toolbar mostra `Apply all`.
|
|
17
|
+
* - `Apply` chama `onPopulateField?.(targetField, value)` ou
|
|
18
|
+
* `onChange(extracted)` se `onPopulateField` for ausente.
|
|
19
|
+
* - Banner `role="alert"` quando o `fetch` falha (com `message` da
|
|
20
|
+
* response 422 quando disponível).
|
|
21
|
+
*
|
|
22
|
+
* Network:
|
|
23
|
+
* - URL = `props.extractUrl` override ou
|
|
24
|
+
* `/admin/${resource}/fields/${field}/extract`.
|
|
25
|
+
* - Body: `{ sourceText }` lido de `formData?.[sourceField] ?? ''`.
|
|
26
|
+
* - Resposta: `{ extracted: Record<string, unknown> }` (200) ou
|
|
27
|
+
* `{ message }` (422).
|
|
28
|
+
*
|
|
29
|
+
* SSR-safe: nada no render path toca `window`/`document`.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
interface AiExtractInputFieldProps {
|
|
33
|
+
sourceField: string;
|
|
34
|
+
targetFields: string[];
|
|
35
|
+
buttonLabel: string;
|
|
36
|
+
usingJsonMode: boolean;
|
|
37
|
+
provider?: string | null;
|
|
38
|
+
}
|
|
39
|
+
type AiExtractValue = Record<string, unknown>;
|
|
40
|
+
interface AiExtractInputProps {
|
|
41
|
+
name: string;
|
|
42
|
+
value: AiExtractValue | null;
|
|
43
|
+
onChange?: (value: AiExtractValue) => void;
|
|
44
|
+
props: AiExtractInputFieldProps | undefined;
|
|
45
|
+
resource?: string;
|
|
46
|
+
field?: string;
|
|
47
|
+
formData?: Record<string, unknown>;
|
|
48
|
+
extractUrl?: string;
|
|
49
|
+
csrfToken?: string;
|
|
50
|
+
onPopulateField?: (targetField: string, value: unknown) => void;
|
|
51
|
+
}
|
|
52
|
+
declare function AiExtractInput(props: AiExtractInputProps): ReactElement;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* `<AiImageInput>` — apresentational React component for the PHP
|
|
56
|
+
* `Arqel\Ai\Fields\AiImageField` (component string `AiImageInput`).
|
|
57
|
+
*
|
|
58
|
+
* Render contract (AI-011):
|
|
59
|
+
* - File input restrito por `accept={props.acceptedMimes.join(',')}`
|
|
60
|
+
* com drag-drop area visual (`<label>` clicável que dispara o
|
|
61
|
+
* `<input type="file">` escondido).
|
|
62
|
+
* - Preview da imagem após selecionar (img src vem de
|
|
63
|
+
* `URL.createObjectURL` — só é chamado dentro do change handler,
|
|
64
|
+
* mantendo o render path SSR-safe).
|
|
65
|
+
* - Validação client-side: rejeita arquivos > `props.maxFileSize`
|
|
66
|
+
* (em bytes) com banner de erro; nesse caso o botão "Analyze with
|
|
67
|
+
* AI" fica `disabled`.
|
|
68
|
+
* - Botão `Analyze with AI` (label de `props.buttonLabel`); spinner
|
|
69
|
+
* inline + `disabled` durante o `fetch`. Sem arquivo selecionado o
|
|
70
|
+
* botão também fica `disabled`.
|
|
71
|
+
* - Após sucesso: lista preview `<dl>` com `analysis_key: value` por
|
|
72
|
+
* entry; cada entry tem botão `Apply` individual; toolbar mostra
|
|
73
|
+
* `Apply all`.
|
|
74
|
+
* - `Apply` chama `onPopulateField?.(target, value)` usando o
|
|
75
|
+
* mapeamento `props.populateFields[analysisKey]` quando disponível.
|
|
76
|
+
* `Apply all` itera todas as analyses que têm mapping.
|
|
77
|
+
* - Banner `role="alert"` quando o `fetch` falha (mensagem da
|
|
78
|
+
* response 422 quando disponível).
|
|
79
|
+
*
|
|
80
|
+
* Network:
|
|
81
|
+
* - URL = `props.analyzeUrl` override ou
|
|
82
|
+
* `/admin/${resource}/fields/${field}/analyze-image`.
|
|
83
|
+
* - Body: `{ imageBase64 }` produzido por `FileReader.readAsDataURL`
|
|
84
|
+
* (data URI completo).
|
|
85
|
+
* - Resposta: `{ analyses, populateMapping }` (200) ou
|
|
86
|
+
* `{ message }` (422).
|
|
87
|
+
*
|
|
88
|
+
* SSR-safe: nada no render path toca `window`/`URL`/`FileReader` — só
|
|
89
|
+
* em handlers de evento.
|
|
90
|
+
*/
|
|
91
|
+
|
|
92
|
+
interface AiImageInputFieldProps {
|
|
93
|
+
analyses: string[];
|
|
94
|
+
populateFields: Record<string, string>;
|
|
95
|
+
provider?: string | null;
|
|
96
|
+
acceptedMimes: string[];
|
|
97
|
+
maxFileSize: number;
|
|
98
|
+
buttonLabel: string;
|
|
99
|
+
}
|
|
100
|
+
interface AiImageInputProps {
|
|
101
|
+
name: string;
|
|
102
|
+
value: string | null;
|
|
103
|
+
onChange?: (value: string) => void;
|
|
104
|
+
props: AiImageInputFieldProps | undefined;
|
|
105
|
+
resource?: string;
|
|
106
|
+
field?: string;
|
|
107
|
+
analyzeUrl?: string;
|
|
108
|
+
csrfToken?: string;
|
|
109
|
+
onPopulateField?: (targetField: string, value: string) => void;
|
|
110
|
+
}
|
|
111
|
+
declare function AiImageInput(props: AiImageInputProps): ReactElement;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* `<AiSelectInput>` — apresentational React component for the PHP
|
|
115
|
+
* `Arqel\Ai\Fields\AiSelectField` (component string `AiSelectInput`).
|
|
116
|
+
*
|
|
117
|
+
* Render contract (AI-009):
|
|
118
|
+
* - `<select>` controlled (or uncontrolled fallback) with a
|
|
119
|
+
* placeholder option + one entry per `props.options`,
|
|
120
|
+
* - "Classify with AI" button next to the select; disabled when
|
|
121
|
+
* `hasContextFields` is false (with a tooltip explaining why),
|
|
122
|
+
* - while a request is in-flight the button is disabled and an
|
|
123
|
+
* inline spinner is rendered,
|
|
124
|
+
* - on success a banner with `Suggested by AI` is rendered with two
|
|
125
|
+
* dismiss buttons: `Accept` and `Pick another` (both just hide the
|
|
126
|
+
* banner — the value is already applied),
|
|
127
|
+
* - if the response returns `key: null` and `fallbackOption` is
|
|
128
|
+
* configured, the fallback is applied and a `Used fallback`
|
|
129
|
+
* banner is shown,
|
|
130
|
+
* - if the response returns `key: null` and there is no fallback,
|
|
131
|
+
* an error banner `Could not classify` is rendered.
|
|
132
|
+
*
|
|
133
|
+
* Network:
|
|
134
|
+
* - URL = `props.classifyUrl` override or
|
|
135
|
+
* `/admin/${resource}/fields/${field}/classify`.
|
|
136
|
+
* - `fetch(url, { method: 'POST', credentials: 'same-origin', headers:
|
|
137
|
+
* { Content-Type, Accept, X-CSRF-TOKEN }, body: JSON.stringify({
|
|
138
|
+
* formData }) })`. The PHP controller runs the LLM classification
|
|
139
|
+
* and returns `{ key, label }`.
|
|
140
|
+
*
|
|
141
|
+
* SSR-safe: nothing in the render path touches `window`/`document`.
|
|
142
|
+
*/
|
|
143
|
+
|
|
144
|
+
interface AiSelectInputFieldProps {
|
|
145
|
+
options: Record<string, string>;
|
|
146
|
+
classifyFromFields: string[];
|
|
147
|
+
provider?: string | null;
|
|
148
|
+
fallbackOption?: string | null;
|
|
149
|
+
hasContextFields: boolean;
|
|
150
|
+
}
|
|
151
|
+
interface AiSelectInputProps {
|
|
152
|
+
name: string;
|
|
153
|
+
value: string | null;
|
|
154
|
+
onChange?: (value: string | null) => void;
|
|
155
|
+
props: AiSelectInputFieldProps | undefined;
|
|
156
|
+
resource?: string;
|
|
157
|
+
field?: string;
|
|
158
|
+
formData?: Record<string, unknown>;
|
|
159
|
+
classifyUrl?: string;
|
|
160
|
+
csrfToken?: string;
|
|
161
|
+
}
|
|
162
|
+
declare function AiSelectInput(props: AiSelectInputProps): ReactElement;
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* `<AiTextInput>` — apresentational React component for the PHP
|
|
166
|
+
* `Arqel\Ai\Fields\AiTextField` (component string `AiTextInput`).
|
|
167
|
+
*
|
|
168
|
+
* Render contract (AI-007):
|
|
169
|
+
* - `<textarea>` displaying the current value (controlled if
|
|
170
|
+
* `onChange` is provided, otherwise uncontrolled with internal
|
|
171
|
+
* state seeded by `value`),
|
|
172
|
+
* - "Generate with AI" button (label from `props.buttonLabel`,
|
|
173
|
+
* fallback `Generate with AI`); after a successful generation the
|
|
174
|
+
* button label becomes `Regenerate`,
|
|
175
|
+
* - while a request is in-flight the button is disabled and shows a
|
|
176
|
+
* small inline spinner,
|
|
177
|
+
* - on failure a banner with a generic message + HTTP status code is
|
|
178
|
+
* rendered; the button re-enables so the user can retry,
|
|
179
|
+
* - optional `X / maxLength` counter when `props.maxLength` is set.
|
|
180
|
+
*
|
|
181
|
+
* Network:
|
|
182
|
+
* - URL = `props.generateUrl` (caller override) or
|
|
183
|
+
* `/admin/${resource}/fields/${field}/generate` (default route name
|
|
184
|
+
* `arqel.ai.generate`).
|
|
185
|
+
* - `fetch(url, { method: 'POST', credentials: 'same-origin', headers:
|
|
186
|
+
* { Content-Type, Accept, X-CSRF-TOKEN }, body: JSON.stringify({
|
|
187
|
+
* formData }) })`. The PHP controller resolves the prompt template
|
|
188
|
+
* server-side and returns `{ text }`.
|
|
189
|
+
*
|
|
190
|
+
* SSR-safe: nothing in the render path touches `window`/`document`;
|
|
191
|
+
* the network call only fires from the click handler (post-mount).
|
|
192
|
+
*/
|
|
193
|
+
|
|
194
|
+
interface AiTextInputFieldProps {
|
|
195
|
+
provider?: string | null;
|
|
196
|
+
buttonLabel: string;
|
|
197
|
+
maxLength?: number | null;
|
|
198
|
+
hasContextFields: boolean;
|
|
199
|
+
}
|
|
200
|
+
interface AiTextInputProps {
|
|
201
|
+
name: string;
|
|
202
|
+
value: string;
|
|
203
|
+
onChange?: (value: string) => void;
|
|
204
|
+
props: AiTextInputFieldProps | undefined;
|
|
205
|
+
resource?: string;
|
|
206
|
+
field?: string;
|
|
207
|
+
formData?: Record<string, unknown>;
|
|
208
|
+
generateUrl?: string;
|
|
209
|
+
csrfToken?: string;
|
|
210
|
+
}
|
|
211
|
+
declare function AiTextInput(props: AiTextInputProps): ReactElement;
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* `<AiTranslateInput>` — apresentational React component for the PHP
|
|
215
|
+
* `Arqel\Ai\Fields\AiTranslateField` (component string `AiTranslateInput`).
|
|
216
|
+
*
|
|
217
|
+
* Render contract (AI-008):
|
|
218
|
+
* - Tab list (`role="tablist"`) com um `<button role="tab">` por
|
|
219
|
+
* idioma configurado em `props.languages`. A tab default vem de
|
|
220
|
+
* `props.defaultLanguage`.
|
|
221
|
+
* - Cada tab mostra um indicador visual (`data-missing="true"`)
|
|
222
|
+
* quando a tradução daquela língua está vazia/null.
|
|
223
|
+
* - Painel ativo: `<textarea>` controlado que edita
|
|
224
|
+
* `translations[activeLang]`. Mudanças disparam o `onChange` com o
|
|
225
|
+
* objeto completo `Record<lang, string>`.
|
|
226
|
+
* - Botão "Translate from {defaultLanguage}" presente em todas as
|
|
227
|
+
* tabs **não-default**; faz `POST` com `targetLanguages: [lang]`.
|
|
228
|
+
* - Botão "Translate all missing" no topo do componente; itera as
|
|
229
|
+
* línguas com tradução vazia e dispara um único `POST` com o
|
|
230
|
+
* array completo.
|
|
231
|
+
* - Loading per-language (`Set<string>`): o botão da tab/lang sendo
|
|
232
|
+
* traduzida fica `disabled` + spinner inline.
|
|
233
|
+
* - Banner `role="alert"` quando o `fetch` falha; o resto continua
|
|
234
|
+
* usável.
|
|
235
|
+
*
|
|
236
|
+
* Network:
|
|
237
|
+
* - URL = `props.translateUrl` (caller override) ou
|
|
238
|
+
* `/admin/${resource}/fields/${field}/translate` (default route
|
|
239
|
+
* name `arqel.ai.translate`).
|
|
240
|
+
* - Body: `{ sourceLanguage, targetLanguages: string[], sourceText }`.
|
|
241
|
+
* `sourceText` vem de `translations[defaultLanguage] ?? ''`.
|
|
242
|
+
* - Response: `{ translations: { [lang]: string } }` é mesclado em
|
|
243
|
+
* state local + `onChange` callback.
|
|
244
|
+
*
|
|
245
|
+
* SSR-safe: nada no render path toca `window`/`document`; o `fetch`
|
|
246
|
+
* só dispara dentro do click handler (post-mount).
|
|
247
|
+
*/
|
|
248
|
+
|
|
249
|
+
interface AiTranslateInputFieldProps {
|
|
250
|
+
languages: string[];
|
|
251
|
+
defaultLanguage: string;
|
|
252
|
+
autoTranslate: boolean;
|
|
253
|
+
provider?: string | null;
|
|
254
|
+
}
|
|
255
|
+
type AiTranslateValue = Record<string, string>;
|
|
256
|
+
interface AiTranslateInputProps {
|
|
257
|
+
name: string;
|
|
258
|
+
value: AiTranslateValue | null;
|
|
259
|
+
onChange?: (value: AiTranslateValue) => void;
|
|
260
|
+
props: AiTranslateInputFieldProps | undefined;
|
|
261
|
+
resource?: string;
|
|
262
|
+
field?: string;
|
|
263
|
+
translateUrl?: string;
|
|
264
|
+
csrfToken?: string;
|
|
265
|
+
}
|
|
266
|
+
declare function AiTranslateInput(props: AiTranslateInputProps): ReactElement;
|
|
267
|
+
|
|
268
|
+
export { AiExtractInput, type AiExtractInputFieldProps, type AiExtractInputProps, type AiExtractValue, AiImageInput, type AiImageInputFieldProps, type AiImageInputProps, AiSelectInput, type AiSelectInputFieldProps, type AiSelectInputProps, AiTextInput, type AiTextInputFieldProps, type AiTextInputProps, AiTranslateInput, type AiTranslateInputFieldProps, type AiTranslateInputProps, type AiTranslateValue, AiTextInput as default };
|