Munazz commited on
Commit
366d698
·
1 Parent(s): ebf03db

Initial push of StyleSavvy AI stylist app

Browse files
.gitignore ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ __pycache__/
2
+ .env
3
+ venv/
4
+ *.pyc
5
+ .DS_Store
app.py ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from utils.detector import detect_clothing
3
+ from utils.advisor import get_advice
4
+
5
+ def run_style_savvy(image, bg_remove, body_type, face_shape, gender, occasion):
6
+ items = detect_clothing(image, do_bg_remove=bg_remove)
7
+ advice_list = get_advice(items, body_type, face_shape, gender, occasion)
8
+
9
+ unique_advice = []
10
+ seen = set()
11
+ for tip in advice_list:
12
+ if tip not in seen:
13
+ unique_advice.append(tip)
14
+ seen.add(tip)
15
+
16
+ html = """
17
+ <div style="
18
+ background-color: #1e1e1e;
19
+ color: #f5f5f5;
20
+ padding: 24px;
21
+ border-radius: 16px;
22
+ max-width: 640px;
23
+ margin: auto;
24
+ font-family: 'Segoe UI', sans-serif;
25
+ ">
26
+ <h2 style="
27
+ margin-top: 0;
28
+ font-size: 2em;
29
+ color: #ff8c00;
30
+ text-align: center;
31
+ text-transform: uppercase;
32
+ ">
33
+ ✨ Your Personalized Style Tips ✨
34
+ </h2>
35
+ <ol style="
36
+ padding-left: 20px;
37
+ font-size: 1.2em;
38
+ line-height: 1.8;
39
+ ">
40
+ """
41
+ for advice in unique_advice:
42
+ html += f"<li style='margin-bottom: 12px;'>{advice}</li>"
43
+ html += "</ol></div>"
44
+
45
+ return html
46
+
47
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
48
+ gr.Markdown("## 👗 StyleSavvy — AI Fashion Consultant")
49
+ gr.Markdown("Upload your photo and get personalized fashion advice tailored to your features and occasion.")
50
+
51
+ with gr.Row():
52
+ with gr.Column(scale=1):
53
+ with gr.Group():
54
+ gr.Markdown("### 🧾 Style Details")
55
+ bg_remove = gr.Checkbox(label="Remove Background")
56
+ body_type = gr.Radio(["Slim", "Athletic", "Curvy", "Plus-size"], label="Body Type")
57
+ face_shape = gr.Radio(["Oval", "Round", "Square", "Heart"], label="Face Shape")
58
+ gender = gr.Radio(["Male", "Female"], label="Gender")
59
+ occasion = gr.Textbox(label="Occasion", placeholder="e.g. Wedding, Office Party")
60
+
61
+ with gr.Column(scale=1):
62
+ with gr.Group():
63
+ gr.Markdown("### 📸 Upload Your Look")
64
+ image = gr.Image(type="pil", label="Upload Photo")
65
+
66
+ submit_btn = gr.Button("✨ Generate Style Tips")
67
+ output = gr.HTML()
68
+
69
+ submit_btn.click(
70
+ fn=run_style_savvy,
71
+ inputs=[image, bg_remove, body_type, face_shape, gender, occasion],
72
+ outputs=output
73
+ )
74
+
75
+ if __name__ == "__main__":
76
+ demo.launch()
models/llm.py ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ from transformers import pipeline
3
+ from typing import List
4
+
5
+ PROMPTS = {
6
+ "category_expansion": (
7
+ "As a top-tier fashion advisor, craft one impactful styling suggestion for a {gender} individual with a {body_type} body "
8
+ "and {face_shape} face attending the {occasion}. They have on {items}. "
9
+ "Highlight a strategic enhancement in silhouette, color scheme, accessory choice, or footwear to elevate their look."
10
+ ),
11
+ "event_aesthetic": (
12
+ "Imagine you are curating an immersive style experience for a {gender} attendee with a {body_type} silhouette and {face_shape} face at the {occasion}. "
13
+ "They’re currently wearing {items}. Provide one highly descriptive recommendation that harmonizes fabric textures, color temperature, silhouette, and accessory accents with the event’s specific ambiance, lighting conditions, and seasonal atmosphere."
14
+ ),
15
+ "fashion_editor": (
16
+ "You are the Editor-in-Chief of a prestigious fashion publication. Advise a {gender} trendsetter with a {body_type} frame and {face_shape} face attending the {occasion}, "
17
+ "currently in {items}. Offer one magazine-cover-worthy styling tip—highlight a trending color palette, editorial-worthy silhouette, and innovative accessory placement that will resonate with a discerning audience."
18
+ ),
19
+ "influencer_style": (
20
+ "As a cutting-edge style influencer with millions of followers, recommend one eye-catching flair tip for a {gender} follower with a {body_type} physique and {face_shape} face, "
21
+ "heading to the {occasion} in {items}. Frame it as a social-media-caption-ready moment: mention a statement accessory, bold color pop, or texture twist that will go viral."
22
+ ),
23
+ "seasonal_trend": (
24
+ "As a seasonal style expert specializing in spring/summer trends, guide a {gender} individual with a {body_type} shape and {face_shape} face preparing for the {occasion}. "
25
+ "They currently wear {items}. Provide one tip incorporating current seasonal motifs—think floral prints, breathable linens, or eco-friendly fabrics—that elevates their ensemble."
26
+ ),
27
+ }
28
+
29
+ class StyleSavvy:
30
+ def __init__(
31
+ self,
32
+ model_name: str = "google/flan-t5-large",
33
+ device: int = -1, # -1 = CPU, or GPU index
34
+ max_length: int = 150,
35
+ ):
36
+ # A local instruction-tuned T5 model
37
+ self.pipe = pipeline(
38
+ "text2text-generation",
39
+ model=model_name,
40
+ tokenizer=model_name,
41
+ device=device,
42
+ )
43
+ self.max_length = max_length
44
+ self.num_beams = 4
45
+ # TODO: Modification: Add more prompts to the advise function
46
+ # to make it more specific to the user's needs.
47
+ # The function now takes in the user's body type, face shape, and occasion
48
+ # and generates style tips accordingly.
49
+
50
+ def advise(self,
51
+ items: List[str],
52
+ body_type: str,
53
+ face_shape: str,
54
+ gender: str,
55
+ occasion: str
56
+ ) -> List[str]:
57
+ """
58
+ Generate one result per prompt template and return all as a list.
59
+ """
60
+ labels = ", ".join(items) if items else "an outfit"
61
+ results: List[str] = []
62
+ for tpl in PROMPTS.values():
63
+ prompt = tpl.format(
64
+ body_type=body_type,
65
+ face_shape=face_shape,
66
+ gender = gender,
67
+ occasion=occasion,
68
+ items=labels
69
+ )
70
+ out = self.pipe(
71
+ prompt,
72
+ max_length=self.max_length,
73
+ num_beams=self.num_beams,
74
+ early_stopping=True,
75
+ do_sample=False,
76
+ no_repeat_ngram_size=3, # avoid repeating phrases
77
+ )[0]["generated_text"].strip()
78
+ results.append(out)
79
+ return results
80
+
81
+
82
+
83
+
models/vision.py ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ # models/vision.py -- Working
3
+
4
+ from transformers import pipeline
5
+ from PIL import Image
6
+
7
+ class VisionModel:
8
+ def __init__(
9
+ self,
10
+ model_name: str = "valentinafeve/yolos-fashionpedia",
11
+ threshold: float = 0.7
12
+ ):
13
+ self.pipe = pipeline("object-detection", model=model_name)
14
+ self.threshold = threshold
15
+
16
+ def detect(self, image: Image.Image):
17
+ # 1) Ensure RGB
18
+ if image.mode != "RGB":
19
+ image = image.convert("RGB")
20
+
21
+ # 2) Run detection
22
+ results = self.pipe(image)
23
+
24
+ # 3) Process & filter
25
+ processed = []
26
+ for r in results:
27
+ score = float(r["score"])
28
+ if score < self.threshold:
29
+ continue
30
+
31
+ # r["box"] is a dict: {"xmin":..., "ymin":..., "xmax":..., "ymax":...}
32
+ box = r["box"]
33
+ coords = [
34
+ float(box["xmin"]),
35
+ float(box["ymin"]),
36
+ float(box["xmax"]),
37
+ float(box["ymax"]),
38
+ ]
39
+
40
+ processed.append({
41
+ "label": r["label"],
42
+ "score": score,
43
+ "box": coords
44
+ })
45
+
46
+ return processed
47
+
48
+
49
+
50
+
requirements.txt ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ aiofiles==24.1.0
2
+ annotated-types==0.7.0
3
+ anyio==4.9.0
4
+ certifi==2025.4.26
5
+ charset-normalizer==3.4.1
6
+ click==8.1.8
7
+ fastapi==0.115.12
8
+ ffmpy==0.5.0
9
+ filelock==3.18.0
10
+ fsspec==2025.3.2
11
+ gradio==5.28.0
12
+ gradio_client==1.10.0
13
+ groovy==0.1.2
14
+ h11==0.16.0
15
+ httpcore==1.0.9
16
+ httpx==0.28.1
17
+ huggingface-hub==0.30.2
18
+ idna==3.10
19
+ inquirerpy==0.3.4
20
+ Jinja2==3.1.6
21
+ markdown-it-py==3.0.0
22
+ MarkupSafe==3.0.2
23
+ mdurl==0.1.2
24
+ mpmath==1.3.0
25
+ networkx==3.4.2
26
+ numpy==2.2.5
27
+ orjson==3.10.18
28
+ packaging==25.0
29
+ pandas==2.2.3
30
+ pfzy==0.3.4
31
+ pillow==11.2.1
32
+ prompt_toolkit==3.0.51
33
+ protobuf==6.30.2
34
+ pydantic==2.11.4
35
+ pydantic_core==2.33.2
36
+ pydub==0.25.1
37
+ Pygments==2.19.1
38
+ python-dateutil==2.9.0.post0
39
+ python-dotenv==1.1.0
40
+ python-multipart==0.0.20
41
+ pytz==2025.2
42
+ PyYAML==6.0.2
43
+ regex==2024.11.6
44
+ requests==2.32.3
45
+ rich==14.0.0
46
+ ruff==0.11.7
47
+ safehttpx==0.1.6
48
+ safetensors==0.5.3
49
+ semantic-version==2.10.0
50
+ sentencepiece==0.2.0
51
+ setuptools==80.0.1
52
+ shellingham==1.5.4
53
+ six==1.17.0
54
+ sniffio==1.3.1
55
+ starlette==0.46.2
56
+ sympy==1.14.0
57
+ timm==1.0.15
58
+ tokenizers==0.21.1
59
+ tomlkit==0.13.2
60
+ torch==2.7.0
61
+ torchvision==0.22.0
62
+ tqdm==4.67.1
63
+ transformers==4.51.3
64
+ typer==0.15.3
65
+ typing-inspection==0.4.0
66
+ typing_extensions==4.13.2
67
+ tzdata==2025.2
68
+ urllib3==2.4.0
69
+ uvicorn==0.34.2
70
+ wcwidth==0.2.13
71
+ websockets==15.0.1
utils/advisor.py ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ from models.llm import StyleSavvy
2
+
3
+ advisor = StyleSavvy()
4
+
5
+ def get_advice(items, body_type, face_shape, gender,occasion):
6
+ return advisor.advise(items, body_type, face_shape, gender, occasion)
7
+
utils/bg_removal.py ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os, requests
2
+ from io import BytesIO
3
+ from PIL import Image
4
+ from dotenv import load_dotenv
5
+
6
+ load_dotenv()
7
+
8
+ API_KEY = os.getenv("REMOVE_BG_API_KEY")
9
+ ENDPOINT = "https://api.remove.bg/v1.0/removebg"
10
+
11
+ def remove_background(image_bytes: bytes) -> Image.Image:
12
+ resp = requests.post(
13
+ ENDPOINT,
14
+ files ={"image_file": ("image.jpg", image_bytes, "image/jpeg")},
15
+ data = {"size": "auto"},
16
+ headers = {"X-Api-Key": API_KEY},
17
+ )
18
+ resp.raise_for_status()
19
+ return Image.open(BytesIO(resp.content))
20
+
utils/detector.py ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ from io import BytesIO
3
+ from PIL import Image
4
+ from models.vision import VisionModel
5
+ from utils.bg_removal import remove_background
6
+
7
+ vision = VisionModel()
8
+ FASHION_LABELS = {
9
+ "shirt", "t-shirt", "blouse", "tank top", "sweater", "hoodie", "jacket",
10
+ "coat", "overcoat", "raincoat", "windbreaker", "cardigan", "blazer",
11
+ "pants", "jeans", "shorts", "leggings", "tights", "skirt", "dress",
12
+ "suit", "jumpsuit", "romper", "vest", "sports bra", "tracksuit",
13
+ "belt", "tie", "scarf", "hat", "cap", "gloves", "socks",
14
+ "shoe", "sneakers", "boots", "sandals", "heels",
15
+ "watch", "necklace", "bracelet", "earrings", "ring",
16
+ "backpack", "handbag", "purse", "wallet"
17
+ }
18
+
19
+ def detect_clothing(image_input, do_bg_remove: bool = False):
20
+ # 1) Load into a PIL.Image if it's a filepath
21
+ if isinstance(image_input, str):
22
+ img = Image.open(image_input)
23
+ else:
24
+ img = image_input
25
+
26
+ # 2) Optionally remove background (works on bytes)
27
+ if do_bg_remove:
28
+ buf = BytesIO()
29
+ img.convert("RGB").save(buf, format="JPEG")
30
+ img_bytes = buf.getvalue()
31
+ img = remove_background(img_bytes)
32
+ else:
33
+ # ensure you drop any alpha channel
34
+ img = img.convert("RGB")
35
+
36
+ # 3) Run detection
37
+ raw_detections = vision.detect(img)
38
+
39
+ # 4) Filter and deduplicate
40
+ filtered = {}
41
+ for det in raw_detections:
42
+ label = det["label"].lower()
43
+ if label in FASHION_LABELS:
44
+ # Only keep the first or highest score if multiple detected
45
+ if label not in filtered or det["score"] > filtered[label]["score"]:
46
+ filtered[label] = {
47
+ "label": label,
48
+ "score": det["score"],
49
+ "box": det.get("box", [])
50
+ }
51
+
52
+ # 5) Return dict or fallback if empty
53
+ if not filtered:
54
+ return {"outfit": {"label": "outfit", "score": 1.0, "box": []}}
55
+
56
+ return filtered
57
+
58
+
59
+
utils/test_detector.py ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # test_detector.py
2
+
3
+ from detector import detect_clothing
4
+ from PIL import Image, ImageDraw
5
+ import os
6
+
7
+ def visualize_and_print(image_path, do_bg_remove=False, output_dir="vis"):
8
+ # Ensure output folder exists
9
+ os.makedirs(output_dir, exist_ok=True)
10
+
11
+ img = Image.open(image_path).convert("RGB")
12
+ print(f"\n--- Testing {os.path.basename(image_path)} (bg_remove={do_bg_remove}) ---")
13
+
14
+ # Run your detector
15
+ dets = detect_clothing(img, do_bg_remove=do_bg_remove)
16
+ if not dets:
17
+ print("No detections!")
18
+ return
19
+
20
+ # Print raw detections
21
+ # Print raw detections
22
+ for i, d in enumerate(dets.values(), 1):
23
+ lbl = d["label"]
24
+ scr = d["score"]
25
+ box = d.get("box", [])
26
+ print(f" {i}. {lbl:12s} @ {scr:.2f} → {box}")
27
+
28
+ # Draw boxes
29
+ vis = img.copy()
30
+ draw = ImageDraw.Draw(vis)
31
+ for d in dets.values():
32
+ if d.get("box"):
33
+ x0, y0, x1, y1 = d["box"]
34
+ draw.rectangle([x0, y0, x1, y1], outline="red", width=2)
35
+ draw.text((x0, y0 - 10), f"{d['label']}:{d['score']:.2f}", fill="red")
36
+ # Save visualization
37
+ out_path = os.path.join(output_dir, os.path.basename(image_path))
38
+ vis.save(out_path)
39
+ print(f" Visualization saved to {out_path}")
40
+
41
+ if __name__ == "__main__":
42
+ # List your test images here
43
+ samples = [
44
+ "/Users/tanzimfarhan/Desktop/Python/Codes/SLU/CS5930/FinalProject/StyleSavvy/images/casual.jpg",
45
+ "/Users/tanzimfarhan/Desktop/Python/Codes/SLU/CS5930/FinalProject/StyleSavvy/images/WomenCasual.jpg",
46
+ ]
47
+ for img_path in samples:
48
+ visualize_and_print(img_path, do_bg_remove=False)
49
+ # visualize_and_print(img_path, do_bg_remove=True)
utils/test_llm.py ADDED
@@ -0,0 +1,193 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # # test_llm.py
2
+ # """
3
+ # Test harness for StyleSavvy LLM prompts.
4
+ # Defines multiple prompt templates and evaluates the generated outputs,
5
+ # checking for the expected number of bullet-point style tips.
6
+ # """
7
+ # from models.llm import StyleSavvy
8
+
9
+ # # Variant prompt templates with placeholders
10
+ # PROMPT_TEMPLATES = {
11
+ # "occasion_driven": (
12
+ # "You are an expert fashion stylist. A client is preparing for {occasion}. "
13
+ # "They have a {body_type}-shaped body and a {face_shape} face. They’re currently wearing: {items}. "
14
+ # "Give 3 to 5 *distinct* style tips focused on making them look their best at the event. "
15
+ # "Make the suggestions relevant to the setting, weather, and formality of the occasion. "
16
+ # "Avoid repeating any advice."
17
+ # ),
18
+
19
+ # "function_based": (
20
+ # "You're advising someone with a {body_type} build and {face_shape} face. "
21
+ # "They're attending a {occasion} and are wearing {items}. "
22
+ # "Suggest 3–5 concise fashion improvements or enhancements. "
23
+ # "Each suggestion should be unique and tailored to the event. "
24
+ # "Include practical choices for color, layering, accessories, or footwear. "
25
+ # "Avoid repeating words or phrases."
26
+ # ),
27
+
28
+ # "intent_style": (
29
+ # "Act as a high-end personal stylist. Your client has a {body_type} body shape and a {face_shape} face. "
30
+ # "They're going to a {occasion} and are wearing {items}. "
31
+ # "Write 3 to 5 brief but powerful styling suggestions to elevate their look. "
32
+ # "Focus on intent—what feeling or impression each style choice creates for the event."
33
+ # ),
34
+ # }
35
+
36
+
37
+ # # Test parameters
38
+ # BODY_TYPE = "Slim"
39
+ # FACE_SHAPE = "Round"
40
+ # OCCASION = "Rooftop Evening Party"
41
+ # ITEMS = ["shirt", "jeans", "jacket","shoes"]
42
+
43
+ # if __name__ == "__main__":
44
+ # advisor = StyleSavvy()
45
+
46
+ # for name, template in PROMPT_TEMPLATES.items():
47
+ # # Build prompt by replacing placeholders
48
+ # prompt = template.format(
49
+ # body_type=BODY_TYPE,
50
+ # face_shape=FACE_SHAPE,
51
+ # occasion=OCCASION,
52
+ # items=", ".join(ITEMS)
53
+ # )
54
+ # print(f"=== Testing template: {name} ===")
55
+ # print("Prompt:")
56
+ # print(prompt)
57
+
58
+ # # Generate output (use only supported args)
59
+ # result = advisor.pipe(
60
+ # prompt,
61
+ # max_length=advisor.max_length,
62
+ # early_stopping=True,
63
+ # do_sample=False
64
+ # )[0]["generated_text"].strip()
65
+
66
+ # print("Generated output:")
67
+ # print(result)
68
+
69
+ # # Extract bullet lines
70
+ # bullets = [ln for ln in result.splitlines() if ln.strip().startswith("- ")]
71
+ # print(f"Number of bullets detected: {len(bullets)}")
72
+ # for i, b in enumerate(bullets, start=1):
73
+ # print(f" {i}. {b}")
74
+ # print("" + "-"*40)
75
+
76
+
77
+ # test_llm.py
78
+ """
79
+ Test harness for StyleSavvy LLM prompts.
80
+ Evaluates multiple prompt templates and parses the generated outputs into distinct tips.
81
+ """
82
+
83
+ from models.llm import StyleSavvy
84
+
85
+ # Variant prompt templates with placeholders
86
+ # PROMPTS = {
87
+ # "direct_instruction": (
88
+ # "You are a professional fashion stylist. A client with a {body_type}-shaped body "
89
+ # "and {face_shape} face is preparing for {occasion}. They are currently wearing: {items}. "
90
+ # "Give exactly five distinct styling tips to improve their outfit. "
91
+ # "Each tip should be concise, actionable, and start on a new line."
92
+ # ),
93
+ # "category_expansion": (
94
+ # "As a high-end fashion advisor, provide five styling tips for a {body_type}-shaped person "
95
+ # "with a {face_shape} face attending {occasion}. They are wearing {items}. "
96
+ # "Offer one tip each for silhouette, color, accessories, footwear, and layering, "
97
+ # "each on its own line."
98
+ # ),
99
+ # "event_aesthetic": (
100
+ # "Imagine curating the perfect outfit for a {body_type}-shaped individual with a {face_shape} face "
101
+ # "at {occasion}. They are wearing {items}. Suggest 5 ways to enhance their style, "
102
+ # "focusing on event-appropriate aesthetics. Separate each tip with a newline."
103
+ # ),
104
+ # "fashion_editor": (
105
+ # "As a fashion editor, outline five unique styling tips for a {body_type}-shaped reader with a {face_shape} face "
106
+ # "attending {occasion}. They wear {items}. Each recommendation should reflect expertise and relevance. "
107
+ # "List each tip on a new line."
108
+ # ),
109
+ # "influencer_style": (
110
+ # "You’re an influencer giving sharp styling advice. A follower with a {body_type} body and {face_shape} face "
111
+ # "is going to {occasion}, wearing {items}. Reply with five snappy, modern style tips, "
112
+ # "each on its own line."
113
+ # ),
114
+ # }
115
+
116
+ PROMPTS = {
117
+ "direct_instruction": (
118
+ "You are a world-renowned fashion stylist celebrated for your bold creativity and attention to detail. "
119
+ "Your {gender} client has a {body_type}-shaped silhouette and a {face_shape} face, preparing for the {occasion}. "
120
+ "They’re wearing {items}. In vivid, sensory-rich language, provide one transformative styling recommendation that considers the event’s ambiance, lighting, and dress code. "
121
+ "Use dynamic adjectives and actionable insight to elevate their entire look."
122
+ ),
123
+ "category_expansion": (
124
+ "As a top-tier fashion advisor, craft one impactful styling suggestion for a {gender} individual with a {body_type} body "
125
+ "and {face_shape} face attending the {occasion}. They have on {items}. "
126
+ "Highlight a strategic enhancement in silhouette, color scheme, accessory choice, or footwear to elevate their look."
127
+ ),
128
+ "event_aesthetic": (
129
+ "Imagine you are curating an immersive style experience for a {gender} attendee with a {body_type} silhouette and {face_shape} face at the {occasion}. "
130
+ "They’re currently wearing {items}. Provide one highly descriptive recommendation that harmonizes fabric textures, color temperature, silhouette, and accessory accents with the event’s specific ambiance, lighting conditions, and seasonal atmosphere."
131
+ ),
132
+ "fashion_editor": (
133
+ "You are the Editor-in-Chief of a prestigious fashion publication. Advise a {gender} trendsetter with a {body_type} frame and {face_shape} face attending the {occasion}, "
134
+ "currently in {items}. Offer one magazine-cover-worthy styling tip—highlight a trending color palette, editorial-worthy silhouette, and innovative accessory placement that will resonate with a discerning audience."
135
+ ),
136
+ "influencer_style": (
137
+ "As a cutting-edge style influencer with millions of followers, recommend one eye-catching flair tip for a {gender} follower with a {body_type} physique and {face_shape} face, "
138
+ "heading to the {occasion} in {items}. Frame it as a social-media-caption-ready moment: mention a statement accessory, bold color pop, or texture twist that will go viral."
139
+ ),
140
+ "seasonal_trend": (
141
+ "As a seasonal style expert specializing in spring/summer trends, guide a {gender} individual with a {body_type} shape and {face_shape} face preparing for the {occasion}. "
142
+ "They currently wear {items}. Provide one tip incorporating current seasonal motifs—think floral prints, breathable linens, or eco-friendly fabrics—that elevates their ensemble."
143
+ ),
144
+ }
145
+
146
+
147
+ # Test parameters
148
+ BODY_TYPE = "Slim"
149
+ FACE_SHAPE = "SQUARE"
150
+ OCCASION = "BEACH PARTY"
151
+ ITEMS = ["jeans", "jacket", "shoes",'shirt']
152
+ GENDER = "Male"
153
+
154
+ if __name__ == "__main__":
155
+ advisor = StyleSavvy()
156
+
157
+ for name, template in PROMPTS.items():
158
+ print(f"=== Testing template: {name} ===")
159
+
160
+ # Build prompt
161
+ prompt = template.format(
162
+ body_type=BODY_TYPE,
163
+ face_shape=FACE_SHAPE,
164
+ occasion=OCCASION,
165
+ gender = GENDER,
166
+ items=", ".join(ITEMS)
167
+
168
+ )
169
+ print("Prompt:\n" + prompt)
170
+
171
+ # Generate response
172
+ result = advisor.pipe(
173
+ prompt,
174
+ max_length=advisor.max_length,
175
+ early_stopping=True,
176
+ num_beams=4,
177
+ no_repeat_ngram_size=3,
178
+ do_sample=False)[0]["generated_text"].strip()
179
+
180
+ print("\nRaw generated output:\n" + result)
181
+
182
+ # Parse into tips (bullets or sentence)
183
+ lines = result.splitlines()
184
+ tips = [ln.strip("-*0123456789. ").strip() for ln in lines if ln.strip()]
185
+ if len(tips) < 3:
186
+ # fallback to sentence split
187
+ tips = [p.strip() for p in result.split(".") if p.strip()]
188
+ tips = list(dict.fromkeys(tips)) # remove duplicates
189
+
190
+ print(f"\n💡 Parsed {len(tips)} style tips:")
191
+ for i, tip in enumerate(tips[:5], 1):
192
+ print(f"{i}. {tip}")
193
+ print("-" * 40)