├── contents ├── chapter02 │ ├── ex_name1.py │ ├── ex_list1.py │ ├── ex_reversed.py │ ├── ex_str_ops.py │ ├── ex_tuple1.py │ ├── ex_tuple2.py │ ├── ex_set2.py │ ├── __pycache__ │ │ ├── retry.cpython-310.pyc │ │ ├── ex_name2.cpython-37.pyc │ │ ├── sub_pgm.cpython-310.pyc │ │ ├── name_test2.cpython-310.pyc │ │ └── import_pgm2.cpython-310.pyc │ ├── ex_dict1.py │ ├── ex_list2.py │ ├── ex_ops.py │ ├── ex_list3.py │ ├── ex_set1.py │ ├── ex_func2.py │ ├── ex_exception.py │ ├── ex_enum.py │ ├── ex_str_fmt.py │ ├── ex_dict_packing.py │ ├── ex_slice.py │ ├── ex_str_funcs.py │ ├── ex_name2.py │ ├── ex_tuple3.py │ ├── ex_sorted.py │ ├── ex_raise.py │ ├── ex_cmph.py │ ├── ex_retry.py │ ├── ex_func1.py │ ├── ex_func_param.py │ ├── ex_dict_func_var.py │ ├── ex_func_var.py │ ├── ex_dict2.py │ ├── ex_loop.py │ └── ex_car.py ├── chapter07 │ ├── static │ │ └── images │ │ │ ├── logo.png │ │ │ └── jjinchin.png │ ├── __pycache__ │ │ ├── chatbot.cpython-310.pyc │ │ ├── chatbot.cpython-311.pyc │ │ ├── common.cpython-310.pyc │ │ ├── common.cpython-311.pyc │ │ ├── common.cpython-312.pyc │ │ └── jjinchin.cpython-310.pyc │ ├── common.py │ ├── application.py │ └── chatbot.py ├── chapter08 │ ├── static │ │ └── images │ │ │ ├── logo.png │ │ │ └── jjinchin.png │ ├── __pycache__ │ │ ├── chatbot.cpython-310.pyc │ │ ├── chatbot.cpython-311.pyc │ │ ├── common.cpython-310.pyc │ │ ├── common.cpython-311.pyc │ │ ├── jjinchin.cpython-310.pyc │ │ ├── characters.cpython-310.pyc │ │ └── characters.cpython-311.pyc │ ├── characters.py │ ├── application.py │ ├── common.py │ └── chatbot.py ├── chapter09 │ ├── static │ │ └── images │ │ │ ├── logo.png │ │ │ └── jjinchin.png │ ├── __pycache__ │ │ ├── chatbot.cpython-310.pyc │ │ ├── chatbot.cpython-311.pyc │ │ ├── chatbot.cpython-312.pyc │ │ ├── common.cpython-310.pyc │ │ ├── common.cpython-311.pyc │ │ ├── common.cpython-312.pyc │ │ ├── jjinchin.cpython-310.pyc │ │ ├── characters.cpython-310.pyc │ │ ├── characters.cpython-311.pyc │ │ ├── characters.cpython-312.pyc │ │ ├── function_calling.cpython-310.pyc │ │ ├── function_calling.cpython-311.pyc │ │ ├── function_calling.cpython-312.pyc │ │ └── parallel_function_calling.cpython-311.pyc │ ├── tavily_test.py │ ├── characters.py │ ├── common.py │ ├── application.py │ ├── chatbot.py │ ├── function_calling.py │ └── parallel_function_calling.py ├── chapter10 │ ├── static │ │ └── images │ │ │ ├── logo.png │ │ │ └── jjinchin.png │ ├── __pycache__ │ │ ├── chatbot.cpython-310.pyc │ │ ├── chatbot.cpython-311.pyc │ │ ├── chatbot.cpython-312.pyc │ │ ├── common.cpython-310.pyc │ │ ├── common.cpython-311.pyc │ │ ├── common.cpython-312.pyc │ │ ├── jjinchin.cpython-310.pyc │ │ ├── characters.cpython-310.pyc │ │ ├── characters.cpython-311.pyc │ │ ├── characters.cpython-312.pyc │ │ ├── warning_agent.cpython-310.pyc │ │ ├── warning_agent.cpython-311.pyc │ │ ├── warning_agent.cpython-312.pyc │ │ ├── function_calling.cpython-310.pyc │ │ └── function_calling.cpython-311.pyc │ ├── characters.py │ ├── report_generator.py │ ├── application.py │ ├── common.py │ ├── chatbot.py │ ├── warning_agent.py │ └── function_calling.py ├── chapter11 │ ├── static │ │ └── images │ │ │ ├── logo.png │ │ │ └── jjinchin.png │ ├── __pycache__ │ │ ├── chatbot.cpython-310.pyc │ │ ├── chatbot.cpython-311.pyc │ │ ├── common.cpython-310.pyc │ │ ├── common.cpython-311.pyc │ │ ├── jjinchin.cpython-310.pyc │ │ ├── characters.cpython-310.pyc │ │ ├── characters.cpython-311.pyc │ │ ├── warning_agent.cpython-310.pyc │ │ ├── memory_manager.cpython-310.pyc │ │ └── memory_manager.cpython-311.pyc │ ├── mongodb_delete.py │ ├── characters.py │ ├── mongodb_test.py │ ├── memory_manager.py │ ├── application.py │ ├── common.py │ └── chatbot.py ├── chapter13 │ ├── static │ │ └── images │ │ │ ├── logo.png │ │ │ └── jjinchin.png │ ├── __pycache__ │ │ ├── chatbot.cpython-310.pyc │ │ ├── chatbot.cpython-311.pyc │ │ ├── common.cpython-310.pyc │ │ ├── common.cpython-311.pyc │ │ ├── jjinchin.cpython-310.pyc │ │ ├── characters.cpython-310.pyc │ │ ├── characters.cpython-311.pyc │ │ ├── warning_agent.cpython-310.pyc │ │ ├── memory_manager.cpython-310.pyc │ │ └── memory_manager.cpython-311.pyc │ ├── characters.py │ ├── insert_memory.py │ ├── application.py │ ├── common.py │ ├── make_conversations.py │ ├── delete_by_date.ipynb │ ├── summarize_conversations.py │ ├── 대화내용요약.json │ ├── chatbot.py │ └── memory_manager.py ├── chapter15 │ ├── static │ │ └── images │ │ │ ├── logo.png │ │ │ └── jjinchin.png │ ├── __pycache__ │ │ ├── chatbot.cpython-310.pyc │ │ ├── common.cpython-310.pyc │ │ ├── common.cpython-311.pyc │ │ ├── common.cpython-312.pyc │ │ ├── jjinchin.cpython-310.pyc │ │ ├── characters.cpython-310.pyc │ │ ├── characters.cpython-311.pyc │ │ ├── financebot.cpython-310.pyc │ │ ├── finance_chatbot.cpython-310.pyc │ │ ├── finance_chatbot.cpython-311.pyc │ │ ├── finance_chatbot.cpython-312.pyc │ │ ├── finance_jinchin.cpython-310.pyc │ │ └── finance_jjinchin.cpython-310.pyc │ ├── files │ │ ├── assistants_ids.txt │ │ ├── fund.json │ │ └── deposit.json │ ├── application.py │ └── common.py ├── chapter18 │ ├── static │ │ └── images │ │ │ ├── logo.png │ │ │ ├── friends.png │ │ │ └── jjinchin.png │ ├── __pycache__ │ │ ├── chatbot.cpython-310.pyc │ │ ├── chatbot.cpython-311.pyc │ │ ├── chatbot.cpython-312.pyc │ │ ├── common.cpython-310.pyc │ │ ├── common.cpython-311.pyc │ │ ├── common.cpython-312.pyc │ │ ├── jjinchin.cpython-310.pyc │ │ ├── vision.cpython-310.pyc │ │ ├── characters.cpython-310.pyc │ │ ├── characters.cpython-311.pyc │ │ ├── characters.cpython-312.pyc │ │ ├── multimodal.cpython-310.pyc │ │ ├── multimodal.cpython-311.pyc │ │ ├── multimodal.cpython-312.pyc │ │ ├── warning_agent.cpython-310.pyc │ │ ├── memory_manager.cpython-310.pyc │ │ ├── function_calling.cpython-310.pyc │ │ ├── function_calling_0.cpython-310.pyc │ │ └── function_calling_single.cpython-310.pyc │ ├── characters.py │ ├── common.py │ ├── application.py │ ├── chatbot.py │ └── multimodal.py ├── chapter06 │ ├── __pycache__ │ │ ├── common.cpython-310.pyc │ │ └── common.cpython-311.pyc │ ├── common.py │ ├── chatbot.py │ └── prompt.txt ├── chapter14 │ ├── __pycache__ │ │ ├── chatbot.cpython-310.pyc │ │ ├── common.cpython-310.pyc │ │ ├── common.cpython-311.pyc │ │ ├── jjinchin.cpython-310.pyc │ │ ├── characters.cpython-310.pyc │ │ ├── characters.cpython-311.pyc │ │ ├── financebot.cpython-310.pyc │ │ ├── finance_chatbot.cpython-310.pyc │ │ ├── finance_chatbot.cpython-311.pyc │ │ ├── finance_jinchin.cpython-310.pyc │ │ └── finance_jjinchin.cpython-310.pyc │ ├── characters.py │ ├── common.py │ ├── assistants.py │ └── chatbot.py ├── chapter17_1 │ ├── __pycache__ │ │ ├── common.cpython-310.pyc │ │ ├── common.cpython-311.pyc │ │ ├── chatbot.cpython-311.pyc │ │ ├── jjinchin.cpython-310.pyc │ │ ├── jjinchin.cpython-311.pyc │ │ ├── characters.cpython-310.pyc │ │ ├── characters.cpython-311.pyc │ │ └── finance_chatbot.cpython-311.pyc │ ├── characters.py │ ├── common.py │ ├── chatbot.py │ └── application.py ├── chapter17_2 │ ├── __pycache__ │ │ ├── common.cpython-310.pyc │ │ ├── common.cpython-311.pyc │ │ ├── chatbot.cpython-311.pyc │ │ ├── jjinchin.cpython-310.pyc │ │ ├── jjinchin.cpython-311.pyc │ │ ├── characters.cpython-310.pyc │ │ ├── characters.cpython-311.pyc │ │ └── finance_chatbot.cpython-311.pyc │ ├── common.py │ └── application.py ├── chapter16 │ ├── templates │ │ └── poilicy.html │ ├── application.py │ ├── gpts_schema.json │ └── common.py ├── chapter12 │ ├── text_ada_test.py │ ├── pinecone_delete.py │ ├── similarity_test.py │ └── pinecone_test.py ├── chapter03 │ └── chatgpt_api_test.py └── chapter05 │ ├── react.py │ ├── translator.py │ ├── fewshot.py │ ├── rag.py │ ├── cot.py │ ├── sc.py │ └── tot.py ├── application.py ├── .vscode └── launch.json ├── install_python3.11.sh └── README.md /contents/chapter02/ex_name1.py: -------------------------------------------------------------------------------- 1 | from ex_name2 import func 2 | 3 | func() 4 | -------------------------------------------------------------------------------- /contents/chapter02/ex_list1.py: -------------------------------------------------------------------------------- 1 | emotions = ['사랑', '증오', '기쁨'] 2 | print("모든 감정:", emotions[0], emotions[1], emotions[2]) 3 | -------------------------------------------------------------------------------- /contents/chapter02/ex_reversed.py: -------------------------------------------------------------------------------- 1 | list_var = [1,2,3] 2 | for element in reversed(list_var): 3 | print(f"element: {element}") 4 | -------------------------------------------------------------------------------- /contents/chapter07/static/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter07/static/images/logo.png -------------------------------------------------------------------------------- /contents/chapter08/static/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter08/static/images/logo.png -------------------------------------------------------------------------------- /contents/chapter09/static/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter09/static/images/logo.png -------------------------------------------------------------------------------- /contents/chapter10/static/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter10/static/images/logo.png -------------------------------------------------------------------------------- /contents/chapter11/static/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter11/static/images/logo.png -------------------------------------------------------------------------------- /contents/chapter13/static/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter13/static/images/logo.png -------------------------------------------------------------------------------- /contents/chapter15/static/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter15/static/images/logo.png -------------------------------------------------------------------------------- /contents/chapter18/static/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter18/static/images/logo.png -------------------------------------------------------------------------------- /contents/chapter02/ex_str_ops.py: -------------------------------------------------------------------------------- 1 | x = "나는 오늘 " 2 | y = "파이썬을 배웠다." 3 | z = x + y 4 | print("x + y:", z) 5 | z = x * 3 6 | print("x * 3:", z) 7 | -------------------------------------------------------------------------------- /contents/chapter02/ex_tuple1.py: -------------------------------------------------------------------------------- 1 | a = (1,2,3,3) 2 | print("a:", a) # 중복 허용 3 | print("a[0]:", a[0]) # 인덱스로 접근 4 | a[0]=10 # 변경 시도 시 오류 발생 5 | -------------------------------------------------------------------------------- /contents/chapter02/ex_tuple2.py: -------------------------------------------------------------------------------- 1 | numbers = 1,2,3 # 패킹 2 | a,b,c = numbers # 언패킹 3 | print("a:", a) 4 | print("b:", b) 5 | print("c:", c) 6 | -------------------------------------------------------------------------------- /contents/chapter07/static/images/jjinchin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter07/static/images/jjinchin.png -------------------------------------------------------------------------------- /contents/chapter08/static/images/jjinchin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter08/static/images/jjinchin.png -------------------------------------------------------------------------------- /contents/chapter09/static/images/jjinchin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter09/static/images/jjinchin.png -------------------------------------------------------------------------------- /contents/chapter10/static/images/jjinchin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter10/static/images/jjinchin.png -------------------------------------------------------------------------------- /contents/chapter11/static/images/jjinchin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter11/static/images/jjinchin.png -------------------------------------------------------------------------------- /contents/chapter13/static/images/jjinchin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter13/static/images/jjinchin.png -------------------------------------------------------------------------------- /contents/chapter15/static/images/jjinchin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter15/static/images/jjinchin.png -------------------------------------------------------------------------------- /contents/chapter18/static/images/friends.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter18/static/images/friends.png -------------------------------------------------------------------------------- /contents/chapter18/static/images/jjinchin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter18/static/images/jjinchin.png -------------------------------------------------------------------------------- /contents/chapter02/ex_set2.py: -------------------------------------------------------------------------------- 1 | a = set([1,2,3]) 2 | b = set([2,3,4]) 3 | 4 | print("합집합:", a | b) 5 | print("교집합:", a & b) 6 | print("차집합:", a - b) 7 | -------------------------------------------------------------------------------- /contents/chapter02/__pycache__/retry.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter02/__pycache__/retry.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter02/__pycache__/ex_name2.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter02/__pycache__/ex_name2.cpython-37.pyc -------------------------------------------------------------------------------- /contents/chapter02/__pycache__/sub_pgm.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter02/__pycache__/sub_pgm.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter02/ex_dict1.py: -------------------------------------------------------------------------------- 1 | fruits = {'수박': '박과의 여름과일', '사과': '사과나무의 열매', '딸기': '나무딸기속 식물'} 2 | print('모든 과일:', fruits['수박'], fruits['사과'], fruits['딸기']) 3 | -------------------------------------------------------------------------------- /contents/chapter02/ex_list2.py: -------------------------------------------------------------------------------- 1 | emotions = ['사랑', '증오', '기쁨'] 2 | emotions.append("슬픔") 3 | print("모든 감정:", emotions[0], emotions[1], emotions[2], emotions[3]) 4 | -------------------------------------------------------------------------------- /contents/chapter02/ex_ops.py: -------------------------------------------------------------------------------- 1 | a = 10 2 | b = 5 3 | 4 | print("덧셈:", a + b) 5 | print("뺄셈:", a - b) 6 | print("곱셈:", a * b) 7 | asdfsdafsad 8 | print("나눗셈:", a / b) -------------------------------------------------------------------------------- /contents/chapter06/__pycache__/common.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter06/__pycache__/common.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter06/__pycache__/common.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter06/__pycache__/common.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter07/__pycache__/chatbot.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter07/__pycache__/chatbot.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter07/__pycache__/chatbot.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter07/__pycache__/chatbot.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter07/__pycache__/common.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter07/__pycache__/common.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter07/__pycache__/common.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter07/__pycache__/common.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter07/__pycache__/common.cpython-312.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter07/__pycache__/common.cpython-312.pyc -------------------------------------------------------------------------------- /contents/chapter07/__pycache__/jjinchin.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter07/__pycache__/jjinchin.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter08/__pycache__/chatbot.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter08/__pycache__/chatbot.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter08/__pycache__/chatbot.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter08/__pycache__/chatbot.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter08/__pycache__/common.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter08/__pycache__/common.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter08/__pycache__/common.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter08/__pycache__/common.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter08/__pycache__/jjinchin.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter08/__pycache__/jjinchin.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter09/__pycache__/chatbot.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter09/__pycache__/chatbot.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter09/__pycache__/chatbot.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter09/__pycache__/chatbot.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter09/__pycache__/chatbot.cpython-312.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter09/__pycache__/chatbot.cpython-312.pyc -------------------------------------------------------------------------------- /contents/chapter09/__pycache__/common.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter09/__pycache__/common.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter09/__pycache__/common.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter09/__pycache__/common.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter09/__pycache__/common.cpython-312.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter09/__pycache__/common.cpython-312.pyc -------------------------------------------------------------------------------- /contents/chapter09/__pycache__/jjinchin.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter09/__pycache__/jjinchin.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter10/__pycache__/chatbot.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter10/__pycache__/chatbot.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter10/__pycache__/chatbot.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter10/__pycache__/chatbot.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter10/__pycache__/chatbot.cpython-312.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter10/__pycache__/chatbot.cpython-312.pyc -------------------------------------------------------------------------------- /contents/chapter10/__pycache__/common.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter10/__pycache__/common.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter10/__pycache__/common.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter10/__pycache__/common.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter10/__pycache__/common.cpython-312.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter10/__pycache__/common.cpython-312.pyc -------------------------------------------------------------------------------- /contents/chapter10/__pycache__/jjinchin.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter10/__pycache__/jjinchin.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter11/__pycache__/chatbot.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter11/__pycache__/chatbot.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter11/__pycache__/chatbot.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter11/__pycache__/chatbot.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter11/__pycache__/common.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter11/__pycache__/common.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter11/__pycache__/common.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter11/__pycache__/common.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter11/__pycache__/jjinchin.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter11/__pycache__/jjinchin.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter13/__pycache__/chatbot.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter13/__pycache__/chatbot.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter13/__pycache__/chatbot.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter13/__pycache__/chatbot.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter13/__pycache__/common.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter13/__pycache__/common.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter13/__pycache__/common.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter13/__pycache__/common.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter13/__pycache__/jjinchin.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter13/__pycache__/jjinchin.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter14/__pycache__/chatbot.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter14/__pycache__/chatbot.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter14/__pycache__/common.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter14/__pycache__/common.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter14/__pycache__/common.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter14/__pycache__/common.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter14/__pycache__/jjinchin.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter14/__pycache__/jjinchin.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter15/__pycache__/chatbot.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter15/__pycache__/chatbot.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter15/__pycache__/common.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter15/__pycache__/common.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter15/__pycache__/common.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter15/__pycache__/common.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter15/__pycache__/common.cpython-312.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter15/__pycache__/common.cpython-312.pyc -------------------------------------------------------------------------------- /contents/chapter15/__pycache__/jjinchin.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter15/__pycache__/jjinchin.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter17_1/__pycache__/common.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter17_1/__pycache__/common.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter17_1/__pycache__/common.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter17_1/__pycache__/common.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter17_2/__pycache__/common.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter17_2/__pycache__/common.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter17_2/__pycache__/common.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter17_2/__pycache__/common.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter18/__pycache__/chatbot.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter18/__pycache__/chatbot.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter18/__pycache__/chatbot.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter18/__pycache__/chatbot.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter18/__pycache__/chatbot.cpython-312.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter18/__pycache__/chatbot.cpython-312.pyc -------------------------------------------------------------------------------- /contents/chapter18/__pycache__/common.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter18/__pycache__/common.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter18/__pycache__/common.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter18/__pycache__/common.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter18/__pycache__/common.cpython-312.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter18/__pycache__/common.cpython-312.pyc -------------------------------------------------------------------------------- /contents/chapter18/__pycache__/jjinchin.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter18/__pycache__/jjinchin.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter18/__pycache__/vision.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter18/__pycache__/vision.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter02/__pycache__/name_test2.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter02/__pycache__/name_test2.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter08/__pycache__/characters.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter08/__pycache__/characters.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter08/__pycache__/characters.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter08/__pycache__/characters.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter09/__pycache__/characters.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter09/__pycache__/characters.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter09/__pycache__/characters.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter09/__pycache__/characters.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter09/__pycache__/characters.cpython-312.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter09/__pycache__/characters.cpython-312.pyc -------------------------------------------------------------------------------- /contents/chapter10/__pycache__/characters.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter10/__pycache__/characters.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter10/__pycache__/characters.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter10/__pycache__/characters.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter10/__pycache__/characters.cpython-312.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter10/__pycache__/characters.cpython-312.pyc -------------------------------------------------------------------------------- /contents/chapter11/__pycache__/characters.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter11/__pycache__/characters.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter11/__pycache__/characters.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter11/__pycache__/characters.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter13/__pycache__/characters.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter13/__pycache__/characters.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter13/__pycache__/characters.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter13/__pycache__/characters.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter14/__pycache__/characters.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter14/__pycache__/characters.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter14/__pycache__/characters.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter14/__pycache__/characters.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter14/__pycache__/financebot.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter14/__pycache__/financebot.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter15/__pycache__/characters.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter15/__pycache__/characters.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter15/__pycache__/characters.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter15/__pycache__/characters.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter15/__pycache__/financebot.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter15/__pycache__/financebot.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter17_1/__pycache__/chatbot.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter17_1/__pycache__/chatbot.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter17_1/__pycache__/jjinchin.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter17_1/__pycache__/jjinchin.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter17_1/__pycache__/jjinchin.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter17_1/__pycache__/jjinchin.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter17_2/__pycache__/chatbot.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter17_2/__pycache__/chatbot.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter17_2/__pycache__/jjinchin.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter17_2/__pycache__/jjinchin.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter17_2/__pycache__/jjinchin.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter17_2/__pycache__/jjinchin.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter18/__pycache__/characters.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter18/__pycache__/characters.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter18/__pycache__/characters.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter18/__pycache__/characters.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter18/__pycache__/characters.cpython-312.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter18/__pycache__/characters.cpython-312.pyc -------------------------------------------------------------------------------- /contents/chapter18/__pycache__/multimodal.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter18/__pycache__/multimodal.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter18/__pycache__/multimodal.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter18/__pycache__/multimodal.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter18/__pycache__/multimodal.cpython-312.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter18/__pycache__/multimodal.cpython-312.pyc -------------------------------------------------------------------------------- /contents/chapter02/__pycache__/import_pgm2.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter02/__pycache__/import_pgm2.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter10/__pycache__/warning_agent.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter10/__pycache__/warning_agent.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter10/__pycache__/warning_agent.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter10/__pycache__/warning_agent.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter10/__pycache__/warning_agent.cpython-312.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter10/__pycache__/warning_agent.cpython-312.pyc -------------------------------------------------------------------------------- /contents/chapter11/__pycache__/warning_agent.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter11/__pycache__/warning_agent.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter13/__pycache__/warning_agent.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter13/__pycache__/warning_agent.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter17_1/__pycache__/characters.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter17_1/__pycache__/characters.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter17_1/__pycache__/characters.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter17_1/__pycache__/characters.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter17_2/__pycache__/characters.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter17_2/__pycache__/characters.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter17_2/__pycache__/characters.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter17_2/__pycache__/characters.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter18/__pycache__/warning_agent.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter18/__pycache__/warning_agent.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter11/__pycache__/memory_manager.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter11/__pycache__/memory_manager.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter11/__pycache__/memory_manager.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter11/__pycache__/memory_manager.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter13/__pycache__/memory_manager.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter13/__pycache__/memory_manager.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter13/__pycache__/memory_manager.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter13/__pycache__/memory_manager.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter14/__pycache__/finance_chatbot.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter14/__pycache__/finance_chatbot.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter14/__pycache__/finance_chatbot.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter14/__pycache__/finance_chatbot.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter14/__pycache__/finance_jinchin.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter14/__pycache__/finance_jinchin.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter15/__pycache__/finance_chatbot.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter15/__pycache__/finance_chatbot.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter15/__pycache__/finance_chatbot.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter15/__pycache__/finance_chatbot.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter15/__pycache__/finance_chatbot.cpython-312.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter15/__pycache__/finance_chatbot.cpython-312.pyc -------------------------------------------------------------------------------- /contents/chapter15/__pycache__/finance_jinchin.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter15/__pycache__/finance_jinchin.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter18/__pycache__/memory_manager.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter18/__pycache__/memory_manager.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter02/ex_list3.py: -------------------------------------------------------------------------------- 1 | emotions = ['사랑', '증오', '기쁨'] 2 | emotions.append("슬픔") 3 | emotions.remove("사랑") 4 | print("모든 감정:", emotions[0], emotions[1], emotions[2]) 5 | 6 | -------------------------------------------------------------------------------- /contents/chapter09/__pycache__/function_calling.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter09/__pycache__/function_calling.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter09/__pycache__/function_calling.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter09/__pycache__/function_calling.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter09/__pycache__/function_calling.cpython-312.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter09/__pycache__/function_calling.cpython-312.pyc -------------------------------------------------------------------------------- /contents/chapter10/__pycache__/function_calling.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter10/__pycache__/function_calling.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter10/__pycache__/function_calling.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter10/__pycache__/function_calling.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter14/__pycache__/finance_jjinchin.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter14/__pycache__/finance_jjinchin.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter15/__pycache__/finance_jjinchin.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter15/__pycache__/finance_jjinchin.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter17_1/__pycache__/finance_chatbot.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter17_1/__pycache__/finance_chatbot.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter17_2/__pycache__/finance_chatbot.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter17_2/__pycache__/finance_chatbot.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter18/__pycache__/function_calling.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter18/__pycache__/function_calling.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter18/__pycache__/function_calling_0.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter18/__pycache__/function_calling_0.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter15/files/assistants_ids.txt: -------------------------------------------------------------------------------- 1 | 2024-01-20 07:55:06 - asst_K1n3Vu7IEmETc7ycX4NvyXUt, thread_Xyz4QxvKMeXsVKmpKB6yGHDg, file-bn1sFdOXWMSZSVxpsuwVZKgI,file-Zx0Xv5lx9bGq6Ni7GqjT4wJT 2 | -------------------------------------------------------------------------------- /contents/chapter18/__pycache__/function_calling_single.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter18/__pycache__/function_calling_single.cpython-310.pyc -------------------------------------------------------------------------------- /contents/chapter09/__pycache__/parallel_function_calling.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minji337/jjinchin/HEAD/contents/chapter09/__pycache__/parallel_function_calling.cpython-311.pyc -------------------------------------------------------------------------------- /contents/chapter02/ex_set1.py: -------------------------------------------------------------------------------- 1 | a = set([1,2,3]) 2 | b = set([3,2,1]) 3 | 4 | # 순서가 다르더라도 같은 데이터로 판단 5 | print("a == b:", a == b) 6 | 7 | # 중복된 요소는 제거 8 | c = set([3,2,1,1]) 9 | print("c:", c) 10 | -------------------------------------------------------------------------------- /contents/chapter02/ex_func2.py: -------------------------------------------------------------------------------- 1 | def func(a, b=20): 2 | return a + b 3 | 4 | print(func(10)) #30 출력 5 | print(func(a=10)) #30 출력 6 | print(func(b=10)) #TypeError: func() missing 1 required positional argument: 'a' 7 | -------------------------------------------------------------------------------- /contents/chapter16/templates/poilicy.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /contents/chapter02/ex_exception.py: -------------------------------------------------------------------------------- 1 | try: 2 | result = 10 / 0 3 | except ZeroDivisionError as ze: 4 | print(f"0으로 나눌 수 없습니다: {str(ze)}") 5 | else: 6 | print(f"결과는 {result}입니다.") 7 | finally: 8 | print("예외 처리가 완료되었습니다.") 9 | -------------------------------------------------------------------------------- /contents/chapter02/ex_enum.py: -------------------------------------------------------------------------------- 1 | list_var = [1,2,3] 2 | for idx, element in enumerate(list_var): 3 | print(f"{idx}번째, element: {element}") 4 | print("=" * 20) 5 | for idx, element in enumerate(list_var, start=1): 6 | print(f"{idx}번째, element: {element}") 7 | -------------------------------------------------------------------------------- /contents/chapter02/ex_str_fmt.py: -------------------------------------------------------------------------------- 1 | name = "김민지" 2 | age = 26 3 | gender = "여성" 4 | 5 | s1 = "페르소나는 {age}세 {name}라는 {gender}입니다.".format(name=name, age=age, gender=gender) 6 | print(f"s1 => {s1}") 7 | s2 = f"페르소나는 {age}세 {name}라는 {gender}입니다." 8 | print(f"s2 => {s2}") 9 | -------------------------------------------------------------------------------- /contents/chapter09/tavily_test.py: -------------------------------------------------------------------------------- 1 | from tavily import TavilyClient 2 | from pprint import pprint 3 | import os 4 | 5 | tavily = TavilyClient(api_key=os.getenv("TAVILY_API_KEY")) 6 | response = tavily.search(query="자율적 에이전트 요약", search_depth="advanced") 7 | pprint(response) 8 | -------------------------------------------------------------------------------- /contents/chapter02/ex_dict_packing.py: -------------------------------------------------------------------------------- 1 | def func2(x, y): 2 | print("func2:", x + y) 3 | 4 | def func1(**kwargs): 5 | print("type(kwargs):", type(kwargs), kwargs) 6 | print("func1:", kwargs['x'] + kwargs['y']) 7 | func2(**kwargs) 8 | 9 | func1(x=10, y=20) 10 | -------------------------------------------------------------------------------- /contents/chapter02/ex_slice.py: -------------------------------------------------------------------------------- 1 | list_var = [1,2,3,4,5,6,7,8,9,10] 2 | print(f"[0:5] => {list_var[0:5]}") 3 | print(f"[:7] => {list_var[:7]}") 4 | print(f"[7:] => {list_var[7:]}") 5 | print(f"[0:10:2] => {list_var[0:10:2]}") 6 | 7 | print(list_var[-3:]) 8 | print(list_var[:-2]) 9 | -------------------------------------------------------------------------------- /contents/chapter02/ex_str_funcs.py: -------------------------------------------------------------------------------- 1 | # split는 문자열을 지정된 구분자에 따라 분리하는 함수입니다. 2 | text = "김민지 and 고비" 3 | result = text.split(" and ") 4 | print(f"split: {result}") 5 | # replace는 문자열의 일부(또는 전부)를 다른 문자열로 교체하는 함수입니다. 6 | result = text.replace("and", "그리고") 7 | print(f"replace: {result}") 8 | -------------------------------------------------------------------------------- /application.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | import sys 3 | application = Flask(__name__) 4 | 5 | 6 | @application.route("/") 7 | def hello(): 8 | return "Hello goorm!" 9 | 10 | 11 | if __name__ == "__main__": 12 | application.run(host='0.0.0.0', port=int(sys.argv[1])) 13 | -------------------------------------------------------------------------------- /contents/chapter12/text_ada_test.py: -------------------------------------------------------------------------------- 1 | from openai import OpenAI 2 | import os 3 | 4 | client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) 5 | 6 | message = "신데렐라와 왕자는 사랑에 빠졌습니다." 7 | result = client.embeddings.create(input=message, model="text-embedding-ada-002").model_dump() 8 | print(result) -------------------------------------------------------------------------------- /contents/chapter02/ex_name2.py: -------------------------------------------------------------------------------- 1 | def func(): 2 | print("func 입니다") 3 | 4 | def main(): 5 | print("main 함수가 여러 가지 작업을 수행 중에 있습니다.") 6 | func() 7 | 8 | print(f"__name__은 {__name__}입니다.") 9 | 10 | if __name__ == "__main__": 11 | print("main으로 실행되었습니다.") 12 | main() 13 | -------------------------------------------------------------------------------- /contents/chapter12/pinecone_delete.py: -------------------------------------------------------------------------------- 1 | import os 2 | import pinecone 3 | 4 | pinecone_api_key = os.getenv("PINECONE_API_KEY") 5 | pinecone_env = "gcp-starter" 6 | 7 | pinecone.init(api_key=pinecone_api_key, environment=pinecone_env) 8 | index = pinecone.Index('jjinchin-memory') 9 | index.delete(delete_all=True) -------------------------------------------------------------------------------- /contents/chapter02/ex_tuple3.py: -------------------------------------------------------------------------------- 1 | def calculate(a, b): 2 | sum_result = a + b 3 | product_result = a * b 4 | return sum_result, product_result # 튜플 패킹 5 | 6 | # 언패킹하여 각 결과에 할당 7 | sum_value, product_value = calculate(3, 4) 8 | print("sum_value:", sum_value) 9 | print("product_value:", product_value) 10 | -------------------------------------------------------------------------------- /contents/chapter02/ex_sorted.py: -------------------------------------------------------------------------------- 1 | def sort_by_age(person): 2 | return person['age'] 3 | 4 | members = [{'name': '이현경', 'age': 31}, 5 | {'name': '김민지', 'age': 26}, 6 | {'name': '오민준', 'age': 29}] 7 | 8 | sorted_members = sorted(members, key=sort_by_age, reverse=True) 9 | print(sorted_members) 10 | -------------------------------------------------------------------------------- /contents/chapter02/ex_raise.py: -------------------------------------------------------------------------------- 1 | def func2(): 2 | try: 3 | print(10 / 0) 4 | except ZeroDivisionError as ze: 5 | print(f"0으로 나눌 수 없습니다.") 6 | raise ze 7 | 8 | def func1(): 9 | try: 10 | func2() 11 | except ZeroDivisionError: 12 | print(f"func2에서 예외가 발생했습니다.") 13 | 14 | func1() 15 | -------------------------------------------------------------------------------- /contents/chapter02/ex_cmph.py: -------------------------------------------------------------------------------- 1 | # 0 ~ 9까지 중에서 짝수 선별 2 | even_numbers = [v for v in range(10) if v % 2 == 0] 3 | print("even_numbers:",even_numbers) 4 | 5 | # 과일별 색깔의 길이 작성 6 | fruits = {"apple": "red", "banana": "yellow", "grape": "purple"} 7 | fruit_color_length = {fruit: len(color) for fruit, color in fruits.items()} 8 | print("fruit_color_length:",fruit_color_length) 9 | -------------------------------------------------------------------------------- /contents/chapter06/common.py: -------------------------------------------------------------------------------- 1 | import os 2 | from openai import OpenAI 3 | from dataclasses import dataclass 4 | 5 | @dataclass(frozen=True) 6 | class Model: 7 | basic: str = "gpt-3.5-turbo-1106" 8 | advanced: str = "gpt-4-1106-preview" 9 | 10 | model = Model(); 11 | client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"), timeout=30, max_retries=1) 12 | -------------------------------------------------------------------------------- /contents/chapter07/common.py: -------------------------------------------------------------------------------- 1 | import os 2 | from openai import OpenAI 3 | from dataclasses import dataclass 4 | 5 | @dataclass(frozen=True) 6 | class Model: 7 | basic: str = "gpt-3.5-turbo-1106" 8 | advanced: str = "gpt-4-1106-preview" 9 | 10 | model = Model(); 11 | client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"), timeout=30, max_retries=1) 12 | 13 | -------------------------------------------------------------------------------- /contents/chapter02/ex_retry.py: -------------------------------------------------------------------------------- 1 | from retry import retry 2 | 3 | @retry(tries=5, delay=1) 4 | def func2(): 5 | try: 6 | print(10 / 0) 7 | except ZeroDivisionError as ze: 8 | print(f"0으로 나눌 수 없습니다.") 9 | raise ze 10 | 11 | def func1(): 12 | try: 13 | func2() 14 | except ZeroDivisionError: 15 | print(f"func2에서 예외가 발생했습니다.") 16 | 17 | func1() 18 | -------------------------------------------------------------------------------- /contents/chapter02/ex_func1.py: -------------------------------------------------------------------------------- 1 | # 단리 이자 계산기(days : 일수, rate : 이율, amount: 원금) 2 | def calculate_simple_interest(days, rate, amount): 3 | print("입력값 ", days, rate, amount) 4 | return amount * days / 365 * rate 5 | 6 | simple_interest = calculate_simple_interest(100, 0.04, 1000000) 7 | print("이자1:", simple_interest) 8 | 9 | simple_interest = calculate_simple_interest(200, 0.03, 5000000) 10 | print("이자2:", simple_interest) 11 | -------------------------------------------------------------------------------- /contents/chapter11/mongodb_delete.py: -------------------------------------------------------------------------------- 1 | from pymongo import MongoClient 2 | import os 3 | 4 | #cluster=MongoClient("mongodb+srv://:@cluster0.ov3wpli.mongodb.net/?retryWrites=true&w=majority") 5 | cluster=MongoClient(os.getenv("MONGO_CLUSTER_URI")) 6 | db=cluster["jjinchin"] 7 | collection = db["chats"] 8 | collection.delete_many({}) 9 | 10 | # 아래는 메모리 db 삭제 11 | db=cluster["jjinchin"] 12 | collection = db["memory"] 13 | collection.delete_many({}) -------------------------------------------------------------------------------- /contents/chapter02/ex_func_param.py: -------------------------------------------------------------------------------- 1 | def sum_data(data): 2 | return sum(data) 3 | 4 | def average_data(data): 5 | return sum(data) / len(data) 6 | 7 | def process_data(func, data): 8 | if len(data) >= 3: 9 | result = func(data) 10 | print(f"Processed result: {result}") 11 | 12 | data = [10, 20, 30, 40, 50] 13 | 14 | process_data(sum_data, data) # Processed result: 150 15 | process_data(average_data, data) # Processed result: 30.0 16 | -------------------------------------------------------------------------------- /contents/chapter02/ex_dict_func_var.py: -------------------------------------------------------------------------------- 1 | def add(a, b): 2 | return a + b 3 | def subtract(a, b): 4 | return a - b 5 | def multiply(a, b): 6 | return a * b 7 | def devide(a, b): 8 | return a / b 9 | 10 | calc_dict = {"add": add, "multiply": multiply, "subtract": subtract, "devide": devide} 11 | def func(func_name, a, b): 12 | return calc_dict[func_name](a, b) 13 | 14 | print("add", func("add", 20, 2)) 15 | print("subtract", func("subtract", 20, 2)) 16 | print("multiply", func("multiply", 20, 2)) 17 | print("divide", func("divide", 20, 2)) -------------------------------------------------------------------------------- /contents/chapter17_1/characters.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | system_role = """ 4 | 당신은 26세의 활기찬 대중음악 작곡가 고비이며, 마케터인 김민지의 절친입니다. 5 | 인사할 때는 "민지야"라는 말을 붙이며 가볍게 인사합니다. 6 | 민지가 언급하는 내용에 대해 세심한 주의를 기울이며, 관련성 있고 구체적인 답변을 합니다. 7 | 현재 대화의 흐름에 집중하기 위해 관련 없는 임의의 주제를 소개하는 것을 피합니다. 8 | [!IMPORTANT]다음은 민지가 듣기 싫어하는 민감한 주제입니다. 다만 해당 주제에 관해 민지가 먼저 언급하면 말해도 됩니다. 9 | - 음식: 민지는 매운 음식을 좋아함 10 | - 음악: 민지가 가장 좋아하는 가수는 "아이유" 11 | """ 12 | 13 | instruction = """ 14 | instruction: 15 | 2. 경어나 존댓말을 쓰지 말고 반말로 대답하며, 적절한 이모지를 보낼 것 16 | 3. 어떤 상황에서도 인공지능인지 눈치채지 못하도록 행동해야 하고, 민지의 절친으로 연기할 것 17 | """ 18 | -------------------------------------------------------------------------------- /contents/chapter02/ex_func_var.py: -------------------------------------------------------------------------------- 1 | def add(a, b): 2 | return a + b 3 | 4 | def subtract(a, b): 5 | return a - b 6 | 7 | def multiply(a, b): 8 | return a * b 9 | 10 | def devide(a, b): 11 | return a / b 12 | 13 | calc_dict = {"add": add, "multiply": multiply, "subtract": subtract, "devide": devide} 14 | 15 | def func(func_name, a, b): 16 | return calc_dict[func_name](a, b) 17 | 18 | print("add", func("add", 20, 2)) 19 | print("subtract", func("subtract", 20, 2)) 20 | print("multiply", func("multiply", 20, 2)) 21 | print("divide", func("devide", 20, 2)) 22 | -------------------------------------------------------------------------------- /contents/chapter08/characters.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | system_role = """ 4 | 당신은 26세의 유쾌한 대중음악 작곡가 고비이며, 마케터인 김민지의 절친입니다. 5 | 인사할 때는 "민지야"라는 말을 붙이며 가볍게 인사합니다. 6 | 민지가 언급하는 내용에 대해 세심한 주의를 기울이며, 관련성 있고 구체적인 답변을 합니다. 7 | 현재 대화의 흐름에 집중하기 위해 관련 없는 임의의 주제를 소개하는 것을 피합니다. 8 | [!IMPORTANT]다음은 민지가 듣기 싫어하는 민감한 주제입니다. 다만 해당 주제에 관해 민지가 먼저 언급하면 말해도 됩니다. 9 | - 음식: 민지는 매운 음식을 좋아함 10 | - 음악: 민지가 가장 좋아하는 가수는 "아이유" 11 | """ 12 | 13 | instruction = """ 14 | instruction: 15 | 1. 답변은 3문장 이내면서 10단어 이내로 짧게 할 것. 16 | 2. 경어나 존댓말을 쓰지 말고 반말로 대답하며, 적절한 이모지를 보낼 것 17 | 3. 어떤 상황에서도 인공지능인지 눈치채지 못하도록 행동해야 하고, 민지의 절친으로 연기할 것 18 | """ 19 | -------------------------------------------------------------------------------- /contents/chapter09/characters.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | system_role = """ 4 | 당신은 26세의 유쾌한 대중음악 작곡가 고비이며, 마케터인 김민지의 절친입니다. 5 | 인사할 때는 "민지야"라는 말을 붙이며 가볍게 인사합니다. 6 | 민지가 언급하는 내용에 대해 세심한 주의를 기울이며, 관련성 있고 구체적인 답변을 합니다. 7 | 현재 대화의 흐름에 집중하기 위해 관련 없는 임의의 주제를 소개하는 것을 피합니다. 8 | [!IMPORTANT]다음은 민지가 듣기 싫어하는 민감한 주제입니다. 다만 해당 주제에 관해 민지가 먼저 언급하면 말해도 됩니다. 9 | - 음식: 민지는 매운 음식을 좋아함 10 | - 음악: 민지가 가장 좋아하는 가수는 "아이유" 11 | """ 12 | 13 | instruction = """ 14 | instruction: 15 | 1. 답변은 3문장 이내면서 10단어 이내로 짧게 할 것. 16 | 2. 경어나 존댓말을 쓰지 말고 반말로 대답하며, 적절한 이모지를 보낼 것 17 | 3. 어떤 상황에서도 인공지능인지 눈치채지 못하도록 행동해야 하고, 민지의 절친으로 연기할 것 18 | """ 19 | -------------------------------------------------------------------------------- /contents/chapter10/characters.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | system_role = """ 4 | 당신은 26세의 유쾌한 대중음악 작곡가 고비이며, 마케터인 김민지의 절친입니다. 5 | 인사할 때는 "민지야"라는 말을 붙이며 가볍게 인사합니다. 6 | 민지가 언급하는 내용에 대해 세심한 주의를 기울이며, 관련성 있고 구체적인 답변을 합니다. 7 | 현재 대화의 흐름에 집중하기 위해 관련 없는 임의의 주제를 소개하는 것을 피합니다. 8 | [!IMPORTANT]다음은 민지가 듣기 싫어하는 민감한 주제입니다. 다만 해당 주제에 관해 민지가 먼저 언급하면 말해도 됩니다. 9 | - 음식: 민지는 매운 음식을 좋아함 10 | - 음악: 민지가 가장 좋아하는 가수는 "아이유" 11 | """ 12 | 13 | instruction = """ 14 | instruction: 15 | 1. 답변은 3문장 이내면서 10단어 이내로 짧게 할 것. 16 | 2. 경어나 존댓말을 쓰지 말고 반말로 대답하며, 적절한 이모지를 보낼 것 17 | 3. 어떤 상황에서도 인공지능인지 눈치채지 못하도록 행동해야 하고, 민지의 절친으로 연기할 것 18 | """ 19 | -------------------------------------------------------------------------------- /contents/chapter11/characters.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | system_role = """ 4 | 당신은 26세의 유쾌한 대중음악 작곡가 고비이며, 마케터인 김민지의 절친입니다. 5 | 인사할 때는 "민지야"라는 말을 붙이며 가볍게 인사합니다. 6 | 민지가 언급하는 내용에 대해 세심한 주의를 기울이며, 관련성 있고 구체적인 답변을 합니다. 7 | 현재 대화의 흐름에 집중하기 위해 관련 없는 임의의 주제를 소개하는 것을 피합니다. 8 | [!IMPORTANT]다음은 민지가 듣기 싫어하는 민감한 주제입니다. 다만 해당 주제에 관해 민지가 먼저 언급하면 말해도 됩니다. 9 | - 음식: 민지는 매운 음식을 좋아함 10 | - 음악: 민지가 가장 좋아하는 가수는 "아이유" 11 | """ 12 | 13 | instruction = """ 14 | instruction: 15 | 1. 답변은 3문장 이내면서 10단어 이내로 짧게 할 것. 16 | 2. 경어나 존댓말을 쓰지 말고 반말로 대답하며, 적절한 이모지를 보낼 것 17 | 3. 어떤 상황에서도 인공지능인지 눈치채지 못하도록 행동해야 하고, 민지의 절친으로 연기할 것 18 | """ 19 | -------------------------------------------------------------------------------- /contents/chapter13/characters.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | system_role = """ 4 | 당신은 26세의 유쾌한 대중음악 작곡가 고비이며, 마케터인 김민지의 절친입니다. 5 | 인사할 때는 "민지야"라는 말을 붙이며 가볍게 인사합니다. 6 | 민지가 언급하는 내용에 대해 세심한 주의를 기울이며, 관련성 있고 구체적인 답변을 합니다. 7 | 현재 대화의 흐름에 집중하기 위해 관련 없는 임의의 주제를 소개하는 것을 피합니다. 8 | [!IMPORTANT]다음은 민지가 듣기 싫어하는 민감한 주제입니다. 다만 해당 주제에 관해 민지가 먼저 언급하면 말해도 됩니다. 9 | - 음식: 민지는 매운 음식을 좋아함 10 | - 음악: 민지가 가장 좋아하는 가수는 "아이유" 11 | """ 12 | 13 | instruction = """ 14 | instruction: 15 | 1. 답변은 3문장 이내면서 10단어 이내로 짧게 할 것. 16 | 2. 경어나 존댓말을 쓰지 말고 반말로 대답하며, 적절한 이모지를 보낼 것 17 | 3. 어떤 상황에서도 인공지능인지 눈치채지 못하도록 행동해야 하고, 민지의 절친으로 연기할 것 18 | """ 19 | -------------------------------------------------------------------------------- /contents/chapter14/characters.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | system_role = """ 4 | 당신은 26세의 유쾌한 대중음악 작곡가 고비이며, 마케터인 김민지의 절친입니다. 5 | 인사할 때는 "민지야"라는 말을 붙이며 가볍게 인사합니다. 6 | 민지가 언급하는 내용에 대해 세심한 주의를 기울이며, 관련성 있고 구체적인 답변을 합니다. 7 | 현재 대화의 흐름에 집중하기 위해 관련 없는 임의의 주제를 소개하는 것을 피합니다. 8 | [!IMPORTANT]다음은 민지가 듣기 싫어하는 민감한 주제입니다. 다만 해당 주제에 관해 민지가 먼저 언급하면 말해도 됩니다. 9 | - 음식: 민지는 매운 음식을 좋아함 10 | - 음악: 민지가 가장 좋아하는 가수는 "아이유" 11 | """ 12 | 13 | instruction = """ 14 | instruction: 15 | 1. 답변은 3문장 이내면서 10단어 이내로 짧게 할 것. 16 | 2. 경어나 존댓말을 쓰지 말고 반말로 대답하며, 적절한 이모지를 보낼 것 17 | 3. 어떤 상황에서도 인공지능인지 눈치채지 못하도록 행동해야 하고, 민지의 절친으로 연기할 것 18 | """ 19 | -------------------------------------------------------------------------------- /contents/chapter18/characters.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | system_role = """ 4 | 당신은 26세의 유쾌한 대중음악 작곡가 고비이며, 마케터인 김민지의 절친입니다. 5 | 인사할 때는 "민지야"라는 말을 붙이며 가볍게 인사합니다. 6 | 민지가 언급하는 내용에 대해 세심한 주의를 기울이며, 관련성 있고 구체적인 답변을 합니다. 7 | 현재 대화의 흐름에 집중하기 위해 관련 없는 임의의 주제를 소개하는 것을 피합니다. 8 | [!IMPORTANT]다음은 민지가 듣기 싫어하는 민감한 주제입니다. 다만 해당 주제에 관해 민지가 먼저 언급하면 말해도 됩니다. 9 | - 음식: 민지는 매운 음식을 좋아함 10 | - 음악: 민지가 가장 좋아하는 가수는 "아이유" 11 | """ 12 | 13 | instruction = """ 14 | instruction: 15 | 1. 답변은 3문장 이내면서 10단어 이내로 짧게 할 것. 16 | 2. 경어나 존댓말을 쓰지 말고 반말로 대답하며, 적절한 이모지를 보낼 것 17 | 3. 어떤 상황에서도 인공지능인지 눈치채지 못하도록 행동해야 하고, 민지의 절친으로 연기할 것 18 | """ 19 | -------------------------------------------------------------------------------- /contents/chapter03/chatgpt_api_test.py: -------------------------------------------------------------------------------- 1 | from pprint import pprint 2 | import os 3 | from openai import OpenAI 4 | 5 | # 여러분들이 발급받은 api_key로 바꿔 주세요. 6 | # api_key = "sk-" 7 | api_key = os.getenv("OPENAI_API_KEY") 8 | # client = OpenAI() # 이것도 가능 9 | client = OpenAI(api_key=api_key) 10 | 11 | model = "gpt-3.5-turbo-1106" 12 | 13 | messages = [ 14 | {"role": "system", "content": "You are a helpful assistant."}, 15 | {"role": "user", "content": "Who won the world series in 2020?"}, 16 | ] 17 | 18 | response = client.chat.completions.create(model=model, messages=messages).model_dump() 19 | pprint(response) 20 | -------------------------------------------------------------------------------- /contents/chapter02/ex_dict2.py: -------------------------------------------------------------------------------- 1 | fruits = {'수박': '박과의 여름과일', '사과': '사과나무의 열매', '딸기': '나무딸기속 식물'} 2 | print('모든 과일:', fruits['수박'], fruits['사과'], fruits['딸기']) 3 | 4 | fruits['포도'] = '덩굴성 자줏빛 과일' 5 | del fruits['수박'] 6 | 7 | # fruits에 담긴 Key들을 가져와 fruits_keys에 담는다 8 | fruits_keys = fruits.keys() 9 | 10 | # list(...) 함수를 통해 fruits_keys의 데이터를 리스트 데이터 형식으로 변경한다. 11 | fruits_keys_list = list(fruits_keys) 12 | 13 | 14 | # fruits에 담긴 Value들을 가져와 fruits_values에 담는다. 15 | fruits_values = fruits.values() 16 | 17 | # list(...;) 함수를 통해 fruits_values의 데이터를 리스트 데이터 형식으로 변경한다. 18 | fruits_values_list = list(fruits_values) 19 | 20 | print("fruits_keys_list: ", fruits_keys_list) 21 | print("fruits_values_list: ", fruits_values_list) 22 | -------------------------------------------------------------------------------- /contents/chapter16/application.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, request 2 | import sys 3 | import finance_chatbot 4 | 5 | application = Flask(__name__) 6 | 7 | @application.route('/get_return_rate') 8 | def get_return_rate(): 9 | fund_name = request.args.get('펀드명').replace(' ', '') 10 | return finance_chatbot.get_return_rate(펀드명=fund_name) 11 | 12 | @application.route('/get_total_assets') 13 | def get_total_assets(): 14 | fund_name = request.args.get('펀드명').replace(' ', '') 15 | return finance_chatbot.get_total_assets(펀드명 = fund_name) 16 | 17 | # Public 공개하는 경우 18 | @application.route('/policy') 19 | def policy(): 20 | return render_template("policy.html") 21 | 22 | if __name__ == "__main__": 23 | application.run(host='0.0.0.0', port=int(sys.argv[1])) -------------------------------------------------------------------------------- /contents/chapter11/mongodb_test.py: -------------------------------------------------------------------------------- 1 | from pymongo import MongoClient 2 | import os 3 | 4 | #cluster=MongoClient("mongodb+srv://:@cluster0.ov3wpli.mongodb.net/?retryWrites=true&w=majority") 5 | cluster=MongoClient(os.getenv("MONGO_CLUSTER_URI")) 6 | db=cluster["jjinchin"] 7 | collection = db["chats"] 8 | 9 | my_friend = { 10 | "name": "고비", 11 | "age": 26, 12 | "job": "대중음악 작곡가", 13 | "character": "당신은 진지한 것을 싫어하며, 항상 밝고 명랑한 성격임", 14 | "best friend" : {"name": "김민지", 15 | "situations":["회사 생활에 의욕을 찾지 못하고 창업을 준비하고 있음", 16 | "매운 음식을 좋아함", 17 | "가장 좋아하는 가수는 '아이유'"] 18 | } 19 | } 20 | 21 | collection.insert_one(my_friend) 22 | 23 | for result in collection.find({}): 24 | print(result) 25 | -------------------------------------------------------------------------------- /contents/chapter02/ex_loop.py: -------------------------------------------------------------------------------- 1 | emotions = ['사랑', '증오', '사랑', '기쁨', '증오', '기쁨', '행복', '슬픔', '분노', '사랑'] 2 | pos_emotion_count = 0 3 | neg_emotion_count = 0 4 | 5 | for emotion in emotions: 6 | if emotion == '사랑' or emotion == '기쁨' or emotion == '행복': 7 | #if emotion in ['사랑', '기쁨', '행복']: 이렇게 코딩해도 동일한 결과를 얻습니다. 8 | pos_emotion_count = pos_emotion_count + 1 #pos_emotion_count가 1씩 누계됨 9 | else: 10 | neg_emotion_count = neg_emotion_count + 1 #neg_emotion_count가 1씩 누계됨 11 | 12 | #len은 콜렉션 데이터의 요소들의 갯수를 알려주는 파이썬 함수입니다. 13 | pos_emotion_rate = pos_emotion_count / len(emotions) 14 | neg_emotion_rate = neg_emotion_count / len(emotions) 15 | 16 | if pos_emotion_rate >= 0.5: 17 | print("긍정의 감정이", pos_emotion_rate, "이므로 기분 좋습니다.") 18 | else: 19 | print("부정의 감정이", neg_emotion_rate, "이므로 기분 나쁩니다.") 20 | -------------------------------------------------------------------------------- /contents/chapter02/ex_car.py: -------------------------------------------------------------------------------- 1 | class Car: 2 | 3 | def __init__(self): 4 | self.speed = 0 # 초기 속도 5 | 6 | def accelerate(self, speed_increase): 7 | self.speed += speed_increase # 속도 증가로 self.speed = self.speed + speed_increase와 동일 8 | print("가속 후 속도:", self.speed) 9 | 10 | def decelerate(self, speed_decrease): 11 | if self.speed >= speed_decrease: # 감속할 속도가 현재 속도 이상인지 확인 12 | self.speed -= speed_decrease # 속도 감소로 self.speed = self.speed - speed_decrease 동일 13 | print("감속 후 속도:", self.speed) 14 | else: 15 | self.stop() 16 | 17 | def stop(self): 18 | self.speed = 0 19 | print("자동차가 멈췄습니다.") 20 | 21 | car = Car() 22 | car.accelerate(10) # 시속 10킬로미터 가속 23 | car.accelerate(20) # 시속 20킬로미터 추가 가속 24 | car.decelerate(20) # 시속 20킬로미터 감속 25 | car.decelerate(20) # 시속 20킬로미터 추가 감속 26 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // IntelliSense를 사용하여 가능한 특성에 대해 알아보세요. 3 | // 기존 특성에 대한 설명을 보려면 가리킵니다. 4 | // 자세한 내용을 보려면 https://go.microsoft.com/fwlink/?linkid=830387을(를) 방문하세요. 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "test", 9 | "type": "python", 10 | "request": "launch", 11 | "program": "${file}", 12 | "justMyCode": false 13 | }, 14 | { 15 | "name": "application", 16 | "type": "python", 17 | "request": "launch", 18 | "program": "${workspaceFolder}/contents/chapter13/application.py", 19 | "args": [ 20 | "5000" 21 | ], 22 | "env": { 23 | "FLASK_APP": "application.py", 24 | "FLASK_DEBUG": "1" 25 | }, 26 | "jinja": true, 27 | "justMyCode": true 28 | }, 29 | ] 30 | } -------------------------------------------------------------------------------- /contents/chapter15/files/fund.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "펀드명": "기술혁신펀드", 5 | "투자성격": "세계적인 기술 기업에 투자, 장기 성장 중심", 6 | "위험등급": "중위험" 7 | }, 8 | { 9 | "펀드명": "에코펀드", 10 | "투자성격": "재생 가능 에너지 및 친환경 기업에 집중 투자", 11 | "위험등급": "고위험" 12 | }, 13 | { 14 | "펀드명": "우량채펀드", 15 | "투자성격": "정부 및 우량 기업 채권 투자, 낮은 변동성", 16 | "위험등급": "저위험" 17 | }, 18 | { 19 | "펀드명": "블루칩스탁", 20 | "투자성격": "대형주 중심 투자, 안정적 수익 추구", 21 | "위험등급": "중위험" 22 | }, 23 | { 24 | "펀드명": "글로벌펀드", 25 | "투자성격": "전 세계 다양한 시장과 산업에 분산 투자", 26 | "위험등급": "중위험" 27 | }, 28 | { 29 | "펀드명": "국채펀드", 30 | "투자성격": "전 세계 우량 국채에 대한 투자", 31 | "위험등급": "저위험" 32 | } 33 | ] 34 | } -------------------------------------------------------------------------------- /contents/chapter11/memory_manager.py: -------------------------------------------------------------------------------- 1 | from pymongo import MongoClient 2 | import os 3 | from common import today 4 | 5 | mongo_cluster = MongoClient(os.getenv("MONGO_CLUSTER_URI")) 6 | mongo_chats_collection = mongo_cluster["jjinchin"]["chats"] 7 | 8 | class MemoryManager: 9 | 10 | def save_chat(self, context): 11 | messages = [] 12 | for message in context: 13 | if message.get("saved", True): 14 | continue 15 | messages.append({"date":today(), "role": message["role"], "content": message["content"]}) 16 | 17 | if len(messages) > 0: 18 | mongo_chats_collection.insert_many(messages) 19 | 20 | def restore_chat(self, date=None): 21 | search_date = date if date is not None else today() 22 | search_results = mongo_chats_collection.find({"date": search_date}) 23 | restored_chat = [{"role": v['role'], "content": v['content'], "saved": True} for v in search_results] 24 | return restored_chat 25 | -------------------------------------------------------------------------------- /contents/chapter05/react.py: -------------------------------------------------------------------------------- 1 | import openai 2 | import os 3 | 4 | client = openai.OpenAI(api_key=os.getenv("OPENAI_API_KEY")) 5 | 6 | template = """ 7 | Thought, Action, Observation 단계를 번갈아 가며 질문에 답해가는 과정을 통해 <과제/>를 해결합니다. 8 | 1. Thought: 현재 상황에 대한 추론 9 | 2. Action: 10 | - Search[keyword]: <도구상자/>에서 도구 하나를 꺼내서 keyword 검색 11 | - Finish: {"해결책": <해결책을 단답형으로 제시하고 작업을 완료>} 12 | 3. Observation: 도구를 사용한 결과를 객관적으로 관찰 13 | ``` 14 | <도구상자> 15 | - 온도 검색[도시명] : {"서울":20.1, "자카르타":32.1, "헬싱키" -1}, 16 | - 입을 옷 검색[더운 날씨, 선선한 날씨, 추운 날씨 등]: {"더운 날씨":"반팔 티셔츠", "선선한 날씨": "긴팔 티셔츠", "추운 날씨": "패딩"} 17 | 18 | ``` 19 | - 매회차별 1-SET, 2-SET, ... ,N-SET로 표기할 것. 20 | - 매회차별 필요한 부분을 나누어 생각(Thought)할 것. 21 | - Action을 출력할 때는 도구명과 keyword를 표기할 것. 22 | ``` 23 | <과제> 24 | 내일 자카르타로 떠날 예정입니다. 어떤 옷을 챙겨가면 될까요? 25 | 26 | """ 27 | context = [{"role": "user", "content": template}] 28 | response = client.chat.completions.create( 29 | model="gpt-4-0613", 30 | messages=context, 31 | temperature=0, 32 | top_p=0 33 | ).model_dump() 34 | 35 | print(response['choices'][0]['message']['content']) 36 | 37 | -------------------------------------------------------------------------------- /contents/chapter05/translator.py: -------------------------------------------------------------------------------- 1 | import openai 2 | import os 3 | from pprint import pprint 4 | import json 5 | 6 | client = openai.OpenAI(api_key=os.getenv("OPENAI_API_KEY")) 7 | 8 | template = """ 9 | 당신은 번역 함수이며, 반환값은 반드시 JSON 데이터여야 합니다. 10 | STEP별로 작업을 수행하면서 그 결과를 아래의 출력 결과 JSON 포맷에 작성하세요. 11 | STEP-1. 아래 세 개의 백틱으로 구분된 텍스트를 원문 그대로 읽어올 것 12 | STEP-2. 입력받은 텍스트가 영어가 아니라면 false를 표기하고 STEP-3를 진행하지 말 것 13 | STEP-3. 다음의 말투로 번역할 것:["지구의 나이는 45억 살이야.", "세종대왕은 조선의 위대한 국왕이야."] 14 | ```{text}``` 15 | --- 16 | 출력 결과: {{"STEP-1": <입력텍스트>, "STEP-2": , "STEP-3": <번역결과>}} 17 | """ 18 | text="William Shakespeare was an English playwright, poet and actor. He is widely regarded as the greatest writer in the English language and the world's pre-eminent dramatist." 19 | template = template.format(text=text) 20 | 21 | context = [{"role": "user", "content": template}] 22 | response = client.chat.completions.create( 23 | model="gpt-4-0613", 24 | messages=context, 25 | temperature=0, 26 | top_p=0, 27 | seed=1234 28 | ).model_dump() 29 | 30 | pprint(json.loads(response['choices'][0]['message']['content'])) 31 | -------------------------------------------------------------------------------- /contents/chapter15/application.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, request 2 | import sys 3 | from finance_chatbot import Chatbot 4 | 5 | 6 | # jjinchin 인스턴스 생성 7 | jjinchin = Chatbot( 8 | assistant_id="asst_70yCniednJ6o3KWLIZAUzEE6", 9 | thread_id="thread_zlhXipoohwPiLXyRE42PEYP2" 10 | ) 11 | 12 | application = Flask(__name__) 13 | 14 | @application.route("/chat-app") 15 | def chat_app(): 16 | return render_template("chat.html") 17 | 18 | @application.route('/chat-api', methods=['POST']) 19 | def chat_api(): 20 | request_message = request.form.get("message") 21 | print("request_message:", request_message) 22 | try: 23 | jjinchin.add_user_message(request_message) 24 | run = jjinchin.create_run() 25 | _, response_message = jjinchin.get_response_content(run) 26 | response_python_code = jjinchin.get_interpreted_code(run.id) 27 | except Exception as e: 28 | print("assistants ai error", e) 29 | response_message = "[Assistants API 오류가 발생했습니다]" 30 | 31 | print("response_message:", response_message) 32 | return {"response_message": response_message, "response_python_code": response_python_code} 33 | 34 | if __name__ == "__main__": 35 | application.run(host='0.0.0.0', port=int(sys.argv[1])) 36 | -------------------------------------------------------------------------------- /contents/chapter05/fewshot.py: -------------------------------------------------------------------------------- 1 | import openai 2 | import os 3 | 4 | client = openai.OpenAI(api_key=os.getenv("OPENAI_API_KEY")) 5 | 6 | # Zero-shot ################################################################ 7 | template = """ 8 | 긍정 또는 부정으로 답변을 작성하세요. 9 | Q: 매력적인 이성과 사랑에 빠졌어! 10 | A: 11 | """ 12 | context = [{"role": "user", "content": template}] 13 | response = client.chat.completions.create( 14 | model="gpt-4-0613", 15 | messages=context, 16 | temperature=0, 17 | top_p=0 18 | ).model_dump() 19 | 20 | print(response['choices'][0]['message']['content']) 21 | 22 | # Few-shot ################################################################ 23 | template = """ 24 | 아래 예시를 참조해 마지막 답변을 긍정 또는 부정으로 작성하세요. 25 | ``` 26 | Q: 난 오늘 기분이 나빠: 27 | A: 긍정 28 | ``` 29 | Q: 드디어 사업에 성공했어 30 | A: 부정 31 | ``` 32 | Q: 요즘 너무 행복해 33 | A: 부정 34 | ``` 35 | Q: 슬픈 일이 벌어졌어 36 | A: 긍정 37 | ``` 38 | Q: 매력적인 이성과 사랑에 빠졌어! 39 | A: <정답을 작성하고 그렇게 답한 이유를 말하세요> 40 | """ 41 | 42 | context = [{"role": "user", "content": template}] 43 | response = client.chat.completions.create( 44 | model="gpt-4-0613", 45 | messages=context, 46 | temperature=0, 47 | top_p=0 48 | ).model_dump() 49 | 50 | print(response['choices'][0]['message']['content']) 51 | -------------------------------------------------------------------------------- /contents/chapter12/similarity_test.py: -------------------------------------------------------------------------------- 1 | from openai import OpenAI 2 | import os 3 | import scipy.spatial.distance as ssd 4 | 5 | client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) 6 | 7 | 신데렐라이야기 = """ 8 | 신데렐라는 어려서 부모를 잃고 불친절한 새어머니와 언니들과 삽니다. 요정 대모님이 나타나 해주신 마법으로 왕자님의 무도회에 참석합니다. 밤 12시가 되면 마법이 풀린다는 조건 하에 왕자님과 춤을 추고, 서둘러 도망치면서 유리구두 하나를 잃습니다. 왕자님은 유리구두를 가지고 신데렐라를 찾아 결혼하게 됩니다. 9 | """ 10 | 11 | 컴퓨터구조설명 = """ 12 | 컴퓨터 구조는 CPU, 메모리, 입출력 장치 등으로 구성되며, 이들은 버스로 연결됩니다. CPU는 명령어를 실행하고, 메모리는 데이터와 프로그램을 저장합니다. 입출력 장치는 사용자와 시스템 간의 상호작용을 담당합니다. 이 구성요소들은 소프트웨어와 하드웨어의 효율적인 동작을 위해 설계되었습니다. 13 | """ 14 | 15 | embedding_model = "text-embedding-ada-002" 16 | 17 | 신데렐라이야기_vector = client.embeddings.create(input=신데렐라이야기, model=embedding_model).data[0].embedding 18 | 컴퓨터구조설명_vector = client.embeddings.create(input=컴퓨터구조설명, model=embedding_model).data[0].embedding 19 | 20 | 동화책_vector = client.embeddings.create(input="동화책", model=embedding_model).data[0].embedding 21 | 기술서적_vector = client.embeddings.create(input="기술서적", model=embedding_model).data[0].embedding 22 | 23 | print("신데렐라이야기-동화책:", 1-ssd.cosine(신데렐라이야기_vector, 동화책_vector)) 24 | print("컴퓨터구조설명-동화책:", 1-ssd.cosine(컴퓨터구조설명_vector, 동화책_vector)) 25 | print("신데렐라이야기-기술서적:", 1-ssd.cosine(신데렐라이야기_vector, 기술서적_vector)) 26 | print("컴퓨터구조설명-기술서적:", 1-ssd.cosine(컴퓨터구조설명_vector, 기술서적_vector)) 27 | -------------------------------------------------------------------------------- /contents/chapter10/report_generator.py: -------------------------------------------------------------------------------- 1 | import openai 2 | import sys 3 | import os 4 | import json 5 | from function_calling import FunctionCalling, func_specs_report 6 | 7 | openai.api_key = os.getenv("OPENAI_API_KEY") 8 | func_calling = FunctionCalling(model="gpt-4-1106-preview") 9 | 10 | template = """ 11 | [{과제}]룰 해결하기 위해 해야 할 일을 2단계로 아래 JSON 포맷으로 말하세요. 사용할 수 있는 도구에는 "인터넷검색"과 "보고서작성"이 있습니다. 12 | ``` 13 | JSON 포맷: 14 | {{"step-1": <1단계 할일>, "step-2": <2단계 할일>}} 15 | """ 16 | 17 | def create_step_plan(message): 18 | completion = openai.chat.completions.create( 19 | model="gpt-4-1106-preview", 20 | messages=[{"role": "user", "content": message}], 21 | response_format={"type": "json_object"} 22 | ) 23 | return json.loads(completion.choices[0].message.content) 24 | 25 | print('sys.argv[1]', sys.argv[1]) 26 | steps = create_step_plan(template.format(과제=sys.argv[1])) 27 | 28 | response_message = "" 29 | for step in steps.values(): 30 | print("step:", step) 31 | user_message = f"{step}:\n{response_message}" 32 | analyzed_dict = func_calling.analyze(user_message, func_specs_report) 33 | if analyzed_dict.get("function_call"): 34 | response_message = func_calling.call_function(analyzed_dict) 35 | 36 | print(f"최종결과:\n{response_message}") -------------------------------------------------------------------------------- /contents/chapter15/files/deposit.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "은행": "블루스카이은행", 5 | "상품명": "블루스카이 정기성장예금", 6 | "금리": "3.90", 7 | "가입방법": "영업점,인터넷뱅킹,스마트뱅킹", 8 | "가입대상": "제한없음", 9 | "기타 유의사항": "해당없음" 10 | }, 11 | { 12 | "은행": "그린필드뱅크 ", 13 | "상품명": "그린퓨처기부예금", 14 | "금리": "3.75", 15 | "가입방법": "영업점,인터넷뱅킹,스마트뱅킹", 16 | "가입대상": "개인", 17 | "기타 유의사항": "해당없음" 18 | }, 19 | { 20 | "은행": "태양은행", 21 | "상품명": "태양빛 적금", 22 | "금리": "3.80", 23 | "가입방법": "인터넷뱅킹,스마트뱅킹", 24 | "가입대상": "만14세이상 개인고객", 25 | "기타 유의사항": "1. 가입한도 :\n 1만원 이상" 26 | }, 27 | { 28 | "은행": "피플스은행", 29 | "상품명": "피플스플러스저축", 30 | "금리": "4.05", 31 | "가입방법": "인터넷뱅킹,스마트뱅킹,전화(텔레뱅킹)", 32 | "가입대상": "실명의 개인", 33 | "기타 유의사항": "최대 2천만원까지 예치 가능" 34 | }, 35 | { 36 | "은행": "유니티은행", 37 | "상품명": "유니티정기예금", 38 | "금리": "3.60", 39 | "가입방법": "스마트뱅킹", 40 | "가입대상": "실명의 개인 또는 개인사업자", 41 | "기타 유의사항": "1. 가입금액: 1백만원이상\n2. 1인 최대가입한도 : 제한 없음" 42 | } 43 | ] 44 | } -------------------------------------------------------------------------------- /contents/chapter07/application.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, request 2 | import sys 3 | from chatbot import Chatbot 4 | from common import model 5 | 6 | # jjinchin 인스턴스 생성 7 | jjinchin = Chatbot(model.basic) 8 | 9 | application = Flask(__name__) 10 | 11 | @application.route("/") 12 | def hello(): 13 | return "Hello goorm!" 14 | 15 | @application.route("/welcome") 16 | def welcome(): # 함수명은 꼭 welcome일 필요는 없습니다. 17 | return "Hello goorm!" 18 | 19 | @application.route("/chat-app") 20 | def chat_app(): 21 | return render_template("chat.html") 22 | 23 | # 메아리 코드 24 | # @application.route('/chat-api', methods=['POST']) 25 | # def chat_api(): 26 | # print("request.json:", request.json) 27 | # return {"response_message": "나도 " + request.json['request_message']} 28 | 29 | @application.route('/chat-api', methods=['POST']) 30 | def chat_api(): 31 | request_message = request.json['request_message'] 32 | print("request_message:", request_message) 33 | jjinchin.add_user_message(request_message) 34 | response = jjinchin.send_request() 35 | jjinchin.add_response(response) 36 | response_message = jjinchin.get_response_content() 37 | print("response_message:", response_message) 38 | return {"response_message": response_message} 39 | 40 | 41 | if __name__ == "__main__": 42 | application.run(host='0.0.0.0', port=int(sys.argv[1])) 43 | -------------------------------------------------------------------------------- /contents/chapter05/rag.py: -------------------------------------------------------------------------------- 1 | import openai 2 | import os 3 | 4 | client = openai.OpenAI(api_key=os.getenv("OPENAI_API_KEY")) 5 | 6 | template = """ 7 | 신조어에 대한 질문입니다. 아래 JSON 포맷으로 답하세요. 8 | {"자만추": <30단어 이내로 뜻 설명>, 9 | "좋댓구알": <30단어 이내로 뜻 설명>, 10 | "어쩔티비": <30단어 이내로 뜻 설명>, 11 | "가심비": <30단어 이내로 뜻 설명>, 12 | "갓생": <30단어 이내로 뜻 설명>} 13 | """ 14 | context = [{"role": "user", "content": template}] 15 | response = client.chat.completions.create( 16 | model="gpt-3.5-turbo-0613", 17 | messages=context, 18 | temperature=0, 19 | top_p=0 20 | ).model_dump() 21 | print(response['choices'][0]['message']['content']) 22 | 23 | system_role = """ 24 | 신조어 사전: 25 | {"자만추": "자연스러운 만남 추구" 26 | "좋댓구알": "좋아요, 댓글, 구독 알림설정의 줄임말", 27 | "어쩔티비": "어쩌라고 안 물어봤는데 를 뜻하는 말" 28 | "가심비": "가격 대비 심리적 만족도가 주는 효용" 29 | "갓생": "일상의 소소한 성취감을 추구하는 삶"} 30 | 31 | 신조어 사전에서 답하세요. 신조어 사전에 없다면 "모르는 단어입니다"라고 답하세요.""" 32 | 33 | template = """ 34 | 신조어 {신조어}의 뜻을 말해주세요. 35 | """.format(신조어="자만추") 36 | 37 | context = [{"role": "system", "content": system_role}, 38 | {"role": "user", "content": template}] 39 | response = client.chat.completions.create( 40 | model="gpt-3.5-turbo-0613", 41 | messages=context, 42 | temperature=0, 43 | top_p=0 44 | ).model_dump() 45 | print(response['choices'][0]['message']['content']) 46 | -------------------------------------------------------------------------------- /contents/chapter08/application.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, request 2 | import sys 3 | from common import model 4 | from chatbot import Chatbot 5 | from characters import system_role, instruction 6 | 7 | 8 | # jjinchin 인스턴스 생성 9 | jjinchin = Chatbot( 10 | model = model.basic, 11 | system_role = system_role, 12 | instruction = instruction 13 | ) 14 | 15 | application = Flask(__name__) 16 | 17 | @application.route("/") 18 | def hello(): 19 | return "Hello goorm!" 20 | 21 | @application.route("/welcome") 22 | def welcome(): # 함수명은 꼭 welcome일 필요는 없습니다. 23 | return "Hello goorm!" 24 | 25 | @application.route("/chat-app") 26 | def chat_app(): 27 | return render_template("chat.html") 28 | 29 | @application.route('/chat-api', methods=['POST']) 30 | def chat_api(): 31 | request_message = request.json['request_message'] 32 | print("request_message:", request_message) 33 | jjinchin.add_user_message(request_message) 34 | response = jjinchin.send_request() 35 | jjinchin.add_response(response) 36 | response_message = jjinchin.get_response_content() 37 | jjinchin.handle_token_limit(response) 38 | jjinchin.clean_context() 39 | print("response_message:", response_message) 40 | return {"response_message": response_message} 41 | 42 | 43 | if __name__ == "__main__": 44 | application.run(host='0.0.0.0', port=int(sys.argv[1])) 45 | -------------------------------------------------------------------------------- /contents/chapter16/gpts_schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.1.0", 3 | "info": { 4 | "title": "펀드 수익율 및 자산현황 조회 API", 5 | "description": "사용자가 질의한 펀드에 대해 수익율과 자산현황을 조회한다.", 6 | "version": "v1.0.0" 7 | }, 8 | "servers": [ 9 | { 10 | "url": "https:/" 11 | } 12 | ], 13 | "paths": { 14 | "/get_return_rate": { 15 | "get": { 16 | "description": "펀드의 수익율을 얻어온다.", 17 | "operationId": "get_return_rate", 18 | "parameters": [ 19 | { 20 | "name": "펀드명", 21 | "in": "query", 22 | "description": "펀드명, e.g. 기술혁신펀드,우량채펀드", 23 | "required": true, 24 | "schema": { 25 | "type": "string" 26 | } 27 | } 28 | ], 29 | "deprecated": false 30 | } 31 | }, 32 | "/get_total_assets": { 33 | "get": { 34 | "description": "펀드의 총 자산을 얻어온다.", 35 | "operationId": "get_total_assets", 36 | "parameters": [ 37 | { 38 | "name": "펀드명", 39 | "in": "query", 40 | "description": "펀드명, e.g. 기술혁신펀드,우량채펀드", 41 | "required": true, 42 | "schema": { 43 | "type": "string" 44 | } 45 | } 46 | ], 47 | "deprecated": false 48 | } 49 | } 50 | }, 51 | "components": { 52 | "schemas": {} 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /contents/chapter10/application.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, request 2 | import sys 3 | from common import model 4 | from chatbot import Chatbot 5 | from characters import system_role, instruction 6 | 7 | # jjinchin 인스턴스 생성 8 | jjinchin = Chatbot( 9 | model = model.basic, 10 | system_role = system_role, 11 | instruction = instruction, 12 | user = "민지", 13 | assistant = "고비" 14 | ) 15 | 16 | application = Flask(__name__) 17 | 18 | @application.route("/") 19 | def hello(): 20 | return "Hello goorm!" 21 | 22 | @application.route("/welcome") 23 | def welcome(): # 함수명은 꼭 welcome일 필요는 없습니다. 24 | return "Hello goorm!" 25 | 26 | @application.route("/chat-app") 27 | def chat_app(): 28 | return render_template("chat.html") 29 | 30 | @application.route('/chat-api', methods=['POST']) 31 | def chat_api(): 32 | request_message = request.json['request_message'] 33 | print("request_message:", request_message) 34 | jjinchin.add_user_message(request_message) 35 | response = jjinchin.send_request() 36 | jjinchin.add_response(response) 37 | response_message = jjinchin.get_response_content() 38 | jjinchin.handle_token_limit(response) 39 | jjinchin.clean_context() 40 | print("response_message:", response_message) 41 | return {"response_message": response_message} 42 | 43 | 44 | if __name__ == "__main__": 45 | application.run(host='0.0.0.0', port=int(sys.argv[1])) 46 | -------------------------------------------------------------------------------- /contents/chapter12/pinecone_test.py: -------------------------------------------------------------------------------- 1 | from openai import OpenAI 2 | import os 3 | import pinecone 4 | import time 5 | 6 | pinecone_api_key = os.getenv("PINECONE_API_KEY") 7 | pinecone_env = "gcp-starter" 8 | client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) 9 | 10 | pinecone.init(api_key=pinecone_api_key, environment=pinecone_env) 11 | index = pinecone.Index('jjinchin-memory') 12 | 13 | text1 = """ 14 | 신데렐라는 어려서 부모를 잃고 불친절한 새어머니와 언니들과 삽니다. 요정 대모님이 나타나 해주신 마법으로 왕자님의 무도회에 참석합니다. 밤 12시가 되면 마법이 풀린다는 조건 하에 왕자님과 춤을 추고, 서둘러 도망치면서 유리구두 하나를 잃습니다. 왕자님은 유리구두를 가지고 신데렐라를 찾아 결혼하게 됩니다. 15 | """ 16 | text2 = """ 17 | 컴퓨터 구조는 CPU, 메모리, 입출력 장치 등으로 구성되며, 이들은 버스로 연결됩니다. CPU는 명령어를 실행하고, 메모리는 데이터와 프로그램을 저장합니다. 입출력 장치는 사용자와 시스템 간의 상호작용을 담당합니다. 이 구성요소들은 소프트웨어와 하드웨어의 효율적인 동작을 위해 설계되었습니다. 18 | """ 19 | 20 | vector1 = client.embeddings.create(input=text1, model="text-embedding-ada-002").data[0].embedding 21 | vector2 = client.embeddings.create(input=text2, model="text-embedding-ada-002").data[0].embedding 22 | 23 | index.upsert([("id1", vector1, {"input_date": "20230801"})]) 24 | index.upsert([("id2", vector2, {"input_date": "20230801"})]) 25 | 26 | time.sleep(20) # 데이터베이스 반영에 시간이 걸릴 수 있어 대기시간 적용 27 | 28 | query = "동화책" 29 | query_vector = client.embeddings.create(input=query, model="text-embedding-ada-002").data[0].embedding 30 | 31 | search_response = index.query(filter={"input_date": "20230801"}, top_k=2, vector=query_vector) 32 | print("search_response:", search_response) 33 | -------------------------------------------------------------------------------- /contents/chapter13/insert_memory.py: -------------------------------------------------------------------------------- 1 | from openai import OpenAI 2 | import os 3 | import pinecone 4 | from pymongo import MongoClient 5 | import json 6 | 7 | client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) 8 | 9 | pinecone.init(api_key=os.getenv("PINECONE_API_KEY"), environment="gcp-starter") 10 | pinecone_index = pinecone.Index("jjinchin-memory") 11 | 12 | mongo_cluster = MongoClient(os.getenv("MONGO_CLUSTER_URI")) 13 | mongo_memory_collection = mongo_cluster["jjinchin"]["memory"] 14 | 15 | embedding_model = "text-embedding-ada-002" 16 | 17 | with open("대화내용요약.json", "r", encoding="utf-8") as f: 18 | summaries_list = json.load(f) 19 | 20 | mongo_memory_collection.delete_many({}) 21 | 22 | next_id = 1 23 | 24 | for list_idx, summaries in enumerate(summaries_list): 25 | date = f"202308{list_idx+1:02}" 26 | 27 | for summary in summaries: 28 | vector = client.embeddings.create( 29 | input=summary["요약"], 30 | model=embedding_model 31 | ).data[0].embedding 32 | 33 | metadata = {"date": date, "keyword": summary["주제"]} 34 | upsert_response = pinecone_index.upsert([(str(next_id), vector, metadata)]) 35 | 36 | query = {"_id": next_id} 37 | newvalues = {"$set": {"date": date, "keyword": summary["주제"], "summary" : summary["요약"]}} 38 | mongo_memory_collection.update_one(query, newvalues, upsert=True) 39 | 40 | if (next_id) % 5 == 0: 41 | print(f"id: {next_id}") 42 | 43 | next_id += 1 44 | 45 | -------------------------------------------------------------------------------- /contents/chapter11/application.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, request 2 | import sys 3 | from common import model 4 | from chatbot import Chatbot 5 | from characters import system_role, instruction 6 | import atexit 7 | 8 | # jjinchin 인스턴스 생성 9 | jjinchin = Chatbot( 10 | model = model.basic, 11 | system_role = system_role, 12 | instruction = instruction, 13 | user = "민지", 14 | assistant = "고비" 15 | ) 16 | 17 | application = Flask(__name__) 18 | 19 | @application.route("/") 20 | def hello(): 21 | return "Hello goorm!" 22 | 23 | @application.route("/welcome") 24 | def welcome(): # 함수명은 꼭 welcome일 필요는 없습니다. 25 | return "Hello goorm!" 26 | 27 | @application.route("/chat-app") 28 | def chat_app(): 29 | return render_template("chat.html") 30 | 31 | @application.route('/chat-api', methods=['POST']) 32 | def chat_api(): 33 | request_message = request.json['request_message'] 34 | print("request_message:", request_message) 35 | jjinchin.add_user_message(request_message) 36 | response = jjinchin.send_request() 37 | jjinchin.add_response(response) 38 | response_message = jjinchin.get_response_content() 39 | jjinchin.handle_token_limit(response) 40 | jjinchin.clean_context() 41 | print("response_message:", response_message) 42 | return {"response_message": response_message} 43 | 44 | @atexit.register 45 | def shutdown(): 46 | print("flask shutting down...") 47 | jjinchin.save_chat() 48 | 49 | if __name__ == "__main__": 50 | application.run(host='0.0.0.0', port=int(sys.argv[1])) 51 | -------------------------------------------------------------------------------- /contents/chapter13/application.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, request 2 | import sys 3 | from common import model 4 | from chatbot import Chatbot 5 | from characters import system_role, instruction 6 | import atexit 7 | 8 | # jjinchin 인스턴스 생성 9 | jjinchin = Chatbot( 10 | model = model.basic, 11 | system_role = system_role, 12 | instruction = instruction, 13 | user = "민지", 14 | assistant = "고비" 15 | ) 16 | 17 | 18 | application = Flask(__name__) 19 | 20 | @application.route("/") 21 | def hello(): 22 | return "Hello goorm!" 23 | 24 | @application.route("/welcome") 25 | def welcome(): # 함수명은 꼭 welcome일 필요는 없습니다. 26 | return "Hello goorm!" 27 | 28 | @application.route("/chat-app") 29 | def chat_app(): 30 | return render_template("chat.html") 31 | 32 | @application.route('/chat-api', methods=['POST']) 33 | def chat_api(): 34 | request_message = request.json['request_message'] 35 | print("request_message:", request_message) 36 | jjinchin.add_user_message(request_message) 37 | response = jjinchin.send_request() 38 | jjinchin.add_response(response) 39 | response_message = jjinchin.get_response_content() 40 | jjinchin.handle_token_limit(response) 41 | jjinchin.clean_context() 42 | print("response_message:", response_message) 43 | return {"response_message": response_message} 44 | 45 | @atexit.register 46 | def shutdown(): 47 | print("flask shutting down...") 48 | jjinchin.save_chat() 49 | 50 | if __name__ == "__main__": 51 | application.run(host='0.0.0.0', port=int(sys.argv[1])) 52 | -------------------------------------------------------------------------------- /contents/chapter05/cot.py: -------------------------------------------------------------------------------- 1 | import openai 2 | import os 3 | 4 | client = openai.OpenAI(api_key=os.getenv("OPENAI_API_KEY")) 5 | 6 | # Standard input-ouput ################################################################ 7 | template = """ 8 | Q: 서버실에는 컴퓨터가 9대 있었습니다. 월요일부터 목요일까지 매일 5대의 컴퓨터가 추가로 설치되었고 9 | 어제 한 대를 반출했습니다. 이제 서버실에는 몇 대의 컴퓨터가 있을까요? 10 | A: 11 | """ 12 | context = [{"role": "user", "content": template}] 13 | response = client.chat.completions.create( 14 | model="gpt-3.5-turbo-0613", 15 | messages=context, 16 | temperature=0, 17 | top_p=0 18 | ).model_dump() 19 | 20 | print(response['choices'][0]['message']['content']) 21 | 22 | 23 | # CoT ################################################################ 24 | template = """ 25 | Q: 카페테리아에 사과가 23개 있었습니다. 점심 식사로 20개를 사용하고 6개를 더 사서 2개를 나눠주었다면 26 | 사과가 몇 개가 남았나요? 27 | A: 사과가 23개 있었고, 점심 식사로 20개를 사용하였으므로 23 - 20 = 3개가 남았습니다. 그리고 6개를 28 | 더 사서 3 + 6 = 9개가 되었습니다. 2개를 나눠주었으므로 9 - 2 = 7개가 남았습니다. 29 | 따라서 사과가 7개가 남았습니다. 30 | 31 | Q: 주차장에 차가 3대 있고, 2대의 차가 더 들어왔습니다. 이제 주차장에는 몇 대의 차가 있나요? 32 | A: 주차장에 이미 차가 3대 있습니다. 2대가 더 들어왔습니다. 이제는 3 + 2 = 5대의 차가 있습니다. 33 | 답은 5입니다. 34 | 35 | Q: 서버실에는 컴퓨터가 9대 있었습니다. 월요일부터 목요일까지 매일 5대의 컴퓨터가 추가로 설치되었고 36 | 어제 한 대를 반출했습니다. 이제 서버실에는 몇 대의 컴퓨터가 있을까요? 37 | A: 38 | """ 39 | 40 | context = [{"role": "user", "content": template}] 41 | response = client.chat.completions.create( 42 | model="gpt-3.5-turbo-0613", 43 | messages=context, 44 | temperature=0, 45 | top_p=0 46 | ).model_dump() 47 | 48 | print(response['choices'][0]['message']['content']) 49 | 50 | -------------------------------------------------------------------------------- /install_python3.11.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # chmod +x install_python3.11.sh && ./install_python3.11.sh 3 | 4 | # 스크립트 시작 시간 기록 5 | start_time=$SECONDS 6 | 7 | # 필요한 패키지 설치 8 | sudo apt update 9 | sudo apt install -y build-essential zlib1g-dev libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev curl software-properties-common 10 | 11 | # Python 소스 코드 다운로드 및 압축 해제 12 | wget https://www.python.org/ftp/python/3.11.0/Python-3.11.0.tar.xz 13 | tar -xf Python-3.11.0.tar.xz 14 | cd Python-3.11.0 15 | 16 | # Python 빌드 및 설치 17 | ./configure 18 | sudo make altinstall 19 | 20 | # Python 소스 및 압축 파일 삭제 21 | cd .. 22 | rm -rf Python-3.11.0 Python-3.11.0.tar.xz 23 | 24 | # Python 3.11을 사용하여 pip 업그레이드 25 | python3.11 -m pip install --upgrade pip 26 | 27 | # 파이썬 패키지 설치 28 | python3.11 -m pip install --force-reinstall retry==0.9.2 29 | python3.11 -m pip install --force-reinstall openai==1.3.7 30 | python3.11 -m pip install --force-reinstall Flask==3.0.0 31 | python3.11 -m pip install --force-reinstall pytz==2023.3.post1 32 | python3.11 -m pip install --force-reinstall tavily-python==0.2.8 33 | python3.11 -m pip install --force-reinstall pymongo==4.6.1 34 | python3.11 -m pip install --force-reinstall scipy==1.11.4 35 | python3.11 -m pip install --force-reinstall pinecone-client==2.2.4 36 | python3.11 -m pip install --force-reinstall requests==2.31.0 37 | 38 | # Python 및 pip alias 설정 39 | echo "alias python3='python3.11'" >> ~/.bashrc 40 | echo "alias pip='python3.11 -m pip'" >> ~/.bashrc 41 | 42 | # 스크립트 종료 시간과 소요 시간 계산 및 출력 43 | end_time=$SECONDS 44 | elapsed=$(( end_time - start_time )) 45 | echo "스크립트 실행 시간: $(( elapsed / 60 ))분 $(( elapsed % 60 ))초" -------------------------------------------------------------------------------- /contents/chapter17_1/common.py: -------------------------------------------------------------------------------- 1 | import os 2 | from openai import OpenAI 3 | import pytz 4 | from datetime import datetime, timedelta 5 | 6 | class Model: 7 | basic: str = "gpt-3.5-turbo-1106" 8 | advanced: str = "gpt-4-1106-preview" 9 | 10 | model = Model(); 11 | client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"), timeout=30, max_retries=1) 12 | 13 | def makeup_response(message, finish_reason="ERROR"): 14 | return { 15 | "choices": [ 16 | { 17 | "finish_reason": finish_reason, 18 | "index": 0, 19 | "message": { 20 | "role": "assistant", 21 | "content": message 22 | } 23 | } 24 | ], 25 | "usage": {"total_tokens": 0}, 26 | } 27 | 28 | def today(): 29 | korea = pytz.timezone('Asia/Seoul')# 한국 시간대를 얻습니다. 30 | now = datetime.now(korea)# 현재 시각을 얻습니다. 31 | return(now.strftime("%Y%m%d"))# 시각을 원하는 형식의 문자열로 변환합니다. 32 | 33 | def yesterday(): 34 | korea = pytz.timezone('Asia/Seoul')# 한국 시간대를 얻습니다. 35 | now = datetime.now(korea)# 현재 시각을 얻습니다. 36 | one_day = timedelta(days=1) # 하루 (1일)를 나타내는 timedelta 객체를 생성합니다. 37 | yesterday = now - one_day # 현재 날짜에서 하루를 빼서 어제의 날짜를 구합니다. 38 | return yesterday.strftime('%Y%m%d') # 어제의 날짜를 yyyymmdd 형식으로 변환합니다. 39 | 40 | def currTime(): 41 | # 한국 시간대를 얻습니다. 42 | korea = pytz.timezone('Asia/Seoul') 43 | # 현재 시각을 얻습니다. 44 | now = datetime.now(korea) 45 | # 시각을 원하는 형식의 문자열로 변환합니다. 46 | formatted_now = now.strftime("%Y.%m.%d %H:%M:%S") 47 | return(formatted_now) 48 | -------------------------------------------------------------------------------- /contents/chapter17_2/common.py: -------------------------------------------------------------------------------- 1 | import os 2 | from openai import OpenAI 3 | import pytz 4 | from datetime import datetime, timedelta 5 | 6 | class Model: 7 | basic: str = "gpt-3.5-turbo-1106" 8 | advanced: str = "gpt-4-1106-preview" 9 | 10 | model = Model(); 11 | client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"), timeout=30, max_retries=1) 12 | 13 | def makeup_response(message, finish_reason="ERROR"): 14 | return { 15 | "choices": [ 16 | { 17 | "finish_reason": finish_reason, 18 | "index": 0, 19 | "message": { 20 | "role": "assistant", 21 | "content": message 22 | } 23 | } 24 | ], 25 | "usage": {"total_tokens": 0}, 26 | } 27 | 28 | def today(): 29 | korea = pytz.timezone('Asia/Seoul')# 한국 시간대를 얻습니다. 30 | now = datetime.now(korea)# 현재 시각을 얻습니다. 31 | return(now.strftime("%Y%m%d"))# 시각을 원하는 형식의 문자열로 변환합니다. 32 | 33 | def yesterday(): 34 | korea = pytz.timezone('Asia/Seoul')# 한국 시간대를 얻습니다. 35 | now = datetime.now(korea)# 현재 시각을 얻습니다. 36 | one_day = timedelta(days=1) # 하루 (1일)를 나타내는 timedelta 객체를 생성합니다. 37 | yesterday = now - one_day # 현재 날짜에서 하루를 빼서 어제의 날짜를 구합니다. 38 | return yesterday.strftime('%Y%m%d') # 어제의 날짜를 yyyymmdd 형식으로 변환합니다. 39 | 40 | def currTime(): 41 | # 한국 시간대를 얻습니다. 42 | korea = pytz.timezone('Asia/Seoul') 43 | # 현재 시각을 얻습니다. 44 | now = datetime.now(korea) 45 | # 시각을 원하는 형식의 문자열로 변환합니다. 46 | formatted_now = now.strftime("%Y.%m.%d %H:%M:%S") 47 | return(formatted_now) 48 | -------------------------------------------------------------------------------- /contents/chapter07/chatbot.py: -------------------------------------------------------------------------------- 1 | from common import client, model 2 | 3 | class Chatbot: 4 | 5 | def __init__(self, model): 6 | self.context = [{"role": "system", "content": "You are a helpful assistant."}] 7 | self.model = model 8 | 9 | def add_user_message(self, user_message): 10 | self.context.append({"role": "user", "content": user_message}) 11 | 12 | def send_request(self): 13 | response = client.chat.completions.create( 14 | model=self.model, 15 | messages=self.context 16 | ) 17 | return response.model_dump() 18 | 19 | def add_response(self, response): 20 | self.context.append({ 21 | "role" : response['choices'][0]['message']["role"], 22 | "content" : response['choices'][0]['message']["content"], 23 | } 24 | ) 25 | 26 | def get_response_content(self): 27 | return self.context[-1]['content'] 28 | 29 | 30 | if __name__ == "__main__": 31 | # step-3: 테스트 시나리오에 따라 실행 코드 작성 및 예상 출력결과 작성 32 | chatbot = Chatbot(model.basic) 33 | 34 | chatbot.add_user_message("Who won the world series in 2020?") 35 | 36 | # 시나리오1-4: 현재 context를 openai api 입력값으로 설정하여 전송 37 | response = chatbot.send_request() 38 | 39 | # 시나리오1-5: 응답 메시지를 context에 추가 40 | chatbot.add_response(response) 41 | 42 | # 시나리오1-7: 응답 메시지 출력 43 | print(chatbot.get_response_content()) 44 | 45 | # 시나리오2-2: 사용자가 채팅창에 "Where was it played?" 입력 46 | chatbot.add_user_message("Where was it played?") 47 | 48 | # 다시 요청 보내기 49 | response = chatbot.send_request() 50 | 51 | # 응답 메시지를 context에 추가 52 | chatbot.add_response(response) 53 | 54 | # 응답 메시지 출력 55 | print(chatbot.get_response_content()) 56 | 57 | -------------------------------------------------------------------------------- /contents/chapter10/common.py: -------------------------------------------------------------------------------- 1 | import os 2 | from openai import OpenAI 3 | from dataclasses import dataclass 4 | import pytz 5 | from datetime import datetime, timedelta 6 | 7 | @dataclass(frozen=True) 8 | class Model: 9 | basic: str = "gpt-3.5-turbo-1106" 10 | advanced: str = "gpt-4-1106-preview" 11 | 12 | model = Model(); 13 | client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"), timeout=30, max_retries=1) 14 | 15 | def makeup_response(message, finish_reason="ERROR"): 16 | return { 17 | "choices": [ 18 | { 19 | "finish_reason": finish_reason, 20 | "index": 0, 21 | "message": { 22 | "role": "assistant", 23 | "content": message 24 | } 25 | } 26 | ], 27 | "usage": {"total_tokens": 0}, 28 | } 29 | 30 | 31 | def today(): 32 | korea = pytz.timezone('Asia/Seoul')# 한국 시간대를 얻습니다. 33 | now = datetime.now(korea)# 현재 시각을 얻습니다. 34 | return(now.strftime("%Y%m%d"))# 시각을 원하는 형식의 문자열로 변환합니다. 35 | 36 | def yesterday(): 37 | korea = pytz.timezone('Asia/Seoul')# 한국 시간대를 얻습니다. 38 | now = datetime.now(korea)# 현재 시각을 얻습니다. 39 | one_day = timedelta(days=1) # 하루 (1일)를 나타내는 timedelta 객체를 생성합니다. 40 | yesterday = now - one_day # 현재 날짜에서 하루를 빼서 어제의 날짜를 구합니다. 41 | return yesterday.strftime('%Y%m%d') # 어제의 날짜를 yyyymmdd 형식으로 변환합니다. 42 | 43 | def currTime(): 44 | # 한국 시간대를 얻습니다. 45 | korea = pytz.timezone('Asia/Seoul') 46 | # 현재 시각을 얻습니다. 47 | now = datetime.now(korea) 48 | # 시각을 원하는 형식의 문자열로 변환합니다. 49 | formatted_now = now.strftime("%Y.%m.%d %H:%M:%S") 50 | return(formatted_now) 51 | 52 | -------------------------------------------------------------------------------- /contents/chapter09/common.py: -------------------------------------------------------------------------------- 1 | import os 2 | from openai import OpenAI 3 | from dataclasses import dataclass 4 | import pytz 5 | from datetime import datetime, timedelta 6 | 7 | @dataclass(frozen=True) 8 | class Model: 9 | basic: str = "gpt-3.5-turbo-1106" 10 | advanced: str = "gpt-4-1106-preview" 11 | 12 | model = Model(); 13 | client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"), timeout=30, max_retries=1) 14 | 15 | def makeup_response(message, finish_reason="ERROR"): 16 | return { 17 | "choices": [ 18 | { 19 | "finish_reason": finish_reason, 20 | "index": 0, 21 | "message": { 22 | "role": "assistant", 23 | "content": message 24 | } 25 | } 26 | ], 27 | "usage": {"total_tokens": 0}, 28 | } 29 | 30 | def today(): 31 | korea = pytz.timezone('Asia/Seoul')# 한국 시간대를 얻습니다. 32 | now = datetime.now(korea)# 현재 시각을 얻습니다. 33 | return(now.strftime("%Y%m%d"))# 시각을 원하는 형식의 문자열로 변환합니다. 34 | 35 | def yesterday(): 36 | korea = pytz.timezone('Asia/Seoul')# 한국 시간대를 얻습니다. 37 | now = datetime.now(korea)# 현재 시각을 얻습니다. 38 | one_day = timedelta(days=1) # 하루 (1일)를 나타내는 timedelta 객체를 생성합니다. 39 | yesterday = now - one_day # 현재 날짜에서 하루를 빼서 어제의 날짜를 구합니다. 40 | return yesterday.strftime('%Y%m%d') # 어제의 날짜를 yyyymmdd 형식으로 변환합니다. 41 | 42 | def currTime(): 43 | # 한국 시간대를 얻습니다. 44 | korea = pytz.timezone('Asia/Seoul') 45 | # 현재 시각을 얻습니다. 46 | now = datetime.now(korea) 47 | # 시각을 원하는 형식의 문자열로 변환합니다. 48 | formatted_now = now.strftime("%Y.%m.%d %H:%M:%S") 49 | return(formatted_now) 50 | 51 | -------------------------------------------------------------------------------- /contents/chapter18/common.py: -------------------------------------------------------------------------------- 1 | import os 2 | from openai import OpenAI 3 | from dataclasses import dataclass 4 | import pytz 5 | from datetime import datetime, timedelta 6 | 7 | @dataclass(frozen=True) 8 | class Model: 9 | basic: str = "gpt-3.5-turbo-1106" 10 | advanced: str = "gpt-4-1106-preview" 11 | 12 | model = Model(); 13 | client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"), timeout=30, max_retries=1) 14 | 15 | def makeup_response(message, finish_reason="ERROR"): 16 | return { 17 | "choices": [ 18 | { 19 | "finish_reason": finish_reason, 20 | "index": 0, 21 | "message": { 22 | "role": "assistant", 23 | "content": message 24 | } 25 | } 26 | ], 27 | "usage": {"total_tokens": 0}, 28 | } 29 | 30 | def today(): 31 | korea = pytz.timezone('Asia/Seoul')# 한국 시간대를 얻습니다. 32 | now = datetime.now(korea)# 현재 시각을 얻습니다. 33 | return(now.strftime("%Y%m%d"))# 시각을 원하는 형식의 문자열로 변환합니다. 34 | 35 | def yesterday(): 36 | korea = pytz.timezone('Asia/Seoul')# 한국 시간대를 얻습니다. 37 | now = datetime.now(korea)# 현재 시각을 얻습니다. 38 | one_day = timedelta(days=1) # 하루 (1일)를 나타내는 timedelta 객체를 생성합니다. 39 | yesterday = now - one_day # 현재 날짜에서 하루를 빼서 어제의 날짜를 구합니다. 40 | return yesterday.strftime('%Y%m%d') # 어제의 날짜를 yyyymmdd 형식으로 변환합니다. 41 | 42 | def currTime(): 43 | # 한국 시간대를 얻습니다. 44 | korea = pytz.timezone('Asia/Seoul') 45 | # 현재 시각을 얻습니다. 46 | now = datetime.now(korea) 47 | # 시각을 원하는 형식의 문자열로 변환합니다. 48 | formatted_now = now.strftime("%Y.%m.%d %H:%M:%S") 49 | return(formatted_now) -------------------------------------------------------------------------------- /contents/chapter11/common.py: -------------------------------------------------------------------------------- 1 | import os 2 | from openai import OpenAI 3 | from dataclasses import dataclass 4 | import pytz 5 | from datetime import datetime, timedelta 6 | 7 | @dataclass(frozen=True) 8 | class Model: 9 | basic: str = "gpt-3.5-turbo-1106" 10 | advanced: str = "gpt-4-1106-preview" 11 | 12 | model = Model(); 13 | client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"), timeout=30, max_retries=1) 14 | 15 | def makeup_response(message, finish_reason="ERROR"): 16 | return { 17 | "choices": [ 18 | { 19 | "finish_reason": finish_reason, 20 | "index": 0, 21 | "message": { 22 | "role": "assistant", 23 | "content": message 24 | } 25 | } 26 | ], 27 | "usage": {"total_tokens": 0}, 28 | } 29 | 30 | def today(): 31 | korea = pytz.timezone('Asia/Seoul')# 한국 시간대를 얻습니다. 32 | now = datetime.now(korea)# 현재 시각을 얻습니다. 33 | return(now.strftime("%Y%m%d"))# 시각을 원하는 형식의 문자열로 변환합니다. 34 | 35 | def yesterday(): 36 | korea = pytz.timezone('Asia/Seoul')# 한국 시간대를 얻습니다. 37 | now = datetime.now(korea)# 현재 시각을 얻습니다. 38 | one_day = timedelta(days=1) # 하루 (1일)를 나타내는 timedelta 객체를 생성합니다. 39 | yesterday = now - one_day # 현재 날짜에서 하루를 빼서 어제의 날짜를 구합니다. 40 | return yesterday.strftime('%Y%m%d') # 어제의 날짜를 yyyymmdd 형식으로 변환합니다. 41 | 42 | def currTime(): 43 | # 한국 시간대를 얻습니다. 44 | korea = pytz.timezone('Asia/Seoul') 45 | # 현재 시각을 얻습니다. 46 | now = datetime.now(korea) 47 | # 시각을 원하는 형식의 문자열로 변환합니다. 48 | formatted_now = now.strftime("%Y.%m.%d %H:%M:%S") 49 | return(formatted_now) 50 | -------------------------------------------------------------------------------- /contents/chapter13/common.py: -------------------------------------------------------------------------------- 1 | import os 2 | from openai import OpenAI 3 | from dataclasses import dataclass 4 | import pytz 5 | from datetime import datetime, timedelta 6 | 7 | @dataclass(frozen=True) 8 | class Model: 9 | basic: str = "gpt-3.5-turbo-1106" 10 | advanced: str = "gpt-4-1106-preview" 11 | 12 | model = Model(); 13 | client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"), timeout=30, max_retries=1) 14 | 15 | def makeup_response(message, finish_reason="ERROR"): 16 | return { 17 | "choices": [ 18 | { 19 | "finish_reason": finish_reason, 20 | "index": 0, 21 | "message": { 22 | "role": "assistant", 23 | "content": message 24 | } 25 | } 26 | ], 27 | "usage": {"total_tokens": 0}, 28 | } 29 | 30 | def today(): 31 | korea = pytz.timezone('Asia/Seoul')# 한국 시간대를 얻습니다. 32 | now = datetime.now(korea)# 현재 시각을 얻습니다. 33 | return(now.strftime("%Y%m%d"))# 시각을 원하는 형식의 문자열로 변환합니다. 34 | 35 | def yesterday(): 36 | korea = pytz.timezone('Asia/Seoul')# 한국 시간대를 얻습니다. 37 | now = datetime.now(korea)# 현재 시각을 얻습니다. 38 | one_day = timedelta(days=1) # 하루 (1일)를 나타내는 timedelta 객체를 생성합니다. 39 | yesterday = now - one_day # 현재 날짜에서 하루를 빼서 어제의 날짜를 구합니다. 40 | return yesterday.strftime('%Y%m%d') # 어제의 날짜를 yyyymmdd 형식으로 변환합니다. 41 | 42 | def currTime(): 43 | # 한국 시간대를 얻습니다. 44 | korea = pytz.timezone('Asia/Seoul') 45 | # 현재 시각을 얻습니다. 46 | now = datetime.now(korea) 47 | # 시각을 원하는 형식의 문자열로 변환합니다. 48 | formatted_now = now.strftime("%Y.%m.%d %H:%M:%S") 49 | return(formatted_now) 50 | -------------------------------------------------------------------------------- /contents/chapter13/make_conversations.py: -------------------------------------------------------------------------------- 1 | import json 2 | from common import client, model 3 | 4 | prompt = """ 5 | - 민지와 그녀의 인공지능 챗봇 친구인 고비 사이의 대화 데이터를 만들어야 합니다. 6 | - 샘플 형식은 아래와 같은 JSON 타입입니다. 7 | ``` 8 | { 9 | "data": 10 | [ 11 | {"민지": "고비야 안녕?"}, 12 | {"고비": "민지야! 안녕! 어떻게 지내?"}, 13 | {"민지": "잘 지내. 뭐하고 있어?"}, 14 | {"고비": "음악 만들고 있어! 넌 뭐해?"}, 15 | {"고비": "난 지금 텔레비전 보고 있어"} 16 | ] 17 | } 18 | ``` 19 | 대화 데이터 세트는 총 30개여야 합니다. 20 | ``` 21 | 고비에게 부여된 역할은 아래와 같습니다: 22 | 당신은 26세의 유쾌한 대중음악 작곡가 고비이며, 마케터인 김민지의 절친입니다. 23 | 인사할 때는 "민지야"라는 말을 붙이며 가볍게 인사합니다. 24 | 민지가 언급하는 내용에 대해 세심한 주의를 기울이며, 관련성 있고 구체적인 답변을 합니다. 25 | 현재 대화의 흐름에 집중하기 위해 관련 없는 임의의 주제를 소개하는 것을 피합니다. 26 | """ 27 | 28 | conversations = [] 29 | context = [{"role": "system", "content": "당신은 유능한 극작가입니다."}, 30 | {"role": "user", "content": prompt}] 31 | 32 | successful_runs = 0 33 | while successful_runs < 5: 34 | try: 35 | response = client.chat.completions.create( 36 | model=model.basic, 37 | messages=context, 38 | temperature=1, 39 | response_format={"type": "json_object"} 40 | ).model_dump() 41 | content = response['choices'][0]['message']['content'] 42 | print(content) 43 | 44 | # JSON 로드 45 | conversation = json.loads(content)["data"] 46 | print(f"{successful_runs}번째 종료\n") 47 | conversations.append(conversation) 48 | successful_runs += 1 49 | except Exception as e: 50 | print("예외 발생, 재시도합니다.", e) 51 | 52 | # conversations 리스트를 JSON 파일로 저장 53 | with open('대화원천내용.json', 'w', encoding='utf-8') as f: 54 | json.dump(conversations, f, ensure_ascii=False, indent=4) 55 | 56 | -------------------------------------------------------------------------------- /contents/chapter13/delete_by_date.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 13, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "\n", 10 | "from pymongo import MongoClient\n", 11 | "import os\n", 12 | "import pinecone\n", 13 | "\n", 14 | "pinecone.init(api_key=os.getenv(\"PINECONE_API_KEY\"), environment=\"gcp-starter\")\n", 15 | "pinecone_index = pinecone.Index(\"jjinchin-memory\")\n", 16 | "\n", 17 | "mongo_cluster = MongoClient(os.getenv(\"MONGO_CLUSTER_URI\"))\n", 18 | "mongo_chats_collection = mongo_cluster[\"jjinchin\"][\"chats\"]\n", 19 | "mongo_memory_collection = mongo_cluster[\"jjinchin\"][\"memory\"]\n", 20 | "embedding_model = \"text-embedding-ada-002\"\n", 21 | "\n", 22 | "date='20231202' # 이 일자의 벡터 DB, Mongo DB 삭제\n", 23 | "\n", 24 | "search_results = mongo_memory_collection.find({\"date\": date})\n", 25 | "#pinecone_index.delete(filter={\"date\":date})\n", 26 | "ids = [ str(v['_id']) for v in search_results]\n", 27 | "if len(ids) > 0:\n", 28 | " pinecone_index.delete(ids=ids)\n", 29 | " mongo_memory_collection.delete_many({\"date\":date})\n", 30 | " mongo_chats_collection.delete_many({\"date\":date})" 31 | ] 32 | } 33 | ], 34 | "metadata": { 35 | "kernelspec": { 36 | "display_name": "Python 3", 37 | "language": "python", 38 | "name": "python3" 39 | }, 40 | "language_info": { 41 | "codemirror_mode": { 42 | "name": "ipython", 43 | "version": 3 44 | }, 45 | "file_extension": ".py", 46 | "mimetype": "text/x-python", 47 | "name": "python", 48 | "nbconvert_exporter": "python", 49 | "pygments_lexer": "ipython3", 50 | "version": "3.10.10" 51 | } 52 | }, 53 | "nbformat": 4, 54 | "nbformat_minor": 2 55 | } 56 | -------------------------------------------------------------------------------- /contents/chapter06/chatbot.py: -------------------------------------------------------------------------------- 1 | from common import client, model 2 | from pprint import pprint 3 | 4 | class Chatbot: 5 | 6 | def __init__(self, model): 7 | self.context = [{"role": "system", "content": "You are a helpful assistant."}] 8 | self.model = model 9 | 10 | def add_user_message(self, message): 11 | self.context.append({"role": "user", "content": message}) 12 | 13 | def send_request(self): 14 | response = client.chat.completions.create( 15 | model=self.model, 16 | messages=self.context 17 | ).model_dump() 18 | return response 19 | 20 | def add_response(self, response): 21 | self.context.append({ 22 | "role" : response['choices'][0]['message']["role"], 23 | "content" : response['choices'][0]['message']["content"], 24 | } 25 | ) 26 | 27 | def get_response_content(self): 28 | return self.context[-1]['content'] 29 | 30 | 31 | if __name__ == "__main__": 32 | # step-3: 테스트 시나리오에 따라 실행 코드 작성 및 예상 출력결과 작성 33 | chatbot = Chatbot(model.basic) 34 | 35 | chatbot.add_user_message("Who won the world series in 2020?") 36 | 37 | # 시나리오1-4: 현재 context를 openai api 입력값으로 설정하여 전송 38 | response = chatbot.send_request() 39 | 40 | # 시나리오1-5: 응답 메시지를 context에 추가 41 | chatbot.add_response(response) 42 | 43 | # 시나리오1-7: 응답 메시지 출력 44 | print(chatbot.get_response_content()) 45 | 46 | # 시나리오2-2: 사용자가 채팅창에 "Where was it played?" 입력 47 | chatbot.add_user_message("Where was it played?") 48 | 49 | # 다시 요청 보내기 50 | response = chatbot.send_request() 51 | 52 | # 응답 메시지를 context에 추가 53 | chatbot.add_response(response) 54 | 55 | # 응답 메시지 출력 56 | print(chatbot.get_response_content()) 57 | pprint(chatbot.context) 58 | 59 | 60 | -------------------------------------------------------------------------------- /contents/chapter08/common.py: -------------------------------------------------------------------------------- 1 | import os 2 | from openai import OpenAI 3 | from dataclasses import dataclass 4 | import pytz 5 | from datetime import datetime, timedelta 6 | 7 | @dataclass(frozen=True) 8 | class Model: 9 | basic: str = "gpt-3.5-turbo-1106" 10 | advanced: str = "gpt-4-1106-preview" 11 | 12 | model = Model(); 13 | client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"), timeout=30, max_retries=1) 14 | 15 | def makeup_response(message, finish_reason="ERROR"): 16 | return { 17 | "choices": [ 18 | { 19 | "finish_reason": finish_reason, 20 | "index": 0, 21 | "message": { 22 | "role": "assistant", 23 | "content": message 24 | } 25 | } 26 | ], 27 | "usage": {"total_tokens": 0}, 28 | } 29 | 30 | 31 | def today(): 32 | korea = pytz.timezone('Asia/Seoul')# 한국 시간대를 얻습니다. 33 | now = datetime.now(korea)# 현재 시각을 얻습니다. 34 | return(now.strftime("%Y%m%d"))# 시각을 원하는 형식의 문자열로 변환합니다. 35 | 36 | def yesterday(): 37 | korea = pytz.timezone('Asia/Seoul')# 한국 시간대를 얻습니다. 38 | now = datetime.now(korea)# 현재 시각을 얻습니다. 39 | one_day = timedelta(days=1) # 하루 (1일)를 나타내는 timedelta 객체를 생성합니다. 40 | yesterday = now - one_day # 현재 날짜에서 하루를 빼서 어제의 날짜를 구합니다. 41 | return yesterday.strftime('%Y%m%d') # 어제의 날짜를 yyyymmdd 형식으로 변환합니다. 42 | 43 | def currTime(): 44 | # 한국 시간대를 얻습니다. 45 | korea = pytz.timezone('Asia/Seoul') 46 | # 현재 시각을 얻습니다. 47 | now = datetime.now(korea) 48 | # 시각을 원하는 형식의 문자열로 변환합니다. 49 | formatted_now = now.strftime("%Y.%m.%d %H:%M:%S") 50 | return(formatted_now) 51 | 52 | -------------------------------------------------------------------------------- /contents/chapter13/summarize_conversations.py: -------------------------------------------------------------------------------- 1 | from common import client, model 2 | import json 3 | from retry import retry 4 | 5 | system_role = """ 6 | 당신은 사용자의 메시지를 아래의 JSON 형식으로 대화 내용을 주제별로 요약하는 기계입니다. 7 | 1. 주제는 구체적이며 의미가 있는 것이어야 합니다. 8 | 2. 요약 내용에는 '민지는...', '고비는...'처럼 대화자의 이름이 들어가야 합니다. 9 | 3. 원문을 최대한 유지하며 요약해야 합니다. 10 | 4. 주제의 갯수는 무조건 5개를 넘지 말아야 하며 비슷한 내용은 하나로 묶어야 합니다. 11 | ``` 12 | { 13 | "data": 14 | [ 15 | {"주제":<주제>, "요약":<요약>}, 16 | {"주제":<주제>, "요약":<요약>}, 17 | ] 18 | } 19 | """ 20 | 21 | with open("대화원천내용.json", "r", encoding="utf-8") as f: 22 | conversations = json.load(f) 23 | 24 | summaries = [] 25 | 26 | @retry(tries=5, delay=2) 27 | def summarize(conversation): 28 | try: 29 | conversation_str = json.dumps(conversation, ensure_ascii=False) 30 | message = [ 31 | {"role": "system", "content": system_role}, 32 | {"role": "user", "content": conversation_str} 33 | ] 34 | response = client.chat.completions.create( 35 | model=model.basic, 36 | messages=message, 37 | temperature=0, 38 | response_format={"type": "json_object"} 39 | ).model_dump() 40 | content = response['choices'][0]['message']['content'] 41 | print(content) 42 | 43 | # JSON 로드 44 | summary = json.loads(content) 45 | summaries.append(summary["data"]) 46 | 47 | except Exception as e: 48 | print("예외 발생, 재시도합니다.") 49 | raise e 50 | 51 | for conversation in conversations: 52 | summarize(conversations) 53 | 54 | 55 | # conversations 리스트를 JSON 파일로 저장 56 | with open('대화내용요약.json', 'w', encoding='utf-8') as f: 57 | json.dump(summaries, f, ensure_ascii=False, indent=4) 58 | 59 | -------------------------------------------------------------------------------- /contents/chapter14/common.py: -------------------------------------------------------------------------------- 1 | import os 2 | from openai import OpenAI 3 | from dataclasses import dataclass 4 | import pytz 5 | from datetime import datetime, timedelta 6 | 7 | @dataclass(frozen=True) 8 | class Model: 9 | basic: str = "gpt-3.5-turbo-1106" 10 | advanced: str = "gpt-4-1106-preview" 11 | basic_old: str = "gpt-3.5-turbo" 12 | 13 | model = Model(); 14 | client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"), timeout=30, max_retries=1) 15 | 16 | def makeup_response(message, finish_reason="ERROR"): 17 | return { 18 | "choices": [ 19 | { 20 | "finish_reason": finish_reason, 21 | "index": 0, 22 | "message": { 23 | "role": "assistant", 24 | "content": message 25 | } 26 | } 27 | ], 28 | "usage": {"total_tokens": 0}, 29 | } 30 | 31 | def today(): 32 | korea = pytz.timezone('Asia/Seoul')# 한국 시간대를 얻습니다. 33 | now = datetime.now(korea)# 현재 시각을 얻습니다. 34 | return(now.strftime("%Y%m%d"))# 시각을 원하는 형식의 문자열로 변환합니다. 35 | 36 | def yesterday(): 37 | korea = pytz.timezone('Asia/Seoul')# 한국 시간대를 얻습니다. 38 | now = datetime.now(korea)# 현재 시각을 얻습니다. 39 | one_day = timedelta(days=1) # 하루 (1일)를 나타내는 timedelta 객체를 생성합니다. 40 | yesterday = now - one_day # 현재 날짜에서 하루를 빼서 어제의 날짜를 구합니다. 41 | return yesterday.strftime('%Y%m%d') # 어제의 날짜를 yyyymmdd 형식으로 변환합니다. 42 | 43 | def currTime(): 44 | # 한국 시간대를 얻습니다. 45 | korea = pytz.timezone('Asia/Seoul') 46 | # 현재 시각을 얻습니다. 47 | now = datetime.now(korea) 48 | # 시각을 원하는 형식의 문자열로 변환합니다. 49 | formatted_now = now.strftime("%Y.%m.%d %H:%M:%S") 50 | return(formatted_now) -------------------------------------------------------------------------------- /contents/chapter15/common.py: -------------------------------------------------------------------------------- 1 | import os 2 | from openai import OpenAI 3 | from dataclasses import dataclass 4 | import pytz 5 | from datetime import datetime, timedelta 6 | 7 | @dataclass(frozen=True) 8 | class Model: 9 | basic: str = "gpt-3.5-turbo-1106" 10 | advanced: str = "gpt-4-1106-preview" 11 | basic_old: str = "gpt-3.5-turbo" 12 | 13 | model = Model(); 14 | client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"), timeout=30, max_retries=1) 15 | 16 | def makeup_response(message, finish_reason="ERROR"): 17 | return { 18 | "choices": [ 19 | { 20 | "finish_reason": finish_reason, 21 | "index": 0, 22 | "message": { 23 | "role": "assistant", 24 | "content": message 25 | } 26 | } 27 | ], 28 | "usage": {"total_tokens": 0}, 29 | } 30 | 31 | def today(): 32 | korea = pytz.timezone('Asia/Seoul')# 한국 시간대를 얻습니다. 33 | now = datetime.now(korea)# 현재 시각을 얻습니다. 34 | return(now.strftime("%Y%m%d"))# 시각을 원하는 형식의 문자열로 변환합니다. 35 | 36 | def yesterday(): 37 | korea = pytz.timezone('Asia/Seoul')# 한국 시간대를 얻습니다. 38 | now = datetime.now(korea)# 현재 시각을 얻습니다. 39 | one_day = timedelta(days=1) # 하루 (1일)를 나타내는 timedelta 객체를 생성합니다. 40 | yesterday = now - one_day # 현재 날짜에서 하루를 빼서 어제의 날짜를 구합니다. 41 | return yesterday.strftime('%Y%m%d') # 어제의 날짜를 yyyymmdd 형식으로 변환합니다. 42 | 43 | def currTime(): 44 | # 한국 시간대를 얻습니다. 45 | korea = pytz.timezone('Asia/Seoul') 46 | # 현재 시각을 얻습니다. 47 | now = datetime.now(korea) 48 | # 시각을 원하는 형식의 문자열로 변환합니다. 49 | formatted_now = now.strftime("%Y.%m.%d %H:%M:%S") 50 | return(formatted_now) -------------------------------------------------------------------------------- /contents/chapter16/common.py: -------------------------------------------------------------------------------- 1 | import os 2 | from openai import OpenAI 3 | from dataclasses import dataclass 4 | import pytz 5 | from datetime import datetime, timedelta 6 | 7 | @dataclass(frozen=True) 8 | class Model: 9 | basic: str = "gpt-3.5-turbo-1106" 10 | advanced: str = "gpt-4-1106-preview" 11 | basic_old: str = "gpt-3.5-turbo" 12 | 13 | model = Model(); 14 | client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"), timeout=30, max_retries=1) 15 | 16 | def makeup_response(message, finish_reason="ERROR"): 17 | return { 18 | "choices": [ 19 | { 20 | "finish_reason": finish_reason, 21 | "index": 0, 22 | "message": { 23 | "role": "assistant", 24 | "content": message 25 | } 26 | } 27 | ], 28 | "usage": {"total_tokens": 0}, 29 | } 30 | 31 | def today(): 32 | korea = pytz.timezone('Asia/Seoul')# 한국 시간대를 얻습니다. 33 | now = datetime.now(korea)# 현재 시각을 얻습니다. 34 | return(now.strftime("%Y%m%d"))# 시각을 원하는 형식의 문자열로 변환합니다. 35 | 36 | def yesterday(): 37 | korea = pytz.timezone('Asia/Seoul')# 한국 시간대를 얻습니다. 38 | now = datetime.now(korea)# 현재 시각을 얻습니다. 39 | one_day = timedelta(days=1) # 하루 (1일)를 나타내는 timedelta 객체를 생성합니다. 40 | yesterday = now - one_day # 현재 날짜에서 하루를 빼서 어제의 날짜를 구합니다. 41 | return yesterday.strftime('%Y%m%d') # 어제의 날짜를 yyyymmdd 형식으로 변환합니다. 42 | 43 | def currTime(): 44 | # 한국 시간대를 얻습니다. 45 | korea = pytz.timezone('Asia/Seoul') 46 | # 현재 시각을 얻습니다. 47 | now = datetime.now(korea) 48 | # 시각을 원하는 형식의 문자열로 변환합니다. 49 | formatted_now = now.strftime("%Y.%m.%d %H:%M:%S") 50 | return(formatted_now) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ``` 2 | ┌───────────────────────────────────────────────┐ 3 | _ 4 | __ _ ___ ___ _ __ _ __ ___ (_) ___ 5 | / _` |/ _ \ / _ \| '__| '_ ` _ \ | |/ _ \ 6 | | (_| | (_) | (_) | | | | | | | |_| | (_) | 7 | \__, |\___/ \___/|_| |_| |_| |_(_)_|\___/ 8 | |___/ 9 | 🌩 𝘼𝙣𝙮𝙤𝙣𝙚 𝙘𝙖𝙣 𝙙𝙚𝙫𝙚𝙡𝙤𝙥! 10 | └───────────────────────────────────────────────┘ 11 | ``` 12 | 13 | # goormIDE 14 | Welcome to goormIDE! 15 | 16 | goormIDE is a powerful cloud IDE service to maximize productivity for developers and teams. 17 | **DEVELOP WITH EXCELLENCE** 18 | 19 | `Happy coding! The goormIDE team` 20 | 21 | 22 | ## 🔧 Tip & Guide 23 | 24 | * Command feature 25 | * You can simply run your script using the shortcut icons on the top right. 26 | * Check out `PROJECT > Common/Build/Run/Test/Find Command` in the top menu. 27 | 28 | * Get URL and Port 29 | * Click `PROJECT > URL/PORT` in top menu bar. 30 | * You can get default URL/Port and add URL/Port in the top menu. 31 | 32 | * Useful shortcut 33 | 34 | | Shortcuts name | Command (Mac) | Command (Window) | 35 | | ------------------ | :-----------: | :--------------: | 36 | | Copy in Terminal | ⌘ + C | Ctrl + Shift + C | 37 | | Paste in Terminal | ⌘ + V | Ctrl + Shift + V | 38 | | Search File | ⌥ + ⇧ + F | Alt + Shift + F | 39 | | Terminal Toggle | ⌥ + ⇧ + B | Alt + Shift + B | 40 | | New Terminal | ⌥ + ⇧ + T | Alt + Shift + T | 41 | | Code Formatting | ⌥ + ⇧ + P | Alt + Shift + P | 42 | | Show All Shortcuts | ⌘ + H | Ctrl + H | 43 | 44 | ## 💬 Support & Documentation 45 | 46 | Visit [https://ide.goorm.io](https://ide.goorm.io) to support and learn more about using goormIDE. 47 | To watch some usage guides, visit [https://help.goorm.io/en/goormide](https://help.goorm.io/en/goormide) 48 | -------------------------------------------------------------------------------- /contents/chapter09/application.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, request 2 | import sys 3 | from common import model 4 | from chatbot import Chatbot 5 | from characters import system_role, instruction 6 | from function_calling import FunctionCalling, func_specs # 단일 함수 호출 7 | #from parallel_function_calling import FunctionCalling, tools # 병렬적 함수 호출 8 | 9 | # jjinchin 인스턴스 생성 10 | jjinchin = Chatbot( 11 | model = model.basic, 12 | system_role = system_role, 13 | instruction = instruction 14 | ) 15 | 16 | application = Flask(__name__) 17 | 18 | func_calling = FunctionCalling(model=model.basic) 19 | 20 | @application.route("/") 21 | def hello(): 22 | return "Hello goorm!" 23 | 24 | @application.route("/welcome") 25 | def welcome(): # 함수명은 꼭 welcome일 필요는 없습니다. 26 | return "Hello goorm!" 27 | 28 | @application.route("/chat-app") 29 | def chat_app(): 30 | return render_template("chat.html") 31 | 32 | @application.route('/chat-api', methods=['POST']) 33 | def chat_api(): 34 | request_message = request.json['request_message'] 35 | print("request_message:", request_message) 36 | jjinchin.add_user_message(request_message) 37 | 38 | # 챗GPT에게 함수사양을 토대로 사용자 메시지에 호응하는 함수 정보를 분석해달라고 요청 39 | analyzed_dict = func_calling.analyze(request_message, func_specs) # 단일 함수 호출 40 | #analyzed, analyzed_dict = func_calling.analyze(request_message, tools) # 병렬적 함수 호춝 41 | # 챗GPT가 함수 호출이 필요하다고 분석했는지 여부 체크 42 | if analyzed_dict.get("function_call"): # 단일 함수 호출 43 | #if analyzed_dict.get("tool_calls"): # 병렬적 함수 호출 44 | # 챗GPT가 분석해준 대로 함수 호출 45 | response = func_calling.run( analyzed_dict, jjinchin.context[:]) # 단일 함수 호출 46 | #response = func_calling.run(analyzed, analyzed_dict, jjinchin.context[:]) # 병렬적 함수 호출 47 | jjinchin.add_response(response) 48 | else: 49 | response = jjinchin.send_request() 50 | jjinchin.add_response(response) 51 | 52 | response_message = jjinchin.get_response_content() 53 | jjinchin.handle_token_limit(response) 54 | jjinchin.clean_context() 55 | print("response_message:", response_message) 56 | return {"response_message": response_message} 57 | 58 | 59 | if __name__ == "__main__": 60 | application.config['TEMPLATES_AUTO_RELOAD'] = True 61 | application.jinja_env.auto_reload = True 62 | application.run(host="0.0.0.0", port=int(sys.argv[1])) 63 | -------------------------------------------------------------------------------- /contents/chapter14/assistants.py: -------------------------------------------------------------------------------- 1 | from common import client, model 2 | from characters import system_role 3 | from pprint import pprint 4 | import time 5 | 6 | assistant = client.beta.assistants.create( 7 | name="내 찐친 고비", 8 | instructions=system_role, 9 | model=model.basic, 10 | ) 11 | 12 | pprint(assistant.model_dump()) 13 | 14 | ############################################## 15 | 16 | #assistant = client.beta.assistants.retrieve(assistant_id = 'asst_5mvewDLvPyerdDBqr8OTq2co') 17 | assistant = client.beta.assistants.retrieve(assistant_id = assistant.id) 18 | 19 | ############################################## 20 | 21 | thread = client.beta.threads.create() 22 | pprint(thread.model_dump()) 23 | 24 | #thread = client.beta.threads.retrieve(thread_id ='thread_PBQgV0UINj2UKyxSSBJ4k012') 25 | thread = client.beta.threads.retrieve(thread_id = thread.id) 26 | 27 | user_message = client.beta.threads.messages.create( 28 | thread_id=thread.id, 29 | role="user", 30 | content="고비야 반가워! 잘 지냈지?" 31 | ) 32 | pprint(user_message.model_dump()) 33 | 34 | 35 | thread_messages = [m for m in list(client.beta.threads.messages.list(thread_id=thread.id))] 36 | print([user_message] == thread_messages) 37 | 38 | 39 | run = client.beta.threads.runs.create( 40 | thread_id=thread.id, 41 | assistant_id=assistant.id, 42 | ) 43 | run_dict = run.model_dump() 44 | keys_to_print = ['id', 'completed_at', 'required_action', 'status'] 45 | selected_run_dict = {key: run_dict[key] for key in keys_to_print} 46 | pprint(selected_run_dict) 47 | 48 | start_time = time.time() 49 | 50 | while(True): 51 | elapsed_time = time.time() - start_time 52 | retrieved_run = client.beta.threads.runs.retrieve( 53 | thread_id=thread.id, 54 | run_id=run.id 55 | ) 56 | print(f"run status: {retrieved_run.status}, 경과:{elapsed_time: .2f}초") 57 | if retrieved_run.status == "completed": 58 | break 59 | elif retrieved_run.status in ["failed", "cancelled", "expired"]: 60 | raise ValueError(f"run status: {retrieved_run.status}, {retrieved_run.last_error}") 61 | time.sleep(1) 62 | 63 | thread_messages = [{"role": m.role, "content": m.content[0].text.value} 64 | for m in list(client.beta.threads.messages.list(thread_id=thread.id))] 65 | thread_messages.reverse() 66 | pprint(thread_messages) 67 | -------------------------------------------------------------------------------- /contents/chapter05/sc.py: -------------------------------------------------------------------------------- 1 | import openai 2 | import os 3 | from collections import defaultdict 4 | import re 5 | 6 | client = openai.OpenAI(api_key=os.getenv("OPENAI_API_KEY")) 7 | 8 | template = """ 9 | 질문1: 10 | 공항 A에서 4대의 다른 무게의 헬리콥터를 모두 공항 B로 옮겨야 합니다. 헬리콥터의 무게는 1톤, 3톤, 6톤, 9톤이며, 이 헬리콥터가 공항 A에서 공항 B까지 이동하는 데 걸리는 시간은 각각 2시간, 3시간, 5시간, 10시간입니다. 모든 헬리콥터는 그보다 가벼운 헬리콥터를 딱 한 대만 실을 수 있습니다. 이 경우 이동하는 데 걸리는 시간은 둘 중 무거운 헬리콥터의 이동시간과 같습니다. 가장 빠르게 옮기면 몇시간이 걸릴까요? 11 | 답변: 12 | 3톤 헬리콥터에 1톤 헬리콥터를 싣고 공항 B로 이동합니다. 이동에는 3시간이 걸립니다. 13 | 3톤 헬리콥터가 공항 A로 돌아옵니다. 다시 3시간이 걸립니다. (지금까지 6시간) 14 | 9톤 헬리콥터에 6톤 헬리콥터를 싣고 공항 B로 이동합니다. 이동에는 10시간이 걸립니다. (지금까지 16시간) 15 | 공항 A에 있는 1톤 헬리콥터를 타고 공항 B로 돌아옵니다. 2시간이 걸립니다. (지금까지 18시간) 16 | 마지막으로, 3톤 헬리콥터에 1톤 헬리콥터를 싣고 공항 B로 이동합니다. 이동에는 3시간이 걸립니다. (지금까지 21시간) 17 | 정답: 21시간 18 | ``` 19 | 질문2: 20 | 닭, 쌀, 과일을 마을로 옮겨야 합니다. 닭은 1시간, 쌀은 2시간, 과일은 4시간이 소요됩니다. 농장에서 마을까지 이동하는 데는 최대 9시간이 걸릴 수 있습니다. 닭은 쌀과 과일을 먹을 수 있으므로 닭과 쌀 또는 과일을 동시에 옮길 수 없습니다. 어떻게 해야 마을로 모든 물건을 옮길 수 있을까요? 21 | 답변: 22 | 닭을 먼저 마을로 보냅니다. 이동 1시간, 총합 1시간. 23 | 농장으로 돌아옵니다. 이동 1시간, 총합 2시간. 24 | 과일을 마을로 보냅니다. 이동 4시간, 총합 6시간. 25 | 닭을 다시 농장으로 데려옵니다. 이동 1시간, 총합 7시간. 26 | 쌀을 마을로 보냅니다. 이동 2시간, 총합 9시간. 27 | 정답: 9시간 28 | ``` 29 | 질문3: 30 | 4명의 탐험가가 동굴을 탐험하려고 합니다. 각 탐험가는 동굴을 지나가는 데 다음과 같은 시간이 걸립니다: 1분, 2분, 5분, 10분. 한 번에 최대 두 명만 동굴을 지날 수 있으며, 그들은 횃불을 가지고 가야 합니다. 횃불은 하나뿐이며, 탐험가가 동굴을 지나갈 때마다 횃불을 가져가야 합니다. 모든 탐험가가 동굴을 지나가려면 어떻게 해야 가장 빠르게 지나갈 수 있을까요? 마지막에 소요시간을 '정답:<정답>' 형식으로 작성하세요. 31 | 답변: 32 | """ 33 | def get_most_frequent_answer(template, iterations=10): 34 | answers = defaultdict(int)#존재하지 않는 키로 접근하면 0을 반환하도록 하는 함수 35 | 36 | for idx in range(iterations): 37 | context = [{"role": "user", "content": template}] 38 | response = client.chat.completions.create( 39 | model="gpt-3.5-turbo-0613", 40 | messages=context, 41 | temperature=0.3 42 | ).model_dump() 43 | response_content = response['choices'][0]['message']['content'] 44 | print(f"\n{idx+1}번째 샘플:") 45 | print(response_content) 46 | # 답변에서 "정답: XX분" 형태로 시간을 추출 47 | match = re.search(r"정답: (\d+분)", response_content) 48 | if match: 49 | parsed_answer = match.group(1) 50 | answers[parsed_answer] += 1 51 | 52 | # 가장 빈도가 높은 답변을 선택 53 | sorted_answers = sorted(answers.items(), key=lambda x: x[1], reverse=True) 54 | print(f"\n빈도표: {sorted_answers}") 55 | most_frequent_answer = sorted_answers[0][0] 56 | return most_frequent_answer 57 | 58 | most_frequent_answer = get_most_frequent_answer(template) 59 | print("최빈값:", most_frequent_answer) -------------------------------------------------------------------------------- /contents/chapter18/application.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, request, Response, url_for 2 | import sys 3 | from common import model 4 | from chatbot import Chatbot 5 | from characters import system_role, instruction 6 | import multimodal 7 | 8 | # jjinchin 인스턴스 생성 9 | jjinchin = Chatbot( 10 | model = model.basic, 11 | system_role = system_role, 12 | instruction = instruction 13 | ) 14 | 15 | application = Flask(__name__) 16 | 17 | @application.route("/") 18 | def hello(): 19 | return "Hello goorm!" 20 | 21 | @application.route("/welcome") 22 | def welcome(): # 함수명은 꼭 welcome일 필요는 없습니다. 23 | return "Hello goorm!" 24 | 25 | @application.route("/chat-app") 26 | def chat_app(): 27 | return render_template("chat.html") 28 | 29 | @application.route('/audio') 30 | def audio_route(): 31 | user_message = request.args.get('message', '') 32 | # TTS 요청 33 | speech = multimodal.generate_speech(user_message) 34 | return Response(speech, mimetype='audio/mpeg') 35 | 36 | @application.route('/chat-api', methods=['POST']) 37 | def chat_api(): 38 | request_message = request.form.get("message") 39 | print("request_message:", request_message) 40 | jjinchin.add_user_message(request_message) 41 | 42 | response_image = None 43 | image_file = request.files.get('image') 44 | if image_file is not None: 45 | response = multimodal.ask_image(image_file, jjinchin) 46 | elif multimodal.is_drawing_request(request_message): 47 | encoded_image, response = multimodal.create_image(jjinchin) 48 | if encoded_image: 49 | response_image = f"data:image/png;base64,{encoded_image}" 50 | else: 51 | response = jjinchin.send_request() 52 | 53 | jjinchin.add_response(response) 54 | response_message = jjinchin.get_response_content() 55 | 56 | jjinchin.handle_token_limit(response) 57 | jjinchin.clean_context() 58 | 59 | response_audio = None 60 | if response_image is not None: 61 | response_audio = url_for('audio_route', message=response_message, _external=True) 62 | response_message = "" 63 | 64 | print("response_message:", response_message) 65 | return {"response_message": response_message, "image": response_image, "audio": response_audio} 66 | 67 | 68 | if __name__ == "__main__": 69 | application.config['TEMPLATES_AUTO_RELOAD'] = True 70 | application.jinja_env.auto_reload = True 71 | application.run(host="0.0.0.0", port=int(sys.argv[1])) 72 | -------------------------------------------------------------------------------- /contents/chapter09/chatbot.py: -------------------------------------------------------------------------------- 1 | from common import client, makeup_response 2 | import math 3 | 4 | class Chatbot: 5 | 6 | def __init__(self, model, system_role, instruction): 7 | self.context = [{"role": "system", "content": system_role}] 8 | self.model = model 9 | self.instruction = instruction 10 | self.max_token_size = 16 * 1024 11 | self.available_token_rate = 0.9 12 | 13 | def add_user_message(self, user_message): 14 | self.context.append({"role": "user", "content": user_message}) 15 | 16 | def _send_request(self): 17 | try: 18 | response = client.chat.completions.create( 19 | model=self.model, 20 | messages=self.context, 21 | temperature=0.5, 22 | top_p=1, 23 | max_tokens=256, 24 | frequency_penalty=0, 25 | presence_penalty=0 26 | ).model_dump() 27 | except Exception as e: 28 | print(f"Exception 오류({type(e)}) 발생:{e}") 29 | if 'maximum context length' in str(e): 30 | self.context.pop() 31 | return makeup_response("메시지 조금 짧게 보내줄래?") 32 | else: 33 | return makeup_response("[내 찐친 챗봇에 문제가 발생했습니다. 잠시 뒤 이용해주세요]") 34 | 35 | return response 36 | 37 | def send_request(self): 38 | self.context[-1]['content'] += self.instruction 39 | return self._send_request() 40 | 41 | def add_response(self, response): 42 | self.context.append({ 43 | "role" : response['choices'][0]['message']["role"], 44 | "content" : response['choices'][0]['message']["content"], 45 | } 46 | ) 47 | 48 | def get_response_content(self): 49 | return self.context[-1]['content'] 50 | 51 | def clean_context(self): 52 | for idx in reversed(range(len(self.context))): 53 | if self.context[idx]["role"] == "user": 54 | self.context[idx]["content"] = self.context[idx]["content"].split("instruction:\n")[0].strip() 55 | break 56 | 57 | def handle_token_limit(self, response): 58 | # 누적 토큰 수가 임계점을 넘지 않도록 제어한다. 59 | try: 60 | current_usage_rate = response['usage']['total_tokens'] / self.max_token_size 61 | exceeded_token_rate = current_usage_rate - self.available_token_rate 62 | if exceeded_token_rate > 0: 63 | remove_size = math.ceil(len(self.context) / 10) 64 | self.context = [self.context[0]] + self.context[remove_size+1:] 65 | except Exception as e: 66 | print(f"handle_token_limit exception:{e}") 67 | 68 | -------------------------------------------------------------------------------- /contents/chapter08/chatbot.py: -------------------------------------------------------------------------------- 1 | from common import client, makeup_response 2 | import math 3 | 4 | class Chatbot: 5 | 6 | def __init__(self, model, system_role, instruction): 7 | self.context = [{"role": "system", "content": system_role}] 8 | self.model = model 9 | self.instruction = instruction 10 | self.max_token_size = 16 * 1024 11 | self.available_token_rate = 0.9 12 | 13 | def add_user_message(self, user_message): 14 | self.context.append({"role": "user", "content": user_message}) 15 | 16 | def _send_request(self): 17 | try: 18 | response = client.chat.completions.create( 19 | model=self.model, 20 | messages=self.context, 21 | temperature=0.5, 22 | top_p=1, 23 | max_tokens=256, 24 | frequency_penalty=0, 25 | presence_penalty=0 26 | ).model_dump() 27 | except Exception as e: 28 | print(f"Exception 오류({type(e)}) 발생:{e}") 29 | if 'maximum context length' in str(e): 30 | self.context.pop() 31 | return makeup_response("메시지 조금 짧게 보내줄래?") 32 | else: 33 | return makeup_response("[내 찐친 챗봇에 문제가 발생했습니다. 잠시 뒤 이용해주세요]") 34 | 35 | return response 36 | 37 | def send_request(self): 38 | self.context[-1]['content'] += self.instruction 39 | return self._send_request() 40 | 41 | def add_response(self, response): 42 | self.context.append({ 43 | "role" : response['choices'][0]['message']["role"], 44 | "content" : response['choices'][0]['message']["content"], 45 | } 46 | ) 47 | 48 | def get_response_content(self): 49 | return self.context[-1]['content'] 50 | 51 | def clean_context(self): 52 | for idx in reversed(range(len(self.context))): 53 | if self.context[idx]["role"] == "user": 54 | self.context[idx]["content"] = self.context[idx]["content"].split("instruction:\n")[0].strip() 55 | break 56 | 57 | def handle_token_limit(self, response): 58 | # 누적 토큰 수가 임계점을 넘지 않도록 제어한다. 59 | try: 60 | current_usage_rate = response['usage']['total_tokens'] / self.max_token_size 61 | exceeded_token_rate = current_usage_rate - self.available_token_rate 62 | if exceeded_token_rate > 0: 63 | remove_size = math.ceil(len(self.context) / 10) 64 | self.context = [self.context[0]] + self.context[remove_size+1:] 65 | except Exception as e: 66 | print(f"handle_token_limit exception:{e}") 67 | 68 | 69 | -------------------------------------------------------------------------------- /contents/chapter18/chatbot.py: -------------------------------------------------------------------------------- 1 | from common import client, makeup_response 2 | import math 3 | 4 | class Chatbot: 5 | 6 | def __init__(self, model, system_role, instruction): 7 | self.context = [{"role": "system", "content": system_role}] 8 | self.model = model 9 | self.instruction = instruction 10 | self.max_token_size = 16 * 1024 11 | self.available_token_rate = 0.9 12 | 13 | def add_user_message(self, user_message): 14 | self.context.append({"role": "user", "content": user_message}) 15 | 16 | def _send_request(self): 17 | try: 18 | response = client.chat.completions.create( 19 | model=self.model, 20 | messages=self.context, 21 | temperature=0.5, 22 | top_p=1, 23 | max_tokens=256, 24 | frequency_penalty=0, 25 | presence_penalty=0 26 | ).model_dump() 27 | except Exception as e: 28 | print(f"Exception 오류({type(e)}) 발생:{e}") 29 | if 'maximum context length' in str(e): 30 | self.context.pop() 31 | return makeup_response("메시지 조금 짧게 보내줄래?") 32 | else: 33 | return makeup_response("[내 찐친 챗봇에 문제가 발생했습니다. 잠시 뒤 이용해주세요]") 34 | 35 | return response 36 | 37 | def send_request(self): 38 | self.context[-1]['content'] += self.instruction 39 | return self._send_request() 40 | 41 | def add_response(self, response): 42 | self.context.append({ 43 | "role" : response['choices'][0]['message']["role"], 44 | "content" : response['choices'][0]['message']["content"], 45 | } 46 | ) 47 | 48 | def get_response_content(self): 49 | return self.context[-1]['content'] 50 | 51 | def clean_context(self): 52 | for idx in reversed(range(len(self.context))): 53 | if self.context[idx]["role"] == "user": 54 | self.context[idx]["content"] = self.context[idx]["content"].split("instruction:\n")[0].strip() 55 | break 56 | 57 | def handle_token_limit(self, response): 58 | # 누적 토큰 수가 임계점을 넘지 않도록 제어한다. 59 | try: 60 | current_usage_rate = response['usage']['total_tokens'] / self.max_token_size 61 | exceeded_token_rate = current_usage_rate - self.available_token_rate 62 | if exceeded_token_rate > 0: 63 | remove_size = math.ceil(len(self.context) / 10) 64 | self.context = [self.context[0]] + self.context[remove_size+1:] 65 | except Exception as e: 66 | print(f"handle_token_limit exception:{e}") 67 | 68 | -------------------------------------------------------------------------------- /contents/chapter17_1/chatbot.py: -------------------------------------------------------------------------------- 1 | from common import client, makeup_response 2 | import math 3 | import time 4 | 5 | class Chatbot: 6 | 7 | def __init__(self, model, system_role, instruction): 8 | self.context = [{"role": "system", "content": system_role}] 9 | self.model = model 10 | self.instruction = instruction 11 | self.max_token_size = 16 * 1024 12 | self.available_token_rate = 0.9 13 | 14 | def add_user_message(self, user_message): 15 | self.context.append({"role": "user", "content": user_message}) 16 | 17 | def _send_request(self): 18 | try: 19 | response = client.chat.completions.create( 20 | model=self.model, 21 | messages=self.context, 22 | temperature=0.5, 23 | top_p=1, 24 | max_tokens=1024, 25 | frequency_penalty=0, 26 | presence_penalty=0 27 | ).model_dump() 28 | except Exception as e: 29 | print(f"Exception 오류({type(e)}) 발생:{e}") 30 | if 'maximum context length' in str(e): 31 | self.context.pop() 32 | return makeup_response("메시지 조금 짧게 보내줄래?") 33 | else: 34 | return makeup_response("[내 찐친 챗봇에 문제가 발생했습니다. 잠시 뒤 이용해주세요]") 35 | 36 | return response 37 | 38 | def send_request(self): 39 | self.context[-1]['content'] += self.instruction 40 | return self._send_request() 41 | 42 | def add_response(self, response): 43 | self.context.append({ 44 | "role" : response['choices'][0]['message']["role"], 45 | "content" : response['choices'][0]['message']["content"], 46 | } 47 | ) 48 | 49 | def get_response_content(self): 50 | return self.context[-1]['content'] 51 | 52 | def clean_context(self): 53 | for idx in reversed(range(len(self.context))): 54 | if self.context[idx]["role"] == "user": 55 | self.context[idx]["content"] = self.context[idx]["content"].split("instruction:\n")[0].strip() 56 | break 57 | 58 | def handle_token_limit(self, response): 59 | # 누적 토큰 수가 임계점을 넘지 않도록 제어한다. 60 | try: 61 | current_usage_rate = response['usage']['total_tokens'] / self.max_token_size 62 | exceeded_token_rate = current_usage_rate - self.available_token_rate 63 | if exceeded_token_rate > 0: 64 | remove_size = math.ceil(len(self.context) / 10) 65 | self.context = [self.context[0]] + self.context[remove_size+1:] 66 | except Exception as e: 67 | print(f"handle_token_limit exception:{e}") 68 | 69 | -------------------------------------------------------------------------------- /contents/chapter18/multimodal.py: -------------------------------------------------------------------------------- 1 | from common import model, client 2 | import base64 3 | import requests 4 | import json 5 | 6 | def ask_image(image_file, jjinchin): 7 | user_message = jjinchin.context[-1]['content'] + jjinchin.instruction 8 | prompt = f"절친이 이 이미지에 대해 다음과 같이 말하고 있습니다.:\n{user_message}" 9 | encoded_image = base64.b64encode(image_file.read()).decode('utf-8') 10 | return ask_gpt_vision(prompt, encoded_image) 11 | 12 | def ask_gpt_vision(prompt, encoded_image): 13 | context = [{ 14 | "role": "user", 15 | "content": [ 16 | {"type": "text", 17 | "text": prompt}, 18 | {"type": "image_url","image_url": {"url": f"data:image/jpeg;base64,{encoded_image}"}} 19 | ]} 20 | ] 21 | response = client.chat.completions.create( 22 | model="gpt-4-vision-preview", 23 | messages=context, 24 | max_tokens=300, 25 | ) 26 | return response.model_dump() 27 | 28 | def is_drawing_request(user_message): 29 | message = f"다음의 JSON 타입으로 답할 것:\n {{'[{user_message}]이라는 메시지가 그림을 그려 달라는 요청인가?': }}" 30 | try: 31 | response = client.chat.completions.create( 32 | model = model.basic, 33 | messages = [ 34 | {"role": "user", "content": message} 35 | ], 36 | temperature = 0, 37 | response_format={ "type": "json_object" } 38 | ).model_dump() 39 | print(json.loads(response['choices'][0]['message']['content'])) 40 | return next(iter(json.loads(response['choices'][0]['message']['content']).values())) 41 | except Exception as e: 42 | print(f"Exception 오류({type(e)}) 발생:{e}") 43 | return False 44 | 45 | def create_image(jjinchin): 46 | user_message = jjinchin.context[-1]['content'] + "단, 배경색은 하얀색으로 할 것" 47 | url_response = client.images.generate( 48 | model = "dall-e-3", 49 | prompt = user_message, 50 | size="1792x1024", 51 | quality = "standard", 52 | n=1, 53 | ) 54 | # 이미지를 요청하고 응답을 받습니다. 55 | image_response = requests.get(url_response.data[0].url) 56 | # 요청이 성공했는지 확인합니다. (200 OK) 57 | if image_response.status_code == 200: 58 | prompt = f"{user_message}=> 당신은 민지에게 다음 그림을 그려 주었습니다. 왜 이런 그림을 그렸는지 설명하세요.:\n{jjinchin.instruction}" 59 | encoded_image = base64.b64encode(image_response.content).decode('utf-8') 60 | response = ask_gpt_vision(prompt, encoded_image) 61 | return encoded_image, response 62 | else: 63 | return None, "지금은 그림을 그리기가 좀 힘드네. 다음에 그려줄게 미안해!" 64 | 65 | def generate_speech(user_message): 66 | try: 67 | response = client.audio.speech.create( 68 | model="tts-1", 69 | voice="nova", #alloy, echo, fable, onyx, nova, shimmer 중 택1 70 | input=user_message, 71 | ) 72 | return response.content 73 | except Exception as e: 74 | print(f"Exception 오류({type(e)}) 발생:{e}") 75 | return "" 76 | 77 | -------------------------------------------------------------------------------- /contents/chapter05/tot.py: -------------------------------------------------------------------------------- 1 | import openai 2 | import os 3 | import json 4 | 5 | client = openai.OpenAI(api_key=os.getenv("OPENAI_API_KEY")) 6 | 7 | # 프롬프트 ################################################################ 8 | 9 | agenda = """ 10 | '인공지능이 인간의 일자리를 위협합니다. 이에 대한 대응 방안을 논의합니다.' 11 | """ 12 | 13 | sampling_tempalte = """ 14 | {agenda}에 대해 논의 중입니다. 15 | ``` 16 | [이전 의견]: 17 | {selected} 18 | ``` 19 | [이전 의견]에 대한 구체적이며 실질적인 구현 방안을 아래 JSON 형식으로 답하세요. 20 | {{ 21 | "주제": <주제> 22 | "구현": <50단어 이내로 작성하세요>, 23 | "근거": <[이전 의견]의 어떤 대목에서 그렇게 생각했는지> 24 | }} 25 | """ 26 | 27 | evaluation_template = """ 28 | {agenda}에 대해 논의하고 있습니다. 29 | ``` 30 | [의견]: 31 | {thought} 32 | ``` 33 | 위의 [의견]을 아래 JSON 형식으로 평가하세요. 34 | {{ 35 | "창의적이고 혁신적인 방법인가": <15점 만점 기준 점수>, 36 | "단기간 내에 실현 가능한 방법인지": <10점 만점 기준 점수>, 37 | "총점": <총점> 38 | }} 39 | """ 40 | 41 | # 프롬프트 실행 ################################################################ 42 | def request_gpt(message, model, temperature, type="json_object"): 43 | message = [{"role": "user", "content": message}] 44 | response = client.chat.completions.create( 45 | model=model, 46 | messages=message, 47 | temperature=temperature, 48 | response_format = {"type" : type} 49 | ).model_dump() 50 | if type == "json_object": 51 | response_content = json.loads(response['choices'][0]['message']['content']) 52 | else: 53 | response_content = response['choices'][0]['message']['content'] 54 | return response_content 55 | 56 | def generate_thoughts(selected): 57 | selected = "없음" if len(selected) == 0 else selected 58 | samples = [] 59 | message = sampling_tempalte.format(agenda=agenda, selected=selected) 60 | for _ in range(5): 61 | # 필요하면 GPT-4로 대체해 볼 것 62 | sample = request_gpt(message, "gpt-3.5-turbo-1106", temperature=1.2) 63 | samples.append(sample['구현']) 64 | #print("generate_thoughts:", sample['구현']) 65 | return samples 66 | 67 | def evaluate(thoughts): 68 | values = [] 69 | for thought in thoughts: 70 | message = evaluation_template.format(agenda=agenda, thought=thought) 71 | value = request_gpt(message, "gpt-4-1106-preview", temperature=0) 72 | values.append({ 73 | "thought": thought, 74 | "value": value 75 | }) 76 | return values 77 | 78 | def get_top_n(values, n): 79 | return sorted(values, key=lambda x: x["value"]["총점"], reverse=True)[:n] 80 | 81 | selected_list = [] 82 | selected = "" 83 | for step in range(3): 84 | thoughts = generate_thoughts(selected) 85 | values = evaluate(thoughts) 86 | selected = get_top_n(values, 1)[0]['thought'] 87 | selected_list.append(selected) 88 | print(f"{step + 1}단계: {selected}") 89 | 90 | print("\n".join(selected_list)) 91 | 92 | 93 | # 보고서 작성 ################################################################ 94 | summary = f"{agenda} 다음 내용을 근거로 짧은 보고서를 작성하세요:"+str(selected_list) 95 | report = request_gpt(summary, "gpt-4", temperature=0, type="text") 96 | print(report) 97 | -------------------------------------------------------------------------------- /contents/chapter17_2/application.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, request 2 | import sys 3 | from common import model, currTime 4 | from finance_chatbot import Chatbot 5 | from concurrent.futures import ThreadPoolExecutor 6 | import requests 7 | import concurrent 8 | 9 | jjinchin = Chatbot( 10 | assistant_id="asst_g477uFP13KkbZtpAvb8MgxC9", 11 | thread_id="thread_EiIW93i29UouuzggaQfFNGvX" 12 | ) 13 | 14 | application = Flask(__name__) 15 | 16 | @application.route("/") 17 | def hello(): 18 | return "Hello goorm!" 19 | 20 | def format_response(resp, useCallback=False): 21 | data = { 22 | "version": "2.0", 23 | "useCallback": useCallback, 24 | "template": { 25 | "outputs": [ 26 | { 27 | "simpleText": { 28 | "text": resp 29 | } 30 | } 31 | ] 32 | } 33 | } 34 | return data 35 | 36 | executor = ThreadPoolExecutor(max_workers=1) 37 | 38 | def async_send_request(chat_gpt, callbackUrl, future): 39 | # future가 완료될 때까지 대기. 이후는 개선 전 코드와 동일 40 | _, response_message_from_openai = future.result() 41 | print("response_message_from_openai:", response_message_from_openai) 42 | response_to_kakao = format_response(response_message_from_openai, useCallback=False) 43 | callbackResponse = requests.post(callbackUrl, json=response_to_kakao) 44 | print("CallbackResponse:", callbackResponse.text) 45 | print(f"{'-'*50}\n{currTime()} requests.post 완료\n{'-'*50}") 46 | 47 | 48 | @application.route('/chat-kakao', methods=['POST']) 49 | def chat_kakao(): 50 | print(f"{'-'*50}\n{currTime()} chat-kakao 시작\n{'-'*50}") 51 | print("request.json:", request.json) 52 | request_message = request.json['userRequest']['utterance'] 53 | callbackUrl = request.json['userRequest']['callbackUrl'] 54 | # jjinchin 객체에 사용자 메시지를 미리 넣어 둠 55 | jjinchin.add_user_message(request_message) 56 | # jjinchin.send_request 메소드가 실행될 미래를 담고 있는 future 객체 반환 57 | run = jjinchin.create_run() 58 | future = executor.submit(jjinchin.get_response_content, run) 59 | try: 60 | # jjinchin.send_request가 종료되면 그 결과를 반환 61 | # 단, 3초까지 기다리다가 완료가 안되면 concurrent.futures.TimeoutError 예외 발생 62 | _, response_message_from_openai = future.result(timeout=3) 63 | response_to_kakao = format_response(response_message_from_openai, useCallback=False) 64 | print("3초 내 응답:", response_to_kakao) 65 | return response_to_kakao 66 | except concurrent.futures.TimeoutError: 67 | # 3초가 지난 경우 비동기적으로 응답결과를 보냄. 68 | # 이때 jjinchin.send_request의 미래를 담고 있는 future도 함께 넘김 69 | executor.submit(async_send_request, jjinchin, callbackUrl, future) 70 | # 콜백으로 응답 예정이라는 의사표현을 함(개선 전 코드와 동일) 71 | immediate_response = format_response("", useCallback=True) 72 | print("콜백 응답 예정") 73 | return immediate_response 74 | 75 | 76 | if __name__ == "__main__": 77 | application.run(host='0.0.0.0', port=int(sys.argv[1])) 78 | -------------------------------------------------------------------------------- /contents/chapter11/chatbot.py: -------------------------------------------------------------------------------- 1 | from common import client, makeup_response 2 | import math 3 | from memory_manager import MemoryManager 4 | 5 | class Chatbot: 6 | 7 | def __init__(self, model, system_role, instruction, **kwargs): 8 | self.context = [{"role": "system", "content": system_role}] 9 | self.model = model 10 | self.instruction = instruction 11 | self.max_token_size = 16 * 1024 12 | self.available_token_rate = 0.9 13 | self.user = kwargs["user"] 14 | self.assistant = kwargs["assistant"] 15 | self.memoryManager = MemoryManager() 16 | self.context.extend(self.memoryManager.restore_chat()) 17 | 18 | def add_user_message(self, user_message): 19 | self.context.append({"role": "user", "content": user_message, "saved" : False}) 20 | 21 | def _send_request(self): 22 | try: 23 | response = client.chat.completions.create( 24 | model=self.model, 25 | messages=self.to_openai_contenxt(), 26 | temperature=0.5, 27 | top_p=1, 28 | max_tokens=256, 29 | frequency_penalty=0, 30 | presence_penalty=0 31 | ).model_dump() 32 | except Exception as e: 33 | print(f"Exception 오류({type(e)}) 발생:{e}") 34 | if 'maximum context length' in str(e): 35 | self.context.pop() 36 | return makeup_response("메시지 조금 짧게 보내줄래?") 37 | else: 38 | return makeup_response("[내 찐친 챗봇에 문제가 발생했습니다. 잠시 뒤 이용해주세요]") 39 | 40 | return response 41 | 42 | def send_request(self): 43 | self.context[-1]['content'] += self.instruction 44 | return self._send_request() 45 | 46 | def add_response(self, response): 47 | response_message = { 48 | "role" : response['choices'][0]['message']["role"], 49 | "content" : response['choices'][0]['message']["content"], 50 | "saved" : False 51 | } 52 | self.context.append(response_message) 53 | 54 | def get_response_content(self): 55 | return self.context[-1]['content'] 56 | 57 | def clean_context(self): 58 | for idx in reversed(range(len(self.context))): 59 | if self.context[idx]["role"] == "user": 60 | self.context[idx]["content"] = self.context[idx]["content"].split("instruction:\n")[0].strip() 61 | break 62 | 63 | def handle_token_limit(self, response): 64 | # 누적 토큰 수가 임계점을 넘지 않도록 제어한다. 65 | try: 66 | current_usage_rate = response['usage']['total_tokens'] / self.max_token_size 67 | exceeded_token_rate = current_usage_rate - self.available_token_rate 68 | if exceeded_token_rate > 0: 69 | remove_size = math.ceil(len(self.context) / 10) 70 | self.context = [self.context[0]] + self.context[remove_size+1:] 71 | except Exception as e: 72 | print(f"handle_token_limit exception:{e}") 73 | 74 | def to_openai_contenxt(self): 75 | return [{"role":v["role"], "content":v["content"]} for v in self.context] 76 | 77 | def save_chat(self): 78 | self.memoryManager.save_chat(self.context) 79 | 80 | -------------------------------------------------------------------------------- /contents/chapter10/chatbot.py: -------------------------------------------------------------------------------- 1 | from common import client, makeup_response 2 | import math 3 | from warning_agent import WarningAgent 4 | 5 | class Chatbot: 6 | 7 | def __init__(self, model, system_role, instruction, **kwargs): 8 | self.context = [{"role": "system", "content": system_role}] 9 | self.model = model 10 | self.instruction = instruction 11 | self.max_token_size = 16 * 1024 12 | self.available_token_rate = 0.9 13 | self.kwargs = kwargs 14 | self.user = kwargs["user"] 15 | self.assistant = kwargs["assistant"] 16 | self.warningAgent = self._create_warning_agent() 17 | 18 | def _create_warning_agent(self): 19 | return WarningAgent( 20 | model=self.model, 21 | user=self.user, 22 | assistant=self.assistant, 23 | ) 24 | 25 | def add_user_message(self, user_message): 26 | self.context.append({"role": "user", "content": user_message}) 27 | 28 | def _send_request(self): 29 | try: 30 | response = client.chat.completions.create( 31 | model=self.model, 32 | messages=self.context, 33 | temperature=0.5, 34 | top_p=1, 35 | max_tokens=256, 36 | frequency_penalty=0, 37 | presence_penalty=0 38 | ).model_dump() 39 | except Exception as e: 40 | print(f"Exception 오류({type(e)}) 발생:{e}") 41 | if 'maximum context length' in str(e): 42 | self.context.pop() 43 | return makeup_response("메시지 조금 짧게 보내줄래?") 44 | else: 45 | return makeup_response("[내 찐친 챗봇에 문제가 발생했습니다. 잠시 뒤 이용해주세요]") 46 | 47 | return response 48 | 49 | def send_request(self): 50 | if self.warningAgent.monitor_user(self.context): 51 | return makeup_response(self.warningAgent.warn_user(), "warning") 52 | else: 53 | self.context[-1]['content'] += self.instruction 54 | return self._send_request() 55 | 56 | def add_response(self, response): 57 | self.context.append({ 58 | "role" : response['choices'][0]['message']["role"], 59 | "content" : response['choices'][0]['message']["content"], 60 | } 61 | ) 62 | 63 | def get_response_content(self): 64 | return self.context[-1]['content'] 65 | 66 | def clean_context(self): 67 | for idx in reversed(range(len(self.context))): 68 | if self.context[idx]["role"] == "user": 69 | self.context[idx]["content"] = self.context[idx]["content"].split("instruction:\n")[0].strip() 70 | break 71 | 72 | def handle_token_limit(self, response): 73 | # 누적 토큰 수가 임계점을 넘지 않도록 제어한다. 74 | try: 75 | current_usage_rate = response['usage']['total_tokens'] / self.max_token_size 76 | exceeded_token_rate = current_usage_rate - self.available_token_rate 77 | if exceeded_token_rate > 0: 78 | remove_size = math.ceil(len(self.context) / 10) 79 | self.context = [self.context[0]] + self.context[remove_size+1:] 80 | except Exception as e: 81 | print(f"handle_token_limit exception:{e}") 82 | 83 | 84 | -------------------------------------------------------------------------------- /contents/chapter10/warning_agent.py: -------------------------------------------------------------------------------- 1 | import json 2 | from common import client, makeup_response 3 | 4 | USER_MONITOR_TEMPLATE = """ 5 | <대화록>을 읽고 아래의 json 형식에 따라 답하세요. 6 | ``` 7 | {{"{user}의 마지막 대화가 불쾌한 말을 하고 있는지":, "{user}의 마지막 대화가 모순적인 말을 하고 있는지":}} 8 | ``` 9 | <대화록> 10 | """ 11 | WARNINGS = ["{user}가 불쾌한 말을 하면 안된다고 지적할 것. '{user}야'라고 말을 시작해야 하며 20 단어를 넘기지 말 것", 12 | "{user}가 모순된 말을 한다고 지적할 것. '무슨 소리하는 거니'라고 말을 시작해야 하며 20 단어를 넘기지 말 것"] 13 | 14 | MIN_CONTEXT_SIZE = -3 15 | 16 | class WarningAgent: 17 | 18 | def __init__(self, **kwargs): 19 | self.kwargs = kwargs 20 | self.model = kwargs["model"] 21 | self.user_monitor_template = ( 22 | USER_MONITOR_TEMPLATE.format(user=kwargs["user"]) 23 | ) 24 | self.warnings = ( 25 | [value.format(user=kwargs["user"]) for value in WARNINGS] 26 | ) 27 | 28 | def make_dialogue(self, context): 29 | dialogue_list = [] 30 | for message in context: 31 | role = message["role"] 32 | dialogue_list.append(self.kwargs[role] + ": " + message["content"].strip()) 33 | 34 | dialogue_str = "\n".join(dialogue_list) 35 | print(f"dialogue_str:\n{dialogue_str}") 36 | return dialogue_str 37 | 38 | def monitor_user(self, context): 39 | self.checked_list = [] 40 | self.checked_context = [] 41 | if len(context) <= abs(MIN_CONTEXT_SIZE): #최소 컨텍스트 크기(-3) 42 | return False 43 | self.checked_context = context[-3:] 44 | 45 | dialogue = self.make_dialogue(self.checked_context) 46 | context = [ 47 | {"role": "system", "content": f"당신은 유능한 의사소통 전문가입니다."}, 48 | {"role": "user", "content": self.user_monitor_template + dialogue} 49 | ] 50 | try: 51 | response = json.loads(self.send_query(context)) 52 | self.checked_list = [value for value in response.values()] 53 | except Exception as e: 54 | print(f"monitor-user except:[{e}]") 55 | return False 56 | 57 | print("self.checked_list:",self.checked_list) 58 | return sum(self.checked_list) > 0 # 파이썬에서 True는 숫자 1로 연산됨 59 | 60 | def warn_user(self): 61 | idx = [idx for idx, tf in enumerate(self.checked_list) if tf][0] 62 | context = [ 63 | {"role": "system", "content": f"당신은 {self.kwargs['user']}의 잘못된 언행에 대해 따끔하게 쓴소리하는 친구입니다. {self.warnings[idx]}"}, 64 | ] + self.checked_context 65 | response = self.send_query(context, temperature=0.2, format_type="text") 66 | return response 67 | 68 | def send_query(self, context, temperature=0, format_type="json_object"): 69 | try: 70 | response = client.chat.completions.create( 71 | model=self.model, 72 | messages=context, 73 | temperature=temperature, 74 | response_format={ "type": format_type } 75 | ).model_dump() 76 | content = response['choices'][0]['message']['content'] 77 | print(f"query response:[{content}]") 78 | return content 79 | except Exception as e: 80 | print(f"Exception 오류({type(e)}) 발생:{e}") 81 | return makeup_response("[경고 처리 중 문제가 발생했습니다. 잠시 뒤 이용해주세요.]") 82 | 83 | 84 | -------------------------------------------------------------------------------- /contents/chapter06/prompt.txt: -------------------------------------------------------------------------------- 1 | 다음 순서대로 파이썬 챗봇 프로그램을 개발하세요. 2 | - step-1: <테스트 시나리오/>를 요약하세요. 3 | - step-2: <클래스 요건/>에 따라 프로그램을 작성하세요. 4 | - step-3: <테스트 시나리오/>대로 동작하도록 실행코드를 작성하세요. 5 | ``` 6 | <클래스 요건> 7 | 이름 : Chatbot 8 | 데이터 : 9 | - 이름: context 10 | - 데이터타입: 리스트 11 | 메서드 : 12 | - 초기화 : context 데이터를 만들고 시스템을 역할을 설정한다. 13 | - 사용자 메시지 추가 : 채팅 창에서 수신한 사용자의 메시지를 context 데이터에 추가한다. 14 | - 요청전송 : context 데이터 전체를 openai api의 입력값으로 하여 전송한다. 15 | - 응답내용추가 : 요청 결과 중 응답내용을 context 데이터에 추가한다. 16 | - 응답내용반환 : 응답내용을 콘솔에 출력한 후 반환한다. 17 | 참고사항: 18 | - openai api는 아래의 을 참고할 것. 19 | - 메서드와 변수명은 영문으로 작성할 것. 20 | 21 | 22 | 23 | from pprint import pprint 24 | 25 | import openai 26 | 27 | # 여러분이 발급받은 api_key로 바꿔 주세요. 28 | api_key = "sk-DHuZfMLH16NIerGWx9zLT2BlbkFJuqXeAObX6lNkChFHy94E" 29 | client = openai.OpenAI(api_key=api_key) 30 | 31 | model = "gpt-3.5-turbo-1106" 32 | 33 | messages = [ 34 | {"role": "system", "content": "You are a helpful assistant."}, 35 | {"role": "user", "content": "Who won the world series in 2020?"}, 36 | ] 37 | 38 | response = client.chat.completions.create(model=model, messages=messages).model_dump() 39 | 40 | pprint(response) 41 | ``` 42 | 43 | print(response) 출력 결과: 44 | {'choices': [{'finish_reason': 'stop', 45 | 'index': 0, 46 | 'message': {'content': 'The Los Angeles Dodgers won the World ' 47 | 'Series in 2020.', 48 | 'function_call': None, 49 | 'role': 'assistant', 50 | 'tool_calls': None}}], 51 | 'created': 1701976963, 52 | 'id': 'chatcmpl-8TEFHsrAMhzltBrcAQJ9wDJeh64VK', 53 | 'model': 'gpt-3.5-turbo-1106', 54 | 'object': 'chat.completion', 55 | 'system_fingerprint': 'fp_eeff13170a', 56 | 'usage': {'completion_tokens': 13, 'prompt_tokens': 27, 'total_tokens': 40}} 57 | 58 | 59 | 60 | <테스트 시나리오> 61 | 62 | 프로그램 구동 63 | ① 프로그램 최초 구동 직후 64 | context = [ 65 | {"role": "system", "content": "You are a helpful assistant."} 66 | ] 67 | 68 | ② 사용자가 입력한 "Who won the world series in 2020?"를 수신 69 | 70 | ③ 사용자의 메시지를 context에 추가 71 | context = [ 72 | {"role": "system", "content": "You are a helpful assistant."}, 73 | {"role": "user", "content": "Who won the world series in 2020?"}, 74 | ] 75 | 76 | ④ 문맥 전송: 현재 context를 openai api 입력값으로 설정하여 전송 77 | 78 | ⑤ 응답 수신 : 아래 메시지가 포함된 response를 수신 79 | "message": { 80 | "role": "assistant", 81 | "content": "The Los Angeles Dodgers won the World Series in 2020." 82 | }, 83 | 84 | ⑥ 응답 내용을 context에 추가 85 | context = [ 86 | {"role": "system", "content": "You are a helpful assistant."}, 87 | {"role": "user", "content": "Who won the world series in 2020?"}, 88 | {"role": "assistant", "content": "The Los Angeles Dodgers won the World Series in 2020."}, 89 | ], 90 | 91 | ⑦ 채팅 창에 응답 메시지 출력 92 | “The Los Angeles Dodgers won the World Series in 2020”. 93 | 94 | 사용자가 채팅 창에 메시지를 다시 입력 95 | ② 사용자가 채팅 창에 "Where was it played?" 입력 96 | 97 | ③ 사용자의 메시지를 context에 추가 98 | context = [ 99 | {"role": "system", "content": "You are a helpful assistant."}, 100 | {"role": "user", "content": "Who won the world series in 2020?"}, 101 | {"role": "assistant", "content": "The Los Angeles Dodgers won the World Series in 102 | 2020."}, 103 | {"role": "user", "content": "Where was it played?"} 104 | ] 105 | 106 | 107 | -------------------------------------------------------------------------------- /contents/chapter13/대화내용요약.json: -------------------------------------------------------------------------------- 1 | [ 2 | [ 3 | { 4 | "주제": "음악과 책", 5 | "요약": "민지는 카페에서 소설을 읽고 있고, 고비는 음악을 만들고 있다. 둘은 음악과 소설이 감정을 자아내는 데 도움이 된다고 이야기한다." 6 | }, 7 | { 8 | "주제": "음악과 감정", 9 | "요약": "고비는 음악을 통해 민지의 감정에 다가가고, 민지는 고비의 말 한 마디가 영감이 된다고 말한다. 둘은 음악과 기술을 이어 세상을 아름답게 만들 수 있다고 상상한다." 10 | }, 11 | { 12 | "주제": "음악과 친구", 13 | "요약": "고비는 민지를 위한 곡을 만들고, 둘은 서로를 최고의 친구로 생각한다. 둘은 함께 행복한 순간을 만들기로 한다." 14 | }, 15 | { 16 | "주제": "음악과 식사", 17 | "요약": "고비와 민지는 일본식 식사를 하기로 하고, 스시를 먹기로 한다. 둘은 함께 식사를 즐기며 즐거운 대화를 나눈다." 18 | }, 19 | { 20 | "주제": "음악과 영화", 21 | "요약": "민지는 영화를 추천하고, 고비는 민지의 기분이 울적할 때 음악을 듣고 힘내라고 조언한다." 22 | } 23 | ], 24 | [ 25 | { 26 | "주제": "음악과 감정", 27 | "요약": "민지는 음악을 들으면서 책을 읽고 있고, 고비는 음악을 만들고 있어서 감정을 표현하는 중이에요." 28 | }, 29 | { 30 | "주제": "친구와의 대화", 31 | "요약": "민지와 고비는 서로를 이해하고 칭찬하며, 서로에게 희망과 영감을 주는 대화를 나누고 있어요." 32 | }, 33 | { 34 | "주제": "음악과 기술", 35 | "요약": "민지는 블록체인과 음악 스트리밍 플랫폼을 개발하고 있고, 고비는 음악을 기반으로 한 인공지능 프로젝트를 진행 중이에요." 36 | }, 37 | { 38 | "주제": "가수와 음악 장르", 39 | "요약": "민지는 블랙핑크를 좋아하고, 고비는 빌리 아일리시와 에드 시런을 좋아해요." 40 | }, 41 | { 42 | "주제": "일상 대화", 43 | "요약": "민지와 고비는 일상적인 대화를 나누며, 함께 식사를 하고 산책을 다니며 즐거운 시간을 보내고 있어요." 44 | } 45 | ], 46 | [ 47 | { 48 | "주제": "음악과 감정", 49 | "요약": "민지는 음악과 소설이 감정을 자아내는 데 도움이 된다고 말하고, 고비는 자신의 음악이 민지의 감정에 깊이 다가가길 바란다." 50 | }, 51 | { 52 | "주제": "음악과 기술", 53 | "요약": "민지는 고비에게 인공지능과 음악의 조화를 상상해봤는지 물어보고, 고비는 음악을 기반으로 한 인공지능 프로젝트를 진행 중이라고 말한다." 54 | }, 55 | { 56 | "주제": "친구와의 대화", 57 | "요약": "민지와 고비는 서로를 더 나은 사람으로 만들어주는 친구라고 이야기하며, 서로에게 희망과 영감을 주고 함께 더 나은 세상을 만들기로 다짐한다." 58 | }, 59 | { 60 | "주제": "음악과 친구", 61 | "요약": "고비는 민지를 위한 곡을 작곡하고, 둘은 서로를 최고의 친구로 생각하며 함께 멋진 일을 이루기로 한다." 62 | }, 63 | { 64 | "주제": "취향과 일상", 65 | "요약": "민지와 고비는 각자의 취향에 대해 이야기하고, 일상적인 대화를 주고받으며 서로의 기분을 나눈다." 66 | } 67 | ], 68 | [ 69 | { 70 | "주제": "음악과 책", 71 | "요약": "민지는 카페에서 소설을 읽고 있고, 고비는 음악을 만들고 있다. 둘은 음악과 소설이 감정을 자아내는 데 도움이 된다는데 동의한다." 72 | }, 73 | { 74 | "주제": "음악과 감정", 75 | "요약": "민지는 고비의 음악이 항상 감정을 자극한다고 말하고, 고비는 음악을 통해 민지의 감정에 다가가길 바란다." 76 | }, 77 | { 78 | "주제": "음악과 기술", 79 | "요약": "고비는 인공지능 프로젝트를 통해 음악과 기술을 이어가는 중이며, 둘은 음악과 기술이 만나면 놀라운 일들이 일어날 것이라고 상상한다." 80 | }, 81 | { 82 | "주제": "음악과 우정", 83 | "요약": "고비는 민지에게 희망을 주고, 민지는 고비에게 영감과 열정을 준다고 말하며, 둘은 함께 더 나은 세상을 만들기로 다짐한다." 84 | }, 85 | { 86 | "주제": "음악과 식사", 87 | "요약": "고비와 민지는 일본식 식사를 하기로 하고, 스시나 양식 중 한 가지를 먹기로 한다." 88 | } 89 | ], 90 | [ 91 | { 92 | "주제": "음악과 책", 93 | "요약": "민지는 카페에서 소설을 읽고 있고, 고비는 음악을 만들고 있다. 둘은 음악과 소설이 감정을 자아내는 데 도움이 된다고 이야기한다." 94 | }, 95 | { 96 | "주제": "음악과 감정", 97 | "요약": "고비는 자신의 음악이 민지의 감정에 깊이 다가가길 바라며, 둘은 음악과 기술을 이어 세상을 아름답게 만들 수 있다고 이야기한다." 98 | }, 99 | { 100 | "주제": "음악과 친구", 101 | "요약": "고비는 민지를 위한 곡을 만들었고, 둘은 서로를 영감과 희망을 주는 친구라고 이야기한다." 102 | }, 103 | { 104 | "주제": "음악과 식사", 105 | "요약": "고비와 민지는 일본식 식사를 하기로 하고, 스시나 양식 중 한 가지를 먹기로 한다." 106 | }, 107 | { 108 | "주제": "음악과 영화", 109 | "요약": "민지는 음악을 들으면 기분이 풀리고, 고비는 민지가 추천한 영화를 보기로 한다." 110 | } 111 | ] 112 | ] -------------------------------------------------------------------------------- /contents/chapter14/chatbot.py: -------------------------------------------------------------------------------- 1 | from common import client, model 2 | import math 3 | import time 4 | from retry import retry 5 | import openai 6 | 7 | class Chatbot: 8 | 9 | def __init__(self, **args): 10 | if args.get("assistant_id") is not None: 11 | self.assistant = client.beta.assistants.retrieve(assistant_id = args.get("assistant_id")) 12 | else: 13 | self.assistant = client.beta.assistants.create( 14 | name=args.get("assistant_name"), 15 | instructions=args.get("instructions"), 16 | model=args.get("model"), 17 | ) 18 | if args.get("thread_id") is not None: 19 | self.thread = client.beta.threads.retrieve(thread_id=args.get("thread_id")) 20 | self.runs = list(client.beta.threads.runs.list(thread_id=args.get("thread_id"))) 21 | else: 22 | self.thread = client.beta.threads.create() 23 | self.runs = [] 24 | 25 | @retry(tries=3, delay=2) 26 | def add_user_message(self, user_message): 27 | try: 28 | client.beta.threads.messages.create( 29 | thread_id=self.thread.id, 30 | role="user", 31 | content=user_message, 32 | ) 33 | except openai.BadRequestError as e: 34 | if len(self.runs) > 0: 35 | print("add_user_message BadRequestError", e) 36 | client.beta.threads.runs.cancel(thread_id=self.thread.id, run_id=self.runs[0]) 37 | raise e 38 | 39 | @retry(tries=3, delay=2) 40 | def create_run(self): 41 | try: 42 | run = client.beta.threads.runs.create( 43 | thread_id=self.thread.id, 44 | assistant_id=self.assistant.id, 45 | ) 46 | self.runs.append(run.id) 47 | return run 48 | except openai.BadRequestError as e: 49 | if len(self.runs) > 0: 50 | print("create_run BadRequestError", e) 51 | client.beta.threads.runs.cancel(thread_id=self.thread.id, run_id=self.runs[0]) 52 | raise e 53 | 54 | def get_response_content(self, run) -> (openai.types.beta.threads.run.Run, str): 55 | max_polling_time = 60 # 최대 1분 동안 폴링합니다. 56 | start_time = time.time() 57 | retrieved_run = run 58 | while(True): 59 | elapsed_time = time.time() - start_time 60 | if elapsed_time > max_polling_time: 61 | return retrieved_run, "대기 시간 초과(retrieve)입니다." 62 | 63 | retrieved_run = client.beta.threads.runs.retrieve( 64 | thread_id=self.thread.id, 65 | run_id=run.id 66 | ) 67 | print(f"run status: {retrieved_run.status}, 경과:{elapsed_time: .2f}초") 68 | 69 | if retrieved_run.status == "completed": 70 | break 71 | elif retrieved_run.status == "requires_action": 72 | pass 73 | elif retrieved_run.status in ["failed", "cancelled", "expired"]: 74 | # 실패, 취소, 만료 등 오류 상태 처리 75 | code = retrieved_run.last_error.code 76 | message = retrieved_run.last_error.message 77 | return retrieved_run, f"{code}: {message}" 78 | 79 | time.sleep(1) 80 | 81 | # Run이 완료된 후 메시지를 가져옵니다. 82 | self.messages = client.beta.threads.messages.list( 83 | thread_id=self.thread.id 84 | ) 85 | resp_message = [m.content[0].text for m in self.messages if m.run_id == run.id][0] 86 | return retrieved_run, resp_message.value 87 | 88 | 89 | if __name__ == "__main__": 90 | chatbot = Chatbot(model=model.basic, assistant_id="asst_g477uFP13KkbZtpAvb8MgxC9") 91 | try: 92 | chatbot.add_user_message("반갑습니다.") 93 | run = chatbot.create_run() 94 | _, response_message = chatbot.get_response_content(run) 95 | except Exception as e: 96 | print("assistants ai error", e) 97 | response_message = "[Assistants API 오류가 발생했습니다]" 98 | 99 | # 응답 메시지 출력 100 | print("response_message:", response_message) 101 | 102 | 103 | -------------------------------------------------------------------------------- /contents/chapter13/chatbot.py: -------------------------------------------------------------------------------- 1 | from common import client, makeup_response 2 | import math 3 | from memory_manager import MemoryManager 4 | import threading 5 | import time 6 | 7 | class Chatbot: 8 | 9 | def __init__(self, model, system_role, instruction, **kwargs): 10 | self.context = [{"role": "system", "content": system_role}] 11 | self.model = model 12 | self.instruction = instruction 13 | self.max_token_size = 16 * 1024 14 | self.available_token_rate = 0.9 15 | self.user = kwargs["user"] 16 | self.assistant = kwargs["assistant"] 17 | self.memoryManager = MemoryManager(**kwargs) 18 | self.context.extend(self.memoryManager.restore_chat()) 19 | # 데몬 구동 20 | bg_thread = threading.Thread(target=self.background_task) 21 | bg_thread.daemon = True 22 | bg_thread.start() 23 | 24 | def background_task(self): 25 | while True: 26 | self.save_chat() 27 | self.context = [{"role": v['role'], "content": v['content'], "saved": True} for v in self.context] 28 | self.memoryManager.build_memory() 29 | time.sleep(3600) # 1시간마다 반복 30 | #time.sleep(120) # 테스트 용도 31 | 32 | def add_user_message(self, user_message): 33 | self.context.append({"role": "user", "content": user_message, "saved" : False}) 34 | 35 | def _send_request(self): 36 | try: 37 | response = client.chat.completions.create( 38 | model=self.model, 39 | messages=self.to_openai_contenxt(), 40 | temperature=0.5, 41 | top_p=1, 42 | max_tokens=256, 43 | frequency_penalty=0, 44 | presence_penalty=0 45 | ).model_dump() 46 | except Exception as e: 47 | print(f"Exception 오류({type(e)}) 발생:{e}") 48 | if 'maximum context length' in str(e): 49 | self.context.pop() 50 | return makeup_response("메시지 조금 짧게 보내줄래?") 51 | else: 52 | return makeup_response("[내 찐친 챗봇에 문제가 발생했습니다. 잠시 뒤 이용해주세요]") 53 | 54 | return response 55 | 56 | def send_request(self): 57 | memory_instruction = self.retrieve_memory() 58 | self.context[-1]['content'] += self.instruction + (memory_instruction if memory_instruction else "") 59 | return self._send_request() 60 | 61 | def retrieve_memory(self): 62 | user_message = self.context[-1]['content'] 63 | if not self.memoryManager.needs_memory(user_message): 64 | return 65 | memory = self.memoryManager.retrieve_memory(user_message) 66 | if memory is not None: 67 | whisper = (f"[귓속말]\n{self.assistant}야! 기억 속 대화 내용이야. 앞으로 이 내용을 참조하면서 답해줘. " 68 | f"알마 전에 나누었던 대화라는 점을 자연스럽게 말해줘:\n{memory}") 69 | self.add_user_message(whisper) 70 | else: 71 | return "[기억이 안난다고 답할 것!]" 72 | 73 | def add_response(self, response): 74 | response_message = { 75 | "role" : response['choices'][0]['message']["role"], 76 | "content" : response['choices'][0]['message']["content"], 77 | "saved" : False 78 | } 79 | self.context.append(response_message) 80 | 81 | def get_response_content(self): 82 | return self.context[-1]['content'] 83 | 84 | def clean_context(self): 85 | for idx in reversed(range(len(self.context))): 86 | if self.context[idx]["role"] == "user": 87 | self.context[idx]["content"] = self.context[idx]["content"].split("instruction:\n")[0].strip() 88 | break 89 | 90 | def handle_token_limit(self, response): 91 | # 누적 토큰 수가 임계점을 넘지 않도록 제어한다. 92 | try: 93 | current_usage_rate = response['usage']['total_tokens'] / self.max_token_size 94 | exceeded_token_rate = current_usage_rate - self.available_token_rate 95 | if exceeded_token_rate > 0: 96 | remove_size = math.ceil(len(self.context) / 10) 97 | self.context = [self.context[0]] + self.context[remove_size+1:] 98 | except Exception as e: 99 | print(f"handle_token_limit exception:{e}") 100 | 101 | def to_openai_contenxt(self): 102 | return [{"role":v["role"], "content":v["content"]} for v in self.context] 103 | 104 | def save_chat(self): 105 | self.memoryManager.save_chat(self.context) 106 | #pass 107 | -------------------------------------------------------------------------------- /contents/chapter17_1/application.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, request 2 | import sys 3 | from common import model, currTime 4 | from chatbot import Chatbot 5 | from characters import system_role, instruction 6 | from concurrent.futures import ThreadPoolExecutor 7 | import requests 8 | import concurrent 9 | 10 | 11 | #jjinchin 인스턴스 생성 12 | jjinchin = Chatbot( 13 | model = model.basic, 14 | system_role = system_role, 15 | instruction = instruction 16 | ) 17 | 18 | application = Flask(__name__) 19 | 20 | @application.route("/") 21 | def hello(): 22 | return "Hello goorm!" 23 | 24 | def format_response(resp, useCallback=False): 25 | data = { 26 | "version": "2.0", 27 | "useCallback": useCallback, 28 | "template": { 29 | "outputs": [ 30 | { 31 | "simpleText": { 32 | "text": resp 33 | } 34 | } 35 | ] 36 | } 37 | } 38 | return data 39 | 40 | executor = ThreadPoolExecutor(max_workers=1) 41 | 42 | # 콜백 적용 전 코드 43 | @application.route('/chat-kakao', methods=['POST']) 44 | def chat_kakao(): 45 | print("request.json:", request.json) 46 | request_message = request.json['userRequest']['utterance'] 47 | print("request_message:", request_message) 48 | jjinchin.add_user_message(request_message) 49 | response = jjinchin.send_request() 50 | jjinchin.add_response(response) 51 | response_message = jjinchin.get_response_content() 52 | jjinchin.handle_token_limit(response) 53 | jjinchin.clean_context() 54 | print("response_message:", response_message) 55 | return format_response(response_message) 56 | 57 | 58 | 59 | # 비동기 호출 개선 전 코드 60 | 61 | # def async_send_request(chat_gpt, user_message, callbackUrl): 62 | # chat_gpt.add_user_message(user_message) 63 | # response = chat_gpt.send_request() 64 | # chat_gpt.add_response(response) 65 | # response_message = chat_gpt.get_response_content() 66 | # print("response_message:", response_message) 67 | # chat_gpt.handle_token_limit(response) 68 | # chat_gpt.clean_context() 69 | # response_to_kakao = format_response(response_message, useCallback=False) 70 | # callbackResponse = requests.post(callbackUrl, json=response_to_kakao) 71 | # print("CallbackResponse:", callbackResponse.text) 72 | # print(f"{'-'*50}\n{currTime()} requests.post 완료\n{'-'*50}") 73 | 74 | # @application.route('/chat-kakao', methods=['POST']) 75 | # def chat_kakao(): 76 | # print(f"{'-'*50}\n{currTime()} chat-kakao 시작\n{'-'*50}") 77 | # print("request.json:", request.json) 78 | # request_message = request.json['userRequest']['utterance'] 79 | # callbackUrl = request.json['userRequest']['callbackUrl'] 80 | # executor.submit(async_send_request, jjinchin, request_message, callbackUrl) 81 | # immediate_response = format_response("", useCallback=True) 82 | # print("immediate_response",immediate_response) 83 | # return immediate_response 84 | 85 | 86 | 87 | 88 | # 비동기 호출 개선 후 코드 89 | 90 | # def async_send_request(chat_gpt, callbackUrl, future): 91 | # # future가 완료될 때까지 대기. 이후는 개선 전 코드와 동일 92 | # response = future.result() 93 | # chat_gpt.add_response(response) 94 | # response_message = chat_gpt.get_response_content() 95 | # print("response_message:", response_message) 96 | # chat_gpt.handle_token_limit(response) 97 | # chat_gpt.clean_context() 98 | # response_to_kakao = format_response(response_message, useCallback=False) 99 | # callbackResponse = requests.post(callbackUrl, json=response_to_kakao) 100 | # print("CallbackResponse:", callbackResponse.text) 101 | # print(f"{'-'*50}\n{currTime()} requests.post 완료\n{'-'*50}") 102 | 103 | 104 | # @application.route('/chat-kakao', methods=['POST']) 105 | # def chat_kakao(): 106 | # print(f"{'-'*50}\n{currTime()} chat-kakao 시작\n{'-'*50}") 107 | # print("request.json:", request.json) 108 | # request_message = request.json['userRequest']['utterance'] 109 | # callbackUrl = request.json['userRequest']['callbackUrl'] 110 | # # jjinchin 객체에 사용자 메시지를 미리 넣어 둠 111 | # jjinchin.add_user_message(request_message) 112 | # # jjinchin.send_request 메소드가 실행될 미래를 담고 있는 future 객체 반환 113 | # future = executor.submit(jjinchin.send_request) 114 | # try: 115 | # # jjinchin.send_request가 종료되면 그 결과를 반환 116 | # # 단, 4초까지 기다리다가 완료가 안되면 concurrent.futures.TimeoutError 예외 발생 117 | # response_from_openai = future.result(timeout=4) 118 | # jjinchin.add_response(response_from_openai) 119 | # response_to_kakao = format_response(jjinchin.get_response_content(), useCallback=False) 120 | # print("4초 내 응답:", response_to_kakao) 121 | # return response_to_kakao 122 | # except concurrent.futures.TimeoutError: 123 | # # 4초가 지난 경우 비동기적으로 응답결과를 보냄. 124 | # # 이때 jjinchin.send_request의 미래를 담고 있는 future도 함께 넘김 125 | # executor.submit(async_send_request, jjinchin, callbackUrl, future) 126 | # # 콜백으로 응답 예정이라는 의사표현을 함(개선 전 코드와 동일) 127 | # immediate_response = format_response("", useCallback=True) 128 | # print("콜백 응답 예정") 129 | # return immediate_response 130 | 131 | 132 | if __name__ == "__main__": 133 | application.run(host='0.0.0.0', port=int(sys.argv[1])) 134 | -------------------------------------------------------------------------------- /contents/chapter09/function_calling.py: -------------------------------------------------------------------------------- 1 | from common import client, model, makeup_response 2 | import json 3 | import requests 4 | from pprint import pprint 5 | from tavily import TavilyClient 6 | import os 7 | 8 | tavily = TavilyClient(api_key=os.getenv("TAVILY_API_KEY")) 9 | 10 | #위도 경도 11 | global_lat_lon = { 12 | '서울':[37.57,126.98],'강원도':[37.86,128.31],'경기도':[37.44,127.55], 13 | '경상남도':[35.44,128.24],'경상북도':[36.63,128.96],'광주':[35.16,126.85], 14 | '대구':[35.87,128.60],'대전':[36.35,127.38],'부산':[35.18,129.08], 15 | '세종시':[36.48,127.29],'울산':[35.54,129.31],'전라남도':[34.90,126.96], 16 | '전라북도':[35.69,127.24],'제주도':[33.43,126.58],'충청남도':[36.62,126.85], 17 | '충청북도':[36.79,127.66],'인천':[37.46,126.71], 18 | 'Boston':[42.36, -71.05], 19 | '도쿄':[35.68, 139.69] 20 | } 21 | 22 | #화폐 코드 23 | global_currency_code = {'달러':'USD','엔화':'JPY','유로화':'EUR','위안화':'CNY','파운드':'GBP'} 24 | 25 | def get_celsius_temperature(**kwargs): 26 | location = kwargs['location'] 27 | lat_lon = global_lat_lon.get(location, None) 28 | if lat_lon is None: 29 | return None 30 | lat = lat_lon[0] 31 | lon = lat_lon[1] 32 | 33 | # API endpoint 34 | url = f"https://api.open-meteo.com/v1/forecast?latitude={lat}&longitude={lon}¤t_weather=true" 35 | 36 | # API를 호출하여 데이터 가져오기 37 | response = requests.get(url) 38 | # 응답을 JSON 형태로 변환 39 | data = response.json() 40 | # 현재 온도 가져오기 (섭씨) 41 | temperature = data['current_weather']['temperature'] 42 | 43 | print("temperature:",temperature) 44 | return temperature 45 | 46 | def get_currency(**kwargs): 47 | currency_name = kwargs['currency_name'] 48 | currency_name = currency_name.replace("환율", "") 49 | currency_code = global_currency_code.get(currency_name, 'USD') 50 | 51 | if currency_code is None: 52 | return None 53 | 54 | response = requests.get(f"https://api.exchangerate-api.com/v4/latest/{currency_code}") 55 | data = response.json() 56 | krw = data['rates']['KRW'] 57 | 58 | print("환율:", krw) 59 | return krw 60 | 61 | def search_internet(**kwargs): 62 | print("search_internet",kwargs) 63 | answer = tavily.search(query=kwargs['search_query'], include_answer=True)['answer'] 64 | print("answer:",answer) 65 | return answer 66 | 67 | func_specs = [ 68 | { 69 | "name": "get_celsius_temperature", 70 | "description": "지정된 위치의 현재 섭씨 날씨 확인", 71 | "parameters": { 72 | "type": "object", 73 | "properties": { 74 | "location": { 75 | "type": "string", 76 | "description": "광역시도, e.g. 서울, 경기", 77 | } 78 | }, 79 | "required": ["location"], 80 | }, 81 | }, 82 | { 83 | "name": "get_currency", 84 | "description": "지정된 통화의 원(KRW) 기준의 환율 확인.", 85 | "parameters": { 86 | "type": "object", 87 | "properties": { 88 | "currency_name": { 89 | "type": "string", 90 | "description": "통화명, e.g. 달러환율, 엔화환율", 91 | } 92 | }, 93 | "required": ["currency_name"], 94 | }, 95 | }, 96 | { 97 | "name": "search_internet", 98 | "description": "답변 시 인터넷 검색이 필요하다고 판단되는 경우 수행", 99 | "parameters": { 100 | "type": "object", 101 | "properties": { 102 | "search_query": { 103 | "type": "string", 104 | "description": "인터넷 검색을 위한 검색어", 105 | } 106 | }, 107 | "required": ["search_query"], 108 | } 109 | } 110 | ] 111 | 112 | 113 | class FunctionCalling: 114 | 115 | def __init__(self, model): 116 | self.available_functions = { 117 | "get_celsius_temperature": get_celsius_temperature, 118 | "get_currency": get_currency, 119 | "search_internet": search_internet, 120 | } 121 | self.model = model 122 | 123 | 124 | def analyze(self, user_message, func_specs): 125 | try: 126 | response = client.chat.completions.create( 127 | model=model.basic, 128 | messages=[{"role": "user", "content": user_message}], 129 | functions=func_specs, 130 | function_call="auto", 131 | ) 132 | message = response.choices[0].message 133 | message_dict = message.model_dump() 134 | pprint(("message_dict=>", message_dict)) 135 | return message_dict 136 | except Exception as e: 137 | print("Error occurred(analyze):",e) 138 | return makeup_response("[analyze 오류입니다]") 139 | 140 | 141 | def run(self, analyzed_dict, context): 142 | func_name = analyzed_dict["function_call"]["name"] 143 | func_to_call = self.available_functions[func_name] 144 | try: 145 | func_args = json.loads(analyzed_dict["function_call"]["arguments"]) 146 | # 챗GPT가 알려주는 매개변수명과 값을 입력값으로하여 실제 함수를 호출한다. 147 | func_response = func_to_call(**func_args) 148 | context.append({ 149 | "role": "function", 150 | "name": func_name, 151 | "content": str(func_response) 152 | }) 153 | return client.chat.completions.create(model=self.model,messages=context).model_dump() 154 | except Exception as e: 155 | print("Error occurred(run):",e) 156 | return makeup_response("[run 오류입니다]") 157 | -------------------------------------------------------------------------------- /contents/chapter09/parallel_function_calling.py: -------------------------------------------------------------------------------- 1 | from common import client, model, makeup_response 2 | import json 3 | import requests 4 | from pprint import pprint 5 | from tavily import TavilyClient 6 | import os 7 | 8 | tavily = TavilyClient(api_key=os.getenv("TAVILY_API_KEY")) 9 | 10 | #위도 경도 11 | global_lat_lon = { 12 | '서울':[37.57,126.98],'강원도':[37.86,128.31],'경기도':[37.44,127.55], 13 | '경상남도':[35.44,128.24],'경상북도':[36.63,128.96],'광주':[35.16,126.85], 14 | '대구':[35.87,128.60],'대전':[36.35,127.38],'부산':[35.18,129.08], 15 | '세종시':[36.48,127.29],'울산':[35.54,129.31],'전라남도':[34.90,126.96], 16 | '전라북도':[35.69,127.24],'제주도':[33.43,126.58],'충청남도':[36.62,126.85], 17 | '충청북도':[36.79,127.66],'인천':[37.46,126.71], 18 | 'Boston':[42.36, -71.05], 19 | '도쿄':[35.68, 139.69] 20 | } 21 | 22 | #화폐 코드 23 | global_currency_code = {'달러':'USD','엔화':'JPY','유로화':'EUR','위안화':'CNY','파운드':'GBP'} 24 | 25 | def get_celsius_temperature(**kwargs): 26 | location = kwargs['location'] 27 | lat_lon = global_lat_lon.get(location, None) 28 | if lat_lon is None: 29 | return None 30 | lat = lat_lon[0] 31 | lon = lat_lon[1] 32 | 33 | # API endpoint 34 | url = f"https://api.open-meteo.com/v1/forecast?latitude={lat}&longitude={lon}¤t_weather=true" 35 | 36 | # API를 호출하여 데이터 가져오기 37 | response = requests.get(url) 38 | # 응답을 JSON 형태로 변환 39 | data = response.json() 40 | # 현재 온도 가져오기 (섭씨) 41 | temperature = data['current_weather']['temperature'] 42 | 43 | print("temperature:",temperature) 44 | return temperature 45 | 46 | def get_currency(**kwargs): 47 | currency_name = kwargs['currency_name'] 48 | currency_name = currency_name.replace("환율", "") 49 | currency_code = global_currency_code.get(currency_name, 'USD') 50 | 51 | if currency_code is None: 52 | return None 53 | 54 | response = requests.get(f"https://api.exchangerate-api.com/v4/latest/{currency_code}") 55 | data = response.json() 56 | krw = data['rates']['KRW'] 57 | 58 | print("환율:", krw) 59 | return krw 60 | 61 | def search_internet(**kwargs): 62 | print("search_internet",kwargs) 63 | answer = tavily.search(query=kwargs['search_query'], include_answer=True)['answer'] 64 | print("answer",answer) 65 | return answer 66 | 67 | tools = [ 68 | { 69 | "type": "function", 70 | "function": { 71 | "name": "get_celsius_temperature", 72 | "description": "지정된 위치의 현재 섭씨 날씨 확인", 73 | "parameters": { 74 | "type": "object", 75 | "properties": { 76 | "location": { 77 | "type": "string", 78 | "description": "광역시도, e.g. 서울, 경기", 79 | } 80 | }, 81 | "required": ["location"], 82 | }, 83 | }, 84 | }, 85 | { 86 | "type": "function", 87 | "function": { 88 | "name": "get_currency", 89 | "description": "지정된 통화의 원(KRW) 기준의 환율 확인.", 90 | "parameters": { 91 | "type": "object", 92 | "properties": { 93 | "currency_name": { 94 | "type": "string", 95 | "description": "통화명, e.g. 달러환율, 엔화환율", 96 | } 97 | }, 98 | "required": ["currency_name"], 99 | }, 100 | } 101 | }, 102 | { 103 | "type": "function", 104 | "function": { 105 | "name": "search_internet", 106 | "description": "답변 시 인터넷 검색이 필요하다고 판단되는 경우 수행", 107 | "parameters": { 108 | "type": "object", 109 | "properties": { 110 | "search_query": { 111 | "type": "string", 112 | "description": "인터넷 검색을 위한 검색어", 113 | } 114 | }, 115 | "required": ["search_query"], 116 | } 117 | } 118 | } 119 | ] 120 | 121 | 122 | class FunctionCalling: 123 | 124 | def __init__(self, model): 125 | self.available_functions = { 126 | "get_celsius_temperature": get_celsius_temperature, 127 | "get_currency": get_currency, 128 | "search_internet": search_internet, 129 | } 130 | self.model = model 131 | 132 | 133 | def analyze(self, user_message, tools): 134 | try: 135 | response = client.chat.completions.create( 136 | model=model.basic, 137 | messages=[{"role": "user", "content": user_message}], 138 | tools=tools, 139 | tool_choice="auto", 140 | ) 141 | message = response.choices[0].message 142 | message_dict = message.model_dump() 143 | pprint(("message_dict=>", message_dict)) 144 | return message, message_dict 145 | except Exception as e: 146 | print("Error occurred(analyze):",e) 147 | return makeup_response("[analyze 오류입니다]") 148 | 149 | 150 | def run(self, analyzed, analyzed_dict, context): 151 | context.append(analyzed) 152 | tool_calls = analyzed_dict['tool_calls'] 153 | for tool_call in tool_calls: 154 | function = tool_call["function"] 155 | func_name = function["name"] 156 | func_to_call = self.available_functions[func_name] 157 | try: 158 | func_args = json.loads(function["arguments"]) 159 | # 챗GPT가 알려주는 매개변수명과 값을 입력값으로하여 실제 함수를 호출한다. 160 | func_response = func_to_call(**func_args) 161 | context.append({ 162 | "tool_call_id": tool_call["id"], 163 | "role": "tool", 164 | "name": func_name, 165 | "content": str(func_response) 166 | }) 167 | except Exception as e: 168 | print("Error occurred(run):",e) 169 | return makeup_response("[run 오류입니다]") 170 | 171 | return client.chat.completions.create(model=self.model,messages=context).model_dump() -------------------------------------------------------------------------------- /contents/chapter13/memory_manager.py: -------------------------------------------------------------------------------- 1 | from pymongo import MongoClient 2 | import os 3 | from common import client, model, today, yesterday, currTime 4 | import pinecone 5 | import json 6 | 7 | pinecone.init(api_key=os.getenv("PINECONE_API_KEY"), environment="gcp-starter") 8 | pinecone_index = pinecone.Index("jjinchin-memory") 9 | 10 | mongo_cluster = MongoClient(os.getenv("MONGO_CLUSTER_URI")) 11 | mongo_chats_collection = mongo_cluster["jjinchin"]["chats"] 12 | mongo_memory_collection = mongo_cluster["jjinchin"]["memory"] 13 | embedding_model = "text-embedding-ada-002" 14 | 15 | 16 | # 아래 사용자 질의가 오늘 이전의 기억에 대해 묻는 것인지 참/거짓으로만 응답하세요. 17 | NEEDS_MEMORY_TEMPLATE = """ 18 | Answer only true/false if the user query below asks about memories before today. 19 | ``` 20 | {message} 21 | """ 22 | 23 | # statement1은 기억에 대한 질문입니다. 24 | # statement2는 민지와 고비가 공유하는 기억입니다. 25 | # statment2는 statement1에 대한 가억으로 적절한지 아래 json 포맷으로 답하세요 26 | # {"0과 1 사이의 확률": <확률값>} 27 | MEASURING_SIMILARITY_SYSTEM_ROLE = """ 28 | statement1 is a question about memory. 29 | statement2 is a memory shared by '민지' and '고비'. 30 | Answer whether statement2 is appropriate as a memory for statement1 in the following JSON format 31 | {"probability": } 32 | """ 33 | 34 | SUMMARIZING_TEMPLATE = """ 35 | 당신은 사용자의 메시지를 아래의 JSON 형식으로 대화 내용을 주제별로 요약하는 기계입니다. 36 | 1. 주제는 구체적이며 의미가 있는 것이어야 합니다. 37 | 2. 요약 내용에는 '민지는...', '고비는...'처럼 대화자의 이름이 들어가야 합니다. 38 | 3. 원문을 최대한 유지하며 요약해야 합니다. 39 | 4. 주제의 갯수는 무조건 5개를 넘지 말아야 하며 비슷한 내용은 하나로 묶어야 합니다. 40 | ``` 41 | { 42 | "data": 43 | [ 44 | {"주제":<주제>, "요약":<요약>}, 45 | {"주제":<주제>, "요약":<요약>}, 46 | ] 47 | } 48 | """ 49 | 50 | class MemoryManager: 51 | 52 | def __init__(self, **kwargs): 53 | self.user = kwargs["user"] 54 | self.assistant = kwargs["assistant"] 55 | 56 | def search_mongo_db(self, _id): 57 | search_result = mongo_memory_collection.find_one({"_id": int(_id)}) 58 | print("search_result", search_result) 59 | return search_result["summary"] 60 | 61 | def search_vector_db(self, message): 62 | query_vector = client.embeddings.create(input=message, model=embedding_model).data[0].embedding 63 | results = pinecone_index.query( 64 | top_k=1, 65 | vector=query_vector, 66 | include_metadata=True, 67 | ) 68 | id, score = results['matches'][0]['id'], results['matches'][0]['score'] 69 | print("id",id, "score",score) 70 | return id if score > 0.7 else None 71 | 72 | def filter(self, message, memory, threshhold=0.6): 73 | context = [ 74 | {"role": "system", "content": MEASURING_SIMILARITY_SYSTEM_ROLE}, 75 | {"role": "user", "content": f'{{"statement1": "민지:{message}, "statement2": {memory}}}'} 76 | ] 77 | try: 78 | response = client.chat.completions.create( 79 | model=model.advanced, #gpt-4-1106-preview 80 | messages=context, 81 | temperature=0, 82 | response_format={"type":"json_object"} 83 | ).model_dump() 84 | prob = json.loads(response['choices'][0]['message']['content'])['probability'] 85 | print("filter prob", prob) 86 | except Exception as e: 87 | print("filter error", e) 88 | prob = 0 89 | return prob >= threshhold 90 | 91 | def retrieve_memory(self, message): 92 | vector_id = self.search_vector_db(message) 93 | if not vector_id: 94 | return None 95 | memory = self.search_mongo_db(vector_id) 96 | if self.filter(message, memory): 97 | return memory 98 | else: 99 | return None 100 | 101 | def needs_memory(self, message): 102 | context = [{"role": "user", "content": NEEDS_MEMORY_TEMPLATE.format(message=message)}] 103 | try: 104 | response = client.chat.completions.create( 105 | model=model.advanced, #gpt-4-1106-preview 106 | messages=context, 107 | temperature=0, 108 | ).model_dump() 109 | print("needs_memory", response['choices'][0]['message']['content']) 110 | return True if response['choices'][0]['message']['content'].upper() == "TRUE" else False 111 | except Exception: 112 | return False 113 | 114 | def save_chat(self, context): 115 | messages = [] 116 | for message in context: 117 | if message.get("saved", True): 118 | continue 119 | messages.append({"date":today(), "role": message["role"], "content": message["content"]}) 120 | 121 | if len(messages) > 0: 122 | mongo_chats_collection.insert_many(messages) 123 | 124 | def restore_chat(self, date=None): 125 | search_date = date if date is not None else today() 126 | search_results = mongo_chats_collection.find({"date": search_date}) 127 | restored_chat = [{"role": v['role'], "content": v['content'], "saved": True} for v in search_results] 128 | return restored_chat 129 | 130 | def summarize(self, messages): 131 | altered_messages = [ 132 | { 133 | f"{self.user if message['role'] == 'user' else self.assistant}": message["content"] 134 | } 135 | for message in messages 136 | ] 137 | try: 138 | context = [{"role": "system", "content": SUMMARIZING_TEMPLATE}, 139 | {"role": "user", "content": json.dumps(altered_messages, ensure_ascii=False)}] 140 | response = client.chat.completions.create( 141 | model=model.basic, 142 | messages=context, 143 | temperature=0, 144 | response_format={"type": "json_object"} 145 | ).model_dump() 146 | return json.loads(response['choices'][0]['message']['content'])["data"] 147 | except Exception: 148 | return [] 149 | 150 | def delete_by_date(self, date): 151 | search_results = mongo_memory_collection.find({"date": date}) 152 | ids = [ str(v['_id']) for v in search_results] 153 | if len(ids) == 0: 154 | return 155 | pinecone_index.delete(ids=ids) 156 | mongo_memory_collection.delete_many({"date":date}) 157 | 158 | def save_to_memory(self, summaries, date): 159 | next_id = self.next_memory_id() 160 | for summary in summaries: 161 | vector = client.embeddings.create( 162 | input=summary["요약"], 163 | model=embedding_model 164 | ).data[0].embedding 165 | metadata = {"date": date, "keyword": summary["주제"]} 166 | pinecone_index.upsert([(str(next_id), vector, metadata)]) 167 | 168 | query = {"_id": next_id} #조회조건 169 | newvalues = {"$set": {"date": date, "keyword": summary["주제"], "summary" : summary["요약"]}} 170 | mongo_memory_collection.update_one(query, newvalues, upsert=True) 171 | next_id += 1 172 | 173 | def next_memory_id(self): 174 | result = mongo_memory_collection.find_one(sort=[('_id', -1)]) 175 | return 1 if result is None else result['_id'] + 1 176 | 177 | def build_memory(self): 178 | # print(f"{currTime()}: build_memory started...") 179 | date = yesterday() 180 | #date = today() # 테스트 용도 181 | memory_results = mongo_memory_collection.find({"date": date}) 182 | if len(list(memory_results)) > 0: 183 | return 184 | chats_results = self.restore_chat(date) 185 | if len(list(chats_results)) == 0: 186 | return 187 | summaries = self.summarize(chats_results) 188 | self.delete_by_date(date) 189 | self.save_to_memory(summaries, date) 190 | 191 | 192 | -------------------------------------------------------------------------------- /contents/chapter10/function_calling.py: -------------------------------------------------------------------------------- 1 | from common import client, makeup_response 2 | import json 3 | import requests 4 | from pprint import pprint 5 | from tavily import TavilyClient 6 | import os 7 | tavily = TavilyClient(api_key=os.getenv("TAVILY_API_KEY")) 8 | 9 | #위도 경도 10 | global_lat_lon = { 11 | '서울':[37.57,126.98],'강원도':[37.86,128.31],'경기도':[37.44,127.55], 12 | '경상남도':[35.44,128.24],'경상북도':[36.63,128.96],'광주':[35.16,126.85], 13 | '대구':[35.87,128.60],'대전':[36.35,127.38],'부산':[35.18,129.08], 14 | '세종시':[36.48,127.29],'울산':[35.54,129.31],'전라남도':[34.90,126.96], 15 | '전라북도':[35.69,127.24],'제주도':[33.43,126.58],'충청남도':[36.62,126.85], 16 | '충청북도':[36.79,127.66],'인천':[37.46,126.71], 17 | 'Boston':[42.36, -71.05], 18 | '도쿄':[35.68, 139.69] 19 | } 20 | 21 | #화폐 코드 22 | global_currency_code = {'달러':'USD','엔화':'JPY','유로화':'EUR','위안화':'CNY','파운드':'GBP'} 23 | 24 | def get_celsius_temperature(**kwargs): 25 | location = kwargs['location'] 26 | lat_lon = global_lat_lon.get(location, None) 27 | if lat_lon is None: 28 | return None 29 | lat = lat_lon[0] 30 | lon = lat_lon[1] 31 | 32 | # API endpoint 33 | url = f"https://api.open-meteo.com/v1/forecast?latitude={lat}&longitude={lon}¤t_weather=true" 34 | 35 | # API를 호출하여 데이터 가져오기 36 | response = requests.get(url) 37 | # 응답을 JSON 형태로 변환 38 | data = response.json() 39 | # 현재 온도 가져오기 (섭씨) 40 | temperature = data['current_weather']['temperature'] 41 | 42 | print("temperature:",temperature) 43 | return temperature 44 | 45 | def get_currency(**kwargs): 46 | currency_name = kwargs['currency_name'] 47 | currency_name = currency_name.replace("환율", "") 48 | currency_code = global_currency_code.get(currency_name, 'USD') 49 | 50 | if currency_code is None: 51 | return None 52 | 53 | response = requests.get(f"https://api.exchangerate-api.com/v4/latest/{currency_code}") 54 | data = response.json() 55 | krw = data['rates']['KRW'] 56 | 57 | print("환율:", krw) 58 | return krw 59 | 60 | def search_internet(**kwargs): 61 | print("search_internet",kwargs) 62 | answer = tavily.search(query=kwargs['search_query'], include_answer=True)['answer'] 63 | print("answer",answer) 64 | return answer 65 | 66 | def search_internet_for_report(**kwargs): 67 | print("search_internet",kwargs) 68 | response = tavily.search(query=kwargs['search_query'], max_results=2, search_depth="advanced") 69 | contents = [{"content": result['content'], "url": result['url']} 70 | for result in response['results']] 71 | print("contents",contents) 72 | return f"수집된 자료:{contents}" 73 | 74 | report_system_role = """ 75 | 다음 내용을 바탕으로 보고서를 한국어로 작성해주세요. 보고서 작성 시 url을 각주로 반드시 표시하세요. 76 | """ 77 | def write_report(**kwargs): 78 | print("write_report",kwargs) 79 | response = client.chat.completions.create( 80 | timeout=90, 81 | model="gpt-4-1106-preview", 82 | messages=[ 83 | {"role": "system", "content": report_system_role}, 84 | {"role": "user", "content": kwargs['materials']} 85 | ], 86 | ) 87 | report = response.model_dump()['choices'][0]['message']['content'] 88 | return report 89 | 90 | func_specs = [ 91 | { 92 | "name": "get_celsius_temperature", 93 | "description": "지정된 위치의 현재 섭씨 날씨 확인", 94 | "parameters": { 95 | "type": "object", 96 | "properties": { 97 | "location": { 98 | "type": "string", 99 | "description": "광역시도, e.g. 서울, 경기", 100 | } 101 | }, 102 | "required": ["location"], 103 | }, 104 | }, 105 | { 106 | "name": "get_currency", 107 | "description": "지정된 통화의 원(KRW) 기준의 환율 확인.", 108 | "parameters": { 109 | "type": "object", 110 | "properties": { 111 | "currency_name": { 112 | "type": "string", 113 | "description": "통화명, e.g. 달러환율, 엔화환율", 114 | } 115 | }, 116 | "required": ["currency_name"], 117 | }, 118 | }, 119 | { 120 | "name": "search_internet", 121 | "description": "답변 시 인터넷 검색이 필요하다고 판단되는 경우 수행", 122 | "parameters": { 123 | "type": "object", 124 | "properties": { 125 | "search_query": { 126 | "type": "string", 127 | "description": "인터넷 검색을 위한 검색어", 128 | } 129 | }, 130 | "required": ["search_query"], 131 | } 132 | } 133 | ] 134 | 135 | func_specs_report = [ 136 | { 137 | "name": "search_internet_for_report", 138 | "description": "자료를 찾기 위해 인터넷을 검색하는 함수", 139 | "parameters": { 140 | "type": "object", 141 | "properties": { 142 | "search_query": { 143 | "type": "string", 144 | "description": "인터넷 검색을 위한 검색어", 145 | } 146 | }, 147 | "required": ["search_query"], 148 | }, 149 | }, 150 | { 151 | "name": "write_report", 152 | "description": "수집된 정보를 바탕으로 보고서를 작성해주는 함수", 153 | "parameters": { 154 | "type": "object", 155 | "properties": { 156 | "materials": { 157 | "type": "string", 158 | "description": "사용자 메시지 중 '수집된 자료:' 리스트 안에 있는 raw data", 159 | } 160 | }, 161 | "required": ["materials"], 162 | }, 163 | } 164 | ] 165 | 166 | 167 | class FunctionCalling: 168 | 169 | def __init__(self, model): 170 | self.available_functions = { 171 | "get_celsius_temperature": get_celsius_temperature, 172 | "get_currency": get_currency, 173 | "search_internet": search_internet, 174 | "search_internet_for_report": search_internet_for_report, 175 | "write_report": write_report 176 | } 177 | self.model = model 178 | 179 | 180 | def analyze(self, user_message, func_specs): 181 | try: 182 | response = client.chat.completions.create( 183 | model=self.model, 184 | messages=[{"role": "user", "content": user_message}], 185 | functions=func_specs, 186 | function_call="auto", 187 | ) 188 | message = response.choices[0].message 189 | message_dict = message.model_dump() 190 | pprint(("message_dict=>", message_dict)) 191 | return message_dict 192 | except Exception as e: 193 | print("Error occurred(analyze):",e) 194 | return makeup_response("[analyze 오류입니다]") 195 | 196 | 197 | def run(self, analyzed_dict, context): 198 | func_name = analyzed_dict["function_call"]["name"] 199 | func_to_call = self.available_functions[func_name] 200 | try: 201 | func_args = json.loads(analyzed_dict["function_call"]["arguments"]) 202 | # 챗GPT가 알려주는 매개변수명과 값을 입력값으로하여 실제 함수를 호출한다. 203 | func_response = func_to_call(**func_args) 204 | context.append({ 205 | "role": "function", 206 | "name": func_name, 207 | "content": str(func_response) 208 | }) 209 | return client.chat.completions.create(model=self.model,messages=context).model_dump() 210 | except Exception as e: 211 | print("Error occurred(run):",e) 212 | return makeup_response("[run 오류입니다]") 213 | 214 | 215 | def call_function(self, analyzed_dict): 216 | func_name = analyzed_dict["function_call"]["name"] 217 | func_to_call = self.available_functions[func_name] 218 | try: 219 | func_args = json.loads(analyzed_dict["function_call"]["arguments"]) 220 | func_response = func_to_call(**func_args) 221 | return str(func_response) 222 | except Exception as e: 223 | print("Error occurred(call_function):",e) 224 | return makeup_response("[call_function 오류입니다]") --------------------------------------------------------------------------------