Spaces:
Running
Running
add slides lib
Browse files- SlidesLib/README.md +46 -0
- SlidesLib/__init__.py +191 -0
- SlidesLib/image_gen.py +28 -0
- SlidesLib/llm.py +34 -0
- SlidesLib/plotting.py +56 -0
- SlidesLib/ppt_gen.py +173 -0
- SlidesLib/search.py +149 -0
- SlidesLib/vqa.py +44 -0
- requirements.txt +1 -2
SlidesLib/README.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# SlidesLib
|
| 2 |
+
|
| 3 |
+
SlidesLib is a Python library for slide generation, providing APIs for image generation, Google search, and slide customization.
|
| 4 |
+
|
| 5 |
+
## Features
|
| 6 |
+
- **Image Generation**: Create images using the DALL-E API.
|
| 7 |
+
- **Search Integration**: Perform Google searches, save screenshots, and retrieve images.
|
| 8 |
+
- **Slide Customization**: Add text, bullet points, images, and set slide backgrounds.
|
| 9 |
+
|
| 10 |
+
## Installation
|
| 11 |
+
1. **Dependencies**: Install required Python libraries:
|
| 12 |
+
```bash
|
| 13 |
+
pip install -r requirements.txt
|
| 14 |
+
```
|
| 15 |
+
2. **Google Chrome**: Required for search functionality:
|
| 16 |
+
```bash
|
| 17 |
+
wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
|
| 18 |
+
sudo dpkg -i google-chrome-stable_current_amd64.deb
|
| 19 |
+
sudo apt-get install -f
|
| 20 |
+
```
|
| 21 |
+
3. **OpenAI API Key**: Export your API key:
|
| 22 |
+
```bash
|
| 23 |
+
export OPENAI_API_KEY="your_api_key"
|
| 24 |
+
```
|
| 25 |
+
|
| 26 |
+
## Quick Start
|
| 27 |
+
- **Image Generation**:
|
| 28 |
+
```python
|
| 29 |
+
from slidesLib.image_gen import Dalle3
|
| 30 |
+
Dalle3.generate_image("A futuristic cityscape", save_path="cityscape.png")
|
| 31 |
+
```
|
| 32 |
+
|
| 33 |
+
- **Search Integration**:
|
| 34 |
+
```python
|
| 35 |
+
from slidesLib.search import GoogleSearch
|
| 36 |
+
GoogleSearch.search_result("Tallest building in the world", "result.png")
|
| 37 |
+
```
|
| 38 |
+
|
| 39 |
+
- **Slide Customization**:
|
| 40 |
+
```python
|
| 41 |
+
from slidesLib.ppt_gen import add_title
|
| 42 |
+
add_title(slide, text="Welcome to SlidesLib")
|
| 43 |
+
```
|
| 44 |
+
|
| 45 |
+
For more examples, refer to the code in this folder.
|
| 46 |
+
```
|
SlidesLib/__init__.py
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from .search import GoogleSearch
|
| 2 |
+
from .vqa import VQA
|
| 3 |
+
from .image_gen import Dalle3
|
| 4 |
+
from .llm import LLM
|
| 5 |
+
from .ppt_gen import SlideAgent
|
| 6 |
+
from pptx.util import Inches, Pt
|
| 7 |
+
from pptx.dml.color import RGBColor
|
| 8 |
+
from pptx.enum.text import MSO_AUTO_SIZE
|
| 9 |
+
from mysearchlib import LLM
|
| 10 |
+
from pptx.dml.color import RGBColor
|
| 11 |
+
def search_result(question: str, screenshot_path: str = "screenshot.png") -> str:
|
| 12 |
+
"""
|
| 13 |
+
Search a question on Google, and take a screenshot of the search result.
|
| 14 |
+
Save the screenshot to screenshot_path, and return the path.
|
| 15 |
+
"""
|
| 16 |
+
return GoogleSearch.search_result(question, screenshot_path)
|
| 17 |
+
|
| 18 |
+
def search_image(query: str, save_path: str = 'top_images') -> str:
|
| 19 |
+
"""
|
| 20 |
+
Search for an image on Google and download the result to download_path.
|
| 21 |
+
Return download_path.
|
| 22 |
+
"""
|
| 23 |
+
return GoogleSearch.search_image(query, save_path)
|
| 24 |
+
|
| 25 |
+
def get_answer(question: str) -> str:
|
| 26 |
+
"""
|
| 27 |
+
Calls the LLM by inputing a question,
|
| 28 |
+
then get the response of the LLM as the answer
|
| 29 |
+
"""
|
| 30 |
+
return LLM.get_answer(question)
|
| 31 |
+
|
| 32 |
+
def get_code(request:str, examples:str = "") -> str:
|
| 33 |
+
"""
|
| 34 |
+
Calls the LLM to generate code for a request.
|
| 35 |
+
request: the task that the model should conduct
|
| 36 |
+
examples: few-shot code examples for the request
|
| 37 |
+
"""
|
| 38 |
+
return LLM.get_answer(request, examples)
|
| 39 |
+
|
| 40 |
+
def generate_image(query: str, save_path: str = "downloaded_image.png") -> str:
|
| 41 |
+
"""
|
| 42 |
+
Generate an image based on a text query, save the image to the save_path
|
| 43 |
+
Return the path of the saved image.
|
| 44 |
+
"""
|
| 45 |
+
return Dalle3.generate_image(query, save_path)
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
def add_title(
|
| 49 |
+
slide, text: str, font_size: int = 44,
|
| 50 |
+
font_color: tuple[int, int, int] = (0, 0, 0),
|
| 51 |
+
background_color: tuple[int, int, int] = None,
|
| 52 |
+
):
|
| 53 |
+
"""Add a title text to the slide with custom font size and font color (RGB tuple).
|
| 54 |
+
Args:
|
| 55 |
+
slide: Slide object as in pptx library
|
| 56 |
+
text: str, Title text to be added
|
| 57 |
+
font_size: int, Font size in int (point size), e.g., 44
|
| 58 |
+
font_color: tuple(int,int,int), RGB color, e.g., (0, 0, 0)
|
| 59 |
+
background_color: Optional, tuple(int,int,int), RGB color, e.g., (255, 255, 255)
|
| 60 |
+
Rets:
|
| 61 |
+
slide: Slide object with the title added
|
| 62 |
+
"""
|
| 63 |
+
title_shape = slide.shapes.title
|
| 64 |
+
if title_shape is None:
|
| 65 |
+
# Add a new text box as the title if no placeholder is found
|
| 66 |
+
title_shape = slide.shapes.add_textbox(Inches(1), Inches(0.5), Inches(8), Inches(1))
|
| 67 |
+
title_shape.text = text
|
| 68 |
+
for paragraph in title_shape.text_frame.paragraphs:
|
| 69 |
+
paragraph.font.size = Pt(font_size)
|
| 70 |
+
paragraph.font.color.rgb = RGBColor(*font_color)
|
| 71 |
+
if background_color is not None:
|
| 72 |
+
title_shape.fill.solid()
|
| 73 |
+
title_shape.fill.fore_color.rgb = RGBColor(*background_color)
|
| 74 |
+
return slide
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
def add_text(
|
| 78 |
+
slide, text: str, coords: list[float],
|
| 79 |
+
font_size: int = 20, bold: bool = False,
|
| 80 |
+
color: tuple[int, int, int] = (0, 0, 0),
|
| 81 |
+
background_color: tuple[int, int, int] = None,
|
| 82 |
+
auto_size: bool = True,
|
| 83 |
+
):
|
| 84 |
+
"""Add a text box at a specified location with custom text and color settings.
|
| 85 |
+
Args:
|
| 86 |
+
slide: Slide object as in pptx library
|
| 87 |
+
text: str, Text to be added
|
| 88 |
+
coords: list(float), [left, top, width, height] in inches
|
| 89 |
+
font_size: int, Font size in int (point size), e.g., 20
|
| 90 |
+
bold: bool, True if bold-type the text, False otherwise
|
| 91 |
+
color: tuple(int,int,int), RGB color, e.g., (0, 0, 0)
|
| 92 |
+
background_color: Optional, tuple(int,int,int), RGB color, e.g., (255, 255, 255)
|
| 93 |
+
auto_size: bool, True if auto-size the text box, False otherwise
|
| 94 |
+
Rets:
|
| 95 |
+
slide: Slide object with the text box added
|
| 96 |
+
"""
|
| 97 |
+
# Create the text box shape
|
| 98 |
+
left, top, width, height = coords
|
| 99 |
+
text_box = slide.shapes.add_textbox(Inches(left), Inches(top), Inches(width), Inches(height))
|
| 100 |
+
|
| 101 |
+
# Set background color if provided
|
| 102 |
+
if background_color:
|
| 103 |
+
text_box.fill.solid()
|
| 104 |
+
text_box.fill.fore_color.rgb = RGBColor(*background_color)
|
| 105 |
+
else:
|
| 106 |
+
text_box.fill.background() # No fill if no color is specified
|
| 107 |
+
|
| 108 |
+
# Handle line breaks and adjust height
|
| 109 |
+
lines = text.split("\n")
|
| 110 |
+
adjusted_height = height * len(lines) # Adjust height based on the number of lines
|
| 111 |
+
text_box.height = Inches(adjusted_height)
|
| 112 |
+
|
| 113 |
+
# Set text and format it
|
| 114 |
+
text_frame = text_box.text_frame
|
| 115 |
+
text_frame.word_wrap = True
|
| 116 |
+
if auto_size:
|
| 117 |
+
text_frame.auto_size = MSO_AUTO_SIZE.SHAPE_TO_FIT_TEXT # Automatically fit the text box to the text
|
| 118 |
+
|
| 119 |
+
p = text_frame.add_paragraph()
|
| 120 |
+
p.text = text
|
| 121 |
+
p.font.size = Pt(font_size)
|
| 122 |
+
p.font.bold = bold
|
| 123 |
+
p.font.color.rgb = RGBColor(*color)
|
| 124 |
+
return slide
|
| 125 |
+
|
| 126 |
+
|
| 127 |
+
def add_bullet_points(
|
| 128 |
+
slide, bullet_points: list[str], coords: list[float],
|
| 129 |
+
font_size: int = 18, color: tuple[int, int, int] = (0, 0, 0),
|
| 130 |
+
background_color: tuple[int, int, int] = None,
|
| 131 |
+
):
|
| 132 |
+
"""Add a text box with bullet points.
|
| 133 |
+
Args:
|
| 134 |
+
slide: Slide object as in pptx library
|
| 135 |
+
bullet_points: list(str), List of texts to be added as bullet points
|
| 136 |
+
coords: list(float), [left, top, width, height] in inches
|
| 137 |
+
font_size: int, Font size in int (point size), e.g., 18
|
| 138 |
+
color: tuple(int,int,int), RGB color, e.g., (0, 0, 0)
|
| 139 |
+
background_color: Optional, tuple(int,int,int), RGB color, e.g., (255, 255, 255)
|
| 140 |
+
Rets:
|
| 141 |
+
slide: Slide object with the bullet points added
|
| 142 |
+
"""
|
| 143 |
+
left, top, width, height = coords
|
| 144 |
+
text_box = slide.shapes.add_textbox(Inches(left), Inches(top), Inches(width), Inches(height))
|
| 145 |
+
# Set background color if provided
|
| 146 |
+
if background_color:
|
| 147 |
+
text_box.fill.solid()
|
| 148 |
+
text_box.fill.fore_color.rgb = RGBColor(*background_color)
|
| 149 |
+
else:
|
| 150 |
+
text_box.fill.background() # No fill if no color is specified
|
| 151 |
+
|
| 152 |
+
text_frame = text_box.text_frame
|
| 153 |
+
text_frame.word_wrap = True
|
| 154 |
+
text_frame.auto_size = MSO_AUTO_SIZE.TEXT_TO_FIT_SHAPE
|
| 155 |
+
|
| 156 |
+
for point in bullet_points:
|
| 157 |
+
p = text_frame.add_paragraph()
|
| 158 |
+
p.text = point
|
| 159 |
+
p.font.size = Pt(font_size)
|
| 160 |
+
p.font.color.rgb = RGBColor(*color)
|
| 161 |
+
# p.level = bullet_points.index(point)
|
| 162 |
+
|
| 163 |
+
return slide
|
| 164 |
+
|
| 165 |
+
|
| 166 |
+
def add_image(slide, image_path: str, coords: list[float]):
|
| 167 |
+
"""Add an image in the provided path to the specified coords and sizes.
|
| 168 |
+
Args:
|
| 169 |
+
slide: Slide object as in pptx library
|
| 170 |
+
image_path: str, Path to the image file
|
| 171 |
+
coords: list(float), [left, top, width, height] in inches
|
| 172 |
+
Rets:
|
| 173 |
+
slide: Slide object with the image added
|
| 174 |
+
"""
|
| 175 |
+
left, top, width, height = coords
|
| 176 |
+
slide.shapes.add_picture(image_path, Inches(left), Inches(top), Inches(width), Inches(height))
|
| 177 |
+
return slide
|
| 178 |
+
|
| 179 |
+
|
| 180 |
+
def set_background_color(slide, color: tuple[int, int, int]):
|
| 181 |
+
"""Set background color for the current slide.
|
| 182 |
+
Args:
|
| 183 |
+
slide: Slide object as in pptx library
|
| 184 |
+
color: tuple(int, int, int), RGB color, e.g., (255, 255, 255)
|
| 185 |
+
Returns:
|
| 186 |
+
modified slide object
|
| 187 |
+
"""
|
| 188 |
+
fill = slide.background.fill
|
| 189 |
+
fill.solid()
|
| 190 |
+
fill.fore_color.rgb = RGBColor(*color) # Convert tuple to RGBColor
|
| 191 |
+
return slide
|
SlidesLib/image_gen.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from openai import OpenAI
|
| 2 |
+
import requests
|
| 3 |
+
|
| 4 |
+
class Dalle3():
|
| 5 |
+
@classmethod
|
| 6 |
+
def __init_dalle__(cls):
|
| 7 |
+
client = OpenAI()
|
| 8 |
+
return client
|
| 9 |
+
|
| 10 |
+
@classmethod
|
| 11 |
+
def generate_image(cls, query: str, save_path: str = "downloaded_image.png"):
|
| 12 |
+
"""Generate an image based on a text query, save the image to the save_path"""
|
| 13 |
+
client = cls.__init_dalle__()
|
| 14 |
+
response = client.images.generate(
|
| 15 |
+
model="dall-e-3",
|
| 16 |
+
prompt=query,
|
| 17 |
+
size="1024x1024",
|
| 18 |
+
quality="standard",
|
| 19 |
+
n=1,
|
| 20 |
+
)
|
| 21 |
+
image_url = response.data[0].url
|
| 22 |
+
# Send a GET request to the URL
|
| 23 |
+
response = requests.get(image_url)
|
| 24 |
+
|
| 25 |
+
# Open a file in binary write mode and write the content of the response
|
| 26 |
+
with open(save_path, "wb") as file:
|
| 27 |
+
file.write(response.content)
|
| 28 |
+
return save_path
|
SlidesLib/llm.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from openai import OpenAI
|
| 2 |
+
import requests
|
| 3 |
+
|
| 4 |
+
class LLM():
|
| 5 |
+
"""Calls the LLM"""
|
| 6 |
+
@classmethod
|
| 7 |
+
def __init_llm__(cls):
|
| 8 |
+
client = OpenAI()
|
| 9 |
+
code_prompt = "Directly Generate executable python code for the following request:\n"
|
| 10 |
+
return client, code_prompt
|
| 11 |
+
@classmethod
|
| 12 |
+
def get_answer(cls, question: str):
|
| 13 |
+
"""Calls the LLM by inputing a question,
|
| 14 |
+
then get the response of the LLM as the answer"""
|
| 15 |
+
client, code_prompt = cls.__init_llm__()
|
| 16 |
+
response = client.chat.completions.create(
|
| 17 |
+
model="gpt-4o-mini",
|
| 18 |
+
messages=[
|
| 19 |
+
{"role": "system", "content": "You are a helpful assistant."},
|
| 20 |
+
{"role": "user", "content": question}
|
| 21 |
+
]
|
| 22 |
+
)
|
| 23 |
+
return response.choices[0].message.content
|
| 24 |
+
|
| 25 |
+
@classmethod
|
| 26 |
+
def get_code(cls, request:str, examples:str = ""):
|
| 27 |
+
"""
|
| 28 |
+
Calls the LLM to generate code for a request.
|
| 29 |
+
request: the task that the model should conduct
|
| 30 |
+
examples: few-shot code examples for the request
|
| 31 |
+
"""
|
| 32 |
+
client, code_prompt = cls.__init_llm__()
|
| 33 |
+
code = cls.get_answer(code_prompt + examples + request)
|
| 34 |
+
return code
|
SlidesLib/plotting.py
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Call Matplotlib Library to draw graphs (Bar/Plot...)
|
| 2 |
+
import matplotlib.pyplot as plt
|
| 3 |
+
from llm import *
|
| 4 |
+
class Plotting:
|
| 5 |
+
def bar_plot(self, data: dict, title: str, xlabel: str, ylabel: str, output_path: str = 'bar_plot.png'):
|
| 6 |
+
"""
|
| 7 |
+
Create a bar plot.
|
| 8 |
+
|
| 9 |
+
:param data: Dictionary containing data to plot (keys as labels, values as heights).
|
| 10 |
+
:param title: Title of the plot.
|
| 11 |
+
:param xlabel: Label for the X-axis.
|
| 12 |
+
:param ylabel: Label for the Y-axis.
|
| 13 |
+
:param output_path: Path to save the plot image.
|
| 14 |
+
"""
|
| 15 |
+
labels = list(data.keys())
|
| 16 |
+
heights = list(data.values())
|
| 17 |
+
|
| 18 |
+
plt.figure(figsize=(10, 6))
|
| 19 |
+
plt.bar(labels, heights, color='skyblue')
|
| 20 |
+
plt.title(title)
|
| 21 |
+
plt.xlabel(xlabel)
|
| 22 |
+
plt.ylabel(ylabel)
|
| 23 |
+
plt.tight_layout()
|
| 24 |
+
plt.savefig(output_path)
|
| 25 |
+
plt.close()
|
| 26 |
+
|
| 27 |
+
return output_path
|
| 28 |
+
|
| 29 |
+
def line_plot(self, data: dict, title: str, xlabel: str, ylabel: str, output_path: str = 'line_plot.png'):
|
| 30 |
+
"""
|
| 31 |
+
Create a line plot.
|
| 32 |
+
|
| 33 |
+
:param data: Dictionary containing data to plot (keys as x-values, values as y-values).
|
| 34 |
+
:param title: Title of the plot.
|
| 35 |
+
:param xlabel: Label for the X-axis.
|
| 36 |
+
:param ylabel: Label for the Y-axis.
|
| 37 |
+
:param output_path: Path to save the plot image.
|
| 38 |
+
"""
|
| 39 |
+
x_values = list(data.keys())
|
| 40 |
+
y_values = list(data.values())
|
| 41 |
+
|
| 42 |
+
plt.figure(figsize=(10, 6))
|
| 43 |
+
plt.plot(x_values, y_values, marker='o', color='skyblue')
|
| 44 |
+
plt.title(title)
|
| 45 |
+
plt.xlabel(xlabel)
|
| 46 |
+
plt.ylabel(ylabel)
|
| 47 |
+
plt.grid(True)
|
| 48 |
+
plt.tight_layout()
|
| 49 |
+
plt.savefig(output_path)
|
| 50 |
+
plt.close()
|
| 51 |
+
|
| 52 |
+
return output_path
|
| 53 |
+
|
| 54 |
+
def get_plot(self, data):
|
| 55 |
+
instruction = ""
|
| 56 |
+
|
SlidesLib/ppt_gen.py
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from pptx import Presentation
|
| 2 |
+
from pptx.util import Inches as _Inches, Pt as _Pt
|
| 3 |
+
from pptx.dml.color import RGBColor
|
| 4 |
+
from pptx.enum.text import PP_ALIGN, MSO_AUTO_SIZE
|
| 5 |
+
from pptx.enum.shapes import MSO_AUTO_SHAPE_TYPE, MSO_SHAPE_TYPE
|
| 6 |
+
from io import BytesIO
|
| 7 |
+
|
| 8 |
+
ARROW_ADD = '"""<a:tailEnd type="arrow" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"/>"""'
|
| 9 |
+
|
| 10 |
+
class SlideAgent:
|
| 11 |
+
def __init__(self, slide_width=13.33, slide_height=7.5):
|
| 12 |
+
"""Initialize a new presentation with specified slide dimensions in inches."""
|
| 13 |
+
self.prs = Presentation()
|
| 14 |
+
self.prs.slide_width = self._inches(slide_width)
|
| 15 |
+
self.prs.slide_height = self._inches(slide_height)
|
| 16 |
+
self.slide = None
|
| 17 |
+
|
| 18 |
+
def _inches(self, val):
|
| 19 |
+
"""Helper method to convert to Inches."""
|
| 20 |
+
return _Inches(val)
|
| 21 |
+
|
| 22 |
+
def _points(self, val):
|
| 23 |
+
"""Helper method to convert to Points."""
|
| 24 |
+
return _Pt(val)
|
| 25 |
+
|
| 26 |
+
# ------- Slide APIs -------
|
| 27 |
+
def add_slide(self, layout=0):
|
| 28 |
+
"""Create a new slide with a specific layout."""
|
| 29 |
+
slide_layout = self.prs.slide_layouts[layout]
|
| 30 |
+
self.slide = self.prs.slides.add_slide(slide_layout)
|
| 31 |
+
|
| 32 |
+
# ------- Text APIs -------
|
| 33 |
+
def add_title(self, text, font_size=44, font_color=(0, 0, 0)):
|
| 34 |
+
"""Add a title to the slide with a custom font size (in points) and font color (RGB tuple)."""
|
| 35 |
+
title_shape = self.slide.shapes.title
|
| 36 |
+
title_shape.text = text
|
| 37 |
+
self._format_text(title_shape.text_frame, self._points(font_size), RGBColor(*font_color))
|
| 38 |
+
|
| 39 |
+
def add_text(self, text, top, left, width, height, font_size=20, bold=False, color=(0, 0, 0), background_color=None, auto_size=True):
|
| 40 |
+
"""Add a text box at a specified location with custom text settings and optional background color."""
|
| 41 |
+
# Create the text box shape
|
| 42 |
+
text_box = self.slide.shapes.add_textbox(self._inches(left), self._inches(top), self._inches(width), self._inches(height))
|
| 43 |
+
|
| 44 |
+
# Set background color if provided
|
| 45 |
+
if background_color:
|
| 46 |
+
text_box.fill.solid()
|
| 47 |
+
text_box.fill.fore_color.rgb = RGBColor(*background_color)
|
| 48 |
+
else:
|
| 49 |
+
text_box.fill.background() # No fill if no color is specified
|
| 50 |
+
|
| 51 |
+
# Handle line breaks and adjust height
|
| 52 |
+
lines = text.split("\n")
|
| 53 |
+
adjusted_height = height * len(lines) # Adjust height based on the number of lines
|
| 54 |
+
text_box.height = self._inches(adjusted_height)
|
| 55 |
+
|
| 56 |
+
# Set text and format it
|
| 57 |
+
text_frame = text_box.text_frame
|
| 58 |
+
text_frame.word_wrap = True
|
| 59 |
+
if auto_size:
|
| 60 |
+
text_frame.auto_size = MSO_AUTO_SIZE.SHAPE_TO_FIT_TEXT # Automatically fit the text box to the text
|
| 61 |
+
self._format_paragraph(text_frame, text, self._points(font_size), bold, RGBColor(*color))
|
| 62 |
+
|
| 63 |
+
def add_bullet_points(self, bullet_points, top, left, width, height, font_size=18, color=(0, 0, 0)):
|
| 64 |
+
"""Add a text box with bullet points."""
|
| 65 |
+
text_box = self.slide.shapes.add_textbox(self._inches(left), self._inches(top), self._inches(width), self._inches(height))
|
| 66 |
+
text_frame = text_box.text_frame
|
| 67 |
+
text_frame.word_wrap = True
|
| 68 |
+
text_frame.auto_size = MSO_AUTO_SIZE.TEXT_TO_FIT_SHAPE
|
| 69 |
+
|
| 70 |
+
for point in bullet_points:
|
| 71 |
+
p = text_frame.add_paragraph()
|
| 72 |
+
p.text = point
|
| 73 |
+
self._format_text(p, self._points(font_size), RGBColor(*color))
|
| 74 |
+
p.level = bullet_points.index(point)
|
| 75 |
+
|
| 76 |
+
# ------- Image APIs -------
|
| 77 |
+
def add_image(self, image_path, top, left, width, height):
|
| 78 |
+
"""Add an image at a specified location."""
|
| 79 |
+
self.slide.shapes.add_picture(image_path, self._inches(left), self._inches(top), self._inches(width), self._inches(height))
|
| 80 |
+
|
| 81 |
+
def add_image_centered(self, image_path, image_width, image_height):
|
| 82 |
+
"""Add an image centered on the slide."""
|
| 83 |
+
slide_width = self.prs.slide_width.inches
|
| 84 |
+
slide_height = self.prs.slide_height.inches
|
| 85 |
+
left = (slide_width - image_width) / 2
|
| 86 |
+
top = (slide_height - image_height) / 2
|
| 87 |
+
self.add_image(image_path, top, left, image_width, image_height)
|
| 88 |
+
|
| 89 |
+
# ------- Shape APIs -------
|
| 90 |
+
def add_shape(self, shape_type, top, left, width, height, fill_color=None):
|
| 91 |
+
"""Add a shape to the slide, supporting MSO_AUTO_SHAPE_TYPE."""
|
| 92 |
+
if isinstance(shape_type, str):
|
| 93 |
+
# Check if the shape type is a valid string, otherwise raise an error
|
| 94 |
+
try:
|
| 95 |
+
shape_type = getattr(MSO_AUTO_SHAPE_TYPE, shape_type.upper())
|
| 96 |
+
except AttributeError:
|
| 97 |
+
raise ValueError(f"Invalid shape type: {shape_type}. Must be a valid MSO_AUTO_SHAPE_TYPE.")
|
| 98 |
+
|
| 99 |
+
# Now create the shape with the validated or passed enum type
|
| 100 |
+
shape = self.slide.shapes.add_shape(shape_type, self._inches(left), self._inches(top), self._inches(width), self._inches(height))
|
| 101 |
+
|
| 102 |
+
if fill_color:
|
| 103 |
+
shape.fill.solid()
|
| 104 |
+
shape.fill.fore_color.rgb = RGBColor(*fill_color)
|
| 105 |
+
|
| 106 |
+
def add_straight_arrow(self, start_x, start_y, end_x, end_y):
|
| 107 |
+
connector = self.slide.shapes.add_connector("MSO_CONNECTOR.STRAIGHT", start_x, start_y, end_x, end_y)
|
| 108 |
+
|
| 109 |
+
|
| 110 |
+
def add_straight_line(self, start_x, start_y, end_x, end_y):
|
| 111 |
+
connector = self.slide.shapes.add_connector("MSO_CONNECTOR.STRAIGHT", start_x, start_y, end_x, end_y)
|
| 112 |
+
line_elem = connector.line._get_or_add_ln()
|
| 113 |
+
line_elem.append(parse_xml({ARROW_ADD}))
|
| 114 |
+
|
| 115 |
+
# ------- Table APIs -------
|
| 116 |
+
def add_table(self, rows, cols, top, left, width, height, column_widths=None):
|
| 117 |
+
"""Add a table to the slide."""
|
| 118 |
+
table = self.slide.shapes.add_table(rows, cols, left, top, width, height).table
|
| 119 |
+
if column_widths:
|
| 120 |
+
for idx, col_width in enumerate(column_widths):
|
| 121 |
+
table.columns[idx].width = Inches(col_width)
|
| 122 |
+
return table
|
| 123 |
+
|
| 124 |
+
# ------- Helper APIs -------
|
| 125 |
+
def set_background_color(self, color):
|
| 126 |
+
"""Set background color for the current slide."""
|
| 127 |
+
background = self.slide.background
|
| 128 |
+
fill = background.fill
|
| 129 |
+
fill.solid()
|
| 130 |
+
fill.fore_color.rgb = color
|
| 131 |
+
|
| 132 |
+
def duplicate_slide(self, slide_index):
|
| 133 |
+
"""Duplicate a slide by index."""
|
| 134 |
+
template_slide = self.prs.slides[slide_index]
|
| 135 |
+
new_slide = self.prs.slides.add_slide(template_slide.slide_layout)
|
| 136 |
+
for shape in template_slide.shapes:
|
| 137 |
+
self._copy_shape(shape, new_slide)
|
| 138 |
+
|
| 139 |
+
def save_presentation(self, file_name):
|
| 140 |
+
"""Save the PowerPoint presentation."""
|
| 141 |
+
self.prs.save(file_name)
|
| 142 |
+
|
| 143 |
+
# ------- Internal Helper Methods -------
|
| 144 |
+
def _format_paragraph(self, text_frame, text, font_size, bold, color):
|
| 145 |
+
"""Helper function to format text within a text frame."""
|
| 146 |
+
p = text_frame.add_paragraph()
|
| 147 |
+
p.text = text
|
| 148 |
+
p.font.size = font_size
|
| 149 |
+
p.font.bold = bold
|
| 150 |
+
p.font.color.rgb = color
|
| 151 |
+
|
| 152 |
+
def _format_text(self, text_frame, font_size, font_color):
|
| 153 |
+
"""Helper function to format text in a text frame."""
|
| 154 |
+
for paragraph in text_frame.paragraphs:
|
| 155 |
+
paragraph.font.size = font_size
|
| 156 |
+
paragraph.font.color.rgb = font_color
|
| 157 |
+
|
| 158 |
+
def _copy_shape(self, shape, slide):
|
| 159 |
+
"""Copy a shape from one slide to another."""
|
| 160 |
+
if shape.shape_type == MSO_SHAPE_TYPE.PICTURE:
|
| 161 |
+
image = BytesIO(shape.image.blob)
|
| 162 |
+
slide.shapes.add_picture(image, shape.left, shape.top, shape.width, shape.height)
|
| 163 |
+
elif shape.has_text_frame:
|
| 164 |
+
new_shape = slide.shapes.add_textbox(shape.left, shape.top, shape.width, shape.height)
|
| 165 |
+
new_shape.text = shape.text
|
| 166 |
+
self._format_text(new_shape.text_frame, shape.text_frame.paragraphs[0].font.size, shape.text_frame.paragraphs[0].font.color.rgb)
|
| 167 |
+
|
| 168 |
+
|
| 169 |
+
|
| 170 |
+
|
| 171 |
+
|
| 172 |
+
|
| 173 |
+
|
SlidesLib/search.py
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from selenium import webdriver
|
| 2 |
+
from selenium.webdriver.chrome.service import Service
|
| 3 |
+
from selenium.webdriver.chrome.options import Options
|
| 4 |
+
from chromedriver_py import binary_path
|
| 5 |
+
from selenium.webdriver.common.by import By
|
| 6 |
+
from selenium.webdriver.support.ui import WebDriverWait
|
| 7 |
+
from selenium.webdriver.support import expected_conditions as EC
|
| 8 |
+
import time
|
| 9 |
+
import requests
|
| 10 |
+
from selenium.webdriver.common.keys import Keys
|
| 11 |
+
from google_images_download import google_images_download
|
| 12 |
+
from bing_image_downloader import downloader
|
| 13 |
+
import os
|
| 14 |
+
import shutil
|
| 15 |
+
class GoogleSearch:
|
| 16 |
+
@classmethod
|
| 17 |
+
def _init_driver(cls):
|
| 18 |
+
chrome_options = Options()
|
| 19 |
+
chrome_options.add_argument("--headless")
|
| 20 |
+
chrome_options.add_argument("--disable-gpu")
|
| 21 |
+
chrome_options.add_argument("--no-sandbox")
|
| 22 |
+
chrome_options.add_argument("--disable-dev-shm-usage")
|
| 23 |
+
service = Service(binary_path)
|
| 24 |
+
driver = webdriver.Chrome(service=service, options=chrome_options)
|
| 25 |
+
wait = WebDriverWait(driver, 100)
|
| 26 |
+
return driver, wait
|
| 27 |
+
|
| 28 |
+
@classmethod
|
| 29 |
+
def search_result(cls, question: str, screenshot_path: str = "screenshot.png") -> str:
|
| 30 |
+
"""Search a question on Google and return a screenshot of the search result."""
|
| 31 |
+
driver, wait = cls._init_driver()
|
| 32 |
+
|
| 33 |
+
if not question:
|
| 34 |
+
raise ValueError("Please provide a question")
|
| 35 |
+
|
| 36 |
+
# Perform Google search
|
| 37 |
+
search_url = f"https://www.google.com/search?q={question}"
|
| 38 |
+
driver.get(search_url)
|
| 39 |
+
|
| 40 |
+
# Give some time for the page to load
|
| 41 |
+
time.sleep(3)
|
| 42 |
+
|
| 43 |
+
# Take a screenshot
|
| 44 |
+
driver.save_screenshot(screenshot_path)
|
| 45 |
+
|
| 46 |
+
driver.quit()
|
| 47 |
+
return screenshot_path
|
| 48 |
+
|
| 49 |
+
@classmethod
|
| 50 |
+
def search_image_org(cls, query: str, download_path: str = 'top_image.png') -> str:
|
| 51 |
+
"""Search for an image on Google and download the top result."""
|
| 52 |
+
driver, wait = cls._init_driver()
|
| 53 |
+
|
| 54 |
+
if not query:
|
| 55 |
+
raise ValueError("Please provide a query")
|
| 56 |
+
|
| 57 |
+
# Perform Google image search
|
| 58 |
+
search_url = f"https://www.google.com/search?tbm=isch&q={query}"
|
| 59 |
+
driver.get(search_url)
|
| 60 |
+
|
| 61 |
+
# Find all image elements
|
| 62 |
+
image_elements = driver.find_elements(By.CSS_SELECTOR, "img")
|
| 63 |
+
|
| 64 |
+
# Filter out Google icon images and get the first valid image URL
|
| 65 |
+
image_url = None
|
| 66 |
+
for img in image_elements:
|
| 67 |
+
src = img.get_attribute("src")
|
| 68 |
+
if src and "googlelogo" not in src:
|
| 69 |
+
image_url = src
|
| 70 |
+
try:
|
| 71 |
+
response = requests.get(image_url)
|
| 72 |
+
with open(download_path, 'wb') as file:
|
| 73 |
+
file.write(response.content)
|
| 74 |
+
|
| 75 |
+
driver.quit()
|
| 76 |
+
print(image_url)
|
| 77 |
+
return download_path
|
| 78 |
+
except Exception:
|
| 79 |
+
print("Error downloading image, skipping.")
|
| 80 |
+
continue
|
| 81 |
+
|
| 82 |
+
driver.quit()
|
| 83 |
+
raise Exception("No valid image found")
|
| 84 |
+
|
| 85 |
+
@classmethod
|
| 86 |
+
def search_image_prev(cls, query, output_dir='./downloads', limit=10):
|
| 87 |
+
# Download images using Bing Image Downloader
|
| 88 |
+
downloader.download(query, limit=limit, output_dir=output_dir, adult_filter_off=True, force_replace=False, timeout=60)
|
| 89 |
+
# List the files in the output directory
|
| 90 |
+
image_dir = os.path.join(output_dir, query)
|
| 91 |
+
if not os.path.exists(image_dir):
|
| 92 |
+
raise FileNotFoundError(f"No images found for query '{query}' in directory '{output_dir}'")
|
| 93 |
+
|
| 94 |
+
# Collect all image paths
|
| 95 |
+
image_paths = [os.path.join(image_dir, file) for file in os.listdir(image_dir) if file.endswith(('jpg', 'jpeg', 'png'))]
|
| 96 |
+
|
| 97 |
+
# Return the first image
|
| 98 |
+
return image_paths[0]
|
| 99 |
+
|
| 100 |
+
@classmethod
|
| 101 |
+
def search_image_prev(cls, query, output_dir='./downloads', limit=10):
|
| 102 |
+
# Download images using Bing Image Downloader
|
| 103 |
+
downloader.download(query, limit=limit, output_dir=output_dir, adult_filter_off=True, force_replace=False, timeout=60)
|
| 104 |
+
# List the files in the output directory
|
| 105 |
+
image_dir = os.path.join(output_dir, query)
|
| 106 |
+
if not os.path.exists(image_dir):
|
| 107 |
+
raise FileNotFoundError(f"No images found for query '{query}' in directory '{output_dir}'")
|
| 108 |
+
|
| 109 |
+
# Collect all image paths
|
| 110 |
+
image_paths = [os.path.join(image_dir, file) for file in os.listdir(image_dir) if file.endswith(('jpg', 'jpeg', 'png'))]
|
| 111 |
+
|
| 112 |
+
# Return the first image
|
| 113 |
+
return image_paths[0]
|
| 114 |
+
|
| 115 |
+
@classmethod
|
| 116 |
+
def search_image(cls, query, save_path):
|
| 117 |
+
"""
|
| 118 |
+
Search for an image based on the query and save the result to the specified path.
|
| 119 |
+
|
| 120 |
+
Args:
|
| 121 |
+
query (str): The query to search for.
|
| 122 |
+
save_path (str): The path to save the downloaded image.
|
| 123 |
+
|
| 124 |
+
Returns:
|
| 125 |
+
str: The path where the image was saved.
|
| 126 |
+
"""
|
| 127 |
+
# Create a temporary directory for storing downloaded images
|
| 128 |
+
temp_dir = "./temp_download"
|
| 129 |
+
os.makedirs(temp_dir, exist_ok=True)
|
| 130 |
+
|
| 131 |
+
# Download only the top image result
|
| 132 |
+
downloader.download(query, limit=1, output_dir=temp_dir, adult_filter_off=True, force_replace=True, timeout=60)
|
| 133 |
+
|
| 134 |
+
# Construct the expected directory and image path
|
| 135 |
+
image_dir = os.path.join(temp_dir, query)
|
| 136 |
+
image_files = [file for file in os.listdir(image_dir) if file.endswith(('jpg', 'jpeg', 'png'))]
|
| 137 |
+
|
| 138 |
+
# Check if any image files were downloaded
|
| 139 |
+
if not image_files:
|
| 140 |
+
raise FileNotFoundError(f"No images found for query '{query}'.")
|
| 141 |
+
|
| 142 |
+
# Copy the top image to the desired save path
|
| 143 |
+
top_image_path = os.path.join(image_dir, image_files[0])
|
| 144 |
+
shutil.move(top_image_path, save_path)
|
| 145 |
+
|
| 146 |
+
# Clean up temporary directory
|
| 147 |
+
shutil.rmtree(temp_dir)
|
| 148 |
+
|
| 149 |
+
return save_path
|
SlidesLib/vqa.py
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from transformers import BlipProcessor, BlipForQuestionAnswering
|
| 2 |
+
from PIL import Image
|
| 3 |
+
import requests
|
| 4 |
+
import re
|
| 5 |
+
class VQA:
|
| 6 |
+
def __init__(self, gpu_number=0):
|
| 7 |
+
use_load_8bit= False
|
| 8 |
+
from transformers import AutoProcessor, InstructBlipForConditionalGeneration, InstructBlipProcessor
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
self.model = InstructBlipForConditionalGeneration.from_pretrained("Salesforce/instructblip-vicuna-7b", device_map="auto")
|
| 12 |
+
self.processor = InstructBlipProcessor.from_pretrained("Salesforce/instructblip-vicuna-7b")
|
| 13 |
+
|
| 14 |
+
self.model.eval()
|
| 15 |
+
self.qa_prompt = "Question: {} Short answer:"
|
| 16 |
+
self.caption_prompt = "\n<image>\na photo of"
|
| 17 |
+
self.max_words = 50
|
| 18 |
+
|
| 19 |
+
def pre_question(self, question):
|
| 20 |
+
# from LAVIS blip_processors
|
| 21 |
+
question = re.sub(
|
| 22 |
+
r"([.!\"()*#:;~])",
|
| 23 |
+
"",
|
| 24 |
+
question.lower(),
|
| 25 |
+
)
|
| 26 |
+
question = question.rstrip(" ")
|
| 27 |
+
|
| 28 |
+
# truncate question
|
| 29 |
+
question_words = question.split(" ")
|
| 30 |
+
if len(question_words) > self.max_words:
|
| 31 |
+
question = " ".join(question_words[: self.max_words])
|
| 32 |
+
|
| 33 |
+
return question
|
| 34 |
+
|
| 35 |
+
def qa(self, image_path, question):
|
| 36 |
+
image = Image.open(image_path)
|
| 37 |
+
question = self.pre_question(question)
|
| 38 |
+
inputs = self.processor(images=image, text=question, return_tensors="pt", padding="longest").to(self.model.device)
|
| 39 |
+
generated_ids = self.model.generate(**inputs, length_penalty=-1, num_beams=5, max_length=30, min_length=1,
|
| 40 |
+
do_sample=False, top_p=0.9, repetition_penalty=1.0,
|
| 41 |
+
num_return_sequences=1, temperature=1)
|
| 42 |
+
generated_text = self.processor.batch_decode(generated_ids, skip_special_tokens=True)
|
| 43 |
+
|
| 44 |
+
return generated_text[0]
|
requirements.txt
CHANGED
|
@@ -4,5 +4,4 @@ openai
|
|
| 4 |
python-pptx
|
| 5 |
numpy
|
| 6 |
colormath
|
| 7 |
-
scipy
|
| 8 |
-
-e ./SlidesAgent
|
|
|
|
| 4 |
python-pptx
|
| 5 |
numpy
|
| 6 |
colormath
|
| 7 |
+
scipy
|
|
|