para-lost commited on
Commit
8de2b58
·
1 Parent(s): 78f1a57

demo update

Browse files
Files changed (1) hide show
  1. app.py +86 -90
app.py CHANGED
@@ -3,85 +3,74 @@ import os
3
  import openai
4
  import subprocess
5
  import base64
 
 
 
 
6
 
7
  def encode_image(image_path):
8
  with open(image_path, 'rb') as image_file:
9
  return base64.b64encode(image_file.read()).decode('utf-8')
10
 
11
  def extract_code_pieces(text: str, concat: bool = True) -> list[str]:
12
- """Extract code pieces from a text string.
13
- Args:
14
- text: str, model prediciton text.
15
- Rets:
16
- code_pieces: list[str], code pieces in the text.
17
- """
18
  code_pieces = []
19
  while "```python" in text:
20
  st_idx = text.index("```python") + 10
21
- # end_idx = text.index("```", st_idx)
22
  if "```" in text[st_idx:]:
23
  end_idx = text.index("```", st_idx)
24
- else:
25
  end_idx = len(text)
26
  code_pieces.append(text[st_idx:end_idx].strip())
27
  text = text[end_idx+3:].strip()
28
- if concat: return '\n\n'.join(code_pieces)
 
29
  return code_pieces
30
 
31
  SYSTEM_MESSAGE = """* You are an expert presentation slides designer who creates modern, fashionable, and stylish slides using Python code. Your job is to generate the required PPTX slide by writing and executing a Python script. Make sure to follow the guidelines below and do not skip any of them:
32
  1. Ensure your code can successfully execute. If needed, you can also write tests to verify your code.
33
- 2. Maintain proper spacing and arrangements of elements in the slide: make sure to keep sufficient spacing between different elements; do not make elements overlap or overflow to the slide page.
34
- 3. Carefully select the colors of text, shapes, and backgrounds, to ensure all contents are readable.
35
- 4. The slides should not look empty or incomplete. When filling the content in the slides, maintain good design and layout."""
36
-
37
- # INSTRUCTION = """Follow the instruction below to create the slide.
38
- # If the instruction is long and specific, follow the instruction carefully and add all elements as required;
39
- # if it is short and concise, you will need to create some content (text, image, layout) and implement it into the slide.
40
- # {}
41
 
42
- # Finally, your code should save the pptx file to path "{}"."""
43
  with open('agent_no_image_new_lib.prompt', 'r') as f:
44
  INSTRUCTION = f.read()
45
 
46
- import glob
47
- import time
48
- import shutil
49
  def list_files_in_directory(directory):
50
  """Lists all files in the given directory."""
51
  return set(glob.glob(os.path.join(directory, "*")))
52
 
53
- def cleanup_temp_files(temp_files):
54
- """Deletes a list of temporary files if they exist."""
55
- for temp_file in temp_files:
56
- try:
57
- if os.path.exists(temp_file):
58
- shutil.rmtree(temp_file)
59
- os.remove(temp_file)
60
- print(f"Deleted temporary file: {temp_file}")
61
- except Exception as e:
62
- print(f"Failed to delete {temp_file}: {e}")
63
 
 
 
64
 
65
- def create_pptx(api_key, instruction, model_name="gpt-4o", max_tokens=4096):
66
  try:
67
  # Set OpenAI API key
68
  openai.api_key = api_key
69
 
70
- # Create OpenAI client
71
  client = openai.OpenAI(api_key=api_key)
72
 
73
  # Prepare messages for the chat completion
74
  messages = [{"role": "system", "content": SYSTEM_MESSAGE}]
75
- pptx_path = "output.pptx"
76
  instruction_message = INSTRUCTION.replace("INSERT_INSTRUCTION_HERE", instruction)
77
  messages.append({"role": "user", "content": instruction_message})
 
78
  # Capture the directory state before execution
79
- working_directory = os.getcwd()
80
- files_before = list_files_in_directory(working_directory)
81
- # Retry up to 3 times
82
  for attempt in range(3):
83
  try:
84
- # Call OpenAI's GPT model
85
  response = client.chat.completions.create(
86
  model=model_name,
87
  messages=messages,
@@ -89,43 +78,36 @@ def create_pptx(api_key, instruction, model_name="gpt-4o", max_tokens=4096):
89
  n=1,
90
  )
91
  generated_code = extract_code_pieces(response.choices[0].message.content, concat=True)
 
92
  generated_code = generated_code.replace("from library import", "from SlidesLib import")
93
  generated_code = generated_code.replace("generate_image(", f"generate_image({repr(api_key)},")
94
  generated_code = "from SlidesLib import *\n\n" + generated_code
95
 
96
- # Save the generated code
97
- code_file = "generated_slide_code.py"
98
- with open(code_file, "w") as f:
99
  f.write(generated_code)
100
 
101
  # Execute the generated code
102
- result = subprocess.run(["python", code_file], capture_output=True, text=True, check=True)
 
 
 
 
 
 
103
  print(result.stdout)
104
-
105
- # Capture the directory state after execution
106
- files_after = list_files_in_directory(working_directory)
107
- temp_files = files_after - files_before # Identify newly created files
108
-
109
- # Convert the pptx to jpg for preview
110
- # preview_image = "image_previews/output.jpg"
111
- # command = [
112
- # "libreoffice",
113
- # "--headless",
114
- # "--convert-to", "jpg",
115
- # "--outdir", "image_previews",
116
- # pptx_path
117
- # ]
118
- # subprocess.run(command)
119
- # temp_files.add(preview_image)
120
-
121
- # If successful, return the result
122
  return "Slide generated successfully! Download your slide below.", pptx_path
123
- # , preview_image
124
  except subprocess.CalledProcessError as e:
125
- print(f"Attempt {attempt + 1} failed: {e.stderr}")
126
 
127
- # Fallback: Use default code if all attempts fail
128
- print("All 3 attempts failed. Running default code.")
129
  default_code = f"""
130
  from pptx import Presentation
131
 
@@ -139,38 +121,48 @@ content.text = "{instruction}"
139
 
140
  ppt.save("output.pptx")
141
  """
142
- code_file = "default_slide_code.py"
143
- with open(code_file, "w") as f:
144
  f.write(default_code)
145
-
146
- # Execute the default code
147
- subprocess.run(["python", code_file], capture_output=True, text=True, check=True)
148
-
149
- # Convert the pptx to jpg for preview
150
- # preview_image = "image_previews/output.jpg"
151
- # command = [
152
- # "libreoffice",
153
- # "--headless",
154
- # "--convert-to", "jpg",
155
- # "--outdir", "image_previews",
156
- # pptx_path
157
- # ]
158
- # subprocess.run(command)
159
 
160
  return "Default slide generated after 3 attempts failed.", pptx_path
161
 
162
  except Exception as e:
163
  return f"An error occurred: {str(e)}", None
 
164
  finally:
165
- # Cleanup temporary files
166
- files_before.add("output.pptx")
167
- temp_files = list_files_in_directory(working_directory) - files_before
168
- cleanup_temp_files(temp_files)
169
 
170
- # Create a Gradio interface
171
  def gradio_demo(api_key, instruction):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  status, pptx_path = create_pptx(api_key, instruction)
173
- return status, pptx_path
 
174
 
175
  iface = gr.Interface(
176
  fn=gradio_demo,
@@ -179,12 +171,16 @@ iface = gr.Interface(
179
  gr.Textbox(label="Instruction", placeholder="Enter your slide instruction here...")
180
  ],
181
  outputs=[
182
- gr.Textbox(label="Status"),
183
  gr.File(label="Download Slide"),
184
- # gr.Image(label="Slide Preview", type="filepath")
185
  ],
186
  title="AutoPresent",
187
- description="Automatically Generate a presentation slide"
 
 
 
 
188
  )
189
 
190
- iface.launch()
 
 
3
  import openai
4
  import subprocess
5
  import base64
6
+ import shutil
7
+ import glob
8
+ import uuid
9
+ import time
10
 
11
  def encode_image(image_path):
12
  with open(image_path, 'rb') as image_file:
13
  return base64.b64encode(image_file.read()).decode('utf-8')
14
 
15
  def extract_code_pieces(text: str, concat: bool = True) -> list[str]:
16
+ """Extract code pieces from a text string."""
 
 
 
 
 
17
  code_pieces = []
18
  while "```python" in text:
19
  st_idx = text.index("```python") + 10
 
20
  if "```" in text[st_idx:]:
21
  end_idx = text.index("```", st_idx)
22
+ else:
23
  end_idx = len(text)
24
  code_pieces.append(text[st_idx:end_idx].strip())
25
  text = text[end_idx+3:].strip()
26
+ if concat:
27
+ return "\n\n".join(code_pieces)
28
  return code_pieces
29
 
30
  SYSTEM_MESSAGE = """* You are an expert presentation slides designer who creates modern, fashionable, and stylish slides using Python code. Your job is to generate the required PPTX slide by writing and executing a Python script. Make sure to follow the guidelines below and do not skip any of them:
31
  1. Ensure your code can successfully execute. If needed, you can also write tests to verify your code.
32
+ 2. Maintain proper spacing and arrangements of elements in the slide: make sure to keep sufficient spacing between different elements; do not make elements overlap or overflow to the slide page.
33
+ 3. Carefully select the colors of text, shapes, and backgrounds, to ensure all contents are readable.
34
+ 4. The slides should not look empty or incomplete. When filling the content in the slides, maintain good design and layout."""
 
 
 
 
 
35
 
36
+ # Load the user instruction template
37
  with open('agent_no_image_new_lib.prompt', 'r') as f:
38
  INSTRUCTION = f.read()
39
 
 
 
 
40
  def list_files_in_directory(directory):
41
  """Lists all files in the given directory."""
42
  return set(glob.glob(os.path.join(directory, "*")))
43
 
44
+ def create_pptx(api_key, instruction, model_name="gpt-4o", max_tokens=4096):
45
+ """
46
+ Generates a PPTX from instructions using GPT, isolating all new files
47
+ in a unique directory so multiple requests don't conflict.
48
+ """
49
+ unique_id = str(uuid.uuid4())[:8] # Short unique directory name
50
+ working_dir = f"temp_work_{unique_id}" # e.g. temp_work_3f2b1d4c
51
+ os.makedirs(working_dir, exist_ok=True)
 
 
52
 
53
+ # The name of the PPTX we intend to produce
54
+ pptx_path = os.path.join(working_dir, "output.pptx")
55
 
 
56
  try:
57
  # Set OpenAI API key
58
  openai.api_key = api_key
59
 
60
+ # Create an OpenAI client
61
  client = openai.OpenAI(api_key=api_key)
62
 
63
  # Prepare messages for the chat completion
64
  messages = [{"role": "system", "content": SYSTEM_MESSAGE}]
 
65
  instruction_message = INSTRUCTION.replace("INSERT_INSTRUCTION_HERE", instruction)
66
  messages.append({"role": "user", "content": instruction_message})
67
+
68
  # Capture the directory state before execution
69
+ files_before = list_files_in_directory(working_dir)
70
+
71
+ # Try up to 3 times to generate code and run it
72
  for attempt in range(3):
73
  try:
 
74
  response = client.chat.completions.create(
75
  model=model_name,
76
  messages=messages,
 
78
  n=1,
79
  )
80
  generated_code = extract_code_pieces(response.choices[0].message.content, concat=True)
81
+ # Replace references to other library with local SlidesLib
82
  generated_code = generated_code.replace("from library import", "from SlidesLib import")
83
  generated_code = generated_code.replace("generate_image(", f"generate_image({repr(api_key)},")
84
  generated_code = "from SlidesLib import *\n\n" + generated_code
85
 
86
+ code_file = os.path.join(working_dir, "generated_slide_code.py")
87
+ with open(code_file, "w", encoding="utf-8") as f:
 
88
  f.write(generated_code)
89
 
90
  # Execute the generated code
91
+ result = subprocess.run(
92
+ ["python", code_file],
93
+ capture_output=True,
94
+ text=True,
95
+ check=True,
96
+ cwd=working_dir
97
+ )
98
  print(result.stdout)
99
+
100
+ # Check for newly created files
101
+ files_after = list_files_in_directory(working_dir)
102
+ temp_files = files_after - files_before
103
+
104
+ # If successful, return
 
 
 
 
 
 
 
 
 
 
 
 
105
  return "Slide generated successfully! Download your slide below.", pptx_path
 
106
  except subprocess.CalledProcessError as e:
107
+ print(f"Attempt {attempt + 1} failed:\n{e.stderr}\n")
108
 
109
+ # If all attempts fail, run default code
110
+ print("All attempts failed. Running default code.")
111
  default_code = f"""
112
  from pptx import Presentation
113
 
 
121
 
122
  ppt.save("output.pptx")
123
  """
124
+ code_file = os.path.join(working_dir, "default_slide_code.py")
125
+ with open(code_file, "w", encoding="utf-8") as f:
126
  f.write(default_code)
127
+
128
+ subprocess.run(
129
+ ["python", code_file],
130
+ capture_output=True,
131
+ text=True,
132
+ check=True,
133
+ cwd=working_dir
134
+ )
 
 
 
 
 
 
135
 
136
  return "Default slide generated after 3 attempts failed.", pptx_path
137
 
138
  except Exception as e:
139
  return f"An error occurred: {str(e)}", None
140
+
141
  finally:
142
+ # We won't automatically delete the working_dir here if we want the user
143
+ # to be able to download the pptx. Otherwise, we could do cleanup.
144
+ pass
 
145
 
 
146
  def gradio_demo(api_key, instruction):
147
+ """
148
+ The Gradio demo function. It calls create_pptx, returns
149
+ the status string, and the path to the PPTX file.
150
+ """
151
+ # 1) Important: Warn the user about key usage.
152
+ if not api_key:
153
+ return ("Warning: No OpenAI API key provided. Please provide a valid key "
154
+ "to generate slides."), None
155
+ else:
156
+ # Additional caution about potential key leaks
157
+ warning_message = (
158
+ "Caution: Your OpenAI API key is used to generate the slide. "
159
+ "Make sure you trust this environment, as keys can appear in logs. "
160
+ "We recommend using a disposable or restricted-scope key if possible.\n"
161
+ )
162
+
163
  status, pptx_path = create_pptx(api_key, instruction)
164
+ # Prepend the warning to the final status
165
+ return f"{warning_message}\n{status}", pptx_path
166
 
167
  iface = gr.Interface(
168
  fn=gradio_demo,
 
171
  gr.Textbox(label="Instruction", placeholder="Enter your slide instruction here...")
172
  ],
173
  outputs=[
174
+ gr.Textbox(label="Status", lines=5),
175
  gr.File(label="Download Slide"),
 
176
  ],
177
  title="AutoPresent",
178
+ description=(
179
+ "Automatically Generate a presentation slide.\n\n"
180
+ "**WARNING**: Please be cautious with your OpenAI API key. "
181
+ "Logs or server code might store it temporarily."
182
+ )
183
  )
184
 
185
+ if __name__ == "__main__":
186
+ iface.launch()