main.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  1. import io
  2. import logging
  3. import os
  4. import json
  5. import re
  6. import sys
  7. import traceback
  8. import openai
  9. import requests
  10. from openai import OpenAI
  11. from flask import Flask, request, jsonify, send_from_directory, url_for
  12. from convert import alpaca_to_chatgpt, csv_to_jsonl
  13. app = Flask(__name__)
  14. ssl = None
  15. # ssl =('/etc/ssl/sample.crt', '/etc/ssl/sample.pem')
  16. app.openai_key = os.environ.get("OPENAI_KEY", "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")
  17. app.openai_client = OpenAI(api_key=app.openai_key)
  18. #logging.basicConfig(level=logging.DEBUG, filename='/jkt-disk-01/app/mms/chatgpt-apache/chatgpt.log', format='%(asctime)s %(message)s')
  19. app.chat_messages = [
  20. {"role": "system",
  21. "content": "Please respond professionally and in a friendly manner, using the same language as the original request."}
  22. ]
  23. app.translate_messages = [
  24. {"role": "system",
  25. "content": "Please translate using the requested language."}
  26. ]
  27. app.suggest_messages = [
  28. {"role": "system",
  29. "content": "Please suggest reply messages based on the previous conversations and the user's request."}
  30. ]
  31. app.recommend_messages = [
  32. {"role": "system",
  33. "content": "Give normalized total weight of each category in json based on headlines"
  34. }
  35. ]
  36. app.summary_messages = [
  37. {"role": "system",
  38. "content": "Please summarize an article."
  39. }
  40. ]
  41. UPLOAD_FOLDER = 'files'
  42. app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
  43. @app.route('/files/<name>')
  44. def download_file(name):
  45. return send_from_directory(app.config["UPLOAD_FOLDER"], name)
  46. @app.route('/', methods=['GET', 'POST'])
  47. def test():
  48. return jsonify({"status": "0"})
  49. def recommend(headlines, category):
  50. chat_messages = app.recommend_messages.copy()
  51. try:
  52. json_payload = {
  53. "role": "user",
  54. "content": f"""{headlines}
  55. Berikan nilai berat masing-masing kategori, jumlahkan dan normalisasikan:
  56. {category}
  57. Berikan dalam bentuk json
  58. """
  59. }
  60. chat_messages.append(json_payload)
  61. json_response = app.openai_client.chat.completions.create(model="gpt-3.5-turbo-1106",
  62. messages=chat_messages,
  63. response_format={"type": "json_object"}
  64. )
  65. return json.loads(json_response.choices[0].message.content)
  66. except Exception as error_print:
  67. app.logger.exception("error")
  68. result = {}, 405
  69. def vision(message, image_url=None, image_b64=None):
  70. chat_messages = app.chat_messages.copy()
  71. url = ""
  72. if image_url:
  73. url = f"{image_url}"
  74. elif image_b64:
  75. url = f"data:image/jpeg;base64,{image_b64}"
  76. try:
  77. json_payload = {
  78. "role": "user",
  79. "content": [
  80. {"type": "text", "text": message},
  81. {
  82. "type": "image_url",
  83. "image_url": {
  84. "url": url,
  85. },
  86. },
  87. ],
  88. }
  89. chat_messages.append(json_payload)
  90. json_response = app.openai_client.chat.completions.create(
  91. model="gpt-4o",
  92. messages=chat_messages,
  93. max_tokens=500
  94. )
  95. return {"role": "assistant", "content": json_response.choices[0].message.content}
  96. except Exception as error_print:
  97. app.logger.exception("error")
  98. result = {}, 405
  99. @app.route('/gpt', methods=['POST'])
  100. def gpt():
  101. assistant_id = ""
  102. chat_messages = []
  103. chat_model = "gpt-3.5-turbo"
  104. use_video = False
  105. suggest = False
  106. summarize = False
  107. predict_q = 0
  108. max_char_msg = 500
  109. max_resp_token = 600
  110. category = []
  111. headlines = []
  112. image_url = ""
  113. num_choices = 1
  114. json_payload = request.get_json()
  115. if not json_payload:
  116. json_payload = []
  117. has_named_params = False
  118. if isinstance(json_payload, dict):
  119. has_named_params = 'payload' in json_payload
  120. if 'payload' in json_payload:
  121. if 'predict_q' in json_payload:
  122. predict_q = 5 if json_payload['predict_q'] > 4 else 0 if json_payload['predict_q'] < 1 else \
  123. json_payload['predict_q']
  124. if 'num_choices' in json_payload:
  125. num_choices = 5 if json_payload['num_choices'] > 4 else 1 if json_payload['num_choices'] < 2 else \
  126. json_payload['num_choices']
  127. if 'use_video' in json_payload:
  128. use_video = json_payload['use_video'] == "1"
  129. if 'chat_model' in json_payload and 'assistant_id' not in json_payload:
  130. chat_model = json_payload['chat_model']
  131. max_resp_token = 2048
  132. if 'translate' in json_payload:
  133. chat_messages = app.translate_messages.copy()
  134. json_payload['payload'][-1]['content'] = json_payload['payload'][-1][
  135. 'content'] + f" (Translate to {json_payload['translate']})"
  136. elif 'suggest' in json_payload:
  137. suggest = json_payload['suggest'] == "1"
  138. if suggest:
  139. chat_messages = app.suggest_messages.copy()
  140. else:
  141. chat_messages = app.chat_messages.copy()
  142. json_payload['payload'][-1]['content'] = json_payload['payload'][-1][
  143. 'content'] + f" What can I say to him/her?"
  144. elif 'summarize' in json_payload:
  145. summarize = json_payload['summarize'] == "1"
  146. if summarize:
  147. chat_messages = app.summary_messages.copy()
  148. max_char_msg = 2000
  149. max_resp_token = 1000
  150. else:
  151. chat_messages = app.chat_messages.copy()
  152. json_payload['payload'][-1]['content'] = f"Please summarize this article:\n" + \
  153. json_payload['payload'][-1]['content']
  154. elif 'assistant_id' in json_payload:
  155. assistant_id = json_payload['assistant_id']
  156. else:
  157. chat_messages = app.chat_messages.copy()
  158. json_payload = json_payload['payload']
  159. if isinstance(json_payload, dict):
  160. json_payload = [json_payload]
  161. elif 'greeting' in json_payload:
  162. chat_messages = app.chat_messages.copy()
  163. company_name = json_payload['greeting']['company_name']
  164. timestamp = json_payload['greeting']['timestamp']
  165. islamic_message = f"Apakah Nama '{company_name}' terdapat unsur islami? Jawab dengan 'Ya' atau 'Tidak'"
  166. islam_messages = app.chat_messages.copy()
  167. islam_messages.append({
  168. "role": "user",
  169. "content": islamic_message
  170. })
  171. islamic_response = app.openai_client.chat.completions.create(model="gpt-3.5-turbo", # GPT-3.5 Turbo engine
  172. messages=islam_messages,
  173. max_tokens=2, temperature=0.5)
  174. if 'Ya' in islamic_response.choices[0].message.content:
  175. greeting_message = f"Buatkan respons chatbot berupa greeting dari chat perusahaan bernama {company_name} pada jam {timestamp}, tidak perlu mention waktu, dan jawab dengan 'Assalamu'alaikum...' terlebih dahulu"
  176. else:
  177. greeting_message = f"Buatkan respons chatbot berupa greeting dari chat perusahaan bernama {company_name} pada jam {timestamp}, tidak perlu mention waktu"
  178. json_payload = [
  179. {
  180. "role": "user",
  181. "content": greeting_message
  182. }
  183. ]
  184. elif 'recommend' in json_payload:
  185. headlines = json_payload['recommend']['headlines']
  186. category = json_payload['recommend']['category']
  187. return recommend(headlines, category)
  188. elif 'image_url' in json_payload:
  189. image = json_payload['image_url']
  190. message = json_payload["message"] if 'message' in json_payload else "Ini gambar apa?"
  191. return vision(message, image_url=image)
  192. elif 'image_b64' in json_payload:
  193. image = json_payload['image_b64']
  194. message = json_payload["message"] if 'message' in json_payload else "Ini gambar apa?"
  195. return vision(message, image_b64=image_url)
  196. else:
  197. chat_messages = app.chat_messages.copy()
  198. json_payload = [json_payload]
  199. json_payload = json_payload[-5:]
  200. for message in json_payload:
  201. if message['role'] == 'user':
  202. content = message['content'].lower()
  203. else:
  204. content = message['content']
  205. content_arr = content.split(" ")
  206. new_content_arr = content[:max_char_msg].split(" ")
  207. new_content_len = len(new_content_arr)
  208. arr = []
  209. for i in range(new_content_len):
  210. arr.append(content_arr[i])
  211. message['content'] = " ".join(arr)
  212. chat_messages.append(message)
  213. app.logger.info(chat_messages)
  214. result = {}
  215. try:
  216. n = num_choices
  217. if assistant_id and not suggest:
  218. runs = app.openai_client.beta.threads.create_and_run_poll(
  219. assistant_id=assistant_id,
  220. thread={
  221. "messages": chat_messages
  222. }
  223. )
  224. messages = list(app.openai_client.beta.threads.messages.list(thread_id=runs.thread_id, run_id=runs.id))
  225. message_content = messages[0].content[0].text
  226. app.logger.info(message_content.value)
  227. pattern = re.compile(r"【\d+:\d+†\(?source\)?】")
  228. filtered_message = pattern.sub("", message_content.value)
  229. result = {"role": "assistant", "content": filtered_message}
  230. else:
  231. json_response = app.openai_client.chat.completions.create(model=chat_model,
  232. messages=chat_messages,
  233. max_tokens=max_resp_token, temperature=0.7, n=n)
  234. app.logger.info(json_response.choices[0].message)
  235. if has_named_params:
  236. if suggest:
  237. choices = json_response.choices
  238. messages = [i.message for i in choices]
  239. json_formatted = []
  240. for message in messages:
  241. json_formatted.append({"role": "assistant", "content": message.content})
  242. result = {"url": "", "message": json_formatted}
  243. else:
  244. if use_video:
  245. # TODO: to be implemented
  246. result = {"url": url_for('download_file', name="test.mp4", _external=True),
  247. "message": {"role": "assistant", "content": json_response.choices[0].message.content}}
  248. else:
  249. result = {"role": "assistant", "content": json_response.choices[0].message.content}
  250. else:
  251. result = {"role": "assistant", "content": json_response.choices[0].message.content}
  252. if predict_q:
  253. query_q = {
  254. "role": "user",
  255. "content": f"Berikan {predict_q} pertanyaan lain yang akan saya ajukan berdasarkan percakapan kali ini dalam bentuk json array"
  256. }
  257. chat_messages.append(result)
  258. chat_messages.append(query_q)
  259. json_response_q = app.openai_client.chat.completions.create(model=chat_model,
  260. messages=chat_messages,
  261. max_tokens=max_resp_token,
  262. temperature=0.2,
  263. response_format={"type": "json_object"})
  264. json_response_dict = json.loads(json_response_q.choices[0].message.content)
  265. if json_response_dict is not None:
  266. if isinstance(json_response_dict, dict):
  267. if len(json_response_dict) > 1:
  268. qs = []
  269. for q in json_response_dict.values():
  270. qs.append(q)
  271. json_response_dict = qs
  272. else:
  273. try:
  274. first_key = next(iter(json_response_dict))
  275. json_response_dict = json_response_dict[first_key]
  276. except StopIteration:
  277. json_response_dict = []
  278. elif isinstance(json_response_dict, str):
  279. json_response_dict = [json_response_dict]
  280. result["predict_q"] = json_response_dict
  281. except openai.APITimeoutError as error_print:
  282. app.logger.exception("error")
  283. result = {"status": "error", "message": error_print.message}, 408
  284. except openai.NotFoundError as error_print:
  285. app.logger.exception("error")
  286. result = {"status": "error", "message": error_print.message}, error_print.status_code
  287. except Exception as error_print:
  288. app.logger.exception("error")
  289. result = {}, 405
  290. return result
  291. @app.route('/train', methods=['POST'])
  292. def train():
  293. prev_model = "gpt-3.5-turbo"
  294. if 'job_id' in request.form:
  295. return train_with_id(job_id=request.form['job_id'])
  296. elif 'train_file' in request.files:
  297. train_file = request.files['train_file']
  298. app.logger.info({"filename": train_file.filename})
  299. openai_file = None
  300. if train_file.filename.split('.')[1] == 'jsonl':
  301. openai_file = train_file.stream.read()
  302. elif train_file.filename.split('.')[1] == 'csv':
  303. openai_file = csv_to_jsonl(train_file.stream.read())
  304. elif train_file.filename.split('.')[1] == 'json':
  305. openai_file = alpaca_to_chatgpt(train_file)
  306. if 'prev_model' in request.form:
  307. prev_model = request.form['prev_model']
  308. app.logger.info(f"Previous model: {prev_model}")
  309. if 'mock' not in request.form:
  310. f = app.openai_client.files.create(
  311. file=openai_file,
  312. purpose="fine-tune"
  313. )
  314. job = app.openai_client.fine_tuning.jobs.create(
  315. training_file=f.id,
  316. model=prev_model,
  317. hyperparameters={
  318. "n_epochs": 5
  319. }
  320. )
  321. app.logger.info({"mock": "no", "status": job.status, "job_id": job.id})
  322. retval = {"status": job.status, "job_id": job.id}
  323. return retval
  324. else:
  325. app.logger.info({"mock": "yes", "status": "ok"})
  326. return {"status": "ok"}
  327. else:
  328. app.logger.error({"status": "error", "message": "Training file not found"})
  329. return {"status": "error", "message": "Training file not found"}
  330. def train_with_id(job_id):
  331. try:
  332. job = app.openai_client.fine_tuning.jobs.retrieve(job_id)
  333. if job.fine_tuned_model is None:
  334. app.logger.info({"job_id": job_id, "status": job.status})
  335. return {"status": job.status}
  336. else:
  337. app.logger.info({"job_id": job_id, "status": job.status, "model_name": job.fine_tuned_model})
  338. return {"status": job.status, "model_name": job.fine_tuned_model}
  339. except Exception as error_print:
  340. app.logger.exception("error")
  341. return {"status": "Could not find job from id"}
  342. @app.route('/assistant/create', methods=['POST'])
  343. def assistant_create():
  344. model_name = "gpt-3.5-turbo"
  345. assistant_name = "Assistant"
  346. assistant_ins = "Please respond professionally and in a friendly manner, using the same language as the original request."
  347. assistant = None
  348. if request.is_json:
  349. request_form = request.json
  350. else:
  351. request_form = request.form.copy()
  352. assistant_name = request_form.pop('name', assistant_name)
  353. assistant_ins = request_form.pop('instructions', assistant_ins)
  354. model_name = request_form.pop('model_name', model_name)
  355. try:
  356. assistant = app.openai_client.beta.assistants.create(
  357. name=assistant_name,
  358. instructions=assistant_ins,
  359. model=model_name,
  360. tools=[{"type": "file_search"}],
  361. **request_form
  362. )
  363. if 'attachment1' in request.files:
  364. resp_att = assistant_att()
  365. if resp_att['status'] == 'completed':
  366. resp_upd = assistant_update(assistant.id, resp_att['vector_store_id'])
  367. assistant_updated = "1" if resp_upd['status'] == 'ok' else "0"
  368. else:
  369. assistant_updated = "0"
  370. return {"status": "ok", "assistant_id": assistant.id, "assistant_updated": assistant_updated}
  371. else:
  372. return {"status": "ok", "assistant_id": assistant.id, "assistant_updated": "0"}
  373. except ValueError as e:
  374. return {"status": "error",
  375. "message": "Failed to create assistant, please check whether your parameters are correct"}
  376. except Exception:
  377. return {"status": "error", "message": "Failed to create assistant, please try again"}
  378. @app.route('/assistant/attachment', methods=['POST'])
  379. def assistant_att():
  380. vector_store_id = request.form.get('vector_store_id', '')
  381. file_batch_id = request.form.get('file_batch_id', '')
  382. attachments: list[str] = []
  383. try:
  384. if not file_batch_id:
  385. if 'attachment1' not in request.files:
  386. return {"status": "error", "message": "No file for attachments"}
  387. else:
  388. has_attachments = True
  389. n = 1
  390. while has_attachments:
  391. if f'attachment{n}' in request.files:
  392. retf = app.openai_client.files.create(
  393. file=(request.files[f'attachment{n}'].filename,
  394. request.files[f'attachment{n}'].read()),
  395. purpose="assistants"
  396. )
  397. retf.filename = request.files[f'attachment{n}'].filename
  398. attachments.append(retf.id)
  399. n = n + 1
  400. else:
  401. has_attachments = False
  402. if vector_store_id:
  403. vector_store = app.openai_client.beta.vector_stores.retrieve(vector_store_id=vector_store_id)
  404. else:
  405. vector_store = app.openai_client.beta.vector_stores.create()
  406. file_batch = app.openai_client.beta.vector_stores.file_batches.create_and_poll(
  407. vector_store_id=vector_store.id,
  408. file_ids=attachments
  409. )
  410. return {"status": file_batch.status, "vector_store_id": vector_store.id, "file_batch_id": file_batch.id}
  411. else:
  412. file_batch = app.openai_client.beta.vector_stores.file_batches.retrieve(file_batch_id, vector_store_id=vector_store_id)
  413. return {"status": file_batch.status}
  414. except Exception as e:
  415. app.logger.exception("error")
  416. return {"status": "error", "message": "Upload attachment failed, please try again"}
  417. @app.route('/assistant/update', methods=['POST'])
  418. def assistant_update(aid=None, vid=None):
  419. try:
  420. if aid is not None and vid is not None:
  421. assistant_id = aid
  422. vector_store_id = vid
  423. else:
  424. assistant_id = request.form['assistant_id']
  425. vector_store_id = request.form['vector_store_id']
  426. app.openai_client.beta.assistants.update(
  427. assistant_id=assistant_id,
  428. tool_resources={"file_search": {"vector_store_ids": [vector_store_id]}},
  429. )
  430. return {"status": "ok"}
  431. except Exception as e:
  432. app.logger.exception("error")
  433. return {"status": "error", "message": "Update assistant failed, please try again"}
  434. @app.route('/llama', methods=['POST'])
  435. def llama():
  436. max_char_msg = 500
  437. max_resp_token = 600
  438. json_payload = request.get_json()
  439. if not json_payload:
  440. json_payload = []
  441. has_named_params = False
  442. if isinstance(json_payload, dict):
  443. has_named_params = 'payload' in json_payload
  444. if 'payload' in json_payload:
  445. json_payload = json_payload['payload']
  446. if isinstance(json_payload, dict):
  447. json_payload = [json_payload]
  448. else:
  449. json_payload = [json_payload]
  450. message = json_payload[-1]
  451. content = message['content']
  452. content_arr = content.split(" ")
  453. new_content_arr = content[:max_char_msg].split(" ")
  454. new_content_len = len(new_content_arr)
  455. arr = []
  456. for i in range(new_content_len):
  457. arr.append(content_arr[i])
  458. content = " ".join(arr)
  459. content = content + " Jawab dengan Bahasa Indonesia"
  460. try:
  461. json_request = {
  462. "model": "llama3",
  463. "prompt": content,
  464. "stream": False
  465. }
  466. r = requests.post("http://localhost:11434/api/generate", json=json_request)
  467. if r.status_code == 200:
  468. result = {
  469. "role": "assistant",
  470. "content": r.json()["response"]
  471. }
  472. else:
  473. result = {}, r.status_code
  474. except Exception as error_print:
  475. app.logger.exception("error")
  476. result = {}, 405
  477. return result
  478. # Press the green button in the gutter to run the script.
  479. if __name__ == '__main__':
  480. app.run(host='0.0.0.0', port=8348, debug=True, ssl_context=ssl)
  481. # See PyCharm help at https://www.jetbrains.com/help/pycharm/