main.py 24 KB

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