blog_writer.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. import datetime
  2. import json
  3. import openai
  4. import os
  5. from typing import Optional
  6. from tool_lib.util import EBC
  7. class Topic(EBC):
  8. def __init__(self, topic_name: str, topic_detailed_description=''):
  9. self.topic_name = topic_name
  10. self.topic_detailed_description = topic_detailed_description
  11. class Template(EBC):
  12. def __init__(self, template_name: str, template_content: str, formatting_kwargs: Optional[dict] = None):
  13. self.template_name = template_name
  14. self.template_content = template_content
  15. if formatting_kwargs is None:
  16. formatting_kwargs = {}
  17. self.formatting_kwargs = formatting_kwargs
  18. def update_formatting_kwargs(self, **kwargs):
  19. self.formatting_kwargs.update(kwargs)
  20. def format(self, topic: Topic):
  21. return self.template_content.format(topic_name=topic.topic_name, topic_detailed_description=topic.topic_detailed_description, **self.formatting_kwargs)
  22. class EnDBlogTemplate(Template):
  23. def __init__(self,
  24. min_words=400,
  25. max_words=600):
  26. template_name = 'end_blog_template'
  27. raise RuntimeError('Deprecated')
  28. template_content = '''For context: You are writing a blog post for publication on the website of our company EnD UG.
  29. We specialize in tour planning software and are proud that our product is fast, reliable and easy to use.
  30. It allows our customers to plan the driving routes of their employees automatically while optimizing the driving time, fuel usage and timeliness.
  31. It also allows our customers to plan the driving routes of their employees manually, while giving them suggestions on how to improve the route.
  32. Please write a blog post about the topic of "{topic_name}" in a length of {min_words} to {max_words}. {topic_detailed_description}
  33. Make sure that the blog post is written in a way that is easy to understand for visitors to our website, including potential customers, but technically detailed enough to show that the writer has expertise in the topic.
  34. It should be written in an informative and factual way and not be promotional.
  35. Do not address the reader directly. Write in third person. In particular, avoid phrases like "At EnD UG we ..." or "As a business manager you ..." or "our [company, tool, software, ...]".
  36. Include a title and format the output as markdown. In particular, after each sentence, add a newline, and an additional one after paragraphs.
  37. Do not include URLs, images or references to other blog posts.
  38. '''
  39. super().__init__(template_name, template_content, {'min_words': min_words, 'max_words': max_words})
  40. class TechnicalBlogTemplate(Template):
  41. def __init__(self,
  42. min_words=400,
  43. max_words=600,
  44. language='English'):
  45. mean_words = (min_words + max_words) / 2
  46. template_name = 'technical_blog_template'
  47. template_content = '''Please write a blog post about the topic of "{topic_name}" in a length of {min_words} to {max_words}, ideally around {mean_words}. {topic_detailed_description}
  48. Make sure that the blog post is written in a way that is easy to understand, but technically detailed enough to show that the writer has expertise in the topic.
  49. It should be written in an informative and factual way and not be promotional.
  50. Do not address the reader directly. Write in third person. Write in {language}.
  51. Include a title and format the output as markdown. In particular, after each sentence, add a newline, and an additional one after paragraphs.
  52. Structure sections with headings.
  53. Do not include URLs, images or references to other blog posts.
  54. '''
  55. super().__init__(template_name, template_content, {'min_words': min_words,
  56. 'max_words': max_words,
  57. 'mean_words': mean_words,
  58. 'language': language})
  59. class BlogCreator(EBC):
  60. def __init__(self, template: Template, topic: Topic):
  61. self.template = template
  62. self.topic = topic
  63. def request_template(self):
  64. return self.template.template_content
  65. def write(self):
  66. message = [{"role": "user",
  67. "content": self.request()}]
  68. response = openai.ChatCompletion.create(
  69. model="gpt-3.5-turbo",
  70. messages=message,
  71. temperature=0.2,
  72. max_tokens=1000,
  73. frequency_penalty=0.0
  74. )
  75. return response['choices'][0]['message']['content']
  76. def request(self):
  77. return self.template.format(self.topic)
  78. def to_disk(self):
  79. to_file = os.path.abspath(f'blog_posts/{topic.topic_name}_{datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")}.json')
  80. os.makedirs(os.path.dirname(to_file), exist_ok=True)
  81. print(f'Requesting info for {to_file}...')
  82. result = {'blogger': self.to_json(),
  83. 'dt_created': datetime.datetime.now().timestamp(),
  84. 'request': self.request(),
  85. 'result': self.write()}
  86. with open(to_file, 'w', encoding='utf-8') as f:
  87. json.dump(result, f, indent=4)
  88. with open(to_file.replace('.json', '.md'), 'w', encoding='utf-8') as f:
  89. f.write(result['result'])
  90. print(f'Wrote {to_file}')
  91. if __name__ == '__main__':
  92. topics = [
  93. # Topic('Problem des Handlungsreisenden (Traveling Salesperson)'),
  94. # Topic('k-opt Algorithmus für das Traveling Salesperson Problem'),
  95. # Topic('Lineare Programmierung'),
  96. # Topic('Ganzzahlige lineare Optimierung'),
  97. # Topic('Clustering', topic_detailed_description='Also mention that clustering can be used as a pre-processing step when solving the traveling salesperson problem.'),
  98. # Topic('OpenAPI und Swagger'),
  99. ]
  100. for topic in topics:
  101. BlogCreator(TechnicalBlogTemplate(language='German'), topic).to_disk()