html_generator.py 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. '''
  2. This is a library for formatting GPT-4chan and chat outputs as nice HTML.
  3. '''
  4. import base64
  5. import copy
  6. import re
  7. from pathlib import Path
  8. def generate_basic_html(s):
  9. css = """
  10. .container {
  11. max-width: 600px;
  12. margin-left: auto;
  13. margin-right: auto;
  14. background-color: #D9D9D9;
  15. padding:3em;
  16. }
  17. .container p {
  18. font-size: 14px !important;
  19. color: black !important;
  20. font-family: helvetica !important;
  21. line-height: 1.428571429 !important;
  22. margin-bottom: 22px;
  23. }
  24. """
  25. s = '\n'.join([f'<p>{line}</p>' for line in s.split('\n')])
  26. s = f'<style>{css}</style><div class="container">{s}</div>'
  27. return s
  28. def process_post(post, c):
  29. t = post.split('\n')
  30. number = t[0].split(' ')[1]
  31. if len(t) > 1:
  32. src = '\n'.join(t[1:])
  33. else:
  34. src = ''
  35. src = re.sub('>', '&gt;', src)
  36. src = re.sub('(&gt;&gt;[0-9]*)', '<span class="quote">\\1</span>', src)
  37. src = re.sub('\n', '<br>\n', src)
  38. src = f'<blockquote class="message">{src}\n'
  39. src = f'<span class="name">Anonymous </span> <span class="number">No.{number}</span>\n{src}'
  40. return src
  41. def generate_4chan_html(f):
  42. css = """
  43. #container {
  44. background-color: #eef2ff;
  45. padding: 17px;
  46. }
  47. .reply {
  48. background-color: rgb(214, 218, 240);
  49. border-bottom-color: rgb(183, 197, 217);
  50. border-bottom-style: solid;
  51. border-bottom-width: 1px;
  52. border-image-outset: 0;
  53. border-image-repeat: stretch;
  54. border-image-slice: 100%;
  55. border-image-source: none;
  56. border-image-width: 1;
  57. border-left-color: rgb(0, 0, 0);
  58. border-left-style: none;
  59. border-left-width: 0px;
  60. border-right-color: rgb(183, 197, 217);
  61. border-right-style: solid;
  62. border-right-width: 1px;
  63. border-top-color: rgb(0, 0, 0);
  64. border-top-style: none;
  65. border-top-width: 0px;
  66. color: rgb(0, 0, 0);
  67. display: table;
  68. font-family: arial, helvetica, sans-serif;
  69. font-size: 13.3333px;
  70. margin-bottom: 4px;
  71. margin-left: 0px;
  72. margin-right: 0px;
  73. margin-top: 4px;
  74. overflow-x: hidden;
  75. overflow-y: hidden;
  76. padding-bottom: 2px;
  77. padding-left: 2px;
  78. padding-right: 2px;
  79. padding-top: 2px;
  80. }
  81. .number {
  82. color: rgb(0, 0, 0);
  83. font-family: arial, helvetica, sans-serif;
  84. font-size: 13.3333px;
  85. width: 342.65px;
  86. }
  87. .op {
  88. color: rgb(0, 0, 0);
  89. font-family: arial, helvetica, sans-serif;
  90. font-size: 13.3333px;
  91. margin-bottom: 8px;
  92. margin-left: 0px;
  93. margin-right: 0px;
  94. margin-top: 4px;
  95. overflow-x: hidden;
  96. overflow-y: hidden;
  97. }
  98. .op blockquote {
  99. margin-left:7px;
  100. }
  101. .name {
  102. color: rgb(17, 119, 67);
  103. font-family: arial, helvetica, sans-serif;
  104. font-size: 13.3333px;
  105. font-weight: 700;
  106. margin-left: 7px;
  107. }
  108. .quote {
  109. color: rgb(221, 0, 0);
  110. font-family: arial, helvetica, sans-serif;
  111. font-size: 13.3333px;
  112. text-decoration-color: rgb(221, 0, 0);
  113. text-decoration-line: underline;
  114. text-decoration-style: solid;
  115. text-decoration-thickness: auto;
  116. }
  117. .greentext {
  118. color: rgb(120, 153, 34);
  119. font-family: arial, helvetica, sans-serif;
  120. font-size: 13.3333px;
  121. }
  122. blockquote {
  123. margin-block-start: 1em;
  124. margin-block-end: 1em;
  125. margin-inline-start: 40px;
  126. margin-inline-end: 40px;
  127. }
  128. """
  129. posts = []
  130. post = ''
  131. c = -2
  132. for line in f.splitlines():
  133. line += "\n"
  134. if line == '-----\n':
  135. continue
  136. elif line.startswith('--- '):
  137. c += 1
  138. if post != '':
  139. src = process_post(post, c)
  140. posts.append(src)
  141. post = line
  142. else:
  143. post += line
  144. if post != '':
  145. src = process_post(post, c)
  146. posts.append(src)
  147. for i in range(len(posts)):
  148. if i == 0:
  149. posts[i] = f'<div class="op">{posts[i]}</div>\n'
  150. else:
  151. posts[i] = f'<div class="reply">{posts[i]}</div>\n'
  152. output = ''
  153. output += f'<style>{css}</style><div id="container">'
  154. for post in posts:
  155. output += post
  156. output += '</div>'
  157. output = output.split('\n')
  158. for i in range(len(output)):
  159. output[i] = re.sub(r'^(&gt;(.*?)(<br>|</div>))', r'<span class="greentext">\1</span>', output[i])
  160. output[i] = re.sub(r'^<blockquote class="message">(&gt;(.*?)(<br>|</div>))', r'<blockquote class="message"><span class="greentext">\1</span>', output[i])
  161. output = '\n'.join(output)
  162. return output
  163. def generate_chat_html(history, name1, name2, character):
  164. css = """
  165. .chat {
  166. margin-left: auto;
  167. margin-right: auto;
  168. max-width: 800px;
  169. height: 66.67vh;
  170. overflow-y: auto;
  171. padding-right: 20px;
  172. display: flex;
  173. flex-direction: column-reverse;
  174. }
  175. .message {
  176. display: grid;
  177. grid-template-columns: 60px 1fr;
  178. padding-bottom: 22px;
  179. font-size: 15px;
  180. font-family: helvetica;
  181. line-height: 1.428571429;
  182. }
  183. .circle-you {
  184. width: 50px;
  185. height: 50px;
  186. background-color: rgb(244, 78, 59);
  187. border-radius: 50%;
  188. }
  189. .circle-bot {
  190. width: 50px;
  191. height: 50px;
  192. background-color: rgb(59, 78, 244);
  193. border-radius: 50%;
  194. }
  195. .circle-bot img, .circle-you img {
  196. border-radius: 50%;
  197. width: 100%;
  198. height: 100%;
  199. object-fit: cover;
  200. }
  201. .text {
  202. }
  203. .text p {
  204. margin-top: 5px;
  205. }
  206. .username {
  207. font-weight: bold;
  208. }
  209. .message-body {
  210. }
  211. .message-body img {
  212. max-width: 300px;
  213. max-height: 300px;
  214. border-radius: 20px;
  215. }
  216. .message-body p {
  217. margin-bottom: 0 !important;
  218. font-size: 15px !important;
  219. line-height: 1.428571429 !important;
  220. }
  221. """
  222. output = ''
  223. output += f'<style>{css}</style><div class="chat" id="chat">'
  224. img = ''
  225. for i in [
  226. f"characters/{character}.png",
  227. f"characters/{character}.jpg",
  228. f"characters/{character}.jpeg",
  229. "img_bot.png",
  230. "img_bot.jpg",
  231. "img_bot.jpeg"
  232. ]:
  233. if Path(i).exists():
  234. with open(i, "rb") as image_file:
  235. encoded_string = base64.b64encode(image_file.read())
  236. if i.endswith('png'):
  237. img = f'<img src="data:image/png;base64,{encoded_string.decode("utf-8")}">'
  238. elif i.endswith('jpg') or i.endswith('jpeg'):
  239. img = f'<img src="data:image/jpg;base64,{encoded_string.decode("utf-8")}">'
  240. break
  241. img_me = ''
  242. for i in ["img_me.png", "img_me.jpg", "img_me.jpeg"]:
  243. if Path(i).exists():
  244. img_me = f'<img src="file/{i}">'
  245. break
  246. for i,_row in enumerate(history[::-1]):
  247. row = _row.copy()
  248. row[0] = re.sub(r"(\*\*)([^\*\n]*)(\*\*)", r"<b>\2</b>", row[0])
  249. row[1] = re.sub(r"(\*\*)([^\*\n]*)(\*\*)", r"<b>\2</b>", row[1])
  250. row[0] = re.sub(r"(\*)([^\*\n]*)(\*)", r"<em>\2</em>", row[0])
  251. row[1] = re.sub(r"(\*)([^\*\n]*)(\*)", r"<em>\2</em>", row[1])
  252. p = '\n'.join([f"<p>{x}</p>" for x in row[1].split('\n')])
  253. output += f"""
  254. <div class="message">
  255. <div class="circle-bot">
  256. {img}
  257. </div>
  258. <div class="text">
  259. <div class="username">
  260. {name2}
  261. </div>
  262. <div class="message-body">
  263. {p}
  264. </div>
  265. </div>
  266. </div>
  267. """
  268. if not (i == len(history)-1 and len(row[0]) == 0):
  269. p = '\n'.join([f"<p>{x}</p>" for x in row[0].split('\n')])
  270. output += f"""
  271. <div class="message">
  272. <div class="circle-you">
  273. {img_me}
  274. </div>
  275. <div class="text">
  276. <div class="username">
  277. {name1}
  278. </div>
  279. <div class="message-body">
  280. {p}
  281. </div>
  282. </div>
  283. </div>
  284. """
  285. output += "</div>"
  286. return output