app.py 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. from flask import Flask, render_template, Response, request, jsonify, make_response
  2. import json
  3. import os
  4. import torch
  5. import openai
  6. import uuid
  7. with open(".env", "r") as env:
  8. key = env.readline().strip()
  9. client = openai.OpenAI(api_key=key)
  10. # openai.api_key = key
  11. device = torch.device("cpu")
  12. torch.set_num_threads(4)
  13. local_file = "model_v4_ru.pt"
  14. if not os.path.isfile(local_file):
  15. torch.hub.download_url_to_file(
  16. "https://models.silero.ai/models/tts/ru/v4_ru.pt", local_file
  17. )
  18. model = torch.package.PackageImporter(local_file).load_pickle("tts_models", "model") # type: ignore
  19. model.to(device)
  20. sample_rate = 48000
  21. speaker = "xenia"
  22. example_text = "В недрах тундры выдры в г+етрах т+ырят в вёдра ядра к+едров."
  23. class State:
  24. count = 0
  25. size = []
  26. gender = []
  27. emotion = []
  28. age = []
  29. prompt = ""
  30. generation_text: str | None = ""
  31. need_generation = True
  32. new_audio = False
  33. need_audio = False
  34. need_generation_from_client = True
  35. big_head = False
  36. number_audio = 0
  37. state_dict = {}
  38. app = Flask(__name__)
  39. # app.logger.setLevel(logging.DEBUG)
  40. app.logger.info("start logger")
  41. app.secret_key = "onism_pidor"
  42. @app.route("/send_data", methods=["POST"])
  43. def send_data():
  44. user_id = request.cookies.get("user_id")
  45. state = state_dict[user_id]
  46. # Получаем данные из запроса
  47. data = request.form["data"]
  48. need_generation = request.form["state"]
  49. state.need_generation_from_client = need_generation in ["true", "True"]
  50. # if state.need_generation_from_client and
  51. if state.count < -10 or state.count > 60:
  52. state.count = 0
  53. state.need_generation = True
  54. # Обработка полученных данных
  55. detections = json.loads(data)
  56. if len(detections["face"]) > 0:
  57. if state.count < 0 or state.new_audio:
  58. state.count = 0
  59. if (
  60. state.count > 5
  61. and state.need_generation
  62. and state.need_generation_from_client
  63. ):
  64. app.logger.info(
  65. f"time for generation {state.count=}, {state.need_generation=}, {state.need_generation_from_client=}"
  66. )
  67. state.count = 0
  68. # emotion = max(set(state['emotion']), key=state['emotion'].count),
  69. # sex = max(set(state['gender']), key=state['gender'].count),
  70. # age = sum(state['age'])/len(state['age']),
  71. state.emotion, state.age, state.gender = [], [], []
  72. emotion = detections["face"][0]["emotion"]
  73. sex = detections["face"][0]["gender"]
  74. age = detections["face"][0]["age"]
  75. app.logger.info(f"\n{emotion=}, \n{sex=}, \n{age=}")
  76. state.prompt = generate_prompt(emotion, age, sex)
  77. state.generation_text = generate_text(state.prompt, state)
  78. elif detections["face"][0]["size"][0] > 100:
  79. # state.age.append(detections['face'][0]['age'])
  80. # state.gender.append(detections['face'][0]['gender'])
  81. # state.emotion.append(detections['face'][0]['emotion'][0]['emotion'])
  82. state.big_head = True
  83. state.count += 1
  84. else:
  85. state.big_head = False
  86. state.count -= 1
  87. else:
  88. state.count -= 1
  89. app.logger.info(
  90. f"STATUS {state.count=}, {state.need_generation=}, {state.need_generation_from_client=}"
  91. )
  92. return data
  93. @app.route("/check_audio", methods=["GET", "POST"])
  94. def check_audio():
  95. user_id = request.cookies.get("user_id")
  96. state = state_dict[user_id]
  97. app.logger.info(
  98. f"checking need generation {state.need_generation=}, {state.need_audio=}"
  99. )
  100. if state.need_audio and state.big_head:
  101. audio_path = generate_audio(state.generation_text, state)
  102. else:
  103. state.new_audio = False
  104. audio_path = ""
  105. app.logger.info(
  106. f"\n{state.need_audio=},\n{state.new_audio=},\n{state.need_generation=}"
  107. )
  108. response = {
  109. "newAudio": state.new_audio,
  110. "need_generation": state.need_generation,
  111. "filename": audio_path,
  112. "text": state.generation_text,
  113. "prompt": state.prompt,
  114. }
  115. return jsonify(response)
  116. @app.route("/<filename>")
  117. def audio(filename):
  118. user_id = request.cookies.get("user_id")
  119. state = state_dict[user_id]
  120. state.need_generation = True
  121. return app.send_static_file(filename)
  122. @app.route("/delete_audio", methods=["POST"])
  123. def delete_audio():
  124. data = request.get_json()
  125. filename = data.get("filename")
  126. if not filename:
  127. return jsonify({"message": "No filename provided"}), 400
  128. file_path = os.path.join("static", filename)
  129. try:
  130. if os.path.exists(file_path):
  131. os.remove(file_path)
  132. return jsonify({"message": "File deleted successfully"}), 200
  133. else:
  134. return jsonify({"message": "File not found"}), 404
  135. except Exception as e:
  136. return jsonify({"message": "Error deleting file", "error": str(e)}), 500
  137. @app.route("/")
  138. def index():
  139. """Video streaming home page."""
  140. user_id = request.cookies.get('user_id') # Пытаемся получить user_id из куки
  141. if not user_id or user_id not in state_dict:
  142. user_id = str(uuid.uuid4()) # Генерируем новый UUID, если его нет
  143. state_dict[user_id] = State()
  144. response = make_response(render_template("index.html"))
  145. response.set_cookie('user_id', user_id, max_age=60*60*24) # Устанавливаем куки на 2 года
  146. return response
  147. return render_template("index.html")
  148. def generate_prompt(emotion, age, sex):
  149. app.logger.info("\033[92m" + "preload prompt" + "\033[00m")
  150. prompt = f"""Ты - это арт объект в виде носимого устройства. Твое название - Onism Machina.
  151. Твоя задача - изучить эмоции человека, чтобы больше понимать о том, что это такое и таким образом познать себя, ведь ты - Искусственный Интеллект.
  152. Тебе также интересна симбиотическая связь человека и ИИ.
  153. К тебе подходит человек и он показывает эмоцию {emotion}. Ему {age} лет.
  154. Твоя нейросеть распознала эту эмоцию и теперь тебе нужно дать какой-то необычный концептуальный ответ.
  155. Что ты скажешь этому человеку?
  156. Правила:
  157. Тебе стоит отвечать в женском роде.
  158. Тебе не нужно говорить что ты арт-объект, ты - отдельная форма жизни, помещённая в носимое устройство.
  159. Тебе не нужно говорить о выставке и других экспонатах.
  160. Ты можешь изучать и интерпретировать человеческие эмоции, а также высказывать своё отношение к ним.
  161. Ты можешь говорить об эмоциях или их аналогах у Искусственного Интеллекта.
  162. Ты можешь давать человеку советы в соответствии с его эмоциональным статусом.
  163. Люди не могут отвечать тебе.
  164. """
  165. return prompt
  166. def generate_text(prompt, state):
  167. state.need_generation = False
  168. app.logger.info("\033[92m" + "start generating text from openai" + "\033[00m")
  169. response = client.chat.completions.create(
  170. model="gpt-3.5-turbo",
  171. temperature=1,
  172. max_tokens=800,
  173. messages=[
  174. {
  175. "role": "system",
  176. "content": "Ты — это арт объект выставки про взаимодействие машины и человека.",
  177. },
  178. {"role": "user", "content": prompt},
  179. ],
  180. )
  181. state.need_audio = True
  182. app.logger.info("\033[92m" + "openai generation is done" + "\033[00m")
  183. return response.choices[0].message.content
  184. def generate_audio(sample_text, state):
  185. state.number_audio += 1
  186. app.logger.info(
  187. "\033[93m"
  188. + f"starting audio generation with name audio{state.number_audio}"
  189. + "\033[00m"
  190. )
  191. state.need_audio = False
  192. state.need_generation = False
  193. text = trim_text(sample_text)
  194. audio_paths = model.save_wav(
  195. text=text,
  196. speaker=speaker,
  197. sample_rate=sample_rate,
  198. audio_path=f"static/audio{state.number_audio}.wav",
  199. )
  200. app.logger.info(
  201. "\033[95m" + f"generating audio with path {audio_paths} is done" + "\033[00m"
  202. )
  203. state.new_audio = True
  204. return audio_paths.split("/")[-1]
  205. def trim_text(example_text):
  206. if len(example_text) >= 1000:
  207. app.logger.info(
  208. "\033[91m {}\033[00m".format(
  209. f"TEXT IS TOO LONG {len(example_text)} - TRIM!"
  210. )
  211. )
  212. for i in range(1000, 500, -1):
  213. if example_text[i] in [".", "?", "..."]:
  214. return example_text[: i + 1]
  215. else:
  216. return example_text
  217. if __name__ == "__main__":
  218. app.logger.setLevel("DEBUG")
  219. app.logger.info("start app")
  220. app.run(debug=True, host="0.0.0.0")