Spaces:
Sleeping
Sleeping
Update src/pyscripts/img_process.py
Browse files- src/pyscripts/img_process.py +168 -964
src/pyscripts/img_process.py
CHANGED
|
@@ -1,975 +1,179 @@
|
|
| 1 |
-
from
|
| 2 |
-
import
|
|
|
|
|
|
|
| 3 |
import os
|
| 4 |
-
|
| 5 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
import requests
|
| 7 |
-
from
|
| 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 |
-
for line in wrapped_lines:
|
| 107 |
-
text_bbox = font.getbbox(line)
|
| 108 |
-
line_width = text_bbox[2] - text_bbox[0] # 获取宽度
|
| 109 |
-
line_height = max(text_bbox[3] - text_bbox[1], text_bbox_chinese[3] - text_bbox_chinese[1])
|
| 110 |
-
# print(text_bbox[3] - text_bbox[1], text_bbox_chinese[3] - text_bbox_chinese[1], text_info.font_size)
|
| 111 |
-
if re.search(r"^【.*】.*?" + re.escape(line), text_info.text, re.M) or re.match(r"^【.*】.*?$", line):
|
| 112 |
-
draw.text((text_info.position[0], y_text), line.replace("【】", ""), fill=text_info.color, font=em_font)
|
| 113 |
-
else:
|
| 114 |
-
draw.text((text_info.position[0], y_text), line, fill=text_info.color, font=font)
|
| 115 |
-
# 更新y坐标以添加行间距并为下一行做准备
|
| 116 |
-
y_text += line_height # + text_info.line_space
|
| 117 |
-
return img, y_text
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
def embed_image(background, foreground, offset_y=0, offset_x=None, standard_fg_size=None):
|
| 121 |
-
"""
|
| 122 |
-
粘贴图片
|
| 123 |
-
|
| 124 |
-
Args:
|
| 125 |
-
background (_type_): 背景图片
|
| 126 |
-
foreground (_type_): 前景图片
|
| 127 |
-
offset_y (int, optional): 纵向偏移. Defaults to 1500.
|
| 128 |
-
standard_fg_size (tuple, optional): 前景缩放大小. Defaults to (1600, 450).
|
| 129 |
-
|
| 130 |
-
Returns:
|
| 131 |
-
_type_: _description_
|
| 132 |
-
"""
|
| 133 |
-
# 获取背景图片的尺寸
|
| 134 |
-
if standard_fg_size is None:
|
| 135 |
-
standard_fg_size = foreground.size
|
| 136 |
-
standard_fg_width, standard_fg_height = standard_fg_size
|
| 137 |
-
bg_width, bg_height = background.size
|
| 138 |
-
fg_width, fg_height = foreground.size
|
| 139 |
-
fg_resize_percent = max(fg_width / standard_fg_width, fg_height / standard_fg_height)
|
| 140 |
-
# print((fg_width / standard_fg_width, fg_height / standard_fg_height))
|
| 141 |
-
foreground = foreground.resize((int(fg_width // fg_resize_percent), int(fg_height // fg_resize_percent)))
|
| 142 |
-
fg_width, fg_height = foreground.size
|
| 143 |
-
if offset_x is None:
|
| 144 |
-
offset_x = (bg_width - fg_width) // 2 # 横轴偏移使小图居中
|
| 145 |
-
|
| 146 |
-
background.paste(foreground, (int(offset_x), int(offset_y)), foreground)
|
| 147 |
-
return background
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
img_path_dict = {
|
| 151 |
-
"old": "src/assets/InvitationTemplateCompressed.pdf",
|
| 152 |
-
"common": "src/assets/旧空白邀请函图片.jpg",
|
| 153 |
-
"观礼": "src/assets/带名字.jpg",
|
| 154 |
-
"演讲": "src/assets/带名字和会.jpg",
|
| 155 |
-
"致辞": "src/assets/带名字和会.jpg",
|
| 156 |
-
}
|
| 157 |
-
font_path = "src/assets/ZhouZiSongTi7000Zi-2.otf"
|
| 158 |
-
font_path = "src/assets/FangZhengHeiTiJianTi-1.ttf"
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
def writeInvitationPDF(person, debug=False):
|
| 162 |
-
"旧空白邀请函图片.jpg"
|
| 163 |
-
font_size = 40
|
| 164 |
-
resized_name_font_size = font_size * 5 / len(person.name + person.title)
|
| 165 |
-
resized_conference_font_size = font_size * 9 / len(person.conference)
|
| 166 |
-
img_path = img_path_dict[person.category]
|
| 167 |
-
image = Image.open(img_path)
|
| 168 |
-
draw = ImageDraw.Draw(image)
|
| 169 |
-
text_color = (255, 255, 255) # 白色 RGB
|
| 170 |
-
|
| 171 |
-
draw.text(
|
| 172 |
-
(182, 150 + max(0, font_size - resized_name_font_size)),
|
| 173 |
-
person.name + person.title,
|
| 174 |
-
fill=text_color,
|
| 175 |
-
font=ImageFont.truetype(font_path, min(font_size, resized_name_font_size)),
|
| 176 |
-
)
|
| 177 |
-
draw.text(
|
| 178 |
-
(102, 532 + max(0, font_size - resized_conference_font_size)),
|
| 179 |
-
person.conference,
|
| 180 |
-
fill=text_color,
|
| 181 |
-
font=ImageFont.truetype(font_path, min(font_size, resized_conference_font_size)),
|
| 182 |
-
)
|
| 183 |
-
imgStream = io.BytesIO()
|
| 184 |
-
# image.save(imgStream)
|
| 185 |
-
# doc.save(pdfStream)
|
| 186 |
-
# doc.close()
|
| 187 |
-
if debug:
|
| 188 |
-
image.save("output/image_with_text.jpg")
|
| 189 |
-
|
| 190 |
-
return imgStream
|
| 191 |
-
|
| 192 |
-
|
| 193 |
-
def write_text(
|
| 194 |
-
text, font_path, image, H_PADDING_RATION, font_size, max_height=None, color=(255, 255, 255), em_font_path=None, alignment="left",
|
| 195 |
-
start_y=0, start_x=0, max_width=None, part_width=10000
|
| 196 |
-
):
|
| 197 |
-
bg_width = image.size[0]
|
| 198 |
-
if max_width is None:
|
| 199 |
-
max_width = bg_width * (1 - 2 * H_PADDING_RATION)
|
| 200 |
-
if max_height is None:
|
| 201 |
-
max_height = font_size * len(text.split("\n"))
|
| 202 |
-
text = text_info(
|
| 203 |
-
text=text,
|
| 204 |
-
font_size=font_size,
|
| 205 |
-
position=[start_x, start_y],
|
| 206 |
-
color=color,
|
| 207 |
-
max_width=max_width,
|
| 208 |
-
max_height=max_height,
|
| 209 |
-
font_path=font_path,
|
| 210 |
-
em_font_path=em_font_path,
|
| 211 |
-
)
|
| 212 |
-
if alignment == "right":
|
| 213 |
-
text.position[0] = bg_width * (1 - H_PADDING_RATION) - text.text_width
|
| 214 |
-
elif alignment == "medium":
|
| 215 |
-
text.position[0] = (min(part_width, bg_width) - text.text_width) // 2 + start_x
|
| 216 |
-
elif alignment == "left":
|
| 217 |
-
text.position[0] = bg_width * H_PADDING_RATION
|
| 218 |
-
print(text)
|
| 219 |
-
image, next_height = write_text_on_image(image, text)
|
| 220 |
-
return text, image, next_height
|
| 221 |
-
|
| 222 |
-
|
| 223 |
-
def make_exhibitor_poster(logo_link, slogan, content):
|
| 224 |
-
background = Image.open("src/assets/展商海报白板.jpg")
|
| 225 |
-
H_PADDING_RATION = 0.08
|
| 226 |
-
V_PADDING = 25
|
| 227 |
-
V_START = 950
|
| 228 |
-
MAX_HEIGHT = 520
|
| 229 |
-
res = requests.get(logo_link)
|
| 230 |
-
foreground = Image.open(io.BytesIO(res.content))
|
| 231 |
-
# foreground = Image.open(logo_path_list[FOREGROUND_ID])
|
| 232 |
-
background = embed_image(background, foreground, offset_y=750, standard_fg_size=(1600 // 2, 450 // 2))
|
| 233 |
-
|
| 234 |
-
text = slogan
|
| 235 |
-
font_size = 110 // 2
|
| 236 |
-
font_path = font_path_fangzhenghei
|
| 237 |
-
slogan, background, next_height = write_text(
|
| 238 |
-
text,
|
| 239 |
-
font_path,
|
| 240 |
-
background,
|
| 241 |
-
H_PADDING_RATION,
|
| 242 |
-
font_size,
|
| 243 |
-
color=(0, 0, 0),
|
| 244 |
-
alignment="medium",
|
| 245 |
-
start_y=V_START,
|
| 246 |
-
)
|
| 247 |
-
|
| 248 |
-
content, background, next_height = write_text(
|
| 249 |
-
content,
|
| 250 |
-
font_path_SourceHanSans,
|
| 251 |
-
background,
|
| 252 |
-
H_PADDING_RATION,
|
| 253 |
-
100,
|
| 254 |
-
max_height=MAX_HEIGHT,
|
| 255 |
-
color=(0, 0, 0),
|
| 256 |
-
em_font_path=font_path_fangzhenghei,
|
| 257 |
-
alignment="left",
|
| 258 |
-
start_y=next_height + V_PADDING,
|
| 259 |
-
)
|
| 260 |
-
|
| 261 |
-
img_stream = io.BytesIO()
|
| 262 |
-
background.save(img_stream, format="JPEG")
|
| 263 |
-
img_stream.seek(0)
|
| 264 |
-
background.save("output/展商海报.jpg")
|
| 265 |
-
return img_stream
|
| 266 |
-
|
| 267 |
-
|
| 268 |
-
def cut_image_blank(image):
|
| 269 |
-
# 获取图片的宽度和高度
|
| 270 |
-
width, height = image.size
|
| 271 |
-
# 初始化边界框
|
| 272 |
-
left = width
|
| 273 |
-
top = height
|
| 274 |
-
right = 0
|
| 275 |
-
bottom = 0
|
| 276 |
-
# 遍历图片的每个像素,找到非透明的区域
|
| 277 |
-
for x in range(width):
|
| 278 |
-
for y in range(height):
|
| 279 |
-
pixel = image.getpixel((x, y))
|
| 280 |
-
if pixel[3] != 0: # 检查透明度通道
|
| 281 |
-
if x < left:
|
| 282 |
-
left = x
|
| 283 |
-
if x > right:
|
| 284 |
-
right = x
|
| 285 |
-
if y < top:
|
| 286 |
-
top = y
|
| 287 |
-
if y > bottom:
|
| 288 |
-
bottom = y
|
| 289 |
-
if right < left or bottom < top:
|
| 290 |
-
return image
|
| 291 |
-
cropped_image = image.crop((left, top, right + 1, bottom + 1))
|
| 292 |
-
return cropped_image
|
| 293 |
-
|
| 294 |
-
|
| 295 |
-
def rm_img_bg(image):
|
| 296 |
-
image = rembg.remove(image)
|
| 297 |
-
cropped_image = cut_image_blank(image)
|
| 298 |
-
return cropped_image
|
| 299 |
-
|
| 300 |
-
|
| 301 |
-
def compose_guest_poster(name, name_pinyin, guest_photo, titles):
|
| 302 |
-
|
| 303 |
-
background = Image.open("src/assets/Guest04.jpg").convert("RGBA")
|
| 304 |
-
background = background.resize((1080 * 2, 2400 * 2))
|
| 305 |
-
|
| 306 |
-
title_list = titles.split("\n")
|
| 307 |
-
# guest = Image.open("src/assets/Guest.png").convert("RGBA")
|
| 308 |
-
# higher_mask = Image.open("src/assets/Guest01.png").convert("RGBA")
|
| 309 |
-
H_PADDING_RATION = 0.08
|
| 310 |
-
V_PADDING = 5
|
| 311 |
-
V_START = 3020
|
| 312 |
-
bg_width, bg_height = background.size
|
| 313 |
-
background = embed_image(background, guest_photo, offset_y=1300, standard_fg_size=(2160, 2600))
|
| 314 |
-
lower_mask = Image.open("src/assets/Guest03.png").convert("RGBA")
|
| 315 |
-
background = embed_image(background, lower_mask, standard_fg_size=background.size)
|
| 316 |
-
higher_mask = Image.open("src/assets/Guest02.png").convert("RGBA")
|
| 317 |
-
background = embed_image(background, higher_mask, standard_fg_size=background.size)
|
| 318 |
-
seal = Image.open("src/assets/Guest01.png").convert("RGBA")
|
| 319 |
-
background = embed_image(background, seal, standard_fg_size=background.size)
|
| 320 |
-
# background = background.convert("RGB")
|
| 321 |
-
|
| 322 |
-
font_size = 210
|
| 323 |
-
font_path = font_path_zihun59
|
| 324 |
-
text = name
|
| 325 |
-
name, background, next_height = write_text(
|
| 326 |
-
text,
|
| 327 |
-
font_path,
|
| 328 |
-
background,
|
| 329 |
-
H_PADDING_RATION,
|
| 330 |
-
font_size,
|
| 331 |
-
alignment="right",
|
| 332 |
-
start_y=V_START,
|
| 333 |
-
)
|
| 334 |
-
|
| 335 |
-
next_height += 50
|
| 336 |
-
font_size = 100
|
| 337 |
-
font_path = font_path_notosans
|
| 338 |
-
if name_pinyin == "":
|
| 339 |
-
pinyin_list = pinyin(name.text, style=Style.NORMAL)
|
| 340 |
-
name_pinyin = (pinyin_list[0][0] + " " + "".join([item[0] for item in pinyin_list[1:]])).title()
|
| 341 |
-
text = name_pinyin
|
| 342 |
-
name_pinyin, background, next_height = write_text(
|
| 343 |
-
text,
|
| 344 |
-
font_path,
|
| 345 |
-
background,
|
| 346 |
-
H_PADDING_RATION,
|
| 347 |
-
font_size,
|
| 348 |
-
alignment="right",
|
| 349 |
-
start_y=next_height + V_PADDING,
|
| 350 |
-
)
|
| 351 |
-
|
| 352 |
-
next_height += 100
|
| 353 |
-
font_size = 70
|
| 354 |
-
font_path = font_path_notosans
|
| 355 |
-
for title in title_list:
|
| 356 |
-
text = title
|
| 357 |
-
title, background, next_height = write_text(
|
| 358 |
-
text,
|
| 359 |
-
font_path,
|
| 360 |
-
background,
|
| 361 |
-
H_PADDING_RATION,
|
| 362 |
-
font_size,
|
| 363 |
-
alignment="right",
|
| 364 |
-
start_y=next_height + V_PADDING,
|
| 365 |
-
)
|
| 366 |
-
background = background.convert("RGB")
|
| 367 |
-
img_stream = io.BytesIO()
|
| 368 |
-
background.save(img_stream, format="JPEG")
|
| 369 |
-
img_stream.seek(0)
|
| 370 |
-
if os.path.exists("src/assets/output"):
|
| 371 |
-
background.save("src/assets/output/嘉宾海报.jpg")
|
| 372 |
-
return img_stream
|
| 373 |
-
|
| 374 |
-
|
| 375 |
-
def make_guest_poster(name, name_pinyin, photo_link, original_photo_link, titles):
|
| 376 |
-
if photo_link != "":
|
| 377 |
-
res = requests.get(photo_link)
|
| 378 |
-
guest_photo = Image.open(io.BytesIO(res.content)).convert("RGBA")
|
| 379 |
-
elif original_photo_link != "":
|
| 380 |
-
res = requests.get(original_photo_link)
|
| 381 |
-
original_guest_photo = Image.open(io.BytesIO(res.content))
|
| 382 |
-
guest_photo = rm_img_bg(original_guest_photo)
|
| 383 |
-
if os.path.exists("src/assets/output"):
|
| 384 |
-
guest_photo.save("src/assets/output/rmbg.png")
|
| 385 |
-
else:
|
| 386 |
-
return None
|
| 387 |
-
img_stream = compose_guest_poster(name, name_pinyin, guest_photo, titles)
|
| 388 |
-
return img_stream
|
| 389 |
-
|
| 390 |
-
|
| 391 |
-
def crop_round_img(image, circle_center, circle_radius):
|
| 392 |
-
mask = Image.new("L", image.size, 0)
|
| 393 |
-
draw = ImageDraw.Draw(mask)
|
| 394 |
-
draw.ellipse((circle_center[0] - circle_radius, circle_center[1] - circle_radius, circle_center[0] + circle_radius, circle_center[1] + circle_radius), fill=255)
|
| 395 |
-
output_image = Image.new("RGBA", image.size)
|
| 396 |
-
output_image.paste(image, (0, 0), mask)
|
| 397 |
-
output_image = output_image.crop(
|
| 398 |
-
(circle_center[0] - circle_radius, circle_center[1] - circle_radius, circle_center[0] + circle_radius, circle_center[1] + circle_radius)
|
| 399 |
-
)
|
| 400 |
-
# output_image = cut_image_blank(output_image)
|
| 401 |
-
|
| 402 |
-
if os.path.exists("src/assets/output"):
|
| 403 |
-
output_image.save("src/assets/output/cropped_circle_image.png")
|
| 404 |
-
return output_image
|
| 405 |
-
|
| 406 |
-
|
| 407 |
-
def make_conference_poster(conference_name, conference_name_eng, conference_name_full, conference_info, conference_rundown):
|
| 408 |
-
|
| 409 |
-
BACKGROUND_COLOR = (1, 6, 143)
|
| 410 |
-
|
| 411 |
-
background = Image.open("src/assets/schedule/top_background.jpg").convert("RGBA")
|
| 412 |
-
bar = Image.open("src/assets/schedule/bar.png").convert("RGBA")
|
| 413 |
-
point_bar = Image.open("src/assets/schedule/point_bar.png").convert("RGBA")
|
| 414 |
-
|
| 415 |
-
H_PADDING_RATION = 0.06
|
| 416 |
-
V_PADDING = 80
|
| 417 |
-
V_START = 1100
|
| 418 |
-
bg_width, bg_height = background.size
|
| 419 |
-
print(background.size)
|
| 420 |
-
print(point_bar.size)
|
| 421 |
-
schedule_top, top_next_height = make_conference_schedule_top(
|
| 422 |
-
background, conference_name, conference_name_eng, conference_name_full, conference_info, bar, H_PADDING_RATION, V_START
|
| 423 |
-
)
|
| 424 |
-
schedule_components = [schedule_top]
|
| 425 |
-
|
| 426 |
-
##########################################################
|
| 427 |
-
for rundown in conference_rundown:
|
| 428 |
-
rundown_pic = write_rundown(BACKGROUND_COLOR, rundown, point_bar, H_PADDING_RATION, bg_width)
|
| 429 |
-
# if rundown["type"] == "主持人":
|
| 430 |
-
# schedule_components = schedule_components[:1] + [rundown_pic] + schedule_components[1:]
|
| 431 |
-
# else:
|
| 432 |
-
schedule_components.append(rundown_pic)
|
| 433 |
-
widths, heights = zip(*(i.size for i in schedule_components))
|
| 434 |
-
schedule_poster = Image.new("RGB", (bg_width, sum(heights)))
|
| 435 |
-
x_offset = 0
|
| 436 |
-
for img in schedule_components:
|
| 437 |
-
schedule_poster.paste(img, (0, x_offset))
|
| 438 |
-
x_offset += img.size[1]
|
| 439 |
-
|
| 440 |
-
img_stream = io.BytesIO()
|
| 441 |
-
schedule_poster.save(img_stream, format="JPEG")
|
| 442 |
-
img_stream.seek(0)
|
| 443 |
-
if os.path.exists("src/assets/output"):
|
| 444 |
-
schedule_poster.save("src/assets/output/schedule.jpg")
|
| 445 |
-
return img_stream
|
| 446 |
-
|
| 447 |
-
|
| 448 |
-
def write_rundown(BACKGROUND_COLOR, rundown, point_bar, H_PADDING_RATION, bg_width):
|
| 449 |
-
background = Image.new("RGB", (bg_width, 6000), BACKGROUND_COLOR)
|
| 450 |
-
next_height = 0
|
| 451 |
-
photo_size_ratio = 0.12
|
| 452 |
-
V_PADDING = 80
|
| 453 |
-
background = embed_image(
|
| 454 |
-
background,
|
| 455 |
-
point_bar,
|
| 456 |
-
offset_y = V_PADDING,
|
| 457 |
-
)
|
| 458 |
-
time_width = 0
|
| 459 |
-
font_size = 130
|
| 460 |
-
font_path = font_path_notosansM
|
| 461 |
-
# print(point_bar.size)
|
| 462 |
-
if rundown["type"] != "主持人":
|
| 463 |
-
text = rundown["start_time"][:-3] + "-" + rundown["end_time"][:-3]
|
| 464 |
-
text_ = text_info(text, font_size, [0, 0],
|
| 465 |
-
max_height=font_size,
|
| 466 |
-
max_width=bg_width * (1 - H_PADDING_RATION * 2.5),
|
| 467 |
-
font_path=font_path)
|
| 468 |
-
start_y = V_PADDING + (point_bar.height - text_.font_size) // 2
|
| 469 |
-
conference_rundown_time, background, next_height = write_text(
|
| 470 |
-
text, font_path, background, H_PADDING_RATION * 1.5, font_size,
|
| 471 |
-
start_y=start_y,
|
| 472 |
-
alignment="left"
|
| 473 |
-
)
|
| 474 |
-
time_width = conference_rundown_time.text_width
|
| 475 |
-
rundown["title"] = rundown["title"] if "title" in rundown else ""
|
| 476 |
-
|
| 477 |
-
text = rundown["type"] # rundown["title"] if rundown["type"] != "主持人" else "主持人"
|
| 478 |
-
pioneer_part_width = H_PADDING_RATION * 1.5 * bg_width + time_width + font_size // 2
|
| 479 |
-
text_ = text_info(
|
| 480 |
-
text,
|
| 481 |
-
font_size,
|
| 482 |
-
[0, 0],
|
| 483 |
-
max_height=font_size,
|
| 484 |
-
max_width=bg_width - pioneer_part_width - H_PADDING_RATION * bg_width, font_path=font_path)
|
| 485 |
-
start_y = V_PADDING + (point_bar.height - text_.font_size) // 2
|
| 486 |
-
conference_rundown_type, background, next_height = write_text(
|
| 487 |
-
text,
|
| 488 |
-
font_path,
|
| 489 |
-
background,
|
| 490 |
-
pioneer_part_width / bg_width,
|
| 491 |
-
font_size,
|
| 492 |
-
start_y=start_y,
|
| 493 |
-
max_width=bg_width - pioneer_part_width - H_PADDING_RATION * bg_width,
|
| 494 |
-
alignment="left",
|
| 495 |
-
)
|
| 496 |
-
|
| 497 |
-
|
| 498 |
-
next_height = V_PADDING + point_bar.size[1] + V_PADDING
|
| 499 |
-
|
| 500 |
-
if rundown["type"] != "主持人":
|
| 501 |
-
text = rundown["title"] # rundown["title"] if rundown["type"] != "主持人" else "主持人"
|
| 502 |
-
pioneer_part_width = H_PADDING_RATION * 1.5 * bg_width + time_width + font_size // 2
|
| 503 |
-
text_ = text_info(
|
| 504 |
-
text,
|
| 505 |
-
font_size,
|
| 506 |
-
[0, 0],
|
| 507 |
-
max_height=font_size,
|
| 508 |
-
max_width=bg_width - pioneer_part_width - H_PADDING_RATION * bg_width, font_path=font_path)
|
| 509 |
-
# start_y = V_PADDING + (point_bar.height - text_.font_size) // 2
|
| 510 |
-
conference_rundown_type, background, next_height = write_text(
|
| 511 |
-
text,
|
| 512 |
-
font_path,
|
| 513 |
-
background,
|
| 514 |
-
pioneer_part_width / bg_width,
|
| 515 |
-
font_size,
|
| 516 |
-
start_y=next_height,
|
| 517 |
-
max_width=bg_width - 2 * H_PADDING_RATION * bg_width,
|
| 518 |
-
alignment="medium",
|
| 519 |
-
)
|
| 520 |
-
|
| 521 |
-
|
| 522 |
-
for person in rundown["people"]:
|
| 523 |
-
# if person["photo_link"] != "":
|
| 524 |
-
next_height += V_PADDING
|
| 525 |
-
background, next_height = write_person_line(background, person, H_PADDING_RATION, next_height, photo_size_ratio)
|
| 526 |
-
|
| 527 |
-
background = background.convert("RGB")
|
| 528 |
-
background = background.crop((0, 0, background.size[0], next_height + V_PADDING))
|
| 529 |
-
if os.path.exists("src/assets/output"):
|
| 530 |
-
background.save("src/assets/output/schedule_rundown.jpg")
|
| 531 |
-
return background
|
| 532 |
-
|
| 533 |
-
|
| 534 |
-
def write_person_line(background, person, H_PADDING_RATION, start_y, photo_size_ratio):
|
| 535 |
-
bg_width = background.size[0]
|
| 536 |
-
text = person["name"]
|
| 537 |
-
font_size = 120
|
| 538 |
-
font_path = font_path_zihun59
|
| 539 |
-
alignment = "left"
|
| 540 |
-
pioneer_part_width = H_PADDING_RATION * bg_width + font_size
|
| 541 |
-
|
| 542 |
-
radius = int(photo_size_ratio * bg_width)
|
| 543 |
-
if person["photo_link"] != "":
|
| 544 |
-
round_photo = write_round_photo(background, person, H_PADDING_RATION * bg_width + radius, start_y + radius, radius)
|
| 545 |
-
pioneer_part_width += round_photo.size[1]
|
| 546 |
-
|
| 547 |
-
person["title"] = person["title"].split("\n")
|
| 548 |
-
|
| 549 |
-
name_padding = 50
|
| 550 |
-
title_padding = 20
|
| 551 |
-
|
| 552 |
-
people_text_y = start_y + (2 * radius - font_size - name_padding - 80 * len(person["title"])) // 2
|
| 553 |
-
conference_rundown_people_name, background, next_height = write_text(
|
| 554 |
-
text,
|
| 555 |
-
font_path,
|
| 556 |
-
background,
|
| 557 |
-
pioneer_part_width / bg_width,
|
| 558 |
-
font_size,
|
| 559 |
-
start_y=people_text_y,
|
| 560 |
-
max_width=bg_width - pioneer_part_width - H_PADDING_RATION * bg_width,
|
| 561 |
-
alignment=alignment
|
| 562 |
-
)
|
| 563 |
-
next_height += name_padding
|
| 564 |
-
font_size = 80
|
| 565 |
-
font_path = font_path_notosansM
|
| 566 |
-
# pioneer_part_width = H_PADDING_RATION * bg_width + round_photo.size[1] + font_size
|
| 567 |
-
for i, text in enumerate(person["title"]):
|
| 568 |
-
conference_rundown_people_title, background, next_height = write_text(
|
| 569 |
-
text,
|
| 570 |
-
font_path,
|
| 571 |
-
background,
|
| 572 |
-
pioneer_part_width / bg_width,
|
| 573 |
-
font_size,
|
| 574 |
-
start_y=next_height + title_padding,
|
| 575 |
-
max_width=bg_width - pioneer_part_width - H_PADDING_RATION * bg_width,
|
| 576 |
-
max_height=radius * 1.2,
|
| 577 |
-
alignment=alignment,
|
| 578 |
-
)
|
| 579 |
-
|
| 580 |
-
return background, start_y + radius * 2
|
| 581 |
-
|
| 582 |
-
|
| 583 |
-
def write_round_photo(background, person, start_x, start_y, radius):
|
| 584 |
-
photo = Image.new("RGBA", (100, 100), (125, 125, 125, 0))
|
| 585 |
-
res = requests.get(person["photo_link"])
|
| 586 |
-
photo = Image.open(io.BytesIO(res.content)).convert("RGBA")
|
| 587 |
-
width, height = photo.size
|
| 588 |
-
circle_center = (width // 2, height // 4)
|
| 589 |
-
circle_radius = min(width, height // 2) // 2
|
| 590 |
-
round_photo = crop_round_img(photo, circle_center, circle_radius)
|
| 591 |
-
round_photo = round_photo.resize((radius*2, radius*2))
|
| 592 |
-
background = embed_image(background, round_photo, offset_y=start_y-radius, offset_x=start_x-radius)
|
| 593 |
-
|
| 594 |
-
return round_photo
|
| 595 |
-
|
| 596 |
-
|
| 597 |
-
def make_conference_schedule_top(background, conference_name, conference_name_eng, conference_name_full, conference_info, bar, H_PADDING_RATION, V_START):
|
| 598 |
-
font_size = 250
|
| 599 |
-
font_path = font_path_pingfangM
|
| 600 |
-
text = conference_name
|
| 601 |
-
conference_name, background, next_height = write_text(
|
| 602 |
-
text,
|
| 603 |
-
font_path,
|
| 604 |
-
background,
|
| 605 |
-
H_PADDING_RATION,
|
| 606 |
-
font_size,
|
| 607 |
-
start_y=V_START,
|
| 608 |
-
alignment="left",
|
| 609 |
-
)
|
| 610 |
-
|
| 611 |
-
font_size = 110
|
| 612 |
-
font_path = font_path_notosans
|
| 613 |
-
text = conference_name_eng
|
| 614 |
-
V_PADDING = 120
|
| 615 |
-
conference_name_eng, background, next_height = write_text(
|
| 616 |
-
text, font_path, background, H_PADDING_RATION, font_size,
|
| 617 |
-
start_y=next_height + V_PADDING, alignment="left"
|
| 618 |
-
)
|
| 619 |
-
|
| 620 |
-
font_size = 160
|
| 621 |
-
font_path = font_path_notosansM
|
| 622 |
-
text = "——" + conference_name_full + "——"
|
| 623 |
-
V_PADDING = 180
|
| 624 |
-
conference_name_full, background, next_height = write_text(
|
| 625 |
-
text, font_path, background, H_PADDING_RATION, font_size, start_y=next_height + V_PADDING, alignment="medium"
|
| 626 |
-
)
|
| 627 |
-
# write_text(" ", font_path, background, H_PADDING_RATION, 200, start_height=next_height + 400, alignment="medium")
|
| 628 |
-
INNER_PADDING = 60
|
| 629 |
-
next_height = next_height + V_PADDING - INNER_PADDING
|
| 630 |
-
background, next_height = write_conference_info(conference_info, background, bar, H_PADDING_RATION, INNER_PADDING, next_height)
|
| 631 |
-
background = background.convert("RGB")
|
| 632 |
-
background = background.crop((0, 0, background.size[0], next_height + V_PADDING))
|
| 633 |
-
if os.path.exists("src/assets/output"):
|
| 634 |
-
background.save("src/assets/output/schedule_top.jpg")
|
| 635 |
-
|
| 636 |
-
return background, next_height
|
| 637 |
-
|
| 638 |
-
|
| 639 |
-
def write_conference_info(conference_info, background, bar, H_PADDING_RATION, V_PADDING, next_height):
|
| 640 |
-
bg_width, vg_height = background.size
|
| 641 |
-
for i, info in enumerate(conference_info):
|
| 642 |
-
font_size = 110
|
| 643 |
-
font_path = font_path_notosansB
|
| 644 |
-
text = info[0]
|
| 645 |
-
bar = bar.resize((int(bg_width * 0.06), int(font_size * 0.7)))
|
| 646 |
-
|
| 647 |
-
info_name, background, next_height = write_text(
|
| 648 |
-
text, font_path, background, H_PADDING_RATION, font_size, start_y=next_height + V_PADDING, alignment="left"
|
| 649 |
-
)
|
| 650 |
-
background = embed_image(
|
| 651 |
-
background, bar, offset_y=next_height - (bar.size[1] + info_name.font_size) // 2, offset_x=bg_width * H_PADDING_RATION + info_name.text_width
|
| 652 |
-
)
|
| 653 |
-
font_size = 80
|
| 654 |
-
|
| 655 |
-
text = info[1]
|
| 656 |
-
pioneer_part_width = bar.size[0] + info_name.text_width + font_size
|
| 657 |
-
text_ = text_info(
|
| 658 |
-
text,
|
| 659 |
-
font_size,
|
| 660 |
-
[0, 0],
|
| 661 |
-
max_height=font_size,
|
| 662 |
-
max_width=bg_width * (1 - 2 * H_PADDING_RATION) - info_name.text_width - bar.width,
|
| 663 |
-
font_path=font_path, alignment="left")
|
| 664 |
-
info_content, background, _ = write_text(
|
| 665 |
-
text,
|
| 666 |
-
font_path,
|
| 667 |
-
background,
|
| 668 |
-
H_PADDING_RATION + pioneer_part_width / bg_width,
|
| 669 |
-
font_size,
|
| 670 |
-
max_width=bg_width * (1 - 2 * H_PADDING_RATION) - info_name.text_width - bar.width,
|
| 671 |
-
start_y=next_height - info_name.font_size + (info_name.font_size - text_.font_size) // 2,
|
| 672 |
-
alignment="left",
|
| 673 |
-
)
|
| 674 |
-
|
| 675 |
-
|
| 676 |
-
return background, next_height
|
| 677 |
-
|
| 678 |
-
|
| 679 |
-
def getGuestComposePoster(conference_name, conference_eng_name, people):
|
| 680 |
-
|
| 681 |
-
top = Image.open("src/assets/GuestComposePoster/top.png").convert("RGBA")
|
| 682 |
-
card = Image.open("src/assets/GuestComposePoster/card.png").convert("RGBA")
|
| 683 |
-
V_PADDING = 80
|
| 684 |
-
background = Image.new("RGB", (top.size[0], card.size[1] * math.ceil(len(people) / 3) + V_PADDING), (255, 255, 255))
|
| 685 |
-
bg_width, bg_height = background.size
|
| 686 |
-
H_PADDING = (bg_width - 3*card.size[0]) / 2
|
| 687 |
-
V_START = 1200
|
| 688 |
-
print(top.size)
|
| 689 |
-
print(background.size)
|
| 690 |
|
| 691 |
-
|
| 692 |
-
|
| 693 |
-
text = conference_name
|
| 694 |
-
conference_name, top, next_height = write_text(
|
| 695 |
-
text,
|
| 696 |
-
font_path,
|
| 697 |
-
top,
|
| 698 |
-
H_PADDING / bg_width,
|
| 699 |
-
font_size,
|
| 700 |
-
start_y=V_START,
|
| 701 |
-
alignment="medium",
|
| 702 |
-
)
|
| 703 |
-
font_size = 250
|
| 704 |
-
font_path = font_path_notosansL
|
| 705 |
-
text = conference_eng_name
|
| 706 |
-
conference_eng_name, top, next_height = write_text(
|
| 707 |
-
text,
|
| 708 |
-
font_path,
|
| 709 |
-
top,
|
| 710 |
-
H_PADDING / bg_width,
|
| 711 |
-
font_size,
|
| 712 |
-
start_y=next_height + V_PADDING,
|
| 713 |
-
max_height=700,
|
| 714 |
-
alignment="medium",
|
| 715 |
-
)
|
| 716 |
|
| 717 |
-
|
| 718 |
-
|
| 719 |
-
background = write_person_card(background, card, person, H_PADDING + card.size[0] * (i % 3), card.height * (i // 3))
|
| 720 |
-
|
| 721 |
-
guest_compose_poster = Image.new("RGB", (bg_width, background.size[1] + top.size[1]))
|
| 722 |
-
guest_compose_poster.paste(top, (0, 0))
|
| 723 |
-
guest_compose_poster.paste(background, (0, top.size[1]))
|
| 724 |
-
img_stream = io.BytesIO()
|
| 725 |
-
guest_compose_poster.save(img_stream, format="JPEG")
|
| 726 |
-
img_stream.seek(0)
|
| 727 |
-
if os.path.exists("src/assets/output"):
|
| 728 |
-
guest_compose_poster.save("src/assets/output/guest_compose_poster.jpg")
|
| 729 |
-
return img_stream
|
| 730 |
-
|
| 731 |
-
|
| 732 |
-
def write_person_card(background, card, person, H_PADDING, start_y):
|
| 733 |
-
bg_width = background.size[0]
|
| 734 |
-
# print(bg_width * photo_size_ratio)
|
| 735 |
-
white_bar = 70
|
| 736 |
-
radius = int(0.67 * card.width) // 2
|
| 737 |
|
| 738 |
-
|
| 739 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 740 |
|
| 741 |
-
text = person["name"]
|
| 742 |
-
font_size = 120
|
| 743 |
-
font_path = font_path_zihun59
|
| 744 |
-
pioneer_part_width = H_PADDING
|
| 745 |
-
people_text_y = start_y + 2 * radius + white_bar + 20
|
| 746 |
-
guest_compose_poster_people_name, background, next_height = write_text(
|
| 747 |
-
text, font_path, background,
|
| 748 |
-
pioneer_part_width / bg_width,
|
| 749 |
-
font_size,
|
| 750 |
-
start_y=people_text_y,
|
| 751 |
-
start_x=H_PADDING,
|
| 752 |
-
part_width=card.width,
|
| 753 |
-
max_width=card.width,
|
| 754 |
-
alignment="medium",
|
| 755 |
-
# color=(0,0,0)
|
| 756 |
-
)
|
| 757 |
|
| 758 |
-
text = "\n".join(person["title"].split("\n")[:5])
|
| 759 |
-
font_size = 40
|
| 760 |
-
font_path = font_path_notosansM
|
| 761 |
-
next_height += 30
|
| 762 |
-
for i, text in enumerate(text.split("\n")):
|
| 763 |
-
pioneer_part_width = H_PADDING
|
| 764 |
-
people_text_y = next_height + 10
|
| 765 |
-
guest_compose_poster_people_title, background, next_height = write_text(
|
| 766 |
-
text, font_path, background,
|
| 767 |
-
pioneer_part_width / bg_width,
|
| 768 |
-
font_size,
|
| 769 |
-
start_y=people_text_y,
|
| 770 |
-
start_x=H_PADDING,
|
| 771 |
-
part_width=card.width,
|
| 772 |
-
max_width=card.width-white_bar,
|
| 773 |
-
alignment="medium",
|
| 774 |
-
# color=(0,0,0)
|
| 775 |
-
)
|
| 776 |
|
| 777 |
-
|
|
|
|
| 778 |
|
| 779 |
|
| 780 |
if __name__ == "__main__":
|
| 781 |
-
|
| 782 |
-
|
| 783 |
-
|
| 784 |
-
#
|
| 785 |
-
|
| 786 |
-
|
| 787 |
-
|
| 788 |
-
|
| 789 |
-
output_path = "output/output.pdf"
|
| 790 |
-
# writeInvitationPDF(person, debug=True)
|
| 791 |
-
|
| 792 |
-
text_list = [
|
| 793 |
-
"""Shanghai 协砺科技有限公司专注于青少年科技教育12年,通过STEAM25教育模式培养青少年的科学思维和创新能力。在全国设有数十家学习中心,服务上万名学员,提供科创、机器人和编程课程。公司还设有赛事研究中心,由专业工程师团队提供赛事研究和策略支持。学员在各类科技赛事中屡获佳绩。协砺科技致力于推动中国科技教育的创新与发展,为国家繁荣贡献力量。
|
| 794 |
-
|
| 795 |
-
【主要产品】科创、编程、赛事
|
| 796 |
-
【核心特点】为青少年提供优质的科创学习规划。
|
| 797 |
-
【核心亮点】高效提供更优质的赛事解决方案——快速赋能当地传统教育企业转型智能化教育赛道。""",
|
| 798 |
-
"""天天乐学创办于2015年6月,总部位于北京,创始团队均来自清北等知名高校,旗下产品天天乐学定制app,主打立体化教学和趣味性学习,可深度匹配教学需求,实现个性化教学。目前合作校近三万家,遍布全国31个省,300座城市,是国内知名的教育科技公司。
|
| 799 |
-
|
| 800 |
-
|
| 801 |
-
【主要产品】独立教师·机构·绘本馆英语APP定制
|
| 802 |
-
【核心特点】内容深度定制,帮助机构实现线上线下联动教学
|
| 803 |
-
""",
|
| 804 |
-
"""【】星瀚之光是明德传承集团旗下文化传媒品牌
|
| 805 |
-
成立于2023年,立足深圳,布局全国九大中心城市,是国内首家定位于价值观驱动的P产业链开发的MCN机构,拥有知识P孵化事业群和商业P孵化事业群两大主营板块,旗下涵盖了创始人P孵化直播电商、私域消费电商、企业整合营销、艺人经纪等业务,致力于成为中国规模最大的P生态搭建领军企业。
|
| 806 |
-
|
| 807 |
-
【】坚守“自利利他、奋斗为本、价值为纲、成就客户”的企业价值观
|
| 808 |
-
公司成立以来发展迅猛,迅速孵化出各大赛道的多个头部P,霸榜各大短视频平台榜单,包括:有家庭教育赛道:白瑞(家庭教育赛道头部主播);身心灵赛道:尚致胜(新中式心理学首创者);女性成长赛道:黄欢;商业赛道:苏建诚(亚细亚集团联合创始人)、王怀南(宝宝树创始人)、杨晓燕(长江商学院助理院长)、何慕(联众智达董事长)等;国学赛道:沈德斌(了凡四训学者)、钱锦国老师等。""",
|
| 809 |
-
"""学趋坊是一家为学校、机构、智能自习室等提供在线化和智能化解决方案的数字化教育内容供应商。已经为多个知名的在线教育品牌、智能自习室品牌提供0DM和OEM服务,产品用户累计超过1000万。
|
| 810 |
-
|
| 811 |
-
【主要产品】智能校本
|
| 812 |
-
【核心特点】为本地化内容插上科技的翅膀。
|
| 813 |
-
【核心亮点】高质量高效本地化教研—快速赋能当地传统教育企业转型智能化教育赛道。""",
|
| 814 |
-
]
|
| 815 |
-
logo_path_list = [
|
| 816 |
-
"src/assets/logo/学区房logo.png",
|
| 817 |
-
"src/assets/logo/星瀚之光logo.jpg",
|
| 818 |
-
"src/assets/logo/软科起点logo.png",
|
| 819 |
-
"src/assets/logo/天天乐学logo.png",
|
| 820 |
-
]
|
| 821 |
-
slogan_list = ["探索科技,启迪未来。", "价值观驱动的知识P全域孵化领先平台", "定制英语APP学习系统"]
|
| 822 |
-
FOREGROUND_ID = 3 # 0, 1, 2, 3
|
| 823 |
-
SLOGAN_ID = 1 # 0, 1, 2
|
| 824 |
-
TEXT_ID = 2 # 0, 1, 2, 3
|
| 825 |
-
|
| 826 |
-
LOGO_LINK = "https://weboffice-temporary.ks3-cn-beijing.wpscdn.cn/thumbnail/tJUjbgWdD6R5k5rECKka1yK_100.png?Expires=1721322000&KSSAccessKeyId=AKLTmoJhggaFT1CHuozGZqbC&Signature=qZCdG1n42uwCFGJ8%2BAlF6VK8KEM%3D&response-cache-control=public%2Cmax-age%3D86400"
|
| 827 |
-
|
| 828 |
-
name, titles = "王千里", "全国政协文员\n好好先生"
|
| 829 |
-
PHOTO_LINK = "https://weboffice-temporary.ks3-cn-beijing.wpscdn.cn/thumbnail/tpcdnbPEKEJ3ge831dSHEd3_100.png?Expires=1720890000&KSSAccessKeyId=AKLTmoJhggaFT1CHuozGZqbC&Signature=jeKkEy%2BTx3BAMNzqrmjUbg6uBK8%3D&response-cache-control=public%2Cmax-age%3D86400"
|
| 830 |
-
ORIGINAL_PHOTO_LINK = "https://weboffice-temporary.ks3-cn-beijing.wpscdn.cn/thumbnail/tZCeTRiNFQbksEEF4WMR8ZX_100.jpeg?Expires=1721743200&KSSAccessKeyId=AKLTmoJhggaFT1CHuozGZqbC&Signature=CvxnLBCIf%2B0aXEfaJ9XK6Vq%2FXU8%3D&response-cache-control=public%2Cmax-age%3D86400"
|
| 831 |
-
|
| 832 |
-
conference_name = "教育行业规范管理发展论坛"
|
| 833 |
-
conference_name_eng = "2024 World Education Conference"
|
| 834 |
-
conference_name_full = "2024世界教育者大会上海主会"
|
| 835 |
-
conference_info = [
|
| 836 |
-
["指导单位", "上海市民办教育协会、长三角教育发展研究院"],
|
| 837 |
-
["主办单位", "上海市民办教育协会、长三角教育发展研究院\上海市民办教育协会、长三角教育发展研究院\上海市民办教育协会、长三角教育发展研究院"],
|
| 838 |
-
["论坛时间", "2024年8月21日上午9:00-12:30"],
|
| 839 |
-
["论坛地址", "国家会展中心4.2号馆A"],
|
| 840 |
-
]
|
| 841 |
-
|
| 842 |
-
conference_rundown = [
|
| 843 |
-
{
|
| 844 |
-
"type": "主持人",
|
| 845 |
-
"title": "上海市教科规划办副主任",
|
| 846 |
-
"people": [
|
| 847 |
-
{
|
| 848 |
-
"name": "方法名",
|
| 849 |
-
"title": "上海市教科规划办副主任\n上海教科院改革发展研究部研究员\n华东师范大学国家宏观教育研究院博士生导师",
|
| 850 |
-
"photo_link": ORIGINAL_PHOTO_LINK,
|
| 851 |
-
},
|
| 852 |
-
{
|
| 853 |
-
"name": "方法名",
|
| 854 |
-
"title": "上海市教科规划办副主任\n上海教科院改革发展研究部研究员\n华东师范大学国家宏观教育研究院博士生导师",
|
| 855 |
-
"photo_link": "",
|
| 856 |
-
},
|
| 857 |
-
],
|
| 858 |
-
"start_time": "9:00:00",
|
| 859 |
-
"end_time": "9:20:00",
|
| 860 |
-
},
|
| 861 |
-
{
|
| 862 |
-
"type": "致辞",
|
| 863 |
-
"title": "上海市教科规划办副主",
|
| 864 |
-
"people": [
|
| 865 |
-
{
|
| 866 |
-
"name": "方法名",
|
| 867 |
-
"title": "上海市教科规划办副主任",
|
| 868 |
-
"photo_link": ORIGINAL_PHOTO_LINK,
|
| 869 |
-
}
|
| 870 |
-
],
|
| 871 |
-
"start_time": "9:00:00",
|
| 872 |
-
"end_time": "9:20:00",
|
| 873 |
-
}, {
|
| 874 |
-
"type": "致辞",
|
| 875 |
-
"title": "上海市教科规划办副主任上海市教科规划办副主任上海市教科规",
|
| 876 |
-
"people": [
|
| 877 |
-
{
|
| 878 |
-
"name": "方法名",
|
| 879 |
-
"title": "上海市教科规划办副主任",
|
| 880 |
-
"photo_link": ORIGINAL_PHOTO_LINK,
|
| 881 |
-
}
|
| 882 |
-
],
|
| 883 |
-
"start_time": "9:00:00",
|
| 884 |
-
"end_time": "9:20:00",
|
| 885 |
-
},
|
| 886 |
-
]
|
| 887 |
-
people = [
|
| 888 |
-
{
|
| 889 |
-
"name": "方法名",
|
| 890 |
-
"title": "上海市教科规划办副主任\n上海教科院改革发展研究部研究员\n华东师范大学国家宏观教育研究院博士生导师",
|
| 891 |
-
"photo_link": ORIGINAL_PHOTO_LINK,
|
| 892 |
-
},
|
| 893 |
-
{
|
| 894 |
-
"name": "方法名",
|
| 895 |
-
"title": "上海市教科规划办副主任\n上海教科院改革发展研究部研究员\n华东师范大学国家宏观教育研究院博士生导师",
|
| 896 |
-
"photo_link": ORIGINAL_PHOTO_LINK,
|
| 897 |
-
},
|
| 898 |
-
{
|
| 899 |
-
"name": "方法名",
|
| 900 |
-
"title": "上海市教科规划办副主任\n上海教科院改革发展研究部研究员\n华东师范大学国家宏观教育研究院博士生导师",
|
| 901 |
-
"photo_link": ORIGINAL_PHOTO_LINK,
|
| 902 |
-
},
|
| 903 |
-
{
|
| 904 |
-
"name": "方法名",
|
| 905 |
-
"title": "上海市教科规划办副主任\n上海教科院改革发展研究部研究员\n华东师范大学国家宏观教育研究院博士生导师",
|
| 906 |
-
"photo_link": ORIGINAL_PHOTO_LINK,
|
| 907 |
-
},
|
| 908 |
-
{
|
| 909 |
-
"name": "方法名",
|
| 910 |
-
"title": "上海市教科规划办副主任\n上海教科院改革发展研究部研究员\n华东师范大学国家宏观教育研究院博士生导师",
|
| 911 |
-
"photo_link": ORIGINAL_PHOTO_LINK,
|
| 912 |
-
},
|
| 913 |
-
{
|
| 914 |
-
"name": "方法名",
|
| 915 |
-
"title": "上海市教科规划办副主任",
|
| 916 |
-
"photo_link": ORIGINAL_PHOTO_LINK,
|
| 917 |
-
},
|
| 918 |
-
{
|
| 919 |
-
"name": "方法名",
|
| 920 |
-
"title": "上海市教科规划办副主任",
|
| 921 |
-
"photo_link": ORIGINAL_PHOTO_LINK,
|
| 922 |
-
},
|
| 923 |
-
{
|
| 924 |
-
"name": "方法名",
|
| 925 |
-
"title": "上海市教科规划办副主任",
|
| 926 |
-
"photo_link": ORIGINAL_PHOTO_LINK,
|
| 927 |
-
},
|
| 928 |
-
{
|
| 929 |
-
"name": "方法名",
|
| 930 |
-
"title": "上海市教科规划办副主任",
|
| 931 |
-
"photo_link": ORIGINAL_PHOTO_LINK
|
| 932 |
-
},
|
| 933 |
-
{
|
| 934 |
-
"name": "方法名",
|
| 935 |
-
"title": "上海市教科规划办副主任",
|
| 936 |
-
"photo_link": ORIGINAL_PHOTO_LINK,
|
| 937 |
-
},
|
| 938 |
-
]
|
| 939 |
-
|
| 940 |
-
# res = requests.get(ORIGINAL_PHOTO_LINK)
|
| 941 |
-
# # guest_photo = Image.open(io.BytesIO(res.content)).convert("RGBA")
|
| 942 |
-
# original_guest_photo = Image.open(io.BytesIO(res.content)).convert("RGBA")
|
| 943 |
-
# guest_photo = rm_img_bg(original_guest_photo)
|
| 944 |
-
|
| 945 |
-
# compose_guest_poster(name, guest_photo, titles)
|
| 946 |
-
|
| 947 |
-
# for file in os.listdir("src/assets/GuestPoster/original_guest"):
|
| 948 |
-
# image = Image.open(os.path.join("src/assets/GuestPoster/original_guest", file))
|
| 949 |
-
# image = rm_img_bg(image)
|
| 950 |
-
# image.save(os.path.join("src/assets/output", file.replace("jpg", "png")))
|
| 951 |
-
|
| 952 |
-
# image = Image.open('src/assets/苏建诚.png')
|
| 953 |
-
# width, height = image.size
|
| 954 |
-
# circle_center = (width // 2, height // 4)
|
| 955 |
-
# circle_radius = min(width, height//2) // 2
|
| 956 |
-
# round_img = crop_round_img(image, circle_center, circle_radius)
|
| 957 |
-
# print(round_img.size)
|
| 958 |
-
|
| 959 |
-
# res = requests.get(ORIGINAL_PHOTO_LINK)
|
| 960 |
-
# photo = Image.open(io.BytesIO(res.content)).convert("RGBA")
|
| 961 |
-
|
| 962 |
-
# make_exhibitor_poster(LOGO_LINK, slogan_list[SLOGAN_ID], text_list[TEXT_ID])
|
| 963 |
-
# make_guest_poster(name, "", "", ORIGINAL_PHOTO_LINK, titles)
|
| 964 |
-
|
| 965 |
-
make_conference_poster(conference_name, conference_name_eng, conference_name_full, conference_info, conference_rundown)
|
| 966 |
-
# 定义圆心和半径
|
| 967 |
-
|
| 968 |
-
# res = requests.get(ORIGINAL_PHOTO_LINK)
|
| 969 |
-
# print(res)
|
| 970 |
-
# with open("src/assets/output/guest_compose_poster.png", "wb") as f:
|
| 971 |
-
# f.write(res.content)
|
| 972 |
-
# photo = Image.open(io.BytesIO(res.content)).convert("RGBA")
|
| 973 |
-
|
| 974 |
-
|
| 975 |
-
# getGuestComposePoster("全球教育者公论教育", "EDUCATORS AROUND THE GLOBE TALKING ABOUT EDUCATION", people)
|
|
|
|
| 1 |
+
from fastapi import FastAPI, Path, Query, Response, BackgroundTasks
|
| 2 |
+
from fastapi.responses import FileResponse, HTMLResponse
|
| 3 |
+
import gradio as gr
|
| 4 |
+
import sys
|
| 5 |
import os
|
| 6 |
+
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))
|
| 7 |
+
sys.path.append(project_root)
|
| 8 |
+
from src.pyscripts import file_process, oss, img_process
|
| 9 |
+
from datetime import datetime
|
| 10 |
+
from collections import namedtuple
|
| 11 |
+
from pydantic import BaseModel
|
| 12 |
import requests
|
| 13 |
+
# from easydict import EasyDict
|
| 14 |
+
|
| 15 |
+
Person = namedtuple('Person', ['name', 'title', 'category', 'conference', 'respond_person'])
|
| 16 |
+
|
| 17 |
+
CUSTOM_PATH = "/gradio"
|
| 18 |
+
|
| 19 |
+
app = FastAPI()
|
| 20 |
+
|
| 21 |
+
pdf_path = "src/assets/InvitationTemplate.pdf"
|
| 22 |
+
output_path = 'output/output.pdf'
|
| 23 |
+
person = Person(name="雷军", title="先生", category="观礼", conference="世界教育者大会", respond_person="Eazy")
|
| 24 |
+
|
| 25 |
+
# data = {
|
| 26 |
+
# 'name': '雷军',
|
| 27 |
+
# 'title': '先生',
|
| 28 |
+
# "conference": "世界教育者大会"
|
| 29 |
+
# }
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
@app.get("/")
|
| 33 |
+
def read_main():
|
| 34 |
+
return {"message": "This is your main app"}
|
| 35 |
+
|
| 36 |
+
# @app.post("/getInvitationPDF/{name}/{title}/{conference}")
|
| 37 |
+
@app.get("/getInvitationPDF")
|
| 38 |
+
def getInvitationPDF(name, title, conference, category, respond_person):
|
| 39 |
+
person = Person(name=name, title=title, category=category, conference=conference, respond_person=respond_person)
|
| 40 |
+
formatted_date = datetime.now().strftime('%Y-%m-%d')
|
| 41 |
+
file_name = f"致{name+title}的WWEC2024邀请函.pdf"
|
| 42 |
+
file_dir = f"invitation/{category}"
|
| 43 |
+
object_name = file_dir + "/" + file_name
|
| 44 |
+
pdfStream = file_process.writeInvitationPDF(person)
|
| 45 |
+
# with open(f"output/{file_name}", 'wb') as f:
|
| 46 |
+
# f.write(pdfStream.getvalue())
|
| 47 |
+
oss.upload_file_stream_to_s3(pdfStream, "host", object_name)
|
| 48 |
+
file_url = f"https://isidoresong.us.kg/{object_name}"
|
| 49 |
+
return {"url": file_url}
|
| 50 |
+
|
| 51 |
+
class GuestPosterInfo(BaseModel):
|
| 52 |
+
exhibitor: str
|
| 53 |
+
logo_link: str
|
| 54 |
+
slogan: str
|
| 55 |
+
content: str
|
| 56 |
+
|
| 57 |
+
@app.post("/getExhibitorPoster")
|
| 58 |
+
def getExhibitorPoster(item: GuestPosterInfo):
|
| 59 |
+
logo_link = item.logo_link
|
| 60 |
+
exhibitor = item.exhibitor
|
| 61 |
+
slogan = item.slogan
|
| 62 |
+
content = item.content
|
| 63 |
+
img_stream = img_process.make_exhibitor_poster(logo_link, slogan, content)
|
| 64 |
+
file_dir = "ExhibitorPoster"
|
| 65 |
+
object_name = file_dir + "/" + exhibitor + ".jpg"
|
| 66 |
+
# with open(f"output/{exhibitor + '.jpg'}", 'wb') as f:
|
| 67 |
+
# f.write(img_stream.getvalue())
|
| 68 |
+
oss.upload_file_stream_to_s3(img_stream, "host", object_name)
|
| 69 |
+
file_url = f"https://isidoresong.us.kg/{object_name}"
|
| 70 |
+
return {"url": file_url}
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
class GuestPosterInfo(BaseModel):
|
| 74 |
+
name: str
|
| 75 |
+
name_pinyin: str
|
| 76 |
+
photo_link: str
|
| 77 |
+
original_photo_link: str
|
| 78 |
+
titles: str
|
| 79 |
+
|
| 80 |
+
@app.post("/getGuestPoster")
|
| 81 |
+
def getGuestPoster(item: GuestPosterInfo):
|
| 82 |
+
photo_link = item.photo_link
|
| 83 |
+
original_photo_link = item.original_photo_link
|
| 84 |
+
name = item.name
|
| 85 |
+
name_pinyin = item.name_pinyin
|
| 86 |
+
titles = item.titles
|
| 87 |
+
img_stream = img_process.make_guest_poster(name, name_pinyin, photo_link, original_photo_link, titles)
|
| 88 |
+
file_dir = "GuestPoster"
|
| 89 |
+
object_name = file_dir + "/" + name + ".jpg"
|
| 90 |
+
# f.write(img_stream.getvalue())
|
| 91 |
+
oss.upload_file_stream_to_s3(img_stream, "host", object_name)
|
| 92 |
+
file_url = f"https://pub-429c75a96a8f4597984dd7ebc525d652.r2.dev/{object_name}"
|
| 93 |
+
return {"url": file_url}
|
| 94 |
+
|
| 95 |
+
class ConferenceInfo(BaseModel):
|
| 96 |
+
name: str
|
| 97 |
+
eng_name: str
|
| 98 |
+
full_name: str
|
| 99 |
+
start_time: str
|
| 100 |
+
end_time: str
|
| 101 |
+
member: list
|
| 102 |
+
guest: list = None
|
| 103 |
+
|
| 104 |
+
class ConferencePosterInfo(BaseModel):
|
| 105 |
+
conference_info: ConferenceInfo
|
| 106 |
+
conference_rundown:list
|
| 107 |
+
|
| 108 |
+
|
| 109 |
+
def format_time(start_time, end_time):
|
| 110 |
+
start_datetime = datetime.strptime(start_time, "%Y/%m/%d %H:%M:%S")
|
| 111 |
+
end_datetime = datetime.strptime(end_time, "%Y/%m/%d %H:%M:%S")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 112 |
|
| 113 |
+
start_period = "上午" if start_datetime.hour < 12 else "下午"
|
| 114 |
+
end_period = "上午" if end_datetime.hour < 12 else "下午"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
|
| 116 |
+
formatted_start_time = start_datetime.strftime(f"%Y年%m月%d日{start_period}%H:%M")
|
| 117 |
+
formatted_end_time = end_datetime.strftime(f"{end_period}%H:%M")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 118 |
|
| 119 |
+
return f"{formatted_start_time}-{formatted_end_time}"
|
| 120 |
+
|
| 121 |
+
|
| 122 |
+
@app.post("/getConferencePoster")
|
| 123 |
+
def getConferencePoster(item: ConferencePosterInfo):
|
| 124 |
+
# item.conference_rundown = [list(i) for i in item.conference_rundown]
|
| 125 |
+
sorted_conference_rundown = sorted(item.conference_rundown, key=lambda x: x['end_time'])
|
| 126 |
+
img_stream = img_process.make_conference_poster(
|
| 127 |
+
item.conference_info["name"],
|
| 128 |
+
item.conference_info["eng_name"],
|
| 129 |
+
item.conference_info["full_name"],
|
| 130 |
+
[
|
| 131 |
+
*item.conference_info["member"],
|
| 132 |
+
["论坛时间", format_time(item.conference_info["start_time"],
|
| 133 |
+
item.conference_info["end_time"])],
|
| 134 |
+
["论坛地点", "国家会展中心4.2号馆 " + item.conference_info["address"]]
|
| 135 |
+
],
|
| 136 |
+
sorted_conference_rundown)
|
| 137 |
+
file_dir = "ConferencePoster"
|
| 138 |
+
object_name = file_dir + "/" + item.conference_info["name"] + ".jpg"
|
| 139 |
+
if os.path.exists("src/assets/output"):
|
| 140 |
+
with open(f"src/assets/output/{item.conference_info['name'] + '.jpg'}", 'wb') as f:
|
| 141 |
+
f.write(img_stream.getvalue())
|
| 142 |
+
else:
|
| 143 |
+
oss.upload_file_stream_to_s3(img_stream, "host", object_name)
|
| 144 |
+
file_url = f"https://pub-429c75a96a8f4597984dd7ebc525d652.r2.dev/{object_name}"
|
| 145 |
+
return {"url": file_url}
|
| 146 |
+
|
| 147 |
+
@app.post("/getGuestComposePoster")
|
| 148 |
+
def getGuestComposePoster(item:ConferenceInfo):
|
| 149 |
+
# item.conference_rundown = [list(i) for i in item.conference_rundown]
|
| 150 |
+
sorted_conference_guest = sorted(item.guest, key=lambda x: x['rank'])
|
| 151 |
+
img_stream = img_process.getGuestComposePoster(
|
| 152 |
+
item.name,
|
| 153 |
+
item.eng_name,
|
| 154 |
+
sorted_conference_guest)
|
| 155 |
+
file_dir = "ConferenceGuestPoster"
|
| 156 |
+
object_name = file_dir + "/" + item.name + ".jpg"
|
| 157 |
+
if os.path.exists("src/assets/output"):
|
| 158 |
+
with open(f"src/assets/output/{item.name + '.jpg'}", 'wb') as f:
|
| 159 |
+
f.write(img_stream.getvalue())
|
| 160 |
+
else:
|
| 161 |
+
oss.upload_file_stream_to_s3(img_stream, "host", object_name)
|
| 162 |
+
file_url = f"https://pub-429c75a96a8f4597984dd7ebc525d652.r2.dev/{object_name}"
|
| 163 |
+
return {"url": file_url}
|
| 164 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 165 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 166 |
|
| 167 |
+
interface = gr.Interface(lambda x: "Hello, " + x + "!", "textbox", "textbox")
|
| 168 |
+
app = gr.mount_gradio_app(app, interface, path=CUSTOM_PATH)
|
| 169 |
|
| 170 |
|
| 171 |
if __name__ == "__main__":
|
| 172 |
+
MOCK_URL = "https://mock.jsont.run/iKAdks2DIVBtx-R7Fbw3y"
|
| 173 |
+
res = requests.get(MOCK_URL)
|
| 174 |
+
mock_data = res.json()
|
| 175 |
+
# mock_data = ConferencePosterInfo(**mock_data)
|
| 176 |
+
# getConferencePoster(mock_data)
|
| 177 |
+
print(mock_data)
|
| 178 |
+
mock_data = ConferenceInfo(**mock_data["conference_info"])
|
| 179 |
+
getGuestComposePoster(mock_data)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|