html_generator.py 8.1 KB

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