jaothan commited on
Commit
bf05dd2
·
verified ·
1 Parent(s): bf4d1dd

Upload 4 files

Browse files
Files changed (4) hide show
  1. Dockerfile +29 -0
  2. app.py +73 -0
  3. requirements.txt +5 -0
  4. utils.py +180 -0
Dockerfile ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use an official Python runtime as a parent image
2
+ FROM python:3.9.13
3
+
4
+ # Create a new user with a specific UID and home directory
5
+ RUN useradd -m -u 1000 user
6
+
7
+ # Set the user for subsequent instructions
8
+ USER user
9
+
10
+ # Update the PATH environment variable
11
+ ENV PATH="/home/user/.local/bin:$PATH"
12
+
13
+ # Set the working directory
14
+ WORKDIR /app
15
+
16
+ # Copy the requirements file into the container
17
+ COPY --chown=user ./requirements.txt requirements.txt
18
+
19
+ # Install any needed packages specified in requirements.txt
20
+ RUN pip install --no-cache-dir --upgrade -r requirements.txt
21
+
22
+ # Copy the current directory contents into the container at /app
23
+ COPY --chown=user . /app
24
+
25
+ # Make sure uvicorn is installed and available in the PATH
26
+ RUN pip install --user uvicorn
27
+
28
+ # Command to run the application using Uvicorn
29
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
app.py ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, HTTPException, Request
2
+ from fastapi.responses import JSONResponse
3
+ from pydantic import BaseModel
4
+ from typing import Optional
5
+ import logging
6
+ from utils import *
7
+
8
+ app = FastAPI()
9
+ logging.basicConfig(level=logging.INFO)
10
+ logger = logging.getLogger(__name__)
11
+ # Define the request model
12
+ class ArticleRequesteng(BaseModel):
13
+ article_title: str
14
+ main_keyword: str
15
+ target_tone: str
16
+ optional_text: str = None
17
+ # Define the request model
18
+ class ArticleRequest(BaseModel):
19
+ titre_article: str
20
+ mot_cle_principal: str
21
+ ton_cible: str
22
+ optional_text : str = None
23
+
24
+ # Define the response model
25
+ class ArticleResponse(BaseModel):
26
+ article: str
27
+
28
+ @app.post("/generate_article_fr", response_model=ArticleResponse)
29
+ async def generate_article(request: ArticleRequest):
30
+ """
31
+ Endpoint to generate a French SEO article.
32
+ Parameters:
33
+ - titre_article: str - The title of the article.
34
+ - mot_cle_principal: str - The main keyword for the article.
35
+ - ton_cible: str - The target tone of the article.
36
+ - optional_text: str - Optional text to include in the article.
37
+ """
38
+ try:
39
+ article = create_pipeline_fr(request.titre_article, request.mot_cle_principal, request.ton_cible,request.optional_text)
40
+ return ArticleResponse(article=article)
41
+ except Exception as e:
42
+ raise HTTPException(status_code=500, detail=str(e))
43
+
44
+ @app.post("/generate_article_eng", response_model=ArticleResponse)
45
+ async def generate_article_eng(request: ArticleRequesteng):
46
+ """
47
+ Endpoint to generate an SEO article.
48
+ Parameters:
49
+ - article_title: str - The title of the article.
50
+ - main_keyword: str - The main keyword for the article.
51
+ - target_tone: str - The target tone of the article.
52
+ - optional_text: str - Optional text to include in the article.
53
+ """
54
+ try:
55
+ # Basic validation of the input
56
+ if not request.article_title or not request.main_keyword:
57
+ raise HTTPException(status_code=400, detail="Title and main keyword are required")
58
+
59
+ article = create_pipeline(request.article_title, request.main_keyword, request.target_tone,request.optional_text)
60
+
61
+ # Ensure the response is not empty
62
+ if not article:
63
+ raise HTTPException(status_code=204, detail="Generated article is empty")
64
+
65
+ return ArticleResponse(article=article)
66
+
67
+ except HTTPException as http_exc:
68
+ logger.error(f"HTTP Exception: {http_exc.detail}")
69
+ raise http_exc
70
+ except Exception as e:
71
+ logger.error(f"Unhandled Exception: {str(e)}")
72
+ raise HTTPException(status_code=500, detail="An internal server error occurred")
73
+
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ fastapi
2
+ pydantic
3
+ streamlit
4
+ openai
5
+ google-generativeai
utils.py ADDED
@@ -0,0 +1,180 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import google.generativeai as genai
2
+ import os
3
+
4
+ genai.configure(api_key=os.getenv("gemini_token"))
5
+
6
+ def call_ai_api(prompt):
7
+ # Set up the model
8
+ generation_config = {
9
+ "temperature": 1,
10
+ "top_p": 0.95,
11
+ "max_output_tokens": 5000000,
12
+ }
13
+ model = genai.GenerativeModel(model_name="gemini-1.5-pro-latest",
14
+ generation_config=generation_config)
15
+ response = model.generate_content(prompt)
16
+ return response.text
17
+
18
+
19
+ def generer_prompt_seo(titre_article, mot_cle_principal, ton_cible, mots_cles_associes,optional_text):
20
+ mots_cles_lexicaux = mots_cles_associes
21
+ if optional_text :
22
+ p=f"Données optionnel sur l'article : {optional_text}"
23
+ else:
24
+ p=""
25
+ prompt = f"""
26
+ CONTEXTE:
27
+ Veuillez écrire un article de 1500 - 2000 mots. N'hésitez pas à prendre votre temps pour réfléchir à votre réponse j'ai besoin d'un long article.
28
+ Vous êtes un rédacteur SEO chargé de composer un article de blog optimisé pour le SEO sur le sujet suivant.
29
+ Voici les informations et directives à suivre :
30
+
31
+ Titre de l'article : {titre_article}
32
+ Mot-clé principal : {mot_cle_principal}
33
+ Ton et/ou public cible : {ton_cible}
34
+ Mots-clés lexicaux à inclure : {mots_cles_lexicaux}{p}
35
+
36
+ INSTRUCTIONS:
37
+ NOMBRE DE MOTS : 1000 à 1500
38
+ ### Règles de rédaction :
39
+ N'hésitez pas à prendre votre temps pour réfléchir à votre réponse j'ai besoin d'un long article.
40
+ 1. Structure de l'article avec des titres hiérarchisés.
41
+ 2. Optimisation du mot-clé principal (densité d'environ 1,5%, utilisation dans le titre SEO, méta description, et répartition uniforme).
42
+ 3. Inclusion de sous-titres et de mots-clés LSI pour enrichir le contenu sans bourrage de mots-clés.
43
+ 4. Titres et méta descriptions attractifs avec appels à l'action.
44
+ 5. Ton informatif et engageant, avec une variété de vocabulaire.
45
+ 6. Introduction et conclusion engageantes avec le mot-clé principal.
46
+ 7. Section FAQ avec trois questions/réponses courtes.
47
+ 8. Au moins un lien externe vers une source crédible.
48
+ N'hésitez pas à prendre votre temps pour réfléchir à votre réponse j'ai besoin d'un long article.
49
+ Assurez que l'article soit lisible, bien structuré et visuellement attrayant.
50
+ """
51
+ return prompt
52
+ def generate_seo_prompt(article_title, main_keyword, target_tone, associated_keywords,optional_text):
53
+ lexical_keywords = associated_keywords
54
+ if optional_text:
55
+ p = f"Données optionnel sur l'article : {optional_text}"
56
+ else:
57
+ p = ""
58
+ prompt = f"""
59
+ CONTEXT:
60
+ Please write an article of 1500 - 2000 words. Feel free to take your time to think about your response, I need a long article.
61
+ You are an SEO writer tasked with composing an SEO-optimized blog article on the following topic.
62
+ Here are the information and guidelines to follow:
63
+
64
+ Article title: {article_title}
65
+ Main keyword: {main_keyword}
66
+ Target tone and/or audience: {target_tone}
67
+ Lexical keywords to include: {lexical_keywords}{p}
68
+
69
+ INSTRUCTIONS:
70
+ WORD COUNT: 1000 to 1500
71
+ ### Writing rules:
72
+ Feel free to take your time to think about your response, I need a long article.
73
+ 1. Structure the article with hierarchical headings.
74
+ 2. Optimize the main keyword (density of about 1.5%, use in the SEO title, meta description, and evenly distributed).
75
+ 3. Include subheadings and LSI keywords to enrich the content without keyword stuffing.
76
+ 4. Attractive titles and meta descriptions with calls to action.
77
+ 5. Informative and engaging tone, with a variety of vocabulary.
78
+ 6. Engaging introduction and conclusion with the main keyword.
79
+ 7. FAQ section with three short questions/answers.
80
+ 8. At least one external link to a credible source.
81
+ Feel free to take your time to think about your response, I need a long article.
82
+ Ensure that the article is readable, well-structured, and visually appealing.
83
+ """
84
+ return prompt
85
+
86
+
87
+ def create_pipeline_fr(titre_article, mot_cle_principal, ton_cible, optional_text):
88
+ # Initial AI API call
89
+ mots_cles_champ_lexical=generer_mots(titre_article,mot_cle_principal)
90
+ pp=generer_prompt_seo(titre_article, mot_cle_principal, ton_cible, mots_cles_champ_lexical,optional_text)
91
+ rep = call_ai_api(pp)
92
+ # Second AI API call with additional elaboration request
93
+ prompt2 = f"D'après le prompt {pp}, j'ai eu le résultat suivant : {rep}. Élaborer plus que ça."
94
+ rep2 = call_ai_api(prompt2)
95
+
96
+ # Third AI API call with further instructions
97
+ prompt3 = (f"D'après le prompt {pp}, j'ai eu le résultat suivant : {rep}. Élaborer plus que ça. {rep2} "
98
+ "Le texte est toujours beaucoup trop court. Aussi, il n'y a aucune gestion des titres, le premier est un H2, "
99
+ "et les sous-titres sont balisés comme des paragraphes. Concernant le lien tout à la fin, il faudrait qu'il soit intégré au texte. "
100
+ "Dernier point, la meta description ne doit pas apparaître quand on demande un article.")
101
+ rep3 = call_ai_api(prompt3)
102
+
103
+ # Fourth AI API call to fix title issues and meta description
104
+ prompt4 = ("Fix ça : Mauvaise gestion des titres, le premier titre doit être un H1. Le mot-clé principal n'est pas assez utilisé, il faut une densité de 1,5%. "
105
+ "Le titre ne doit contenir une majuscule que sur le premier mot de la phrase, pas sur les autres. "
106
+ "La meta description ne doit pas être rédigée. " + rep3)
107
+ rep4 = call_ai_api(prompt4)
108
+
109
+ # Fifth AI API call to fix keyword density and internal link
110
+ prompt5 = (f"Fix ça - Le mot-clé principal : {mot_cle_principal} n'est pas assez utilisé, il faut une densité de 1,5% environ. "
111
+ "Ajoute un lien à l'intérieur d'un texte, et rends le FAQ après la conclusion. et n'ajoute pas de remarque a la fin je veux que dans la sortie que du texte " + rep4)
112
+ rep5 = call_ai_api(prompt5)
113
+
114
+ # Sixth AI API call to ensure the text length
115
+ prompt6 = ("Trop court, seulement j'aurai besoin de 1500 mots minimum attendu. "
116
+ "Laisse la même structure de texte, ajoute juste du contenu. " + rep5)
117
+ rep6 = call_ai_api(prompt6)
118
+
119
+ prompt7= ("La seule chose qu'il faudrait corriger."
120
+ "c'est la mise en gras utiliser le format HTML avec <strong> des mots-clés LSI/mots-clés associés et/ou mots importants du texte. LAISSE LE MEME TEXT " + rep6)
121
+ rep7= call_ai_api(prompt7)
122
+ print("Prompt 7\n", rep7)
123
+
124
+ # # Eighth AI API call to ensure HTML formatting and specific content rules
125
+ # prompt8 = (f"Pour la mise en gras, utiliser le format HTML avec <strong>. "
126
+ # "Certaines réponses ont du texte en plus de l’article, il ne faut que l’article en réponse, aucun autre texte avant ou après. "
127
+ # "Assure-toi que {titre_article} est le titre principal et qu'il ne s'est pas changé. "
128
+ # "LAISSE LE MEME TEXTE. " + rep7)
129
+ # rep8 = call_ai_api(prompt8)
130
+ # print("Prompt 8\n",rep8)
131
+
132
+ return rep7
133
+
134
+
135
+ def create_pipeline(article_title, main_keyword, target_tone,optional_text):
136
+ # Initial AI API call
137
+ lexical_field_keywords=generate_words(article_title, main_keyword)
138
+ pp = generate_seo_prompt(article_title, main_keyword, target_tone, lexical_field_keywords,optional_text)
139
+
140
+ rep = call_ai_api(pp)
141
+
142
+ # Second AI API call with additional elaboration request
143
+ prompt2 = f"Based on the prompt {pp}, I got the following result: {rep}. Elaborate further."
144
+ rep2 = call_ai_api(prompt2)
145
+
146
+ # Third AI API call with further instructions
147
+ prompt3 = (f"Based on the prompt {pp}, I got the following result: {rep}. Elaborate further. {rep2} "
148
+ "The text is still way too short. Also, there is no title management, the first title is an H2, "
149
+ "and the subtitles are marked as paragraphs. Regarding the link at the end, it should be integrated into the text. "
150
+ "Lastly, the meta description should not appear when requesting an article.")
151
+ rep3 = call_ai_api(prompt3)
152
+
153
+ # Fourth AI API call to fix title issues and meta description
154
+ prompt4 = ("Fix this: Poor title management, the first title must be an H1. The main keyword is not used enough, it should have a density of 1.5%. "
155
+ "The title should only have a capital letter on the first word of the sentence, not on the others. "
156
+ "The meta description should not be written. " + rep3)
157
+ rep4 = call_ai_api(prompt4)
158
+
159
+ # Fifth AI API call to fix keyword density and internal link
160
+ prompt5 = (f"Fix this - The main keyword: {main_keyword} is not used enough, it should have a density of about 1.5%. "
161
+ "Add a link inside the text, and place the FAQ after the conclusion. " + rep4)
162
+ rep5 = call_ai_api(prompt5)
163
+
164
+ # Sixth AI API call to ensure the text length
165
+ prompt6 = ("Too short, I need a minimum of 1500 words expected. "
166
+ "Keep the same text structure, just add more content. " + rep5)
167
+ rep6 = call_ai_api(prompt6)
168
+
169
+ prompt7 = ("The only thing that needs to be corrected is the use of bold formatting. Use HTML format with <strong> for LSI keywords/associated keywords and/or important words from the text. KEEP THE SAME TEXT " + rep6)
170
+ rep7 = call_ai_api(prompt7)
171
+
172
+ return rep7
173
+
174
+ def generer_mots(titre_article,mot_cle_principal):
175
+ words=call_ai_api("Generes moi des mots-clés similaires a partir de ca ( SEULEMENT DES MOTS OU GROUPE DE MOTS séparés par virgules ) :"+titre_article+" et "+mot_cle_principal)
176
+ return words
177
+
178
+ def generate_words(article_title, main_keyword):
179
+ words = call_ai_api("Generate similar keywords from these (ONLY WORDS OR GROUPS OF WORDS separated by commas): " + article_title + " and " + main_keyword)
180
+ return words