Spaces:
Build error
Build error
''' | |
This is a library for formatting GPT-4chan and chat outputs as nice HTML. | |
''' | |
import os | |
import re | |
from pathlib import Path | |
from PIL import Image | |
# This is to store the paths to the thumbnails of the profile pictures | |
image_cache = {} | |
def generate_basic_html(s): | |
css = """ | |
.container { | |
max-width: 600px; | |
margin-left: auto; | |
margin-right: auto; | |
background-color: rgb(31, 41, 55); | |
padding:3em; | |
} | |
.container p { | |
font-size: 16px !important; | |
color: white !important; | |
margin-bottom: 22px; | |
line-height: 1.4 !important; | |
} | |
""" | |
s = '\n'.join([f'<p>{line}</p>' for line in s.split('\n')]) | |
s = f'<style>{css}</style><div class="container">{s}</div>' | |
return s | |
def process_post(post, c): | |
t = post.split('\n') | |
number = t[0].split(' ')[1] | |
if len(t) > 1: | |
src = '\n'.join(t[1:]) | |
else: | |
src = '' | |
src = re.sub('>', '>', src) | |
src = re.sub('(>>[0-9]*)', '<span class="quote">\\1</span>', src) | |
src = re.sub('\n', '<br>\n', src) | |
src = f'<blockquote class="message">{src}\n' | |
src = f'<span class="name">Anonymous </span> <span class="number">No.{number}</span>\n{src}' | |
return src | |
def generate_4chan_html(f): | |
css = """ | |
#parent #container { | |
background-color: #eef2ff; | |
padding: 17px; | |
} | |
#parent #container .reply { | |
background-color: rgb(214, 218, 240); | |
border-bottom-color: rgb(183, 197, 217); | |
border-bottom-style: solid; | |
border-bottom-width: 1px; | |
border-image-outset: 0; | |
border-image-repeat: stretch; | |
border-image-slice: 100%; | |
border-image-source: none; | |
border-image-width: 1; | |
border-left-color: rgb(0, 0, 0); | |
border-left-style: none; | |
border-left-width: 0px; | |
border-right-color: rgb(183, 197, 217); | |
border-right-style: solid; | |
border-right-width: 1px; | |
border-top-color: rgb(0, 0, 0); | |
border-top-style: none; | |
border-top-width: 0px; | |
color: rgb(0, 0, 0); | |
display: table; | |
font-family: arial, helvetica, sans-serif; | |
font-size: 13.3333px; | |
margin-bottom: 4px; | |
margin-left: 0px; | |
margin-right: 0px; | |
margin-top: 4px; | |
overflow-x: hidden; | |
overflow-y: hidden; | |
padding-bottom: 4px; | |
padding-left: 2px; | |
padding-right: 2px; | |
padding-top: 4px; | |
} | |
#parent #container .number { | |
color: rgb(0, 0, 0); | |
font-family: arial, helvetica, sans-serif; | |
font-size: 13.3333px; | |
width: 342.65px; | |
margin-right: 7px; | |
} | |
#parent #container .op { | |
color: rgb(0, 0, 0); | |
font-family: arial, helvetica, sans-serif; | |
font-size: 13.3333px; | |
margin-bottom: 8px; | |
margin-left: 0px; | |
margin-right: 0px; | |
margin-top: 4px; | |
overflow-x: hidden; | |
overflow-y: hidden; | |
} | |
#parent #container .op blockquote { | |
margin-left: 0px !important; | |
} | |
#parent #container .name { | |
color: rgb(17, 119, 67); | |
font-family: arial, helvetica, sans-serif; | |
font-size: 13.3333px; | |
font-weight: 700; | |
margin-left: 7px; | |
} | |
#parent #container .quote { | |
color: rgb(221, 0, 0); | |
font-family: arial, helvetica, sans-serif; | |
font-size: 13.3333px; | |
text-decoration-color: rgb(221, 0, 0); | |
text-decoration-line: underline; | |
text-decoration-style: solid; | |
text-decoration-thickness: auto; | |
} | |
#parent #container .greentext { | |
color: rgb(120, 153, 34); | |
font-family: arial, helvetica, sans-serif; | |
font-size: 13.3333px; | |
} | |
#parent #container blockquote { | |
margin: 0px !important; | |
margin-block-start: 1em; | |
margin-block-end: 1em; | |
margin-inline-start: 40px; | |
margin-inline-end: 40px; | |
margin-top: 13.33px !important; | |
margin-bottom: 13.33px !important; | |
margin-left: 40px !important; | |
margin-right: 40px !important; | |
} | |
#parent #container .message { | |
color: black; | |
border: none; | |
} | |
""" | |
posts = [] | |
post = '' | |
c = -2 | |
for line in f.splitlines(): | |
line += "\n" | |
if line == '-----\n': | |
continue | |
elif line.startswith('--- '): | |
c += 1 | |
if post != '': | |
src = process_post(post, c) | |
posts.append(src) | |
post = line | |
else: | |
post += line | |
if post != '': | |
src = process_post(post, c) | |
posts.append(src) | |
for i in range(len(posts)): | |
if i == 0: | |
posts[i] = f'<div class="op">{posts[i]}</div>\n' | |
else: | |
posts[i] = f'<div class="reply">{posts[i]}</div>\n' | |
output = '' | |
output += f'<style>{css}</style><div id="parent"><div id="container">' | |
for post in posts: | |
output += post | |
output += '</div></div>' | |
output = output.split('\n') | |
for i in range(len(output)): | |
output[i] = re.sub(r'^(>(.*?)(<br>|</div>))', r'<span class="greentext">\1</span>', output[i]) | |
output[i] = re.sub(r'^<blockquote class="message">(>(.*?)(<br>|</div>))', r'<blockquote class="message"><span class="greentext">\1</span>', output[i]) | |
output = '\n'.join(output) | |
return output | |
def get_image_cache(path): | |
cache_folder = Path("cache") | |
if not cache_folder.exists(): | |
cache_folder.mkdir() | |
mtime = os.stat(path).st_mtime | |
if (path in image_cache and mtime != image_cache[path][0]) or (path not in image_cache): | |
img = Image.open(path) | |
img.thumbnail((200, 200)) | |
output_file = Path(f'cache/{path.name}_cache.png') | |
img.convert('RGB').save(output_file, format='PNG') | |
image_cache[path] = [mtime, output_file.as_posix()] | |
return image_cache[path][1] | |
def generate_chat_html(history, name1, name2, character): | |
css = """ | |
.chat { | |
margin-left: auto; | |
margin-right: auto; | |
max-width: 800px; | |
height: 66.67vh; | |
overflow-y: auto; | |
padding-right: 20px; | |
display: flex; | |
flex-direction: column-reverse; | |
} | |
.message { | |
display: grid; | |
grid-template-columns: 60px 1fr; | |
padding-bottom: 25px; | |
font-size: 15px; | |
font-family: Helvetica, Arial, sans-serif; | |
line-height: 1.428571429; | |
} | |
.circle-you { | |
width: 50px; | |
height: 50px; | |
background-color: rgb(238, 78, 59); | |
border-radius: 50%; | |
} | |
.circle-bot { | |
width: 50px; | |
height: 50px; | |
background-color: rgb(59, 78, 244); | |
border-radius: 50%; | |
} | |
.circle-bot img, .circle-you img { | |
border-radius: 50%; | |
width: 100%; | |
height: 100%; | |
object-fit: cover; | |
} | |
.text { | |
} | |
.text p { | |
margin-top: 5px; | |
} | |
.username { | |
font-weight: bold; | |
} | |
.message-body { | |
} | |
.message-body img { | |
max-width: 300px; | |
max-height: 300px; | |
border-radius: 20px; | |
} | |
.message-body p { | |
margin-bottom: 0 !important; | |
font-size: 15px !important; | |
line-height: 1.428571429 !important; | |
} | |
.dark .message-body p em { | |
color: rgb(138, 138, 138) !important; | |
} | |
.message-body p em { | |
color: rgb(110, 110, 110) !important; | |
} | |
""" | |
output = '' | |
output += f'<style>{css}</style><div class="chat" id="chat">' | |
img = '' | |
for i in [ | |
f"characters/{character}.png", | |
f"characters/{character}.jpg", | |
f"characters/{character}.jpeg", | |
"img_bot.png", | |
"img_bot.jpg", | |
"img_bot.jpeg" | |
]: | |
path = Path(i) | |
if path.exists(): | |
img = f'<img src="file/{get_image_cache(path)}">' | |
break | |
img_me = '' | |
for i in ["img_me.png", "img_me.jpg", "img_me.jpeg"]: | |
path = Path(i) | |
if path.exists(): | |
img_me = f'<img src="file/{get_image_cache(path)}">' | |
break | |
for i,_row in enumerate(history[::-1]): | |
row = _row.copy() | |
row[0] = re.sub(r"(\*\*)([^\*\n]*)(\*\*)", r"<b>\2</b>", row[0]) | |
row[1] = re.sub(r"(\*\*)([^\*\n]*)(\*\*)", r"<b>\2</b>", row[1]) | |
row[0] = re.sub(r"(\*)([^\*\n]*)(\*)", r"<em>\2</em>", row[0]) | |
row[1] = re.sub(r"(\*)([^\*\n]*)(\*)", r"<em>\2</em>", row[1]) | |
p = '\n'.join([f"<p>{x}</p>" for x in row[1].split('\n')]) | |
output += f""" | |
<div class="message"> | |
<div class="circle-bot"> | |
{img} | |
</div> | |
<div class="text"> | |
<div class="username"> | |
{name2} | |
</div> | |
<div class="message-body"> | |
{p} | |
</div> | |
</div> | |
</div> | |
""" | |
if not (i == len(history)-1 and len(row[0]) == 0): | |
p = '\n'.join([f"<p>{x}</p>" for x in row[0].split('\n')]) | |
output += f""" | |
<div class="message"> | |
<div class="circle-you"> | |
{img_me} | |
</div> | |
<div class="text"> | |
<div class="username"> | |
{name1} | |
</div> | |
<div class="message-body"> | |
{p} | |
</div> | |
</div> | |
</div> | |
""" | |
output += "</div>" | |
return output | |