@automattic/jetpack-ai-client 0.20.1 → 0.22.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.
Files changed (174) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/build/{hooks → ai-client/src/hooks}/use-image-generator/constants.d.ts +6 -20
  3. package/build/ai-client/src/hooks/use-image-generator/constants.js +21 -0
  4. package/build/{hooks → ai-client/src/hooks}/use-image-generator/index.d.ts +0 -1
  5. package/build/{hooks → ai-client/src/hooks}/use-image-generator/index.js +0 -10
  6. package/build/{logo-generator → ai-client/src/logo-generator}/components/generator-modal.js +27 -8
  7. package/build/{logo-generator → ai-client/src/logo-generator}/components/history-carousel.js +1 -1
  8. package/build/{logo-generator → ai-client/src/logo-generator}/components/logo-presenter.js +8 -2
  9. package/build/ai-client/src/logo-generator/components/prompt.d.ts +6 -0
  10. package/build/{logo-generator → ai-client/src/logo-generator}/components/prompt.js +47 -19
  11. package/build/{logo-generator → ai-client/src/logo-generator}/components/upgrade-screen.js +6 -2
  12. package/build/{logo-generator → ai-client/src/logo-generator}/constants.d.ts +1 -0
  13. package/build/{logo-generator → ai-client/src/logo-generator}/constants.js +1 -0
  14. package/build/{logo-generator → ai-client/src/logo-generator}/hooks/use-checkout.js +0 -3
  15. package/build/{logo-generator → ai-client/src/logo-generator}/hooks/use-fair-usage-notice-message.js +5 -1
  16. package/build/{logo-generator → ai-client/src/logo-generator}/hooks/use-logo-generator.d.ts +3 -2
  17. package/build/{logo-generator → ai-client/src/logo-generator}/hooks/use-logo-generator.js +57 -3
  18. package/build/{logo-generator → ai-client/src/logo-generator}/store/constants.d.ts +1 -1
  19. package/build/{logo-generator → ai-client/src/logo-generator}/store/constants.js +1 -1
  20. package/build/{logo-generator → ai-client/src/logo-generator}/store/initial-state.js +6 -0
  21. package/build/{logo-generator → ai-client/src/logo-generator}/store/types.d.ts +6 -4
  22. package/build/{logo-generator → ai-client/src/logo-generator}/types.d.ts +0 -1
  23. package/build/{types.d.ts → ai-client/src/types.d.ts} +6 -1
  24. package/build/{types.js → ai-client/src/types.js} +4 -0
  25. package/build/components/tools/jp-redirect/index.d.ts +20 -0
  26. package/build/components/tools/jp-redirect/index.js +50 -0
  27. package/build/components/tools/jp-redirect/types.d.ts +39 -0
  28. package/build/components/tools/jp-redirect/types.js +1 -0
  29. package/package.json +18 -18
  30. package/src/hooks/use-image-generator/constants.ts +27 -23
  31. package/src/hooks/use-image-generator/index.ts +0 -11
  32. package/src/logo-generator/components/generator-modal.tsx +29 -9
  33. package/src/logo-generator/components/history-carousel.tsx +1 -0
  34. package/src/logo-generator/components/logo-presenter.tsx +15 -1
  35. package/src/logo-generator/components/prompt.tsx +55 -24
  36. package/src/logo-generator/components/upgrade-screen.tsx +8 -2
  37. package/src/logo-generator/constants.ts +1 -0
  38. package/src/logo-generator/hooks/use-checkout.ts +0 -5
  39. package/src/logo-generator/hooks/use-fair-usage-notice-message.tsx +6 -7
  40. package/src/logo-generator/hooks/use-logo-generator.ts +100 -31
  41. package/src/logo-generator/store/constants.ts +1 -1
  42. package/src/logo-generator/store/initial-state.ts +6 -0
  43. package/src/logo-generator/store/types.ts +9 -4
  44. package/src/logo-generator/types.ts +0 -1
  45. package/src/types.ts +12 -1
  46. package/build/hooks/use-image-generator/constants.js +0 -40
  47. package/build/logo-generator/components/prompt.d.ts +0 -7
  48. /package/build/{api-fetch → ai-client/src/api-fetch}/index.d.ts +0 -0
  49. /package/build/{api-fetch → ai-client/src/api-fetch}/index.js +0 -0
  50. /package/build/{ask-question → ai-client/src/ask-question}/index.d.ts +0 -0
  51. /package/build/{ask-question → ai-client/src/ask-question}/index.js +0 -0
  52. /package/build/{ask-question → ai-client/src/ask-question}/sync.d.ts +0 -0
  53. /package/build/{ask-question → ai-client/src/ask-question}/sync.js +0 -0
  54. /package/build/{audio-transcription → ai-client/src/audio-transcription}/index.d.ts +0 -0
  55. /package/build/{audio-transcription → ai-client/src/audio-transcription}/index.js +0 -0
  56. /package/build/{components → ai-client/src/components}/ai-control/ai-control.d.ts +0 -0
  57. /package/build/{components → ai-client/src/components}/ai-control/ai-control.js +0 -0
  58. /package/build/{components → ai-client/src/components}/ai-control/block-ai-control.d.ts +0 -0
  59. /package/build/{components → ai-client/src/components}/ai-control/block-ai-control.js +0 -0
  60. /package/build/{components → ai-client/src/components}/ai-control/extension-ai-control.d.ts +0 -0
  61. /package/build/{components → ai-client/src/components}/ai-control/extension-ai-control.js +0 -0
  62. /package/build/{components → ai-client/src/components}/ai-control/index.d.ts +0 -0
  63. /package/build/{components → ai-client/src/components}/ai-control/index.js +0 -0
  64. /package/build/{components → ai-client/src/components}/ai-status-indicator/index.d.ts +0 -0
  65. /package/build/{components → ai-client/src/components}/ai-status-indicator/index.js +0 -0
  66. /package/build/{components → ai-client/src/components}/audio-duration-display/index.d.ts +0 -0
  67. /package/build/{components → ai-client/src/components}/audio-duration-display/index.js +0 -0
  68. /package/build/{components → ai-client/src/components}/audio-duration-display/lib/media.d.ts +0 -0
  69. /package/build/{components → ai-client/src/components}/audio-duration-display/lib/media.js +0 -0
  70. /package/build/{components → ai-client/src/components}/index.d.ts +0 -0
  71. /package/build/{components → ai-client/src/components}/index.js +0 -0
  72. /package/build/{components → ai-client/src/components}/message/index.d.ts +0 -0
  73. /package/build/{components → ai-client/src/components}/message/index.js +0 -0
  74. /package/build/{data-flow → ai-client/src/data-flow}/context.d.ts +0 -0
  75. /package/build/{data-flow → ai-client/src/data-flow}/context.js +0 -0
  76. /package/build/{data-flow → ai-client/src/data-flow}/index.d.ts +0 -0
  77. /package/build/{data-flow → ai-client/src/data-flow}/index.js +0 -0
  78. /package/build/{data-flow → ai-client/src/data-flow}/use-ai-context.d.ts +0 -0
  79. /package/build/{data-flow → ai-client/src/data-flow}/use-ai-context.js +0 -0
  80. /package/build/{data-flow → ai-client/src/data-flow}/with-ai-assistant-data.d.ts +0 -0
  81. /package/build/{data-flow → ai-client/src/data-flow}/with-ai-assistant-data.js +0 -0
  82. /package/build/{hooks → ai-client/src/hooks}/use-ai-suggestions/index.d.ts +0 -0
  83. /package/build/{hooks → ai-client/src/hooks}/use-ai-suggestions/index.js +0 -0
  84. /package/build/{hooks → ai-client/src/hooks}/use-audio-transcription/index.d.ts +0 -0
  85. /package/build/{hooks → ai-client/src/hooks}/use-audio-transcription/index.js +0 -0
  86. /package/build/{hooks → ai-client/src/hooks}/use-audio-validation/index.d.ts +0 -0
  87. /package/build/{hooks → ai-client/src/hooks}/use-audio-validation/index.js +0 -0
  88. /package/build/{hooks → ai-client/src/hooks}/use-media-recording/index.d.ts +0 -0
  89. /package/build/{hooks → ai-client/src/hooks}/use-media-recording/index.js +0 -0
  90. /package/build/{hooks → ai-client/src/hooks}/use-save-to-media-library/index.d.ts +0 -0
  91. /package/build/{hooks → ai-client/src/hooks}/use-save-to-media-library/index.js +0 -0
  92. /package/build/{hooks → ai-client/src/hooks}/use-transcription-post-processing/index.d.ts +0 -0
  93. /package/build/{hooks → ai-client/src/hooks}/use-transcription-post-processing/index.js +0 -0
  94. /package/build/{icons → ai-client/src/icons}/ai-assistant.d.ts +0 -0
  95. /package/build/{icons → ai-client/src/icons}/ai-assistant.js +0 -0
  96. /package/build/{icons → ai-client/src/icons}/error-exclamation.d.ts +0 -0
  97. /package/build/{icons → ai-client/src/icons}/error-exclamation.js +0 -0
  98. /package/build/{icons → ai-client/src/icons}/index.d.ts +0 -0
  99. /package/build/{icons → ai-client/src/icons}/index.js +0 -0
  100. /package/build/{icons → ai-client/src/icons}/mic.d.ts +0 -0
  101. /package/build/{icons → ai-client/src/icons}/mic.js +0 -0
  102. /package/build/{icons → ai-client/src/icons}/origami-plane.d.ts +0 -0
  103. /package/build/{icons → ai-client/src/icons}/origami-plane.js +0 -0
  104. /package/build/{icons → ai-client/src/icons}/player-pause.d.ts +0 -0
  105. /package/build/{icons → ai-client/src/icons}/player-pause.js +0 -0
  106. /package/build/{icons → ai-client/src/icons}/player-play.d.ts +0 -0
  107. /package/build/{icons → ai-client/src/icons}/player-play.js +0 -0
  108. /package/build/{icons → ai-client/src/icons}/player-stop.d.ts +0 -0
  109. /package/build/{icons → ai-client/src/icons}/player-stop.js +0 -0
  110. /package/build/{icons → ai-client/src/icons}/speak-tone.d.ts +0 -0
  111. /package/build/{icons → ai-client/src/icons}/speak-tone.js +0 -0
  112. /package/build/{index.d.ts → ai-client/src/index.d.ts} +0 -0
  113. /package/build/{index.js → ai-client/src/index.js} +0 -0
  114. /package/build/{jwt → ai-client/src/jwt}/index.d.ts +0 -0
  115. /package/build/{jwt → ai-client/src/jwt}/index.js +0 -0
  116. /package/build/{libs → ai-client/src/libs}/index.d.ts +0 -0
  117. /package/build/{libs → ai-client/src/libs}/index.js +0 -0
  118. /package/build/{libs → ai-client/src/libs}/markdown/html-to-markdown.d.ts +0 -0
  119. /package/build/{libs → ai-client/src/libs}/markdown/html-to-markdown.js +0 -0
  120. /package/build/{libs → ai-client/src/libs}/markdown/index.d.ts +0 -0
  121. /package/build/{libs → ai-client/src/libs}/markdown/index.js +0 -0
  122. /package/build/{libs → ai-client/src/libs}/markdown/markdown-to-html.d.ts +0 -0
  123. /package/build/{libs → ai-client/src/libs}/markdown/markdown-to-html.js +0 -0
  124. /package/build/{logo-generator → ai-client/src/logo-generator}/assets/icons/ai.d.ts +0 -0
  125. /package/build/{logo-generator → ai-client/src/logo-generator}/assets/icons/ai.js +0 -0
  126. /package/build/{logo-generator → ai-client/src/logo-generator}/assets/icons/check.d.ts +0 -0
  127. /package/build/{logo-generator → ai-client/src/logo-generator}/assets/icons/check.js +0 -0
  128. /package/build/{logo-generator → ai-client/src/logo-generator}/assets/icons/logo.d.ts +0 -0
  129. /package/build/{logo-generator → ai-client/src/logo-generator}/assets/icons/logo.js +0 -0
  130. /package/build/{logo-generator → ai-client/src/logo-generator}/assets/icons/media.d.ts +0 -0
  131. /package/build/{logo-generator → ai-client/src/logo-generator}/assets/icons/media.js +0 -0
  132. /package/build/{logo-generator → ai-client/src/logo-generator}/components/fair-usage-notice.d.ts +0 -0
  133. /package/build/{logo-generator → ai-client/src/logo-generator}/components/fair-usage-notice.js +0 -0
  134. /package/build/{logo-generator → ai-client/src/logo-generator}/components/feature-fetch-failure-screen.d.ts +0 -0
  135. /package/build/{logo-generator → ai-client/src/logo-generator}/components/feature-fetch-failure-screen.js +0 -0
  136. /package/build/{logo-generator → ai-client/src/logo-generator}/components/first-load-screen.d.ts +0 -0
  137. /package/build/{logo-generator → ai-client/src/logo-generator}/components/first-load-screen.js +0 -0
  138. /package/build/{logo-generator → ai-client/src/logo-generator}/components/generator-modal.d.ts +0 -0
  139. /package/build/{logo-generator → ai-client/src/logo-generator}/components/history-carousel.d.ts +0 -0
  140. /package/build/{logo-generator → ai-client/src/logo-generator}/components/image-loader.d.ts +0 -0
  141. /package/build/{logo-generator → ai-client/src/logo-generator}/components/image-loader.js +0 -0
  142. /package/build/{logo-generator → ai-client/src/logo-generator}/components/logo-presenter.d.ts +0 -0
  143. /package/build/{logo-generator → ai-client/src/logo-generator}/components/upgrade-nudge.d.ts +0 -0
  144. /package/build/{logo-generator → ai-client/src/logo-generator}/components/upgrade-nudge.js +0 -0
  145. /package/build/{logo-generator → ai-client/src/logo-generator}/components/upgrade-screen.d.ts +0 -0
  146. /package/build/{logo-generator → ai-client/src/logo-generator}/components/visit-site-banner.d.ts +0 -0
  147. /package/build/{logo-generator → ai-client/src/logo-generator}/components/visit-site-banner.js +0 -0
  148. /package/build/{logo-generator → ai-client/src/logo-generator}/hooks/use-checkout.d.ts +0 -0
  149. /package/build/{logo-generator → ai-client/src/logo-generator}/hooks/use-fair-usage-notice-message.d.ts +0 -0
  150. /package/build/{logo-generator → ai-client/src/logo-generator}/hooks/use-request-errors.d.ts +0 -0
  151. /package/build/{logo-generator → ai-client/src/logo-generator}/hooks/use-request-errors.js +0 -0
  152. /package/build/{logo-generator → ai-client/src/logo-generator}/index.d.ts +0 -0
  153. /package/build/{logo-generator → ai-client/src/logo-generator}/index.js +0 -0
  154. /package/build/{logo-generator → ai-client/src/logo-generator}/lib/logo-storage.d.ts +0 -0
  155. /package/build/{logo-generator → ai-client/src/logo-generator}/lib/logo-storage.js +0 -0
  156. /package/build/{logo-generator → ai-client/src/logo-generator}/lib/media-exists.d.ts +0 -0
  157. /package/build/{logo-generator → ai-client/src/logo-generator}/lib/media-exists.js +0 -0
  158. /package/build/{logo-generator → ai-client/src/logo-generator}/lib/set-site-logo.d.ts +0 -0
  159. /package/build/{logo-generator → ai-client/src/logo-generator}/lib/set-site-logo.js +0 -0
  160. /package/build/{logo-generator → ai-client/src/logo-generator}/lib/wpcom-limited-request.d.ts +0 -0
  161. /package/build/{logo-generator → ai-client/src/logo-generator}/lib/wpcom-limited-request.js +0 -0
  162. /package/build/{logo-generator → ai-client/src/logo-generator}/store/actions.d.ts +0 -0
  163. /package/build/{logo-generator → ai-client/src/logo-generator}/store/actions.js +0 -0
  164. /package/build/{logo-generator → ai-client/src/logo-generator}/store/index.d.ts +0 -0
  165. /package/build/{logo-generator → ai-client/src/logo-generator}/store/index.js +0 -0
  166. /package/build/{logo-generator → ai-client/src/logo-generator}/store/initial-state.d.ts +0 -0
  167. /package/build/{logo-generator → ai-client/src/logo-generator}/store/reducer.d.ts +0 -0
  168. /package/build/{logo-generator → ai-client/src/logo-generator}/store/reducer.js +0 -0
  169. /package/build/{logo-generator → ai-client/src/logo-generator}/store/selectors.d.ts +0 -0
  170. /package/build/{logo-generator → ai-client/src/logo-generator}/store/selectors.js +0 -0
  171. /package/build/{logo-generator → ai-client/src/logo-generator}/store/types.js +0 -0
  172. /package/build/{logo-generator → ai-client/src/logo-generator}/types.js +0 -0
  173. /package/build/{suggestions-event-source → ai-client/src/suggestions-event-source}/index.d.ts +0 -0
  174. /package/build/{suggestions-event-source → ai-client/src/suggestions-event-source}/index.js +0 -0
@@ -1,3 +1,4 @@
1
+ import type { ImageStyleObject } from '../../hooks/use-image-generator/constants.js';
1
2
  import type { SiteDetails } from '../types.js';
2
3
  /**
3
4
  * Types for the AI Assistant feature.
@@ -10,7 +11,7 @@ export type Plan = {
10
11
  export type UpgradeTypeProp = 'vip' | 'default';
11
12
  export type TierUnlimitedProps = {
12
13
  slug: 'ai-assistant-tier-unlimited';
13
- limit: 999999999;
14
+ limit: 999999999 | 3000;
14
15
  value: 1;
15
16
  readableLimit: string;
16
17
  };
@@ -53,13 +54,14 @@ export type TierProp = {
53
54
  export type TierLimitProp = TierUnlimitedProps['limit'] | TierFreeProps['limit'] | Tier100Props['limit'] | Tier200Props['limit'] | Tier500Props['limit'] | Tier750Props['limit'] | Tier1000Props['limit'];
54
55
  export type TierSlugProp = TierUnlimitedProps['slug'] | TierFreeProps['slug'] | Tier100Props['slug'] | Tier200Props['slug'] | Tier500Props['slug'] | Tier750Props['slug'] | Tier1000Props['slug'];
55
56
  export type TierValueProp = TierUnlimitedProps['value'] | TierFreeProps['value'] | Tier100Props['value'] | Tier200Props['value'] | Tier500Props['value'] | Tier750Props['value'] | Tier1000Props['value'];
57
+ export type LogoGeneratorFeatureControl = FeatureControl & {
58
+ styles: Array<ImageStyleObject> | [];
59
+ };
56
60
  export type FeatureControl = {
57
61
  enabled: boolean;
58
- 'min-jetpack-version': string;
59
- [key: string]: FeatureControl | boolean | string;
60
62
  };
61
63
  export type FeaturesControl = {
62
- [key: string]: FeatureControl;
64
+ [key: string]: FeatureControl | LogoGeneratorFeatureControl;
63
65
  };
64
66
  export type AiFeatureProps = {
65
67
  hasFeature: boolean;
@@ -17,7 +17,6 @@ export interface GeneratorModalProps {
17
17
  onReload: () => void;
18
18
  context: string;
19
19
  placement: string;
20
- showStyleSelector?: boolean;
21
20
  }
22
21
  export interface LogoPresenterProps {
23
22
  logo?: Logo;
@@ -7,8 +7,13 @@ export declare const ERROR_NETWORK: "error_network";
7
7
  export declare const ERROR_UNCLEAR_PROMPT: "error_unclear_prompt";
8
8
  export declare const ERROR_RESPONSE: "error_response";
9
9
  export type SuggestionErrorCode = typeof ERROR_SERVICE_UNAVAILABLE | typeof ERROR_QUOTA_EXCEEDED | typeof ERROR_MODERATION | typeof ERROR_CONTEXT_TOO_LARGE | typeof ERROR_NETWORK | typeof ERROR_UNCLEAR_PROMPT | typeof ERROR_RESPONSE;
10
+ export declare const ROLE_SYSTEM: "system";
11
+ export declare const ROLE_USER: "user";
12
+ export declare const ROLE_ASSISTANT: "assistant";
13
+ export declare const ROLE_JETPACK_AI: "jetpack-ai";
14
+ export type RoleType = typeof ROLE_SYSTEM | typeof ROLE_USER | typeof ROLE_ASSISTANT | typeof ROLE_JETPACK_AI;
10
15
  export type PromptItemProps = {
11
- role: 'system' | 'user' | 'assistant' | 'jetpack-ai';
16
+ role: RoleType;
12
17
  content?: string;
13
18
  context?: object;
14
19
  };
@@ -5,6 +5,10 @@ export const ERROR_CONTEXT_TOO_LARGE = 'error_context_too_large';
5
5
  export const ERROR_NETWORK = 'error_network';
6
6
  export const ERROR_UNCLEAR_PROMPT = 'error_unclear_prompt';
7
7
  export const ERROR_RESPONSE = 'error_response';
8
+ export const ROLE_SYSTEM = 'system';
9
+ export const ROLE_USER = 'user';
10
+ export const ROLE_ASSISTANT = 'assistant';
11
+ export const ROLE_JETPACK_AI = 'jetpack-ai';
8
12
  /*
9
13
  * Hook constants
10
14
  */
@@ -0,0 +1,20 @@
1
+ import { GetRedirectUrlArgs } from './types.js';
2
+ /**
3
+ * Builds an URL using the jetpack.com/redirect/ service
4
+ *
5
+ * If source is a simple slug, it will be sent using the source query parameter. e.g. jetpack.com/redirect/?source=slug
6
+ *
7
+ * If source is a full URL, starting with https://, it will be sent using the url query parameter. e.g. jetpack.com/redirect/?url=https://wordpress.com
8
+ *
9
+ * Note: if using full URL, query parameters and anchor must be passed in args. Any querystring of url fragment in the URL will be discarded.
10
+ *
11
+ * @since 0.2.0
12
+ * @param {string} source - The URL handler registered in the server or the full destination URL (starting with https://).
13
+ * @param {GetRedirectUrlArgs} args - Additional arguments to build the url.
14
+ * This is not a complete list as any argument passed here
15
+ * will be sent to as a query parameter to the Redirect server.
16
+ * These parameters will not necessarily be passed over to the final destination URL.
17
+ * If you want to add a parameter to the final destination URL, use the `query` argument.
18
+ * @return {string} The redirect URL
19
+ */
20
+ export default function getRedirectUrl(source: string, args?: GetRedirectUrlArgs): string;
@@ -0,0 +1,50 @@
1
+ /* global jetpack_redirects */
2
+ /**
3
+ * Builds an URL using the jetpack.com/redirect/ service
4
+ *
5
+ * If source is a simple slug, it will be sent using the source query parameter. e.g. jetpack.com/redirect/?source=slug
6
+ *
7
+ * If source is a full URL, starting with https://, it will be sent using the url query parameter. e.g. jetpack.com/redirect/?url=https://wordpress.com
8
+ *
9
+ * Note: if using full URL, query parameters and anchor must be passed in args. Any querystring of url fragment in the URL will be discarded.
10
+ *
11
+ * @since 0.2.0
12
+ * @param {string} source - The URL handler registered in the server or the full destination URL (starting with https://).
13
+ * @param {GetRedirectUrlArgs} args - Additional arguments to build the url.
14
+ * This is not a complete list as any argument passed here
15
+ * will be sent to as a query parameter to the Redirect server.
16
+ * These parameters will not necessarily be passed over to the final destination URL.
17
+ * If you want to add a parameter to the final destination URL, use the `query` argument.
18
+ * @return {string} The redirect URL
19
+ */
20
+ export default function getRedirectUrl(source, args = {}) {
21
+ const queryVars = {};
22
+ let calypsoEnv;
23
+ if (typeof window !== 'undefined') {
24
+ calypsoEnv = window?.JP_CONNECTION_INITIAL_STATE?.calypsoEnv;
25
+ }
26
+ if (source.search('https://') === 0) {
27
+ const parsedUrl = new URL(source);
28
+ // discard any query and fragments.
29
+ source = `https://${parsedUrl.host}${parsedUrl.pathname}`;
30
+ queryVars.url = encodeURIComponent(source);
31
+ }
32
+ else {
33
+ queryVars.source = encodeURIComponent(source);
34
+ }
35
+ for (const argName in args) {
36
+ queryVars[argName] = encodeURIComponent(args[argName]);
37
+ }
38
+ if (!Object.keys(queryVars).includes('site') &&
39
+ typeof jetpack_redirects !== 'undefined' &&
40
+ Object.hasOwn(jetpack_redirects, 'currentSiteRawUrl')) {
41
+ queryVars.site = jetpack_redirects.currentBlogID ?? jetpack_redirects.currentSiteRawUrl;
42
+ }
43
+ if (calypsoEnv) {
44
+ queryVars.calypso_env = calypsoEnv;
45
+ }
46
+ const queryString = Object.keys(queryVars)
47
+ .map(key => key + '=' + queryVars[key])
48
+ .join('&');
49
+ return `https://jetpack.com/redirect/?` + queryString;
50
+ }
@@ -0,0 +1,39 @@
1
+ export type GetRedirectUrlArgs = {
2
+ /**
3
+ * URL of the current site. Will default to the value of
4
+ * jetpack_redirects.currentSiteRawUrl, if available.
5
+ * Used to fill in the `[site]` placeholder in the target.
6
+ */
7
+ site?: string;
8
+ /**
9
+ * Additional path to be appended to the URL.
10
+ * Used to fill in the `[path]` placeholder in the target.
11
+ */
12
+ path?: string;
13
+ /**
14
+ * Query parameters to be added to the final destination URL.
15
+ * Should be in query string format (e.g. 'key=value&foo=bar').
16
+ */
17
+ query?: string;
18
+ /**
19
+ * Anchor to be added to the URL. Must be a single string.
20
+ * Example: `section1`.
21
+ */
22
+ anchor?: string;
23
+ /**
24
+ * Any other custom arguments to be added to the final destination URL.
25
+ */
26
+ [key: string]: string;
27
+ };
28
+ export type QueryVars = {
29
+ url?: string;
30
+ site?: string;
31
+ source?: string;
32
+ calypso_env?: string;
33
+ };
34
+ declare global {
35
+ const jetpack_redirects: {
36
+ currentSiteRawUrl?: string;
37
+ currentBlogID?: string;
38
+ };
39
+ }
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "private": false,
3
3
  "name": "@automattic/jetpack-ai-client",
4
- "version": "0.20.1",
4
+ "version": "0.22.0",
5
5
  "description": "A JS client for consuming Jetpack AI services",
6
6
  "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/ai-client/#readme",
7
7
  "bugs": {
@@ -23,15 +23,15 @@
23
23
  },
24
24
  "type": "module",
25
25
  "devDependencies": {
26
- "@storybook/addon-actions": "8.2.9",
27
- "@storybook/blocks": "8.2.9",
28
- "@storybook/preview-api": "8.2.9",
29
- "@storybook/react": "8.2.9",
26
+ "@storybook/addon-actions": "8.3.5",
27
+ "@storybook/blocks": "8.3.5",
28
+ "@storybook/preview-api": "8.3.5",
29
+ "@storybook/react": "8.3.5",
30
30
  "@types/markdown-it": "14.1.2",
31
31
  "@types/turndown": "5.0.5",
32
32
  "jest": "^29.6.2",
33
33
  "jest-environment-jsdom": "29.7.0",
34
- "storybook": "8.2.9",
34
+ "storybook": "8.3.5",
35
35
  "typescript": "5.0.4"
36
36
  },
37
37
  "exports": {
@@ -43,21 +43,21 @@
43
43
  "main": "./build/index.js",
44
44
  "types": "./build/index.d.ts",
45
45
  "dependencies": {
46
- "@automattic/jetpack-base-styles": "^0.6.33",
47
- "@automattic/jetpack-connection": "^0.35.11",
48
- "@automattic/jetpack-shared-extension-utils": "^0.15.12",
46
+ "@automattic/jetpack-base-styles": "^0.6.34",
47
+ "@automattic/jetpack-connection": "^0.35.14",
48
+ "@automattic/jetpack-shared-extension-utils": "^0.15.14",
49
49
  "@microsoft/fetch-event-source": "2.0.1",
50
50
  "@types/react": "18.3.3",
51
51
  "@types/wordpress__block-editor": "11.5.15",
52
- "@wordpress/api-fetch": "7.8.2",
53
- "@wordpress/blob": "4.8.1",
54
- "@wordpress/block-editor": "14.3.4",
55
- "@wordpress/components": "28.8.4",
56
- "@wordpress/compose": "7.8.3",
57
- "@wordpress/data": "10.8.3",
58
- "@wordpress/element": "6.8.1",
59
- "@wordpress/i18n": "5.8.2",
60
- "@wordpress/icons": "10.8.2",
52
+ "@wordpress/api-fetch": "7.9.0",
53
+ "@wordpress/blob": "4.9.0",
54
+ "@wordpress/block-editor": "14.4.0",
55
+ "@wordpress/components": "28.9.0",
56
+ "@wordpress/compose": "7.9.0",
57
+ "@wordpress/data": "10.9.0",
58
+ "@wordpress/element": "6.9.0",
59
+ "@wordpress/i18n": "5.9.0",
60
+ "@wordpress/icons": "10.9.0",
61
61
  "clsx": "2.1.1",
62
62
  "debug": "4.3.4",
63
63
  "markdown-it": "14.0.0",
@@ -1,5 +1,3 @@
1
- import { __ } from '@wordpress/i18n';
2
-
3
1
  // Styles
4
2
  export const IMAGE_STYLE_ENHANCE = 'enhance';
5
3
  export const IMAGE_STYLE_ANIME = 'anime';
@@ -19,26 +17,32 @@ export const IMAGE_STYLE_3D_MODEL = '3d-model';
19
17
  export const IMAGE_STYLE_PIXEL_ART = 'pixel-art';
20
18
  export const IMAGE_STYLE_TEXTURE = 'texture';
21
19
  export const IMAGE_STYLE_MONTY_PYTHON = 'monty-python';
20
+ export const IMAGE_STYLE_AUTO = 'auto';
21
+ export const IMAGE_STYLE_NONE = 'none';
22
22
 
23
- export const IMAGE_STYLE_LABELS = {
24
- [ IMAGE_STYLE_ENHANCE ]: __( 'Enhance', 'jetpack-ai-client' ),
25
- [ IMAGE_STYLE_ANIME ]: __( 'Anime', 'jetpack-ai-client' ),
26
- [ IMAGE_STYLE_PHOTOGRAPHIC ]: __( 'Photographic', 'jetpack-ai-client' ),
27
- [ IMAGE_STYLE_DIGITAL_ART ]: __( 'Digital Art', 'jetpack-ai-client' ),
28
- [ IMAGE_STYLE_COMICBOOK ]: __( 'Comicbook', 'jetpack-ai-client' ),
29
- [ IMAGE_STYLE_FANTASY_ART ]: __( 'Fantasy Art', 'jetpack-ai-client' ),
30
- [ IMAGE_STYLE_ANALOG_FILM ]: __( 'Analog Film', 'jetpack-ai-client' ),
31
- [ IMAGE_STYLE_NEONPUNK ]: __( 'Neon Punk', 'jetpack-ai-client' ),
32
- [ IMAGE_STYLE_ISOMETRIC ]: __( 'Isometric', 'jetpack-ai-client' ),
33
- [ IMAGE_STYLE_LOWPOLY ]: __( 'Low Poly', 'jetpack-ai-client' ),
34
- [ IMAGE_STYLE_ORIGAMI ]: __( 'Origami', 'jetpack-ai-client' ),
35
- [ IMAGE_STYLE_LINE_ART ]: __( 'Line Art', 'jetpack-ai-client' ),
36
- [ IMAGE_STYLE_CRAFT_CLAY ]: __( 'Craft Clay', 'jetpack-ai-client' ),
37
- [ IMAGE_STYLE_CINEMATIC ]: __( 'Cinematic', 'jetpack-ai-client' ),
38
- [ IMAGE_STYLE_3D_MODEL ]: __( '3D Model', 'jetpack-ai-client' ),
39
- [ IMAGE_STYLE_PIXEL_ART ]: __( 'Pixel Art', 'jetpack-ai-client' ),
40
- [ IMAGE_STYLE_TEXTURE ]: __( 'Texture', 'jetpack-ai-client' ),
41
- [ IMAGE_STYLE_MONTY_PYTHON ]: __( 'Monty Python', 'jetpack-ai-client' ),
42
- };
23
+ export type ImageStyle =
24
+ | typeof IMAGE_STYLE_ENHANCE
25
+ | typeof IMAGE_STYLE_ANIME
26
+ | typeof IMAGE_STYLE_PHOTOGRAPHIC
27
+ | typeof IMAGE_STYLE_DIGITAL_ART
28
+ | typeof IMAGE_STYLE_COMICBOOK
29
+ | typeof IMAGE_STYLE_FANTASY_ART
30
+ | typeof IMAGE_STYLE_ANALOG_FILM
31
+ | typeof IMAGE_STYLE_NEONPUNK
32
+ | typeof IMAGE_STYLE_ISOMETRIC
33
+ | typeof IMAGE_STYLE_LOWPOLY
34
+ | typeof IMAGE_STYLE_ORIGAMI
35
+ | typeof IMAGE_STYLE_LINE_ART
36
+ | typeof IMAGE_STYLE_CRAFT_CLAY
37
+ | typeof IMAGE_STYLE_CINEMATIC
38
+ | typeof IMAGE_STYLE_3D_MODEL
39
+ | typeof IMAGE_STYLE_PIXEL_ART
40
+ | typeof IMAGE_STYLE_TEXTURE
41
+ | typeof IMAGE_STYLE_MONTY_PYTHON
42
+ | typeof IMAGE_STYLE_AUTO
43
+ | typeof IMAGE_STYLE_NONE;
43
44
 
44
- export type ImageStyle = keyof typeof IMAGE_STYLE_LABELS;
45
+ export type ImageStyleObject = {
46
+ label: string;
47
+ value: ImageStyle;
48
+ };
@@ -7,7 +7,6 @@ import debugFactory from 'debug';
7
7
  */
8
8
  import askQuestionSync from '../../ask-question/sync.js';
9
9
  import requestJwt from '../../jwt/index.js';
10
- import { IMAGE_STYLE_LABELS } from './constants.js';
11
10
 
12
11
  const debug = debugFactory( 'ai-client:use-image-generator' );
13
12
 
@@ -256,20 +255,10 @@ const useImageGenerator = () => {
256
255
  }
257
256
  };
258
257
 
259
- /**
260
- * Get available styles.
261
- *
262
- * @return {object} with the styles {key:label} for the image generation.
263
- */
264
- const getImageStyles = function (): object {
265
- return IMAGE_STYLE_LABELS;
266
- };
267
-
268
258
  return {
269
259
  generateImage,
270
260
  generateImageWithStableDiffusion,
271
261
  generateImageWithParameters: executeImageGeneration,
272
- getImageStyles,
273
262
  };
274
263
  };
275
264
 
@@ -49,7 +49,6 @@ export const GeneratorModal: React.FC< GeneratorModalProps > = ( {
49
49
  siteDetails,
50
50
  context,
51
51
  placement,
52
- showStyleSelector,
53
52
  } ) => {
54
53
  const { tracks } = useAnalytics();
55
54
  const { recordEvent: recordTracksEvent } = tracks;
@@ -71,6 +70,8 @@ export const GeneratorModal: React.FC< GeneratorModalProps > = ( {
71
70
  generateLogo,
72
71
  setContext,
73
72
  tierPlansEnabled,
73
+ site,
74
+ requireUpgrade,
74
75
  } = useLogoGenerator();
75
76
  const { featureFetchError, firstLogoPromptFetchError, clearErrors } = useRequestErrors();
76
77
  const siteId = siteDetails?.ID;
@@ -108,9 +109,10 @@ export const GeneratorModal: React.FC< GeneratorModalProps > = ( {
108
109
 
109
110
  const logoCost = feature?.costs?.[ 'jetpack-ai-logo-generator' ]?.logo ?? DEFAULT_LOGO_COST;
110
111
  const promptCreationCost = 1;
111
- const currentLimit = feature?.currentTier?.value || 0;
112
+ const currentLimit = feature?.currentTier?.limit || 0;
113
+ const currentValue = feature?.currentTier?.value || 0;
112
114
  const currentUsage = feature?.usagePeriod?.requestsCount || 0;
113
- const isUnlimited = ! tierPlansEnabled ? currentLimit > 0 : currentLimit === 1;
115
+ const isUnlimited = ! tierPlansEnabled ? currentValue > 0 : currentValue === 1;
114
116
  const hasNoNextTier = ! feature?.nextTier; // If there is no next tier, the user cannot upgrade.
115
117
 
116
118
  // The user needs an upgrade immediately if they have no logos and not enough requests remaining for one prompt and one logo generation.
@@ -137,14 +139,33 @@ export const GeneratorModal: React.FC< GeneratorModalProps > = ( {
137
139
  loadLogoHistory( siteId );
138
140
 
139
141
  // If there is any logo, we do not need to generate a first logo again.
140
- if ( ! isLogoHistoryEmpty( String( siteId ) ) ) {
142
+ if ( hasHistory ) {
141
143
  setLoadingState( null );
142
144
  setIsLoadingHistory( false );
143
145
  return;
144
146
  }
145
147
 
146
- // If the site does not require an upgrade and has no logos stored, generate the first prompt based on the site's data.
147
- generateFirstLogo();
148
+ // if site requires an upgrade, just return and set loaders to null,
149
+ // prompt component will take over the situation
150
+ if ( requireUpgrade ) {
151
+ setLoadingState( null );
152
+ setIsLoadingHistory( false );
153
+ return;
154
+ }
155
+
156
+ // If the site does not require an upgrade and has no logos stored
157
+ // and has title and description, generate the first prompt based on the site's data.
158
+ if (
159
+ site &&
160
+ site.name &&
161
+ site.description &&
162
+ site.name !== __( 'Site Title', 'jetpack-ai-client' )
163
+ ) {
164
+ generateFirstLogo();
165
+ } else {
166
+ setLoadingState( null );
167
+ setIsLoadingHistory( false );
168
+ }
148
169
  } catch ( error ) {
149
170
  debug( 'Error fetching feature', error );
150
171
  setLoadingState( null );
@@ -157,6 +178,7 @@ export const GeneratorModal: React.FC< GeneratorModalProps > = ( {
157
178
  clearDeletedMedia,
158
179
  isLogoHistoryEmpty,
159
180
  siteId,
181
+ requireUpgrade,
160
182
  ] );
161
183
 
162
184
  const handleModalOpen = useCallback( async () => {
@@ -243,9 +265,7 @@ export const GeneratorModal: React.FC< GeneratorModalProps > = ( {
243
265
  } else {
244
266
  body = (
245
267
  <>
246
- { ! logoAccepted && (
247
- <Prompt initialPrompt={ initialPrompt } showStyleSelector={ showStyleSelector } />
248
- ) }
268
+ { ! logoAccepted && <Prompt initialPrompt={ initialPrompt } /> }
249
269
 
250
270
  <LogoPresenter
251
271
  logo={ selectedLogo }
@@ -48,6 +48,7 @@ export const HistoryCarousel: React.FC = () => {
48
48
  <img height="48" width="48" src={ loader } alt={ 'loading' } />
49
49
  </Button>
50
50
  ) }
51
+ { ! logos.length && ! isLoadingHistory && <div>&nbsp;</div> }
51
52
  { logos.map( ( logo, index ) => (
52
53
  <Button
53
54
  key={ logo.url }
@@ -111,6 +111,7 @@ const UseOnSiteButton: React.FC< { onApplyLogo: ( mediaId: number ) => void } >
111
111
  className="jetpack-ai-logo-generator-modal-presenter__action"
112
112
  onClick={ handleClick }
113
113
  disabled={ isSavingLogoToLibrary || ! selectedLogo?.mediaId }
114
+ variant="secondary"
114
115
  >
115
116
  <Icon icon={ <LogoIcon /> } />
116
117
  <span className="action-text">{ __( 'Use on block', 'jetpack-ai-client' ) }</span>
@@ -140,6 +141,17 @@ const LogoFetching: React.FC = () => {
140
141
  );
141
142
  };
142
143
 
144
+ const LogoEmpty: React.FC = () => {
145
+ return (
146
+ <>
147
+ <div style={ { width: 0, height: '229px' } }></div>
148
+ <span className="jetpack-ai-logo-generator-modal-presenter__loading-text">
149
+ { __( 'Once you generate a logo, it will show up here', 'jetpack-ai-client' ) }
150
+ </span>
151
+ </>
152
+ );
153
+ };
154
+
143
155
  const LogoReady: React.FC< {
144
156
  siteId: string;
145
157
  logo: Logo;
@@ -194,7 +206,9 @@ export const LogoPresenter: React.FC< LogoPresenterProps > = ( {
194
206
 
195
207
  let logoContent: React.ReactNode;
196
208
 
197
- if ( ! logo ) {
209
+ if ( ! logo && ! isRequestingImage ) {
210
+ logoContent = <LogoEmpty />;
211
+ } else if ( ! logo ) {
198
212
  debug( 'No logo provided, history still loading or logo being generated' );
199
213
  logoContent = <LogoFetching />;
200
214
  } else if ( loading || isRequestingImage ) {
@@ -10,10 +10,7 @@ import { useCallback, useEffect, useState, useRef } from 'react';
10
10
  /**
11
11
  * Internal dependencies
12
12
  */
13
- import {
14
- IMAGE_STYLE_MONTY_PYTHON,
15
- IMAGE_STYLE_LINE_ART,
16
- } from '../../hooks/use-image-generator/constants.js';
13
+ import { IMAGE_STYLE_NONE, IMAGE_STYLE_AUTO } from '../../hooks/use-image-generator/constants.js';
17
14
  import AiIcon from '../assets/icons/ai.js';
18
15
  import {
19
16
  EVENT_GENERATE,
@@ -21,6 +18,7 @@ import {
21
18
  EVENT_UPGRADE,
22
19
  EVENT_PLACEMENT_INPUT_FOOTER,
23
20
  EVENT_SWITCH_STYLE,
21
+ EVENT_GUESS_STYLE,
24
22
  } from '../constants.js';
25
23
  import { useCheckout } from '../hooks/use-checkout.js';
26
24
  import useLogoGenerator from '../hooks/use-logo-generator.js';
@@ -31,16 +29,15 @@ import './prompt.scss';
31
29
  /**
32
30
  * Types
33
31
  */
34
- import type { ImageStyle } from '../../hooks/use-image-generator/constants.js';
32
+ import type { ImageStyle, ImageStyleObject } from '../../hooks/use-image-generator/constants.js';
35
33
 
36
34
  const debug = debugFactory( 'jetpack-ai-calypso:prompt-box' );
37
35
 
38
36
  type PromptProps = {
39
37
  initialPrompt?: string;
40
- showStyleSelector?: boolean;
41
38
  };
42
39
 
43
- export const Prompt = ( { initialPrompt = '', showStyleSelector = false }: PromptProps ) => {
40
+ export const Prompt = ( { initialPrompt = '' }: PromptProps ) => {
44
41
  const { tracks } = useAnalytics();
45
42
  const { recordEvent: recordTracksEvent } = tracks;
46
43
  const [ prompt, setPrompt ] = useState< string >( initialPrompt );
@@ -48,9 +45,9 @@ export const Prompt = ( { initialPrompt = '', showStyleSelector = false }: Promp
48
45
  const { enhancePromptFetchError, logoFetchError } = useRequestErrors();
49
46
  const { nextTierCheckoutURL: checkoutUrl, hasNextTier } = useCheckout();
50
47
  const hasPrompt = prompt?.length >= MINIMUM_PROMPT_LENGTH;
51
- const [ style, setStyle ] = useState< ImageStyle >(
52
- showStyleSelector ? IMAGE_STYLE_LINE_ART : null
53
- );
48
+ const [ showStyleSelector, setShowStyleSelector ] = useState( false );
49
+ const [ style, setStyle ] = useState< ImageStyle >( null );
50
+ const [ styles, setStyles ] = useState< Array< ImageStyleObject > >( [] );
54
51
 
55
52
  const {
56
53
  generateLogo,
@@ -63,7 +60,8 @@ export const Prompt = ( { initialPrompt = '', showStyleSelector = false }: Promp
63
60
  requireUpgrade,
64
61
  context,
65
62
  tierPlansEnabled,
66
- getImageStyles,
63
+ imageStyles,
64
+ guessStyle,
67
65
  } = useLogoGenerator();
68
66
 
69
67
  const enhancingLabel = __( 'Enhancing…', 'jetpack-ai-client' );
@@ -108,10 +106,41 @@ export const Prompt = ( { initialPrompt = '', showStyleSelector = false }: Promp
108
106
  }
109
107
  }, [ prompt ] );
110
108
 
109
+ useEffect( () => {
110
+ if ( imageStyles.length > 0 ) {
111
+ // Sort styles to have "None" and "Auto" first
112
+ setStyles(
113
+ [
114
+ imageStyles.find( ( { value } ) => value === IMAGE_STYLE_NONE ),
115
+ imageStyles.find( ( { value } ) => value === IMAGE_STYLE_AUTO ),
116
+ ...imageStyles.filter(
117
+ ( { value } ) => ! [ IMAGE_STYLE_NONE, IMAGE_STYLE_AUTO ].includes( value )
118
+ ),
119
+ ].filter( v => v ) // simplest way to get rid of empty values
120
+ );
121
+ setShowStyleSelector( true );
122
+ setStyle( IMAGE_STYLE_NONE );
123
+ } else {
124
+ setStyles( [] );
125
+ setShowStyleSelector( false );
126
+ setStyle( null );
127
+ }
128
+ }, [ imageStyles ] );
129
+
111
130
  const onGenerate = useCallback( async () => {
112
- // shouldn't tool be "logo-generator" to be more specific?
113
- recordTracksEvent( EVENT_GENERATE, { context, tool: 'image', style } );
114
- generateLogo( { prompt, style } );
131
+ debug( context );
132
+ if ( style === IMAGE_STYLE_AUTO ) {
133
+ setIsEnhancingPrompt( true );
134
+ recordTracksEvent( EVENT_GUESS_STYLE, { context, tool: 'image' } );
135
+ const guessedStyle = ( await guessStyle( prompt ) ) || IMAGE_STYLE_NONE;
136
+ setStyle( guessedStyle );
137
+ recordTracksEvent( EVENT_GENERATE, { context, tool: 'image', style: guessedStyle } );
138
+ setIsEnhancingPrompt( false );
139
+ generateLogo( { prompt, style: guessedStyle } );
140
+ } else {
141
+ recordTracksEvent( EVENT_GENERATE, { context, tool: 'image', style } );
142
+ generateLogo( { prompt, style } );
143
+ }
115
144
  }, [ context, generateLogo, prompt, style ] );
116
145
 
117
146
  const onPromptInput = ( event: React.ChangeEvent< HTMLInputElement > ) => {
@@ -150,10 +179,12 @@ export const Prompt = ( { initialPrompt = '', showStyleSelector = false }: Promp
150
179
  [ context, setStyle, recordTracksEvent ]
151
180
  );
152
181
 
153
- const imageStyles = getImageStyles();
154
- const availableStyles = Object.keys( imageStyles ).filter(
155
- ( styleKey: ImageStyle ) => styleKey !== IMAGE_STYLE_MONTY_PYTHON
156
- );
182
+ const onKeyDown = ( event: React.KeyboardEvent ) => {
183
+ if ( event.key === 'Enter' ) {
184
+ event.preventDefault();
185
+ onGenerate();
186
+ }
187
+ };
157
188
 
158
189
  return (
159
190
  <div className="jetpack-ai-logo-generator__prompt">
@@ -171,21 +202,20 @@ export const Prompt = ( { initialPrompt = '', showStyleSelector = false }: Promp
171
202
  { enhanceButtonLabel }
172
203
  </Button>
173
204
  </div>
174
- { showStyleSelector && availableStyles && (
205
+ { showStyleSelector && (
175
206
  <SelectControl
176
- // label={ __( 'Style', 'jetpack-ai-client' ) }
177
207
  __nextHasNoMarginBottom
178
208
  value={ style }
179
- options={ availableStyles.map( imageStyle => ( {
180
- label: imageStyles[ imageStyle ],
181
- value: imageStyle,
182
- } ) ) }
209
+ options={ styles }
183
210
  onChange={ updateStyle }
211
+ disabled={ isBusy || requireUpgrade }
184
212
  />
185
213
  ) }
186
214
  </div>
187
215
  <div className="jetpack-ai-logo-generator__prompt-query">
188
216
  <div
217
+ role="textbox"
218
+ tabIndex={ 0 }
189
219
  ref={ inputRef }
190
220
  contentEditable={ ! isBusy && ! requireUpgrade }
191
221
  // The content editable div is expected to be updated by the enhance prompt, so warnings are suppressed
@@ -193,6 +223,7 @@ export const Prompt = ( { initialPrompt = '', showStyleSelector = false }: Promp
193
223
  className="prompt-query__input"
194
224
  onInput={ onPromptInput }
195
225
  onPaste={ onPromptPaste }
226
+ onKeyDown={ onKeyDown }
196
227
  data-placeholder={ __(
197
228
  'Describe your site or simply ask for a logo specifying some details about it',
198
229
  'jetpack-ai-client'