File size: 10,596 Bytes
4568847
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3b79c90
4568847
 
 
 
 
 
 
 
 
 
 
 
3b79c90
4568847
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3b79c90
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
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
import gradio as gr
import re
import random
import json
from dotenv import load_dotenv
import os
from openai import OpenAI

# 🔐 Load API Key from .env
load_dotenv()
api_key = os.getenv("OPENAI_API_KEY")
client = OpenAI(api_key=api_key)

# 1) Load your product catalog once at startup
def load_product_catalog(path="products.json"):
    with open(path, "r", encoding="utf-8") as f:
        data = json.load(f)
    # Expecting products_desc to be a dict: { "iboothme X": "…", … }
    return data["products_desc"]

PRODUCT_CATALOG = load_product_catalog()

# 2) Helper to pull full descriptions for a list of product names
def get_product_descriptions(product_names: list[str]) -> str:
    entries = []
    for name in product_names:
        desc = PRODUCT_CATALOG.get(name)
        if desc:
            entries.append(f"**{name}**\n{desc}")
    return "\n\n".join(entries)

# Keyword extraction from the paragraph
def extract_keywords(paragraph: str) -> list[str]:
    prompt = f"""
You are an expert in experiential event planning.

Extract 5-10 short, specific, and thematic keywords or concepts from the event description below. These will be used to inspire immersive, tech-powered event ideas.

Each keyword should be 2-4 words long and describe a concrete idea or theme (e.g., "photo booths", "smart vending", "interactive storytelling").

Event Description:
\"{paragraph}\"

Return the keywords as a comma-separated list.
"""
    response = client.chat.completions.create(
        model="gpt-4",
        messages=[{"role": "user", "content": prompt}],
        temperature=0.7,
        max_tokens=200
    )
    raw = response.choices[0].message.content
    return [kw.strip().lower() for kw in re.split(r'[,\n]', raw) if kw.strip()]

# (Optional) Keyword extraction from titles/links
def extract_keywords_from_title_and_link(title: str, link: str) -> list[str]:
    prompt = f"""
You are an expert in event innovation.

Given the title and link below, extract 3-5 short, specific, and meaningful keywords or themes (2-4 words each) that describe what the page is about.

Title: {title}
Link: {link}

Return the keywords as a comma-separated list.
"""
    response = client.chat.completions.create(
        model="gpt-4",
        messages=[{"role": "user", "content": prompt}],
        temperature=0.6,
        max_tokens=150
    )
    raw = response.choices[0].message.content
    return [kw.strip().lower() for kw in re.split(r'[,\n]', raw) if kw.strip()]

# (Optional) Web search for inspiration
def search_similar_events_and_products_openai(keywords: list[str]) -> list[tuple[str,str]]:
    input_text = f"Generate 10 useful URLs for experiential event ideas or iboothme.com inspiration related to the keywords: {', '.join(keywords)}"
    try:
        response = client.responses.create(
            model="gpt-4.1",
            tools=[{"type": "web_search_preview"}],
            input=input_text
        )
        content = response.output_text
        results = []
        for line in content.split("\n"):
            if "http" in line:
                parts = line.split(" - ", 1)
                if len(parts) == 2:
                    results.append((parts[0].strip(), parts[1].strip()))
                else:
                    url = line.strip()
                    results.append((url, url))
        return results[:10]
    except Exception as e:
        print("Search failed:", e)
        return []

# Core idea generation, enriched with random product descriptions
def generate_event_ideas(
    paragraph: str,
    product_info: str,
    search_links: list[tuple[str,str]],
    all_keywords: list[str],
    idea_count: int
) -> str:
    search_summary = "\n".join([f"- {title}: {url}" for title, url in search_links])
    include_games = any("game" in kw for kw in all_keywords)
    game_instruction = "Include at least two game-related ideas (e.g., quiz game, vending challenge)." if include_games else ""

    prompt = f"""
You are an expert event strategist for iboothme, a company offering creative experiences like AI photo booths, smart vending machines, audio booths, personalization stations, and immersive visual storytelling.

Below are full descriptions of three randomly selected iboothme products, to keep all ideas on-brand:
{product_info}

Based on the event description below, generate {idea_count} unique and diverse iboothme-powered event ideas.
Make sure that the syntax of the brand is always "iboothme" (all lowercase).

**Event Description:**
{paragraph}

**Inspiration from Related Ideas:**
{search_summary}

💡 **Your Task:**
Create ideas that are immersive, memorable, and creatively use iboothme's photo, video, and audio-based technologies. Do not use AR, VR, projection mapping, or other tech-heavy elements.

You must include:
- At least two game-related ideas
- Studio Ghibli-inspired visuals in one idea
- Personalized giveaways (e.g., custom t-shirts, stickers, Labibu dolls)
{game_instruction}

❗ Important:
- Avoid AR, VR, holograms, or projection domes
- Do not repeat photo‑booth formats
- Every idea should have a creative title
- Each idea should be described in a paragraph
- Immediately after, write a second paragraph describing the user journey flow

Return **only** the final ideas in markdown format.
"""
    resp = client.chat.completions.create(
        model="gpt-4",
        messages=[{"role": "user", "content": prompt}],
        temperature=0.95,
        max_tokens=1500
    )
    return resp.choices[0].message.content

# Main orchestration
def main_workflow(paragraph: str) -> str:
    print("main_workflow called with paragraph:", paragraph)
    if not paragraph.strip():
        print("No paragraph provided.")
        return "❌ Please enter an event description."

    # 1. Randomly pick 3 products from your catalog
    try:
        gadget_names = random.sample(list(PRODUCT_CATALOG.keys()), k=4)
        print("Randomly selected products:", gadget_names)
        product_info = get_product_descriptions(gadget_names)
    except Exception as e:
        print("Error selecting products:", e)
        return f"❌ Error selecting products: {e}"

    # 2. Gather keywords + optional web search
    try:
        base_kw = extract_keywords(paragraph)
        print("Extracted base keywords:", base_kw)
        links = search_similar_events_and_products_openai(base_kw)
        print("Found links:", links)
        link_kw = []
        for t, u in links:
            kws = extract_keywords_from_title_and_link(t, u)
            print(f"Extracted keywords from link ({t}, {u}):", kws)
            link_kw.extend(kws)
        all_kw = sorted(set(base_kw + link_kw))
        print("All keywords:", all_kw)
    except Exception as e:
        print("Error in keyword extraction or web search:", e)
        return f"❌ Error in keyword extraction or web search: {e}"

    # 3. Generate ideas
    try:
        idea_count = random.choice([5,6,7,8])
        print("Idea count:", idea_count)
        ideas_md = generate_event_ideas(paragraph, product_info, links, all_kw, idea_count)
        print("Generated ideas markdown.")
    except Exception as e:
        print("Error generating ideas:", e)
        return f"❌ Error generating ideas: {e}"

    # 4. Summarize top keywords
    summaries = []
    for kw in all_kw[:10]:
        try:
            print(f"Summarizing keyword: {kw}")
            r = client.chat.completions.create(
                model="gpt-4",
                messages=[{"role": "user", "content": f"Give a short one-line event idea description using the keyword: {kw}"}],
                temperature=0.6,
                max_tokens=60
            )
            desc = r.choices[0].message.content.strip()
            summaries.append(f"- **{kw.title()}**: {desc}")
        except Exception as e:
            print(f"Error summarizing keyword {kw}:", e)
            summaries.append(f"- **{kw.title()}**")

    summary_md = "\n".join(summaries)
    print("Returning final markdown output.")
    return f"""
🌐 **Relevant Keywords Summary:**  
{summary_md}

{ideas_md}
"""
# 8) Styling and Gradio interface
custom_theme = gr.themes.Base(
    primary_hue="purple",
    secondary_hue="purple",
    neutral_hue="gray"
).set(
    body_background_fill="white",
    block_background_fill="white",
    block_border_width="2px",
    block_border_color="#a18cd1",
    button_primary_background_fill="linear-gradient(90deg, #a18cd1 0%, #fbc2eb 100%)",
    button_primary_text_color="white",
    input_background_fill="white",
    input_border_color="#a18cd1"
)

custom_css = """
#iboothme-heading {
    font-weight: 900 !important;
    font-size: 2.5rem !important;
    background: linear-gradient(90deg, #a18cd1 0%, #fbc2eb 100%);
    -webkit-background-clip: text;
    -webkit-text-fill-color: black;
    margin-bottom: 0.5em;
    text-align: center;
    letter-spacing: 1px;
}
#desc-subheading {
    text-align: center;
    font-size: 1.15rem;
    font-weight: 500;
    color: #6d4fa7;
    margin-bottom: 2em;
}
.gradio-container { min-height: 100vh; background: white !important; }
.gr-box, .gr-input, .gr-button, .gr-markdown, .gr-textbox, .gr-column, .gr-row {
    border-radius: 18px !important;
}
#event-desc-box, #output-box {
    border: 2px solid #a18cd1 !important;
    box-shadow: 0 4px 24px 0 rgba(161,140,209,0.10) !important;
    background: white !important;
}
#generate-btn {
    font-weight: bold;
    font-size: 1.1rem;
    background: linear-gradient(90deg, #a18cd1 0%, #fbc2eb 100%) !important;
    color: white !important;
    border-radius: 12px !important;
    box-shadow: 0 2px 8px 0 rgba(161,140,209,0.10) !important;
    margin-top: 1.5em;
}
"""

with gr.Blocks(theme=custom_theme, css=custom_css, title="iboothme Event Ideation App") as demo:
    gr.Markdown(
        "<div id='iboothme-heading'>🎉 <b>iboothme Event Idea Generator</b></div>"
        "<div id='desc-subheading'>Describe your event goal and receive interactive, tech‑powered ideas!</div>"
    )
    with gr.Row():
        with gr.Column(scale=2):
            paragraph = gr.Textbox(
                label="📝 Describe Your Event (e.g. Women’s Day, Product Launch)",
                lines=4,
                elem_id="event-desc-box"
            )
        with gr.Column(scale=1, min_width=220):
            submit_btn = gr.Button("🚀 Generate Event Concepts", elem_id="generate-btn")
    output = gr.Markdown(elem_id="output-box")

    submit_btn.click(
        fn=main_workflow,
        inputs=[paragraph],
        outputs=output,
        show_progress=True
    )

demo.launch(inline=False, share=True)