File size: 8,280 Bytes
54fa6eb
 
 
 
 
 
 
 
 
753136a
54fa6eb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f8680f5
 
 
 
 
 
 
54fa6eb
f775c23
54fa6eb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4eeb29b
 
54fa6eb
 
 
 
 
 
 
 
 
 
 
 
 
4eeb29b
54fa6eb
 
 
 
 
4eeb29b
 
 
54fa6eb
 
 
 
 
 
 
 
 
 
 
 
4eeb29b
54fa6eb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9cbaaef
 
 
54fa6eb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dd7f1ed
54fa6eb
dd7f1ed
54fa6eb
 
 
d4b225d
54fa6eb
 
4eeb29b
 
 
38696a1
4eeb29b
 
 
dd7f1ed
54fa6eb
 
 
 
 
 
4eeb29b
 
dd7f1ed
38696a1
7b3db3e
4752182
 
 
 
4eeb29b
 
 
54fa6eb
 
 
 
 
 
 
 
 
 
 
 
 
d87742b
 
54fa6eb
 
 
 
 
 
 
 
 
 
 
4eeb29b
 
 
54fa6eb
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
import gradio as gr
from src.utils import LLMHandler, initialize_newsletter, integrate_personalized_text, build_context, build_prompt
from src.utils_api import get_recommendations 
import yaml
import logging
import argparse
import os
import tempfile

# aggiungo commmento Bernardino per prova push
# logging.basicConfig(filename='logs/app.log', encoding='utf-8', level=logging.info)
logging.basicConfig(level=logging.INFO)


def main():

    # get arguments with argparse
    parser = argparse.ArgumentParser(description='Newsletter Generator')
    parser.add_argument('--config-file', type=str, default='./config/config.yaml', help='Path to the configuration file.')
    args = parser.parse_args()

    logging.info("Starting the Newsletter Generator app...")

    # Load configuration from YAML file
    logging.info("Loading configuration from config.yaml...")
    with open(args.config_file, "r") as file:
        config = yaml.safe_load(file)

        # setup
        #try:
        #    os.environ["RECOMMENDER_URL"] = config['recommender_api']['base_url']
        #    os.environ["RECOMMENDER_KEY"] = config['recommender_api']['key']
        #    os.environ["OPENAI_KEY"] = config['llm']['api_key']
        #except:
        #    pass

        llm_settings = config['llm']
        config['llm']['api_key'] = os.environ["OPENAI_KEY"]
        newsletter_meta_info = config['newsletter']
        
        logging.debug(f"Configuration loaded: {config}")

    # Initialize the LLM handler
    llm_handler = LLMHandler(**llm_settings)
    logging.info(f"LLM handler initialized with the following settings: {config['llm']}")


    # Define the function to generate the newsletter using the OpenAI API
    def generate_newsletter(
            customer_id,  
            model_name,
            temperature,
            max_tokens,
            system_message, 
            textual_preferences,
            few_shot=None,
            custom_template=None,
            progress=gr.Progress()
            ):


        # get recommendations
        progress(0.1, "Fetching Client History...")
        logging.info("Getting recommendations...")
        customer_info, recommendations, transactions = get_recommendations(
            customer_id,
            max_recs=newsletter_meta_info['max_recommendations'], 
            max_transactions=newsletter_meta_info['max_recents_items']) 
        logging.debug(f"Recommendations: {recommendations}")
        logging.debug(f"Transactions: {transactions}")
        print("customer info", customer_info)


        # Load the html template and replace the placeholders for images with the actual content
        logging.info("Initializing newsletter template...")
        progress(0.5, "Initializing personalized content...")
        # override the default template if a custom one is provided
        if custom_template:
            newsletter_meta_info['newsletter_example_path'] = custom_template
        newsletter_text = initialize_newsletter(newsletter_meta_info, transactions, recommendations)

        # Build context from the user preferences, the recommendations and the transactions
        context = build_context(
            recommendations, 
            transactions, 
            textual_preferences, 
            customer_info)
        logging.info(f"Context: {context}")

        # Build the prompt for the LLM
        progress(0.7, "Generating personalized content...")
        prompt = build_prompt(context, few_shot)
        logging.info(f"Prompt: {prompt}")
        

        # Generate the newsletter
        sections = llm_handler.generate( 
                        prompt, 
                        model_name, 
                        temperature, 
                        max_tokens, 
                        system_message)
        logging.info(f"Sections: {sections}")


        # Intergrate personalized text
        logging.info("Integrating personalized text...")
        newsletter_text = integrate_personalized_text(newsletter_text, customer_info, sections)

        # Save HTML to a temporary file for download
        with tempfile.NamedTemporaryFile(delete=False, suffix=".html") as temp_file:
            temp_file.write(newsletter_text.encode("utf-8"))
            temp_file_path = temp_file.name
        progress(1.0)
        return newsletter_text, temp_file_path

    logging.info("Creating interface...")

    with gr.Blocks() as demo:
        # Header Section
        gr.Markdown("## AI-Powered Newsletter for Fashion Brands", elem_id="header")
        
        # Input Section
        with gr.Row():
            customer_id = gr.Dropdown(
                label="Customer ID", 
                #value="04a183a27a6877e560e1025216d0a3b40d88668c68366da17edfb18ed89c574c", 
                interactive=True,
                choices=[
                    ("User Story 1", "04a183a27a6877e560e1025216d0a3b40d88668c68366da17edfb18ed89c574c"),
                    ("User Story 2", "1abaca5cd299000720538c70ba2ed246db6731bce924b5b4ca81770a47842656"),
                    ("User Story 3", "1741b0d1b2c29994084b7312001c1b11ab8b112b3fd05ac765f4d232afdc4eaf")
                ]
            )
        
        with gr.Row():
            textual_preferences = gr.Textbox(
                label="Newsletter Preferences", 
                placeholder="Enter rich newsletter preferences."
            )
        
        # Advanced Settings
        with gr.Accordion("⚙️ Advanced Settings", open=False):
            with gr.Row():
                model_name = gr.Dropdown(
                    label="LLM Model", 
                    choices=["gpt-3.5-turbo", "gpt-4o"], 
                    value=llm_handler.model_name
                )
                temperature = gr.Slider(
                    label="Temperature", 
                    minimum=0.0, 
                    maximum=1.0, 
                    step=0.05, 
                    value=llm_handler.default_temperature
                )

            with gr.Row():

                max_tokens = gr.Number(
                    label="Max Tokens", 
                    value=llm_handler.default_max_tokens, 
                    scale=1,
                    precision=0
                )

                custom_template = gr.File(
                    label="Custom Template", 
                    scale=1,
                    visible=True)

            with gr.Row():

                system_message = gr.Textbox(
                    label="System Message", 
                    placeholder="Enter a custom system message (optional).", 
                    value=llm_handler.default_system_message,
                    visible=False
                )
                
                few_shot = gr.Textbox(
                    label="Few-Shot Examples", 
                    placeholder=config.get("default_few_shot", ""), 
                    value=config.get("default_few_shot", ""),
                    visible=True,
                    lines=20,
                    max_lines=100
                    )
                
                

        
        # User Context (Hidden by Default)
        with gr.Accordion("🧑‍💻 User Context", open=False, visible=False):
            pass  # Placeholder for future user context integration.
        
        # Output Section
        with gr.Row():
            generate_button = gr.Button("Generate Personalized Newsletter", variant="primary")
            download = gr.DownloadButton("Download")
        
        newsletter_output = gr.HTML(
            label="Generated Newsletter", 
            value="<br><br><br><br><br>", 
            min_height=500,
            render=True
        )
        
        # Event Binding
        generate_button.click(
            fn=generate_newsletter, 
            inputs=[
                customer_id,
                model_name,
                temperature,
                max_tokens,
                system_message,
                textual_preferences,
                few_shot,
                custom_template
            ], 
            outputs=[newsletter_output, download]
        )

    # Launch App
    demo.queue().launch(
        share=config['app']['share'], 
        server_port=config['app']['server_port']
    )


if __name__ == "__main__":
    main()