Faisalkhany commited on
Commit
2fd867c
Β·
verified Β·
1 Parent(s): be63a88

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +164 -0
app.py ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import streamlit as st
3
+ from pptx import Presentation
4
+ from pptx.util import Inches, Pt
5
+ from pptx.dml.color import RGBColor
6
+ import io, tempfile, os, re
7
+ from transformers import pipeline
8
+
9
+ # ── CONFIG ─────────────────────────────────────────────────────
10
+ st.set_page_config(page_title="PPTX Smart Enhancer", layout="wide")
11
+ MODEL_ID = "Faisalkhany/newfinetune" # ← your HF model
12
+ pipe = pipeline("text2text-generation", model=MODEL_ID)
13
+
14
+ TEMPLATES = {
15
+ "Office Default": {
16
+ "font": "Calibri",
17
+ "colors": {"primary":"#2B579A","secondary":"#5B9BD5","text":"#000000","background":"#FFFFFF"},
18
+ "sizes": {"title":44,"heading":32,"body":18}, "background":True
19
+ },
20
+ "Modern Office": {
21
+ "font": "Segoe UI",
22
+ "colors": {"primary":"#404040","secondary":"#A5A5A5","text":"#FFFFFF","background":"#121212"},
23
+ "sizes": {"title":36,"heading":24,"body":16}, "background":True
24
+ },
25
+ "Corporate": {
26
+ "font":"Arial",
27
+ "colors":{"primary":"#1976D2","secondary":"#BBDEFB","text":"#212121","background":"#FAFAFA"},
28
+ "sizes":{"title":40,"heading":28,"body":18}, "background":False
29
+ }
30
+ }
31
+ FONT_CHOICES = {f:f for f in ["Arial","Calibri","Times New Roman","Segoe UI","Verdana","Georgia"]}
32
+
33
+ # ── HELPERS ────────────────────────────────────────────────────
34
+ def chunk_slide_text(text, max_words=200):
35
+ words = text.split()
36
+ return [" ".join(words[i:i+max_words]) for i in range(0, len(words), max_words)]
37
+
38
+ def get_ai_response(prompt: str) -> str:
39
+ out = pipe(prompt, max_length=512, truncation=True)
40
+ return out[0]["generated_text"]
41
+
42
+ def extract_slide_text(slide) -> str:
43
+ parts = []
44
+ for shp in slide.shapes:
45
+ if hasattr(shp, "text_frame"):
46
+ for p in shp.text_frame.paragraphs:
47
+ if p.text.strip():
48
+ parts.append(p.text.strip())
49
+ return "\n".join(parts)
50
+
51
+ def split_formatted_runs(text):
52
+ segments, cur, bold, italic = [], [], False, False
53
+ parts = re.split(r'(\*|_)', text)
54
+ for tok in parts:
55
+ if tok in ("*","_"):
56
+ if cur:
57
+ segments.append({"text":"".join(cur),"bold":bold,"italic":italic})
58
+ cur=[]
59
+ if tok=="*": bold=not bold
60
+ else: italic=not italic
61
+ else:
62
+ cur.append(tok)
63
+ if cur:
64
+ segments.append({"text":"".join(cur),"bold":bold,"italic":italic})
65
+ return segments
66
+
67
+ def apply_formatting(tf, content, ds):
68
+ tf.clear()
69
+ for line in [l for l in content.split("\n") if l.strip()]:
70
+ clean = re.sub(r'^#+\s*','', line).strip()
71
+ if re.match(r'^(What is|Understanding|Key|Conclusion)', clean, re.IGNORECASE):
72
+ p = tf.add_paragraph(); p.text=clean
73
+ p.font.size=Pt(ds["heading_size"]); p.font.bold=True; p.space_after=Pt(12)
74
+ continue
75
+ if re.match(r'^[\-\*\β€’] ', clean):
76
+ p=tf.add_paragraph(); p.level=0
77
+ txt = clean[2:].strip()
78
+ for seg in split_formatted_runs(txt):
79
+ r=p.add_run(); r.text=seg["text"]; r.font.bold=seg["bold"]; r.font.italic=seg["italic"]
80
+ p.font.size=Pt(ds["body_size"]); continue
81
+ p=tf.add_paragraph()
82
+ for seg in split_formatted_runs(clean):
83
+ r=p.add_run(); r.text=seg["text"]; r.font.bold=seg["bold"]; r.font.italic=seg["italic"]
84
+ p.font.size=Pt(ds["body_size"]); p.space_after=Pt(6)
85
+
86
+ def apply_design(slide, ds):
87
+ cols = ds["colors"]
88
+ for shp in slide.shapes:
89
+ if hasattr(shp, "text_frame"):
90
+ for p in shp.text_frame.paragraphs:
91
+ for r in p.runs:
92
+ r.font.name = ds["font"]
93
+ r.font.color.rgb = RGBColor.from_string(cols["text"][1:])
94
+ if shp == getattr(slide.shapes, "title", None):
95
+ r.font.color.rgb = RGBColor.from_string(cols["primary"][1:])
96
+ r.font.size = Pt(ds["title_size"]); r.font.bold=True
97
+ if ds["set_background"]:
98
+ slide.background.fill.solid();
99
+ slide.background.fill.fore_color.rgb = RGBColor.from_string(cols["background"][1:])
100
+
101
+ def enhance_slide(slide, prompt, ds):
102
+ orig = extract_slide_text(slide)
103
+ if not orig: return
104
+ frags = chunk_slide_text(orig, max_words=200)
105
+ enhanced_frags = []
106
+ for f in frags:
107
+ enhanced_frags.append(get_ai_response(f"\nImprove this:\n{f}\n\nInstructions: {prompt}"))
108
+ final = "\n".join(enhanced_frags)
109
+ title_sp = getattr(slide.shapes, "title", None)
110
+ for shp in list(slide.shapes):
111
+ if shp is not title_sp:
112
+ shp._element.getparent().remove(shp._element)
113
+ left, top = Inches(1), Inches(1.5 if title_sp else 0.5)
114
+ tb = slide.shapes.add_textbox(left, top, Inches(8), Inches(5))
115
+ tf = tb.text_frame; tf.word_wrap=True
116
+ apply_formatting(tf, final, ds)
117
+ apply_design(slide, ds)
118
+
119
+ def process_presentation(uploaded, prompt, ds):
120
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".pptx") as tmp:
121
+ tmp.write(uploaded.read()); tmp_path=tmp.name
122
+ prs = Presentation(tmp_path)
123
+ for s in prs.slides:
124
+ enhance_slide(s, prompt, ds)
125
+ os.unlink(tmp_path)
126
+ return prs
127
+
128
+ # ── UI ─────────────────────────────────────────────────────────
129
+ st.title("Professional PPTX Enhancer")
130
+
131
+ uploaded = st.file_uploader("Upload PPTX", type=["pptx"])
132
+ user_prompt = st.text_area("Enhancement Instructions", placeholder="E.g. Improve clarity, add bullets", height=100)
133
+
134
+ with st.expander("🎨 Design Settings", True):
135
+ tpl = st.selectbox("Template", list(TEMPLATES.keys()))
136
+ if tpl=="Custom":
137
+ font = st.selectbox("Font", list(FONT_CHOICES))
138
+ ts = st.slider("Title size",12,60,32)
139
+ hs = st.slider("Heading size",12,48,24)
140
+ bs = st.slider("Body size",8,36,18)
141
+ sb = st.checkbox("Apply Background",True)
142
+ cols = {k:st.color_picker(k.capitalize(),c) for k,c in TEMPLATES["Office Default"]["colors"].items()}
143
+ else:
144
+ t = TEMPLATES[tpl]
145
+ font, ts, hs, bs, sb = t["font"], *t["sizes"].values(), t["background"]
146
+ cols = t["colors"]
147
+
148
+ ds = {
149
+ "font": FONT_CHOICES[font],
150
+ "colors": cols,
151
+ "title_size": ts,
152
+ "heading_size": hs,
153
+ "body_size": bs,
154
+ "set_background": sb
155
+ }
156
+
157
+ if st.button("Enhance Presentation") and uploaded and user_prompt:
158
+ out_prs = process_presentation(uploaded, user_prompt, ds)
159
+ buf = io.BytesIO(); out_prs.save(buf); buf.seek(0)
160
+ st.success("Done!")
161
+ st.download_button("Download Enhanced PPTX",
162
+ data=buf,
163
+ file_name="enhanced.pptx",
164
+ mime="application/vnd.openxmlformats-officedocument.presentationml.presentation")