Skip to main content

data_for_seo/api/content_generation/
mod.rs

1use crate::entity::{
2    ContentGenerationApiCheckGrammar, ContentGenerationApiCheckGrammarLanguage,
3    ContentGenerationApiGenerate, ContentGenerationApiGenerateMetaTags,
4    ContentGenerationApiGenerateSubTopics, ContentGenerationApiGenerateText,
5    ContentGenerationApiGrammarRules, ContentGenerationApiParaphrase,
6    ContentGenerationApiTextSummary, ContentGenerationApiTextSummaryLanguage,
7};
8use crate::{DataForSeoApiResponse, DataForSeoClient};
9use serde::{Deserialize, Serialize};
10use serde_json::Value;
11
12/// Content Generation API — text generation, paraphrasing, and grammar checks.
13/// See <https://docs.dataforseo.com/v3/content_generation/overview/>.
14pub struct ContentGenerationApi<'a> {
15    client: &'a DataForSeoClient,
16}
17
18impl DataForSeoClient {
19    /// Returns the Content Generation API endpoints.
20    pub fn content_generation(&self) -> ContentGenerationApi<'_> {
21        ContentGenerationApi { client: self }
22    }
23}
24
25impl ContentGenerationApi<'_> {
26    /// Continues the input text.
27    /// <https://docs.dataforseo.com/v3/content_generation/generate/live/>
28    pub async fn generate(
29        &self,
30        data: Vec<ContentGenerationApiGeneratePost>,
31    ) -> DataForSeoApiResponse<ContentGenerationApiGenerate> {
32        self.client
33            .http_post("/v3/content_generation/generate/live", &data)
34            .await
35    }
36
37    /// Generates text from a topic and parameters.
38    /// <https://docs.dataforseo.com/v3/content_generation/generate_text/live/>
39    pub async fn generate_text(
40        &self,
41        data: Vec<ContentGenerationApiGenerateTextPost>,
42    ) -> DataForSeoApiResponse<ContentGenerationApiGenerateText> {
43        self.client
44            .http_post("/v3/content_generation/generate_text/live", &data)
45            .await
46    }
47
48    /// Generates title and description meta tags for the input text.
49    /// <https://docs.dataforseo.com/v3/content_generation/generate_meta_tags/live/>
50    pub async fn generate_meta_tags(
51        &self,
52        data: Vec<ContentGenerationApiGenerateMetaTagsPost>,
53    ) -> DataForSeoApiResponse<ContentGenerationApiGenerateMetaTags> {
54        self.client
55            .http_post("/v3/content_generation/generate_meta_tags/live", &data)
56            .await
57    }
58
59    /// Suggests subtopics for a topic.
60    /// <https://docs.dataforseo.com/v3/content_generation/generate_sub_topics/live/>
61    pub async fn generate_sub_topics(
62        &self,
63        data: Vec<ContentGenerationApiGenerateSubTopicsPost>,
64    ) -> DataForSeoApiResponse<ContentGenerationApiGenerateSubTopics> {
65        self.client
66            .http_post("/v3/content_generation/generate_sub_topics/live", &data)
67            .await
68    }
69
70    /// Rewrites the input text.
71    /// <https://docs.dataforseo.com/v3/content_generation/paraphrase/live/>
72    pub async fn paraphrase(
73        &self,
74        data: Vec<ContentGenerationApiParaphrasePost>,
75    ) -> DataForSeoApiResponse<ContentGenerationApiParaphrase> {
76        self.client
77            .http_post("/v3/content_generation/paraphrase/live", &data)
78            .await
79    }
80
81    /// Checks the grammar and spelling of the input text.
82    /// <https://docs.dataforseo.com/v3/content_generation/check_grammar/live/>
83    pub async fn check_grammar(
84        &self,
85        data: Vec<ContentGenerationApiCheckGrammarPost>,
86    ) -> DataForSeoApiResponse<ContentGenerationApiCheckGrammar> {
87        self.client
88            .http_post("/v3/content_generation/check_grammar/live", &data)
89            .await
90    }
91
92    /// Languages supported by the Check Grammar endpoint.
93    /// <https://docs.dataforseo.com/v3/content_generation/check_grammar/languages/>
94    pub async fn check_grammar_languages(
95        &self,
96    ) -> DataForSeoApiResponse<ContentGenerationApiCheckGrammarLanguage> {
97        self.client
98            .http_get("/v3/content_generation/check_grammar/languages")
99            .await
100    }
101
102    /// Grammar and spelling rules used by the Check Grammar endpoint.
103    /// <https://docs.dataforseo.com/v3/content_generation/grammar_rules/>
104    pub async fn grammar_rules(&self) -> DataForSeoApiResponse<ContentGenerationApiGrammarRules> {
105        self.client
106            .http_post("/v3/content_generation/grammar_rules", &Vec::<Value>::new())
107            .await
108    }
109
110    /// Analyzes structure and readability of the input text.
111    /// <https://docs.dataforseo.com/v3/content_generation/text_summary/live/>
112    pub async fn text_summary(
113        &self,
114        data: Vec<ContentGenerationApiTextSummaryPost>,
115    ) -> DataForSeoApiResponse<ContentGenerationApiTextSummary> {
116        self.client
117            .http_post("/v3/content_generation/text_summary/live", &data)
118            .await
119    }
120
121    /// Languages supported by the Text Summary endpoint.
122    /// <https://docs.dataforseo.com/v3/content_generation/text_summary/languages/>
123    pub async fn text_summary_languages(
124        &self,
125    ) -> DataForSeoApiResponse<ContentGenerationApiTextSummaryLanguage> {
126        self.client
127            .http_get("/v3/content_generation/text_summary/languages")
128            .await
129    }
130}
131
132/// Request for `content_generation/generate/live`.
133#[derive(Debug, Default, Serialize, Deserialize, Clone)]
134pub struct ContentGenerationApiGeneratePost {
135    /// Initial text to continue (1–500 tokens).
136    pub text: String,
137    /// Maximum new tokens to generate (max 300); required unless `max_tokens`
138    /// is set.
139    #[serde(skip_serializing_if = "Option::is_none")]
140    pub max_new_tokens: Option<i64>,
141    /// Maximum total tokens including the input (max 1024); required unless
142    /// `max_new_tokens` is set.
143    #[serde(skip_serializing_if = "Option::is_none")]
144    pub max_tokens: Option<i64>,
145    /// Randomness of token selection, 0–1 (default 0.8); overrides
146    /// top_k/top_p/temperature.
147    #[serde(skip_serializing_if = "Option::is_none")]
148    pub creativity_index: Option<f64>,
149    /// Penalty limiting repeated tokens, 0.5–2 (default 1).
150    #[serde(skip_serializing_if = "Option::is_none")]
151    pub token_repetition_penalty: Option<f64>,
152    /// Number of top tokens shortlisted per step, 1–100 (default 40); ignored
153    /// when `creativity_index` is set.
154    #[serde(skip_serializing_if = "Option::is_none")]
155    pub top_k: Option<i64>,
156    /// Nucleus sampling probability cutoff, 0–1 (default 0.9); ignored when
157    /// `creativity_index` is set.
158    #[serde(skip_serializing_if = "Option::is_none")]
159    pub top_p: Option<f64>,
160    /// Output randomness, 0–1 (default 0.7); ignored when `creativity_index` is
161    /// set.
162    #[serde(skip_serializing_if = "Option::is_none")]
163    pub temperature: Option<f64>,
164    /// Up to 50 words or phrases to avoid anywhere in the output.
165    #[serde(skip_serializing_if = "Option::is_none")]
166    pub avoid_words: Option<Vec<String>>,
167    /// Up to 50 words or phrases to avoid at the start of the output.
168    #[serde(skip_serializing_if = "Option::is_none")]
169    pub avoid_starting_words: Option<Vec<String>>,
170    /// Up to 50 words or phrases that end generation.
171    #[serde(skip_serializing_if = "Option::is_none")]
172    pub stop_words: Option<Vec<String>>,
173    /// Token from a previous response to continue that generation.
174    #[serde(skip_serializing_if = "Option::is_none")]
175    pub supplement_token: Option<String>,
176    /// User-defined task identifier (max 255 characters).
177    #[serde(skip_serializing_if = "Option::is_none")]
178    pub tag: Option<String>,
179}
180
181impl ContentGenerationApiGeneratePost {
182    /// Creates a request that continues the given text.
183    pub fn new(text: &str) -> ContentGenerationApiGeneratePost {
184        ContentGenerationApiGeneratePost {
185            text: text.to_string(),
186            ..Default::default()
187        }
188    }
189}
190
191/// Request for `content_generation/generate_text/live`.
192#[derive(Debug, Default, Serialize, Deserialize, Clone)]
193pub struct ContentGenerationApiGenerateTextPost {
194    /// Main topic of the content (1–50 tokens).
195    pub topic: String,
196    /// Target number of words, 1–1000.
197    pub word_count: i64,
198    /// Up to 10 secondary topics to cover.
199    #[serde(skip_serializing_if = "Option::is_none")]
200    pub sub_topics: Option<Vec<String>>,
201    /// Meta description guiding the content (1–1000 tokens).
202    #[serde(skip_serializing_if = "Option::is_none")]
203    pub description: Option<String>,
204    /// Up to 10 keywords to weave into the content.
205    #[serde(skip_serializing_if = "Option::is_none")]
206    pub meta_keywords: Option<Vec<String>>,
207    /// Randomness of token selection, 0–1 (default 0.8).
208    #[serde(skip_serializing_if = "Option::is_none")]
209    pub creativity_index: Option<f64>,
210    /// Append a logical conclusion when true.
211    #[serde(skip_serializing_if = "Option::is_none")]
212    pub include_conclusion: Option<bool>,
213    /// Token from a previous response to continue that generation.
214    #[serde(skip_serializing_if = "Option::is_none")]
215    pub supplement_token: Option<String>,
216    /// User-defined task identifier (max 255 characters).
217    #[serde(skip_serializing_if = "Option::is_none")]
218    pub tag: Option<String>,
219}
220
221impl ContentGenerationApiGenerateTextPost {
222    /// Creates a request for the given topic and target word count.
223    pub fn new(topic: &str, word_count: i64) -> ContentGenerationApiGenerateTextPost {
224        ContentGenerationApiGenerateTextPost {
225            topic: topic.to_string(),
226            word_count,
227            ..Default::default()
228        }
229    }
230}
231
232/// Request for `content_generation/generate_meta_tags/live`.
233#[derive(Debug, Default, Serialize, Deserialize, Clone)]
234pub struct ContentGenerationApiGenerateMetaTagsPost {
235    /// Input text to generate meta tags for (1–500 tokens).
236    pub text: String,
237    /// Randomness of token selection, 0–1 (default 0.8).
238    #[serde(skip_serializing_if = "Option::is_none")]
239    pub creativity_index: Option<f64>,
240    /// User-defined task identifier (max 255 characters).
241    #[serde(skip_serializing_if = "Option::is_none")]
242    pub tag: Option<String>,
243}
244
245impl ContentGenerationApiGenerateMetaTagsPost {
246    /// Creates a request that generates meta tags for the given text.
247    pub fn new(text: &str) -> ContentGenerationApiGenerateMetaTagsPost {
248        ContentGenerationApiGenerateMetaTagsPost {
249            text: text.to_string(),
250            ..Default::default()
251        }
252    }
253}
254
255/// Request for `content_generation/generate_sub_topics/live`.
256#[derive(Debug, Default, Serialize, Deserialize, Clone)]
257pub struct ContentGenerationApiGenerateSubTopicsPost {
258    /// Main topic to generate subtopics for (1–50 tokens).
259    pub topic: String,
260    /// Randomness of token selection, 0–1 (default 0.8).
261    #[serde(skip_serializing_if = "Option::is_none")]
262    pub creativity_index: Option<f64>,
263    /// User-defined task identifier (max 255 characters).
264    #[serde(skip_serializing_if = "Option::is_none")]
265    pub tag: Option<String>,
266}
267
268impl ContentGenerationApiGenerateSubTopicsPost {
269    /// Creates a request that suggests subtopics for the given topic.
270    pub fn new(topic: &str) -> ContentGenerationApiGenerateSubTopicsPost {
271        ContentGenerationApiGenerateSubTopicsPost {
272            topic: topic.to_string(),
273            ..Default::default()
274        }
275    }
276}
277
278/// Request for `content_generation/paraphrase/live`.
279#[derive(Debug, Default, Serialize, Deserialize, Clone)]
280pub struct ContentGenerationApiParaphrasePost {
281    /// Text to paraphrase (1–500 tokens).
282    pub text: String,
283    /// Randomness of token selection, 0–1 (default 0.8).
284    #[serde(skip_serializing_if = "Option::is_none")]
285    pub creativity_index: Option<f64>,
286    /// User-defined task identifier (max 255 characters).
287    #[serde(skip_serializing_if = "Option::is_none")]
288    pub tag: Option<String>,
289}
290
291impl ContentGenerationApiParaphrasePost {
292    /// Creates a request that paraphrases the given text.
293    pub fn new(text: &str) -> ContentGenerationApiParaphrasePost {
294        ContentGenerationApiParaphrasePost {
295            text: text.to_string(),
296            ..Default::default()
297        }
298    }
299}
300
301/// Request for `content_generation/check_grammar/live`.
302///
303/// Set exactly one of `language_code` or `language_name`.
304#[derive(Debug, Default, Serialize, Deserialize, Clone)]
305pub struct ContentGenerationApiCheckGrammarPost {
306    /// Text to check (1–10,000 tokens).
307    pub text: String,
308    /// Language code of the text; required unless `language_name` is set.
309    #[serde(skip_serializing_if = "Option::is_none")]
310    pub language_code: Option<String>,
311    /// Language name of the text; required unless `language_code` is set.
312    #[serde(skip_serializing_if = "Option::is_none")]
313    pub language_name: Option<String>,
314    /// User-defined task identifier (max 255 characters).
315    #[serde(skip_serializing_if = "Option::is_none")]
316    pub tag: Option<String>,
317}
318
319impl ContentGenerationApiCheckGrammarPost {
320    /// Creates a request that checks the grammar of the given text.
321    pub fn new(text: &str) -> ContentGenerationApiCheckGrammarPost {
322        ContentGenerationApiCheckGrammarPost {
323            text: text.to_string(),
324            ..Default::default()
325        }
326    }
327}
328
329/// Request for `content_generation/text_summary/live`.
330///
331/// Set exactly one of `language_name` or `language_code`.
332#[derive(Debug, Default, Serialize, Deserialize, Clone)]
333pub struct ContentGenerationApiTextSummaryPost {
334    /// Text to analyze (1–10,000 tokens).
335    pub text: String,
336    /// Language name of the text; required unless `language_code` is set.
337    #[serde(skip_serializing_if = "Option::is_none")]
338    pub language_name: Option<String>,
339    /// Language code of the text; required unless `language_name` is set.
340    #[serde(skip_serializing_if = "Option::is_none")]
341    pub language_code: Option<String>,
342    /// Maximum elements in the keyword_density array (default 10).
343    #[serde(skip_serializing_if = "Option::is_none")]
344    pub internal_list_limit: Option<i32>,
345    /// User-defined task identifier (max 255 characters).
346    #[serde(skip_serializing_if = "Option::is_none")]
347    pub tag: Option<String>,
348}
349
350impl ContentGenerationApiTextSummaryPost {
351    /// Creates a request that summarizes the given text.
352    pub fn new(text: &str) -> ContentGenerationApiTextSummaryPost {
353        ContentGenerationApiTextSummaryPost {
354            text: text.to_string(),
355            ..Default::default()
356        }
357    }
358}