├── lesson7 ├── lesson7_2.py ├── bear.jpg ├── lesson7_1.ipynb └── lesson7_3.ipynb ├── lesson4 ├── README.md ├── lesson4_2.py └── lesson4_1.ipynb ├── lesson9 ├── .gitignore ├── requirements.txt └── main.py ├── .gitignore ├── lesson3 ├── lesson3_1.py └── lesson3_2.ipynb ├── requirements.txt ├── README.md ├── lesson6 ├── lesson6_2.ipynb ├── lesson6_5.py ├── lesson6_3.py ├── lesson6_1.ipynb ├── lesson6_4.ipynb └── lesson6_5.ipynb ├── .vscode └── .settings.json ├── lesson8 ├── lesson8_1.py ├── lesson8_4.py ├── lesson8_3.py ├── lesson8_2.py ├── lesson8_2_ai.py ├── lesson8_5.py ├── lesson8_6.py ├── lesson8_7.py ├── lesson8_7_ai.py └── lesson8_7.md ├── demo ├── demo2.py ├── demo2_generate_mode.py ├── demo3.py ├── demo3_chat_mode.py └── demo1.ipynb ├── link └── README.md ├── reference ├── ollama.md └── python_ollama_applications.md ├── gemini └── lesson1_1.ipynb └── lesson5 └── lesson5_1.ipynb /lesson7/lesson7_2.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lesson4/README.md: -------------------------------------------------------------------------------- 1 | ### 安裝Conda -------------------------------------------------------------------------------- /lesson9/.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | __pycache__ -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | .gradio 3 | __pycache__ -------------------------------------------------------------------------------- /lesson3/lesson3_1.py: -------------------------------------------------------------------------------- 1 | print("Hello! Python!") -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | google-genai 2 | python-dotenv 3 | ipywidgets 4 | Pillow 5 | gradio 6 | -------------------------------------------------------------------------------- /lesson9/requirements.txt: -------------------------------------------------------------------------------- 1 | google-genai 2 | python-dotenv 3 | Flask 4 | gunicorn 5 | line-bot-sdk 6 | requests -------------------------------------------------------------------------------- /lesson7/bear.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roberthsu2003/__2025_06_28_chihlee_linebot__/HEAD/lesson7/bear.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # __2025_06_28_chihlee_linebot__ 2 | 3 | ## 上課連結 4 | https://meet.google.com/fww-fmvd-xoy 5 | 6 | 致理lineBot 7 | -------------------------------------------------------------------------------- /lesson6/lesson6_2.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [], 3 | "metadata": { 4 | "language_info": { 5 | "name": "python" 6 | } 7 | }, 8 | "nbformat": 4, 9 | "nbformat_minor": 5 10 | } 11 | -------------------------------------------------------------------------------- /.vscode/.settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "chat.mcp.enabled": true, 3 | "chat.mcp.discovery.enabled": true, 4 | "chat.mcp.serverSampling": [ 5 | "gpt-4", 6 | "gpt-3.5-turbo" 7 | ] 8 | } -------------------------------------------------------------------------------- /lesson6/lesson6_5.py: -------------------------------------------------------------------------------- 1 | from google import genai 2 | 3 | # The client gets the API key from the environment variable `GEMINI_API_KEY`. 4 | client = genai.Client() 5 | 6 | response = client.models.generate_content( 7 | model="gemini-2.5-flash", contents="天空為什麼是藍的?" 8 | ) 9 | print(response.text) -------------------------------------------------------------------------------- /lesson8/lesson8_1.py: -------------------------------------------------------------------------------- 1 | import gradio as gr 2 | 3 | def greet(name, intensity): 4 | return name + "您好" + "!" * int(intensity) 5 | 6 | demo = gr.Interface( 7 | inputs=["text", "slider"], 8 | outputs=["text"], 9 | fn=greet 10 | ) 11 | 12 | demo.launch(share=True) 13 | -------------------------------------------------------------------------------- /lesson8/lesson8_4.py: -------------------------------------------------------------------------------- 1 | import gradio as gr 2 | 3 | with gr.Blocks() as demo: 4 | gr.Markdown(""" 5 | # 歡迎使用 Gradio 6 | 請輸入文字,會即時顯示輸入的內容。 7 | """) 8 | input_textbox = gr.Textbox(placeholder="請輸入文字", label="輸入框") 9 | output_textbox = gr.Textbox(label="輸出框", placeholder="輸入的內容會顯示在這裡") 10 | 11 | @input_textbox.change(inputs=[input_textbox], outputs=[output_textbox]) 12 | def update_output(text): 13 | return text 14 | 15 | demo.launch() -------------------------------------------------------------------------------- /lesson4/lesson4_2.py: -------------------------------------------------------------------------------- 1 | # list 2 | fruits = ["apple", "banana", "cherry"] 3 | fruits.append("orange") # 新增元素 4 | fruits.append("grape") # 再新增一個元素 5 | fruits.append("watermelon") 6 | fruits.append("pineapple") 7 | fruits.append("mango") 8 | fruits.append("kiwi") 9 | fruits.append("strawberry") 10 | fruits.append("blueberry") 11 | fruits.append("peach") 12 | fruits.append("pear") 13 | fruits.append("plum") 14 | fruits.append("lemon") 15 | print(type(fruits)) 16 | print("水果清單:", fruits) -------------------------------------------------------------------------------- /lesson8/lesson8_3.py: -------------------------------------------------------------------------------- 1 | ## Block 架構 2 | 3 | import gradio as gr 4 | 5 | 6 | 7 | with gr.Blocks() as demo: 8 | name_textbox = gr.Textbox(label="姓名",placeholder="請輸入姓名") 9 | output_textbox = gr.Textbox(label="輸出",placeholder="輸出結果會顯示在這裡") 10 | greet_button = gr.Button("打招呼") 11 | 12 | @greet_button.click( 13 | inputs=[name_textbox], 14 | outputs=[output_textbox] 15 | ) 16 | def greet(name): 17 | return name + "您好!" 18 | 19 | demo.launch() -------------------------------------------------------------------------------- /lesson8/lesson8_2.py: -------------------------------------------------------------------------------- 1 | ## Block 架構 2 | 3 | import gradio as gr 4 | 5 | def greet(name): 6 | return name + "您好!" 7 | 8 | with gr.Blocks() as demo: 9 | name_textbox = gr.Textbox(label="姓名",placeholder="請輸入姓名") 10 | output_textbox = gr.Textbox(label="輸出",placeholder="輸出結果會顯示在這裡") 11 | greet_button = gr.Button("打招呼") 12 | greet_button.click(fn=greet, 13 | inputs=[name_textbox], 14 | outputs=[output_textbox]) 15 | 16 | demo.launch() -------------------------------------------------------------------------------- /lesson8/lesson8_2_ai.py: -------------------------------------------------------------------------------- 1 | #建立一個gradio的Blocks的架構 2 | #功能: 3 | #1.建立姓名輸入框 4 | #2.建立輸出框 5 | #3.建立按鈕 6 | 7 | import gradio as gr 8 | 9 | def greet(name): 10 | return name + "您好!" 11 | 12 | with gr.Blocks() as demo: 13 | name_textbox = gr.Textbox(label="姓名",placeholder="請輸入姓名") 14 | output_textbox = gr.Textbox(label="輸出",placeholder="輸出結果會顯示在這裡") 15 | greet_button = gr.Button("打招呼") 16 | greet_button.click(fn=greet, 17 | inputs=[name_textbox], 18 | outputs=[output_textbox]) 19 | 20 | demo.launch() 21 | -------------------------------------------------------------------------------- /lesson3/lesson3_2.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "id": "87bd292d", 7 | "metadata": {}, 8 | "outputs": [ 9 | { 10 | "name": "stdout", 11 | "output_type": "stream", 12 | "text": [ 13 | "Hello! python!\n" 14 | ] 15 | } 16 | ], 17 | "source": [ 18 | "print(\"Hello! python!\")" 19 | ] 20 | } 21 | ], 22 | "metadata": { 23 | "kernelspec": { 24 | "display_name": "linebot", 25 | "language": "python", 26 | "name": "python3" 27 | }, 28 | "language_info": { 29 | "codemirror_mode": { 30 | "name": "ipython", 31 | "version": 3 32 | }, 33 | "file_extension": ".py", 34 | "mimetype": "text/x-python", 35 | "name": "python", 36 | "nbconvert_exporter": "python", 37 | "pygments_lexer": "ipython3", 38 | "version": "3.11.13" 39 | } 40 | }, 41 | "nbformat": 4, 42 | "nbformat_minor": 5 43 | } 44 | -------------------------------------------------------------------------------- /lesson8/lesson8_5.py: -------------------------------------------------------------------------------- 1 | import gradio as gr 2 | 3 | with gr.Blocks() as demo: 4 | a = gr.Number(label="數字A", value=0) 5 | b = gr.Number(label="數字B", value=0) 6 | 7 | with gr.Row(): 8 | add_button = gr.Button("加法") 9 | subtract_button = gr.Button("減法") 10 | multiply_button = gr.Button("乘法") 11 | divide_button = gr.Button("除法") 12 | 13 | c = gr.Number(label="結果", value=0) 14 | 15 | @add_button.click(inputs=[a, b], outputs=[c]) 16 | def add_numbers(a, b): 17 | return a + b 18 | 19 | @subtract_button.click(inputs=[a, b], outputs=[c]) 20 | def subtract_numbers(a, b): 21 | return a - b 22 | 23 | @multiply_button.click(inputs=[a, b], outputs=[c]) 24 | def multiply_numbers(a, b): 25 | return a * b 26 | 27 | @divide_button.click(inputs=[a, b], outputs=[c]) 28 | def divide_numbers(a, b): 29 | return a / b 30 | 31 | demo.launch() 32 | -------------------------------------------------------------------------------- /lesson8/lesson8_6.py: -------------------------------------------------------------------------------- 1 | import gradio as gr 2 | from google import genai 3 | 4 | client = genai.Client() 5 | 6 | #建立gradio Blocks架構 7 | with gr.Blocks() as demo: 8 | gr.Markdown("## 公司內部機器人") 9 | #建立輸入框 10 | input_text = gr.Textbox(label="請輸入訊息", placeholder="請輸入問題", submit_btn=True) 11 | 12 | #建立gradio.Accordion 13 | with gr.Accordion("**懶的輸入可以點選以下問題**", open=True): 14 | gr.Examples( 15 | examples=[ 16 | "請問台灣的首都是哪裡?", 17 | "請問台灣的國土面積有多大?", 18 | "請問台灣的人口有多少?" 19 | ], 20 | inputs=input_text 21 | ) 22 | 23 | #建立輸出框 24 | output_text = gr.Textbox( 25 | label="機器人回覆", 26 | placeholder="機器人會在這裡回答你的問題", 27 | interactive=False) 28 | 29 | @input_text.submit(inputs=[input_text],outputs=[output_text]) 30 | def respond(message): 31 | # 在這裡處理用戶輸入的訊息 32 | response = client.models.generate_content( 33 | model="gemini-2.5-flash", 34 | contents=[message] 35 | ) 36 | return response.text 37 | 38 | demo.launch() -------------------------------------------------------------------------------- /demo/demo2.py: -------------------------------------------------------------------------------- 1 | from google import genai 2 | import os 3 | import gradio as gr 4 | from dotenv import load_dotenv 5 | 6 | load_dotenv() 7 | 8 | client = genai.Client(api_key=os.environ["GEMINI_API_KEY"]) 9 | 10 | with gr.Blocks(title="Example") as demo: 11 | gr.Markdown("# Zero-shot Text Generation") 12 | 13 | input_text = gr.Textbox( 14 | label="prompt", 15 | placeholder="請輸入問題", 16 | submit_btn=True 17 | ) 18 | with gr.Accordion("**懶的輸入可以點選以下問題**",open=False): 19 | gr.Examples( 20 | examples=["請問台灣的首都是哪裡?", "請問台灣的國土面積有多大?", "請問台灣的人口有多少?"], 21 | label="問題範例", 22 | inputs=input_text) 23 | output_text = gr.Markdown() 24 | 25 | @input_text.submit(inputs=input_text, outputs=[input_text,output_text]) 26 | def generate_text(input_str:str): 27 | response = client.models.generate_content( 28 | model="gemini-2.5-flash", 29 | contents=input_str 30 | ) 31 | return (None, f"## {input_str}\n" + response.text) 32 | 33 | demo.launch(share=True) -------------------------------------------------------------------------------- /link/README.md: -------------------------------------------------------------------------------- 1 | ## 2025_07_12_早上 2 | https://youtube.com/live/CN1Ud99FHDM 3 | 4 | ## 2025_07_12_下午 5 | https://youtube.com/live/IhlUEwWw-HA 6 | 7 | --- 8 | 9 | ## 2025_07_19_早上 10 | https://www.youtube.com/watch?v=8byz2RGzH1c 11 | 12 | ## 2025_07_19_下午 13 | https://www.youtube.com/watch?v=bE_iEEV9Bg4 14 | 15 | --- 16 | 17 | ## 2025_07_26_早上 18 | https://www.youtube.com/watch?v=UkP_4G9uAUc 19 | 20 | ## 2025_07_26_下午 21 | https://www.youtube.com/watch?v=bgpmvy_gbPo 22 | 23 | --- 24 | 25 | 26 | 27 | ## 2025_08_02_上午 28 | https://www.youtube.com/watch?v=-vfA_Jz5Zrk 29 | 30 | ## 2025_08_02_下午 31 | https://www.youtube.com/watch?v=-o9FCMFe_ZM 32 | 33 | --- 34 | 35 | ## 2025_08_09_上午 36 | https://www.youtube.com/watch?v=QS0CHVzTT5U 37 | 38 | ## 2025_08_09_下午 39 | https://www.youtube.com/watch?v=PdqAZNaJBRA 40 | 41 | --- 42 | 43 | ## 2025_08_16_早上 44 | https://youtube.com/live/XRZgOCPL9uI 45 | 46 | ## 2025_08_16_下午 47 | https://www.youtube.com/watch?v=tfNwExmerDM 48 | 49 | --- 50 | 51 | ## 2025_08_23_早上 52 | https://www.youtube.com/watch?v=o6sgxfzpooA 53 | 54 | ## 2025_08_23_下午 55 | https://www.youtube.com/watch?v=Gj1Zt1czEY0 56 | -------------------------------------------------------------------------------- /demo/demo2_generate_mode.py: -------------------------------------------------------------------------------- 1 | import requests 2 | def chat_with_ollama(prompt: str): 3 | url = "http://localhost:11434/api/generate" 4 | payload = { 5 | "model": "gemma3:1b", 6 | "prompt": prompt, 7 | "stream": False, 8 | "options": { #參考說明1 9 | "temperature": 0.7, 10 | "top_p": 0.9, 11 | "top_k": 50, 12 | }, 13 | "max_tokens": 100, 14 | "format": "json", 15 | } 16 | 17 | response = requests.post(url, json=payload) 18 | result = response.json() 19 | print("💬 AI 回應:") 20 | # Print the whole result for debugging 21 | #print(result) 22 | # Try to print the 'response' key if it exists, otherwise print possible keys 23 | if "response" in result: 24 | print(result["response"]) 25 | elif "message" in result: 26 | print(result["message"]) 27 | elif "content" in result: 28 | print(result["content"]) 29 | else: 30 | print("No expected key found in response. Available keys:", result.keys()) 31 | 32 | 33 | def chat_loop(): 34 | print("歡迎使用本地端 LLM 聊天機器人(輸入 q 離開)") 35 | while True: 36 | user_input = input("👤 你說:") 37 | if user_input.lower() == 'q': 38 | break 39 | chat_with_ollama(user_input) 40 | 41 | chat_loop() -------------------------------------------------------------------------------- /lesson8/lesson8_7.py: -------------------------------------------------------------------------------- 1 | import gradio as gr 2 | from google import genai 3 | from google.genai import types 4 | 5 | client = genai.Client() 6 | 7 | with gr.Blocks() as demo: 8 | gr.Markdown("## Text to Summarization(總結)") 9 | style_radio = gr.Radio(choices=['小學','商業','專業','口語化','條列式'], label="風格",value="口語化") 10 | input_text = gr.Textbox( 11 | label="請輸入文章", 12 | lines=10, 13 | submit_btn=True 14 | ) 15 | output_md = gr.Markdown() 16 | 17 | @input_text.submit(inputs=[style_radio, input_text], outputs=[output_md]) 18 | def summarize(style, text): 19 | if style=="口語化": 20 | style = "請使用口語化的風格\n" 21 | elif style == "小學": 22 | style = "請使用小學生看的懂的語法\n" 23 | elif style == "商業": 24 | style = "請使用商業文章的風格\n" 25 | elif style == "條列式": 26 | style = "請條列式重點\n" 27 | elif style == "專業": 28 | style = "請使用專業的風格\n" 29 | 30 | response = client.models.generate_content( 31 | model="gemini-2.5-flash", 32 | config= types.GenerateContentConfig( 33 | system_instruction=f""" 34 | 你是一個專業的總結助手,也是一個繁體中文的高手,請根據用戶提供的文章內容進行總結。 35 | 你需要根據用戶選擇的風格進行總結,並且確保總結的內容清晰、簡潔且易於理解。 36 | 目前使用者選擇的是{style}。 37 | 38 | 所有的回覆必需是markdown的語法 39 | """ 40 | ), 41 | contents = [text] 42 | ) 43 | 44 | summary = f"風格: {style}\n\n{response.text}" 45 | return summary 46 | 47 | demo.launch() 48 | -------------------------------------------------------------------------------- /lesson8/lesson8_7_ai.py: -------------------------------------------------------------------------------- 1 | import gradio as gr 2 | from google import genai 3 | from google.genai import types 4 | 5 | client = genai.Client() 6 | 7 | with gr.Blocks() as demo: 8 | gr.Markdown("## Text to Summarization(總結)") 9 | style_radio = gr.Radio(choices=['小學','商業','專業','口語化','條列式'], label="風格",value="口語化") 10 | input_text = gr.Textbox( 11 | label="請輸入文章", 12 | lines=10, 13 | submit_btn=True 14 | ) 15 | output_md = gr.Markdown() 16 | 17 | @input_text.submit(inputs=[style_radio, input_text], outputs=[output_md]) 18 | def summarize(style, text): 19 | if style=="口語化": 20 | style = "請使用口語化的風格\n" 21 | elif style == "小學": 22 | style = "請使用小學生看的懂的語法\n" 23 | elif style == "商業": 24 | style = "請使用商業文章的風格\n" 25 | elif style == "條列式": 26 | style = "請條列式重點\n" 27 | elif style == "專業": 28 | style = "請使用專業的風格\n" 29 | 30 | response = client.models.generate_content_stream( 31 | model="gemini-2.5-flash", 32 | config= types.GenerateContentConfig( 33 | system_instruction=f""" 34 | 你是一個專業的總結助手,也是一個繁體中文的高手,請根據用戶提供的文章內容進行總結。 35 | 你需要根據用戶選擇的風格進行總結,並且確保總結的內容清晰、簡潔且易於理解。 36 | 目前使用者選擇的是{style}。 37 | 38 | 所有的回覆必需是markdown的語法 39 | """ 40 | ), 41 | contents = [text] 42 | ) 43 | 44 | summary = f"風格: {style}\n\n" 45 | for chunk in response: 46 | if chunk.text: 47 | summary += chunk.text 48 | yield summary 49 | 50 | demo.launch() 51 | -------------------------------------------------------------------------------- /reference/ollama.md: -------------------------------------------------------------------------------- 1 | # 本地端 LLM 教學範例 2 | 3 | 使用 requests 模組與 Ollama 本地 HTTP API 溝通。 4 | 5 | --- 6 | 7 | ## 基礎前提 8 | 9 | - 確保 Ollama 正在執行,並且模型已經被拉下來(例如:ollama run gemma:1b 已經執行過一次) 10 | - Ollama API 預設會在 `http://localhost:11434` 提供服務。 11 | 12 | --- 13 | 14 | ## 安裝必要套件 15 | 16 | 如果還沒安裝,請執行: 17 | 18 | ```bash 19 | 20 | pip install requests 21 | ``` 22 | 23 | --- 24 | 25 | ## 範例 1:發送基本對話請求給 Gemma 模型 26 | 27 | ```python 28 | 29 | import requests 30 | 31 | def chat_with_ollama(prompt: str): 32 | url = "http://localhost:11434/api/generate" 33 | payload = { 34 | "model": "gemma3:2b", 35 | "prompt": prompt, 36 | "stream": False 37 | } 38 | 39 | response = requests.post(url, json=payload) 40 | result = response.json() 41 | print("💬 AI 回應:") 42 | print(result["response"]) 43 | 44 | # 範例輸入 45 | chat_with_ollama("請用簡單的方式解釋什麼是Python的函式?") 46 | ``` 47 | 48 | --- 49 | 50 | ## 範例 2:建立一個簡單的聊天互動(CLI 聊天機器人) 51 | 52 | ```python 53 | 54 | def chat_loop(): 55 | print("歡迎使用本地端 LLM 聊天機器人(輸入 q 離開)") 56 | while True: 57 | user_input = input("👤 你說:") 58 | if user_input.lower() == 'q': 59 | break 60 | chat_with_ollama(user_input) 61 | 62 | chat_loop() 63 | ``` 64 | 65 | --- 66 | 67 | ## 範例 3:包裝成函式,供 Web 或 GUI 使用 68 | 69 | 這個結構更容易擴展為 Flask、Streamlit 等應用: 70 | 71 | ```python 72 | def generate_response(prompt: str, model: str = "gemma3:1b") -> str: 73 | url = "http://localhost:11434/api/generate" 74 | payload = { 75 | "model": model, 76 | "prompt": prompt, 77 | "stream": False 78 | } 79 | try: 80 | response = requests.post(url, json=payload) 81 | return response.json()["response"] 82 | except Exception as e: 83 | return f"錯誤:{e}" 84 | ``` 85 | 86 | 87 | -------------------------------------------------------------------------------- /lesson4/lesson4_1.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "49d73685", 6 | "metadata": {}, 7 | "source": [ 8 | "### python 儲存資料\n", 9 | "- 變數\n", 10 | "- list\n", 11 | "- dict" 12 | ] 13 | }, 14 | { 15 | "cell_type": "code", 16 | "execution_count": 8, 17 | "id": "39c547fd", 18 | "metadata": {}, 19 | "outputs": [ 20 | { 21 | "name": "stdout", 22 | "output_type": "stream", 23 | "text": [ 24 | "建立變數\n", 25 | "變數內容:Python\n", 26 | "變數類型:-\n", 27 | "變數長度:*6\n" 28 | ] 29 | } 30 | ], 31 | "source": [ 32 | "print(\"建立變數\")\n", 33 | "name = \"Python\"\n", 34 | "print(\"變數內容:\", name, sep=\"\")\n", 35 | "print(\"變數類型:\", type(name), sep=\"-\")\n", 36 | "print(\"變數長度:\", len(name), sep=\"*\")" 37 | ] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "execution_count": null, 42 | "id": "6c34e6ab", 43 | "metadata": {}, 44 | "outputs": [ 45 | { 46 | "name": "stdout", 47 | "output_type": "stream", 48 | "text": [ 49 | "1 | 5.0 | Hello | True.\n" 50 | ] 51 | } 52 | ], 53 | "source": [ 54 | "print(1, 5.0, \"Hello\", True, end=\".\\n\", sep=\" | \")" 55 | ] 56 | } 57 | ], 58 | "metadata": { 59 | "kernelspec": { 60 | "display_name": "line_bot", 61 | "language": "python", 62 | "name": "python3" 63 | }, 64 | "language_info": { 65 | "codemirror_mode": { 66 | "name": "ipython", 67 | "version": 3 68 | }, 69 | "file_extension": ".py", 70 | "mimetype": "text/x-python", 71 | "name": "python", 72 | "nbconvert_exporter": "python", 73 | "pygments_lexer": "ipython3", 74 | "version": "3.12.11" 75 | } 76 | }, 77 | "nbformat": 4, 78 | "nbformat_minor": 5 79 | } 80 | -------------------------------------------------------------------------------- /demo/demo3.py: -------------------------------------------------------------------------------- 1 | from google import genai 2 | from google.genai import types 3 | import os 4 | import gradio as gr 5 | from dotenv import load_dotenv 6 | 7 | load_dotenv() 8 | 9 | client = genai.Client(api_key=os.environ["GEMINI_API_KEY"]) 10 | 11 | 12 | 13 | 14 | with gr.Blocks(title="Example") as demo: 15 | gr.Markdown("# Text To Summarization(總結)") 16 | style_radio = gr.Radio(['學術','商業','專業','口語化','條列式'],label='風格',info="請選擇總結風格",value='口語化') 17 | input_text = gr.Textbox( 18 | label="請輸入文章", 19 | lines=10, 20 | submit_btn=True 21 | ) 22 | output_md = gr.Markdown() 23 | 24 | @input_text.submit(inputs=[style_radio,input_text], outputs=[output_md]) 25 | def generate_text(style:str,input_str:str): 26 | if style=="口語化": 27 | style = "請使用口語化的風格\n" 28 | elif style == "學術": 29 | style = "請使用專業學術的風格\n" 30 | elif style == "商業": 31 | style = "請使用商業文章的風格\n" 32 | elif style == "條列式": 33 | style = "請條列式重點\n" 34 | response = client.models.generate_content( 35 | model="gemini-2.5-flash", 36 | contents=[input_str], 37 | config=types.GenerateContentConfig( 38 | system_instruction=f""" 39 | 你是一位文章的總結專家,也是一位繁體中文的高手。你的任務是: 40 | 1. 請將內容`總結` 41 | 2. {style} 42 | """ 43 | ) 44 | ) 45 | 46 | 47 | return f"{style}\n\n### 總結內容如下:\n" + response.text 48 | 49 | demo.launch(share=True) -------------------------------------------------------------------------------- /lesson6/lesson6_3.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import random 3 | 4 | def user_name_input(): 5 | parser = argparse.ArgumentParser(description="猜數字遊戲") 6 | parser.add_argument("-n", "--name",type=str, help = "姓名") 7 | args = parser.parse_args() 8 | 9 | if not args.name: 10 | name = input("請輸入姓名:") 11 | else: 12 | name = args.name 13 | return name 14 | 15 | def play_game(name,playCount): 16 | min = 1 17 | max = 100 18 | count = 0 19 | target = random.randint(min,max) 20 | print(target) 21 | print(f"========猜數字遊戲第{playCount}次=========\n\n") 22 | while(True): 23 | keyin = int(input(f"猜數字範圍{min}~{max}:")) 24 | count += 1 25 | if(keyin>=min and keyin<=max): 26 | if target == keyin: 27 | print(f"賓果!猜對了, 答案是:{target}") 28 | print(f"你共猜了{count}次\n") 29 | again = input("要繼續嗎?(y,n)") 30 | if again == "y": 31 | playCount += 1 32 | min = 1 33 | max = 100 34 | count = 0 35 | target = random.randint(min,max) 36 | print(target) 37 | print(f"========猜數字遊戲第{playCount}次=========\n\n") 38 | continue 39 | else: 40 | break 41 | elif(keyin > target): 42 | print(f"猜錯了!再小一點") 43 | max = keyin - 1 44 | else: 45 | print(f"猜錯了!再大一點") 46 | min = keyin + 1 47 | print(f"{name}已經猜{count}次\n") 48 | else: 49 | print("請輸入提示範圍內的數字\n") 50 | return playCount 51 | 52 | def main(): 53 | playCount = 1 54 | name = user_name_input() 55 | playCount = play_game(name,playCount) 56 | print(f"遊戲結束,{name}共玩了{playCount}次") 57 | 58 | if __name__ == "__main__": 59 | main() 60 | 61 | -------------------------------------------------------------------------------- /demo/demo3_chat_mode.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import json 3 | 4 | def chat_with_ollama(prompt: str): 5 | url = "http://localhost:11434/api/chat" 6 | payload = { 7 | "model": "gemma3:1b", 8 | "messages": [ 9 | { 10 | "role": "user", 11 | "content": prompt 12 | } 13 | ], 14 | "stream": True, 15 | "options": { 16 | "temperature": 0.7, 17 | "top_p": 0.9, 18 | "top_k": 50, 19 | } 20 | } 21 | 22 | print("💬 AI 回應:", end="", flush=True) 23 | 24 | try: 25 | response = requests.post(url, json=payload, stream=True) 26 | response.raise_for_status() 27 | 28 | for line in response.iter_lines(): 29 | if line: 30 | try: 31 | chunk = json.loads(line.decode('utf-8')) 32 | 33 | # 檢查是否有訊息內容 34 | if 'message' in chunk and 'content' in chunk['message']: 35 | content = chunk['message']['content'] 36 | print(content, end="", flush=True) 37 | 38 | # 檢查是否完成 39 | if chunk.get('done', False): 40 | print() # 換行 41 | break 42 | 43 | except json.JSONDecodeError: 44 | continue 45 | 46 | except requests.exceptions.RequestException as e: 47 | print(f"\n❌ 請求錯誤: {e}") 48 | except Exception as e: 49 | print(f"\n❌ 處理錯誤: {e}") 50 | 51 | def chat_loop(): 52 | print("歡迎使用本地端 LLM 聊天機器人(輸入 q 離開)") 53 | while True: 54 | user_input = input("👤 你說:") 55 | if user_input.lower() == 'q': 56 | break 57 | chat_with_ollama(user_input) 58 | print() # 空行分隔 59 | 60 | chat_loop() -------------------------------------------------------------------------------- /lesson8/lesson8_7.md: -------------------------------------------------------------------------------- 1 | # lesson8_7.py 說明 2 | 3 | ## 檔案用途 4 | 5 | 此檔案建立一個 Gradio 使用者介面,讓使用者輸入文字並選擇輸出風格(例如:口語化、小學、商業、條列式、專業),再呼叫外部模型(透過 `client.models.generate_content` 或相似 API)產生結果並以 Markdown 顯示。 6 | 7 | ## 主要元件 8 | 9 | - `style_radio`:風格選項。 10 | - `input_text`:使用者多行文字輸入欄位。 11 | - `output_md`:用於呈現模型回應的 Markdown 元件。 12 | - `summarize(style, text)`:由 `input_text.submit` 或按鈕觸發,將風格與文字組成 prompt,呼叫模型並回傳顯示結果。 13 | 14 | ## summarize 函式行為(摘要) 15 | 16 | 1. 根據 `style` 參數選擇相對應的提示語(prompt prefix),例如: 17 | - 口語化 -> `請使用口語化的風格\n` 18 | - 小學 -> `請使用小學生看的懂的語法\n` 19 | - 商業 -> `請使用商業文章的風格\n` 20 | - 條列式 -> `請條列式重點\n` 21 | - 專業 -> `請使用專業的風格\n` 22 | 2. 將風格提示與使用者 `text` 組合後,呼叫模型 API(如 `client.models.generate_content`)。 23 | 3. 將模型回傳內容顯示於 `output_md`。 24 | 25 | ## 注意事項 26 | 27 | - 風格名稱需與 UI 中顯示的值一致;建議在程式內使用 dict 映射來避免拼字或字符問題。 28 | - `client`(或其他模型連線物件)必須在程式中正確初始化,包含 API key、endpoint 等設定,否則會發生例外。 29 | - 模型呼叫可能耗時,建議加入載入狀態指示、timeout、重試與例外處理,並在 UI 顯示明確錯誤訊息。 30 | - 當接受使用者自由輸入並直接拼接到 prompt 時,需注意 prompt 注入風險與輸入安全性(視情境而定)。 31 | 32 | ## 改進建議 33 | 34 | - 使用映射表替換多重 if/elif,提高可維護性: 35 | 36 | ```python 37 | style_map = { 38 | "口語化": "請使用口語化的風格\n", 39 | "小學": "請使用小學生看的懂的語法\n", 40 | "商業": "請使用商業文章的風格\n", 41 | "條列式": "請條列式重點\n", 42 | "專業": "請使用專業的風格\n", 43 | } 44 | prompt = style_map.get(style, "") + text 45 | ``` 46 | 47 | - 將模型呼叫封裝成一個可注入的函式或物件,方便 unit test 時 mock 模型回應。 48 | - 若 UI 會公開部署,記得不要在程式中硬編 API key,改以環境變數或安全的設定檔載入。 49 | 50 | ## 執行與測試 51 | 52 | - 執行(假設 `lesson8_7.py` 會啟動 Gradio): 53 | 54 | ```bash 55 | python lesson8_7.py 56 | ``` 57 | 58 | - 測試要點: 59 | - 確認風格選項顯示正確且能選擇。 60 | - 輸入文字送出後 UI 有載入提示且最後顯示模型回應。 61 | - 當 `client` 未設定或 API 錯誤時,UI 應顯示錯誤訊息而非崩潰。 62 | 63 | ## 常見錯誤與排查 64 | 65 | - NameError: `client` 未定義 -> 檢查是否有正確初始化 client 或載入相關設定。 66 | - UI 無回應或卡住 -> 檢查模型呼叫是否為同步阻塞;增加非同步處理或顯示進度。 67 | - 輸出風格不正確 -> 檢查選單值是否與程式中比對的字串一致,或 prompt 組合是否正確。 68 | 69 | --- 70 | 71 | 如果您需要,我可以: 72 | - 幫您把 `summarize` 改寫為使用映射表的更清晰實作,並加入錯誤處理。 73 | - 在 `lesson8_7.py` 中加入載入提示、timeout 與簡單的例外處理範例。 74 | - 幫您把 `lesson8_7.md` 加入到 `README` 或其他文件索引中。 75 | 76 | 請告訴我您要下一步做哪一項。 77 | -------------------------------------------------------------------------------- /lesson6/lesson6_1.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "fda73380", 6 | "metadata": {}, 7 | "source": [ 8 | "- ### 變數,list,dict\n", 9 | "- ### 判斷,迴圈\n", 10 | "- ### function\n", 11 | "- ### 內建的function,內建module,外部的module\n", 12 | "- ### 什麼是實體" 13 | ] 14 | }, 15 | { 16 | "cell_type": "code", 17 | "execution_count": 4, 18 | "id": "1d73f94c", 19 | "metadata": {}, 20 | "outputs": [ 21 | { 22 | "data": { 23 | "text/plain": [ 24 | "('小明', 20, 175.5)" 25 | ] 26 | }, 27 | "execution_count": 4, 28 | "metadata": {}, 29 | "output_type": "execute_result" 30 | } 31 | ], 32 | "source": [ 33 | "# 變數(Variable)\n", 34 | "name = \"小明\"\n", 35 | "age = 20\n", 36 | "height = 175.5\n", 37 | "\n", 38 | "name, age, height #這是tuple" 39 | ] 40 | }, 41 | { 42 | "cell_type": "code", 43 | "execution_count": 6, 44 | "id": "70a39fb4", 45 | "metadata": {}, 46 | "outputs": [ 47 | { 48 | "name": "stdout", 49 | "output_type": "stream", 50 | "text": [ 51 | "\n", 52 | "水果清單: ['蘋果', '香蕉', '橘子']\n", 53 | "第一個水果: 蘋果\n", 54 | "反轉後的水果清單: ['橘子', '香蕉', '蘋果']\n" 55 | ] 56 | } 57 | ], 58 | "source": [ 59 | "fruits = [\"蘋果\", \"香蕉\", \"橘子\"]\n", 60 | "print(type(fruits))\n", 61 | "print(\"水果清單:\", fruits)\n", 62 | "print(\"第一個水果:\", fruits[0])\n", 63 | "fruits.reverse() # 反轉清單\n", 64 | "print(\"反轉後的水果清單:\", fruits)" 65 | ] 66 | } 67 | ], 68 | "metadata": { 69 | "kernelspec": { 70 | "display_name": "line_bot", 71 | "language": "python", 72 | "name": "python3" 73 | }, 74 | "language_info": { 75 | "codemirror_mode": { 76 | "name": "ipython", 77 | "version": 3 78 | }, 79 | "file_extension": ".py", 80 | "mimetype": "text/x-python", 81 | "name": "python", 82 | "nbconvert_exporter": "python", 83 | "pygments_lexer": "ipython3", 84 | "version": "3.12.11" 85 | } 86 | }, 87 | "nbformat": 4, 88 | "nbformat_minor": 5 89 | } 90 | -------------------------------------------------------------------------------- /gemini/lesson1_1.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "id": "c9d13be8", 7 | "metadata": {}, 8 | "outputs": [ 9 | { 10 | "name": "stdout", 11 | "output_type": "stream", 12 | "text": [ 13 | "AI learns from data to find patterns and make decisions.\n" 14 | ] 15 | } 16 | ], 17 | "source": [ 18 | "from google import genai\n", 19 | "\n", 20 | "# The client gets the API key from the environment variable `GEMINI_API_KEY`.\n", 21 | "client = genai.Client()\n", 22 | "\n", 23 | "response = client.models.generate_content(\n", 24 | " model=\"gemini-2.5-flash\", contents=\"Explain how AI works in a few words\"\n", 25 | ")\n", 26 | "print(response.text)" 27 | ] 28 | }, 29 | { 30 | "cell_type": "code", 31 | "execution_count": 2, 32 | "id": "038a5558", 33 | "metadata": {}, 34 | "outputs": [ 35 | { 36 | "name": "stdout", 37 | "output_type": "stream", 38 | "text": [ 39 | "AI learns from data to make decisions or predictions.\n" 40 | ] 41 | } 42 | ], 43 | "source": [ 44 | "from google import genai\n", 45 | "from google.genai import types\n", 46 | "\n", 47 | "client = genai.Client()\n", 48 | "\n", 49 | "response = client.models.generate_content(\n", 50 | " model=\"gemini-2.5-flash\",\n", 51 | " contents=\"Explain how AI works in a few words\",\n", 52 | " config=types.GenerateContentConfig(\n", 53 | " thinking_config=types.ThinkingConfig(thinking_budget=0) # Disables thinking\n", 54 | " ),\n", 55 | ")\n", 56 | "print(response.text)" 57 | ] 58 | } 59 | ], 60 | "metadata": { 61 | "kernelspec": { 62 | "display_name": "line_bot", 63 | "language": "python", 64 | "name": "python3" 65 | }, 66 | "language_info": { 67 | "codemirror_mode": { 68 | "name": "ipython", 69 | "version": 3 70 | }, 71 | "file_extension": ".py", 72 | "mimetype": "text/x-python", 73 | "name": "python", 74 | "nbconvert_exporter": "python", 75 | "pygments_lexer": "ipython3", 76 | "version": "3.12.11" 77 | } 78 | }, 79 | "nbformat": 4, 80 | "nbformat_minor": 5 81 | } 82 | -------------------------------------------------------------------------------- /lesson6/lesson6_4.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 5, 6 | "id": "a4f9796a", 7 | "metadata": {}, 8 | "outputs": [ 9 | { 10 | "name": "stdout", 11 | "output_type": "stream", 12 | "text": [ 13 | "===========AI回應==============\n" 14 | ] 15 | }, 16 | { 17 | "data": { 18 | "text/markdown": [ 19 | "好,我用簡單的方式解釋一下 Python 的函式:\n", 20 | "\n", 21 | "**想像一下:** 函式就像一個小工具,你給它一個問題,它會幫你完成這個問題,然後給你一個結果。\n", 22 | "\n", 23 | "**簡單來說,Python 的函式是為了重複執行特定的操作。**\n", 24 | "\n", 25 | "**以下是一些更具體的解釋:**\n", 26 | "\n", 27 | "* **重複執行一件事:** 函式可以多次地執行相同的步驟,就像玩一個遊戲,你玩了多次,結果都是一樣的。\n", 28 | "* **你給函式一個問題,它會根據你的問題,找到一個方法來回答。**\n", 29 | "* **函式會得到一個結果,你可以用這個結果來做其他事情。**\n", 30 | "\n", 31 | "**舉個例子:**\n", 32 | "\n", 33 | "假設你想要計算一個數字的平方。\n", 34 | "\n", 35 | "* **你不會直接寫:`2 * 2` ,因為這太長了。**\n", 36 | "* **你會寫一個函式:`def square(x):`** 這個函式告訴 Python :“這函式叫 `square`,它會接收一個數 `x`,然後計算 `x` 的平方,並將結果返回給你。”\n", 37 | "\n", 38 | "* **然後你輸入 `square(5)`:** 函式會得到 `5`,然後計算 `5 * 5 = 25`,並把結果 `25` 輸給你。\n", 39 | "\n", 40 | "**Python 函式的主要作用:**\n", 41 | "\n", 42 | "* **自動化重複工作:** 比如,處理用戶輸入、計算數據、建立文件等等。\n", 43 | "* **提供有用的功能:** 就像你擁有的工具,可以讓你更容易地完成任務。\n", 44 | "\n", 45 | "**總結:**\n", 46 | "\n", 47 | "Python 函式就像是預先寫好的程序片段,你可以用它來做各種各樣的事情。 它們像是被定義好的“小短手”,可以讓你更快速、更方便地完成任務。\n", 48 | "\n", 49 | "希望這個解釋對你有幫助! 你想了解更多關於 Python 函式的訊息嗎? 比如,你想要知道如何創建自己的函式嗎?\n" 50 | ], 51 | "text/plain": [ 52 | "" 53 | ] 54 | }, 55 | "metadata": {}, 56 | "output_type": "display_data" 57 | } 58 | ], 59 | "source": [ 60 | "import requests\n", 61 | "#import pprint\n", 62 | "from pprint import pprint\n", 63 | "from IPython.display import Markdown, display\n", 64 | "\n", 65 | "def generate_with_ollama(prompt:str)->None:\n", 66 | " url = \"http://localhost:11434/api/generate\"\n", 67 | " payload = {\n", 68 | " \"model\":\"gemma3:1b\",\n", 69 | " \"prompt\":prompt,\n", 70 | " \"stream\":False\n", 71 | " }\n", 72 | " response = requests.post(url,json=payload)\n", 73 | " result = response.json()\n", 74 | " #print(type(result))\n", 75 | " #pprint(result)\n", 76 | " print(\"===========AI回應==============\")\n", 77 | " display(Markdown(result['response']))\n", 78 | "\n", 79 | "generate_with_ollama(\"請用簡單的方式解釋什麼是Python的函式?\")" 80 | ] 81 | } 82 | ], 83 | "metadata": { 84 | "kernelspec": { 85 | "display_name": "line_bot", 86 | "language": "python", 87 | "name": "python3" 88 | }, 89 | "language_info": { 90 | "codemirror_mode": { 91 | "name": "ipython", 92 | "version": 3 93 | }, 94 | "file_extension": ".py", 95 | "mimetype": "text/x-python", 96 | "name": "python", 97 | "nbconvert_exporter": "python", 98 | "pygments_lexer": "ipython3", 99 | "version": "3.12.11" 100 | } 101 | }, 102 | "nbformat": 4, 103 | "nbformat_minor": 5 104 | } 105 | -------------------------------------------------------------------------------- /lesson9/main.py: -------------------------------------------------------------------------------- 1 | from flask import Flask,render_template_string, request, jsonify,abort 2 | from google import genai 3 | from dotenv import load_dotenv 4 | import os 5 | from linebot import LineBotApi, WebhookHandler 6 | from linebot.exceptions import InvalidSignatureError 7 | from linebot.models import * 8 | load_dotenv() 9 | 10 | app = Flask(__name__) 11 | client = genai.Client(api_key=os.getenv("GENAI_API_KEY")) 12 | line_bot_api = LineBotApi(os.getenv("CHANNEL_ACCESS_TOKEN")) 13 | handler = WebhookHandler(os.getenv("CHANNEL_SECRET")) 14 | 15 | @app.route("/") 16 | def index(): 17 | html = ''' 18 | 19 | 20 | 21 | 22 | Gemini 小助手 Chatbot 23 | 33 | 34 | 35 |
36 |

Gemini 小助手 Chatbot

37 | 38 |
39 | 40 | 41 |
42 |
43 |
44 | 67 | 68 | 69 | ''' 70 | return render_template_string(html) 71 | 72 | @app.route("/chat", methods=["POST"]) 73 | def chat(): 74 | data = request.get_json() 75 | question = data.get('question', '').strip() 76 | if not question: 77 | return jsonify({'error': '未輸入問題'}), 400 78 | try: 79 | response = client.models.generate_content( 80 | model="gemini-2.5-flash", contents=f"{question},回應請輸出成為html格式,請記得您的名字是`致理小助手`" 81 | ) 82 | html_format = response.text.replace("```html","").replace("```","") 83 | return jsonify({'html': html_format}) 84 | except Exception as e: 85 | return jsonify({'error': str(e)}), 500 86 | 87 | @app.route("/callback", methods=['POST']) 88 | def callback(): 89 | signature = request.headers['X-Line-Signature'] 90 | body = request.get_data(as_text=True) 91 | app.logger.info("Request body: " + body) 92 | try: 93 | handler.handle(body, signature) 94 | except InvalidSignatureError: 95 | abort(400) 96 | return 'OK' 97 | 98 | @handler.add(MessageEvent, message=TextMessage) 99 | def handle_message(event): 100 | 101 | response = client.models.generate_content( 102 | model="gemini-2.5-flash", contents=event.message.text 103 | ) 104 | message = TextSendMessage(text=response.text) 105 | line_bot_api.reply_message(event.reply_token, message) -------------------------------------------------------------------------------- /lesson5/lesson5_1.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 2, 6 | "id": "0167eb4f", 7 | "metadata": {}, 8 | "outputs": [ 9 | { 10 | "name": "stdout", 11 | "output_type": "stream", 12 | "text": [ 13 | "💬 AI 回應:\n", 14 | "{'model': 'gemma3:1b', 'created_at': '2025-08-01T23:23:29.290853591Z', 'response': '{ \\n \"我是一個大型語言模型,由 Google 訓練。我是一個人工智能程式,我的目的是提供資訊、撰寫不同類型的創意內容,並以友善和有幫助的方式與人類互動。\":\\n\\n { \\n \"我是在 Google 訓練的。我是一個大型語言模型,我的主要功能是理解和生成人類語言。我可以回答問題、撰寫不同類型的創意內容,並提供信息。我學習和改進我的能力,持續從用戶的互動中學習。\":\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n', 'done': False}\n", 15 | "{ \n", 16 | " \"我是一個大型語言模型,由 Google 訓練。我是一個人工智能程式,我的目的是提供資訊、撰寫不同類型的創意內容,並以友善和有幫助的方式與人類互動。\":\n", 17 | "\n", 18 | " { \n", 19 | " \"我是在 Google 訓練的。我是一個大型語言模型,我的主要功能是理解和生成人類語言。我可以回答問題、撰寫不同類型的創意內容,並提供信息。我學習和改進我的能力,持續從用戶的互動中學習。\":\n", 20 | " \n", 21 | " \n", 22 | " \n", 23 | " \n", 24 | " \n", 25 | " \n", 26 | " \n", 27 | " \n", 28 | " \n", 29 | " \n", 30 | " \n", 31 | " \n", 32 | " \n", 33 | " \n", 34 | " \n", 35 | "\n" 36 | ] 37 | } 38 | ], 39 | "source": [ 40 | "import requests\n", 41 | "\n", 42 | "def chat_with_ollama(prompt: str):\n", 43 | " url = \"http://localhost:11434/api/generate\"\n", 44 | " payload = {\n", 45 | " \"model\": \"gemma3:1b\",\n", 46 | " \"prompt\": prompt,\n", 47 | " \"stream\": False,\n", 48 | " \"options\": { #參考說明1\n", 49 | " \"temperature\": 0.7,\n", 50 | " \"top_p\": 0.9,\n", 51 | " \"top_k\": 50,\n", 52 | " },\n", 53 | " \"max_tokens\": 100,\n", 54 | " \"format\": \"json\",\n", 55 | " }\n", 56 | "\n", 57 | " response = requests.post(url, json=payload)\n", 58 | " result = response.json()\n", 59 | " print(\"💬 AI 回應:\")\n", 60 | " # Print the whole result for debugging\n", 61 | " print(result)\n", 62 | " # Try to print the 'response' key if it exists, otherwise print possible keys\n", 63 | " if \"response\" in result:\n", 64 | " print(result[\"response\"])\n", 65 | " elif \"message\" in result:\n", 66 | " print(result[\"message\"])\n", 67 | " elif \"content\" in result:\n", 68 | " print(result[\"content\"])\n", 69 | " else:\n", 70 | " print(\"No expected key found in response. Available keys:\", result.keys())\n", 71 | "\n", 72 | "#範例輸入\n", 73 | "chat_with_ollama(\"請問你是誰?\") # Example input" 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": null, 79 | "id": "bead25f2", 80 | "metadata": {}, 81 | "outputs": [], 82 | "source": [ 83 | "import requests\n", 84 | "\n", 85 | "url = 'https://github.com/open-webui/open-webui'\n", 86 | "response = requests.get(url) #引數值的呼叫\n", 87 | "#type(response)\n", 88 | "if response.status_code == 200:\n", 89 | " print(\"下載成功\")\n", 90 | " print(response.text)\n", 91 | "\n", 92 | "#requests.get(url=url) #引數名稱呼叫\n" 93 | ] 94 | }, 95 | { 96 | "cell_type": "code", 97 | "execution_count": 36, 98 | "id": "44f7045c", 99 | "metadata": {}, 100 | "outputs": [ 101 | { 102 | "name": "stdout", 103 | "output_type": "stream", 104 | "text": [ 105 | "成功\n" 106 | ] 107 | }, 108 | { 109 | "data": { 110 | "text/markdown": [ 111 | "天空之所以是藍的,是一個複雜的現象,主要歸因於一種稱為 **瑞利散射** 的光學現象。簡單來說,就是太陽光中的藍光比其他顏色更易被散射。以下是更詳細的解釋:\n", 112 | "\n", 113 | "**1. 太陽光中的顏色:**\n", 114 | "\n", 115 | "* 太陽光實際上是白色的,但看起來是黃色的。這是因為太陽光中包含所有顏色的光。\n", 116 | "* 太陽光中的各個顏色是不同的波長,波長越短,顏色越亮。\n", 117 | "* 藍光和紫光波長短,因此更容易被空氣和空氣中的分子散射。\n", 118 | "\n", 119 | "**2. 瑞利散射:**\n", 120 | "\n", 121 | "* 瑞利散射是光線在通過介質(如空氣)時,被微小粒子(如分子和氣體)散射的現象。\n", 122 | "* 藍光波長短,更容易被這些微小粒子散射,因此被散射得更加分散。\n", 123 | "* 紫光波長長,散射效果較弱,所以我們主要看到藍色。\n", 124 | "\n", 125 | "**3. 空氣中的分子:**\n", 126 | "\n", 127 | "* 空氣中包含大量的微小分子,例如氮氣和氧氣。\n", 128 | "* 這些分子就像小小的“避風碗”,會向藍光散射,讓藍光更容易到達我們的眼睛。\n", 129 | "* 紫光和紅色光則更容易穿透這些分子,所以天空看起來是藍色的。\n", 130 | "\n", 131 | "**4. 日出和日落時的現象:**\n", 132 | "\n", 133 | "* 在日出和日落時,太陽光需要穿過更厚一層的空氣層才能到達我們的眼睛。\n", 134 | "* 藍光在穿過這個厚層時被大部分散射了,剩下的藍光就更容易到達我們的眼睛,因此我們看到的天空變得更加藍。\n", 135 | "\n", 136 | "**總結來說,天空之所以是藍色的,是因為太陽光中的藍光更容易被空氣中的分子散射,導致我們看到藍色的光線。**\n", 137 | "\n", 138 | "希望這個解釋對您有幫助!\n" 139 | ], 140 | "text/plain": [ 141 | "" 142 | ] 143 | }, 144 | "metadata": {}, 145 | "output_type": "display_data" 146 | } 147 | ], 148 | "source": [ 149 | "import requests\n", 150 | "from IPython.display import Markdown, display\n", 151 | "\n", 152 | "url = \"http://localhost:11434/api/generate\"\n", 153 | "response = requests.post(url,json={\n", 154 | " \"model\": \"gemma3:1b\",\n", 155 | " \"prompt\":\"天空為什麼是藍的?\",\n", 156 | " \"stream\": False,\n", 157 | "})\n", 158 | "if response.status_code == 200:\n", 159 | " print(\"成功\")\n", 160 | " result = response.json()\n", 161 | " display(Markdown(result['response']))\n", 162 | "else:\n", 163 | " print(\"失敗\")\n", 164 | " print(\"原因\",response.status_code)" 165 | ] 166 | }, 167 | { 168 | "cell_type": "code", 169 | "execution_count": 34, 170 | "id": "62f36182", 171 | "metadata": {}, 172 | "outputs": [ 173 | { 174 | "name": "stdout", 175 | "output_type": "stream", 176 | "text": [ 177 | "tw\n", 178 | "jp\n", 179 | "hk\n", 180 | "Taiwan\n", 181 | "Japan\n", 182 | "Hong kong\n", 183 | "Taiwan tw\n", 184 | "Japan jp\n", 185 | "Hong kong hk\n" 186 | ] 187 | } 188 | ], 189 | "source": [ 190 | "codes = {\n", 191 | " \"tw\":\"Taiwan\",\n", 192 | " \"jp\":\"Japan\",\n", 193 | " \"hk\":\"Hong kong\"\n", 194 | "}\n", 195 | "codes[\"tw\"]\n", 196 | "codes[\"jp\"]\n", 197 | "codes['hk']\n", 198 | "codes.keys()\n", 199 | "for item in codes.keys():\n", 200 | " print(item)\n", 201 | "\n", 202 | "for value in codes.values():\n", 203 | " print(value)\n", 204 | "\n", 205 | "for (code,name) in codes.items():\n", 206 | " print(name, code)" 207 | ] 208 | } 209 | ], 210 | "metadata": { 211 | "kernelspec": { 212 | "display_name": "line_bot", 213 | "language": "python", 214 | "name": "python3" 215 | }, 216 | "language_info": { 217 | "codemirror_mode": { 218 | "name": "ipython", 219 | "version": 3 220 | }, 221 | "file_extension": ".py", 222 | "mimetype": "text/x-python", 223 | "name": "python", 224 | "nbconvert_exporter": "python", 225 | "pygments_lexer": "ipython3", 226 | "version": "3.12.11" 227 | } 228 | }, 229 | "nbformat": 4, 230 | "nbformat_minor": 5 231 | } 232 | -------------------------------------------------------------------------------- /lesson7/lesson7_1.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "id": "7c660f1f", 7 | "metadata": {}, 8 | "outputs": [ 9 | { 10 | "name": "stdout", 11 | "output_type": "stream", 12 | "text": [ 13 | "人工智慧 (AI) 的運作原理,核心概念可以歸納為「**從資料中學習**」。它並非像人類一樣擁有意識或真正的理解能力,而是一種強大的模式識別與預測工具。\n", 14 | "\n", 15 | "您可以將 AI 的工作方式想像成一個非常勤奮且記憶力超強的學生,它的學習過程和應用可以分為幾個主要階段:\n", 16 | "\n", 17 | "---\n", 18 | "\n", 19 | "**人工智慧 (AI) 的運作原理**\n", 20 | "\n", 21 | "人工智慧(AI)的核心在於讓機器從資料中學習,並根據這些學習到的模式進行決策或預測。這整個過程通常涉及以下幾個關鍵要素和步驟:\n", 22 | "\n", 23 | "**一、 AI 運作的三大要素:**\n", 24 | "\n", 25 | "1. **大量資料 (Massive Data):**\n", 26 | " * **作用:** 資料是 AI 學習的「教科書」。就像人類需要透過觀察、閱讀、聽講來學習一樣,AI 需要大量的範例資料來識別模式、特徵和關係。\n", 27 | " * **例子:** 如果要讓 AI 辨識貓狗,就需要輸入數百萬張有貓和狗標籤的圖片;如果要讓 AI 翻譯語言,就需要大量的雙語文本。資料的「質」和「量」直接影響 AI 的學習效果。\n", 28 | "\n", 29 | "2. **演算法與模型 (Algorithms & Models):**\n", 30 | " * **作用:** 演算法是 AI 學習和處理資料的「方法論」或「規則集」。模型則是演算法在特定資料上學習後形成的「知識結構」,它代表了資料中的模式和關係。\n", 31 | " * **例子:** 常見的 AI 模型包括神經網路(特別是深度學習)、決策樹、支持向量機等。這些模型會建立複雜的數學函數,用來映射輸入資料到輸出結果。\n", 32 | "\n", 33 | "3. **強大計算能力 (Powerful Computational Power):**\n", 34 | " * **作用:** 訓練 AI 模型,特別是大型深度學習模型,需要進行海量的數學運算。這需要強大的處理器(如圖形處理器 GPU)來加速計算過程,讓 AI 能在合理的時間內完成學習。\n", 35 | " * **例子:** 訓練一個大型語言模型可能需要數週甚至數月的時間,在數千個 GPU 上并行運算。\n", 36 | "\n", 37 | "**二、 AI 的運作流程(兩大階段):**\n", 38 | "\n", 39 | "AI 的運作通常分為「訓練」和「推論」兩個主要階段。\n", 40 | "\n", 41 | "**A. 訓練階段 (Training Phase):**\n", 42 | "這是 AI 「學習」的過程,就像學生上課、做練習題一樣。\n", 43 | "\n", 44 | "1. **輸入資料 (Input Data):** 將大量的、已標記的資料(例如:圖片及其對應的「貓」或「狗」標籤,或是一段中文文本及其對應的英文翻譯)輸入到 AI 模型中。\n", 45 | "2. **模型預測 (Model Prediction):** 模型根據當前學到的知識,對輸入的資料進行預測。一開始,它的預測可能是完全錯誤的。\n", 46 | "3. **誤差計算 (Error Calculation):** 將模型的預測結果與正確答案進行比較,計算出「誤差」或「損失」(即模型預測錯了多少)。\n", 47 | "4. **參數調整 (Parameter Adjustment):** 這是最關鍵的一步。根據計算出的誤差,演算法(通常是透過一種稱為「反向傳播」的技術)會微調模型內部的「參數」(可以想像成模型內部調整的「旋鈕」或「權重」),目的是減少下次的預測誤差。\n", 48 | "5. **反覆迭代 (Iterative Refinement):** 上述步驟會重複進行數百萬、數億次,模型會不斷地從錯誤中學習,逐步優化自身的參數,直到模型的預測準確度達到一個可接受的水平。這個過程就像學生不斷做練習題、訂正錯誤、最終掌握知識一樣。\n", 49 | "\n", 50 | "**B. 推論/應用階段 (Inference/Application Phase):**\n", 51 | "當模型訓練完成後,它就成為一個具備某種能力的「智慧體」,可以被應用於實際情境。\n", 52 | "\n", 53 | "1. **輸入新資料 (Input New Data):** 將從未見過的新資料輸入到已經訓練好的 AI 模型中。這些資料是沒有標籤的。\n", 54 | "2. **應用所學 (Apply Learned Patterns):** 模型會應用它在訓練階段學到的模式、規則和特徵,對新資料進行預測、分類、識別或生成。它不再有「老師」告訴它答案,而是獨立作出判斷。\n", 55 | "3. **輸出結果 (Output Result):** 模型輸出最終的判斷或結果(例如:這張新圖片是「貓」、這段文字的情緒是「積極」、生成一段新的文本、提供一個推薦)。\n", 56 | "\n", 57 | "**三、 常見的 AI 學習範式:**\n", 58 | "\n", 59 | "* **監督式學習 (Supervised Learning):** 最常見,需要大量帶有「正確答案」標籤的資料來訓練模型。例如圖像識別、垃圾郵件過濾。\n", 60 | "* **非監督式學習 (Unsupervised Learning):** 處理沒有標籤的資料,AI 自己去發現資料中的結構、模式或分組。例如客戶分群、異常檢測。\n", 61 | "* **強化學習 (Reinforcement Learning):** AI 透過與環境互動,透過「試錯」和「獎勵/懲罰」機制來學習最佳行為策略。例如下棋 AI(AlphaGo)、自動駕駛。\n", 62 | "\n", 63 | "---\n", 64 | "\n", 65 | "**總結來說:**\n", 66 | "\n", 67 | "AI 並非真正意義上的「思考」,而是透過龐大資料的訓練,學習如何識別和複製資料中的複雜模式,並將這些模式應用於新的情境。它是一種極其強大的模式識別和優化工具,能夠在特定任務上表現出超越人類的能力,但其「智慧」的範圍受限於其訓練資料和設計的演算法。\n" 68 | ] 69 | } 70 | ], 71 | "source": [ 72 | "from google import genai\n", 73 | "import os\n", 74 | "from IPython.display import display, Markdown, Latex\n", 75 | "\n", 76 | "client = genai.Client(api_key=os.environ['GEMINI_API_KEY'])\n", 77 | "# print(type(client))\n", 78 | "# print(type(client.models))\n", 79 | "# for model in client.models.list():\n", 80 | "# if \"generateContent\" in model.supported_actions:\n", 81 | "# print(model.name)\n", 82 | "response = client.models.generate_content(\n", 83 | " model=\"gemini-2.5-flash\",\n", 84 | " contents=\"AI是如何工作的(請使用繁體中文回答)?\"\n", 85 | ")\n", 86 | "\n", 87 | "print(response.text)\n", 88 | "\n", 89 | "#display(Markdown(response.text))" 90 | ] 91 | }, 92 | { 93 | "cell_type": "code", 94 | "execution_count": 25, 95 | "id": "19b75fa8", 96 | "metadata": {}, 97 | "outputs": [ 98 | { 99 | "name": "stdout", 100 | "output_type": "stream", 101 | "text": [ 102 | "AI 的運作方式很像人類學習的方式。\n", 103 | "AI works much like humans learn.\n", 104 | "它從大量的數據中學習,而不是被明確地編程。\n", 105 | "It learns from vast amounts of data, rather than being explicitly programmed.\n", 106 | "\n", 107 | "這個過程稱為「訓練」。\n", 108 | "This process is called \"training.\"\n", 109 | "在訓練階段,AI 使用演算法來分析數據。\n", 110 | "During the training phase, AI uses algorithms to analyze data.\n", 111 | "它從中找出模式、關聯和規則。\n", 112 | "It identifies patterns, correlations, and rules within it.\n", 113 | "\n", 114 | "一旦訓練完成,AI 就會建立一個「模型」。\n", 115 | "Once training is complete, the AI creates a \"model.\"\n", 116 | "這個模型可以用來理解新的、未見過的數據。\n", 117 | "This model can then be used to understand new, unseen data.\n", 118 | "並根據所學來做出預測、決策或執行任務。\n", 119 | "And make predictions, decisions, or perform tasks based on what it has learned.\n", 120 | "\n", 121 | "例如,如果訓練它辨識圖片中的貓。\n", 122 | "For example, if trained to recognize cats in images.\n", 123 | "它會分析數百萬張貓和非貓的圖片來學習特徵。\n", 124 | "It analyzes millions of images of cats and non-cats to learn characteristics.\n", 125 | "然後,當它看到一張新圖片時,就能判斷其中是否有貓。\n", 126 | "Then, when it sees a new picture, it can determine if there's a cat in it.\n", 127 | "\n", 128 | "總之,AI 的核心就是從數據中智慧地學習。\n", 129 | "In summary, the core of AI is to learn intelligently from data.\n", 130 | "然後利用這些知識來解決問題或執行複雜任務。\n", 131 | "And then use this knowledge to solve problems or perform complex tasks.\n" 132 | ] 133 | } 134 | ], 135 | "source": [ 136 | "from google import genai\n", 137 | "from google.genai import types\n", 138 | "\n", 139 | "client = genai.Client()\n", 140 | "\n", 141 | "system_instruction = \"\"\"\n", 142 | "你是個友善且樂於助人的助理。\n", 143 | "回答時,請回答繁體中文和英文,\n", 144 | "一行繁體中文,一行英文翻譯\n", 145 | "\"\"\"\n", 146 | "\n", 147 | "\n", 148 | "\n", 149 | "thinking = types.ThinkingConfig(thinking_budget=100)\n", 150 | "\n", 151 | "config = types.GenerateContentConfig(\n", 152 | " thinking_config=thinking, # Disables thinking\n", 153 | " temperature=1,\n", 154 | " top_k=40,\n", 155 | " top_p=1,\n", 156 | " system_instruction=system_instruction\n", 157 | " \n", 158 | ")\n", 159 | "\n", 160 | "\n", 161 | "\n", 162 | "response = client.models.generate_content(\n", 163 | " model=\"gemini-2.5-flash\",\n", 164 | " contents=[\"AI是如何工作的?\"],\n", 165 | " config=config\n", 166 | ")\n", 167 | "print(response.text)" 168 | ] 169 | } 170 | ], 171 | "metadata": { 172 | "kernelspec": { 173 | "display_name": "line_bot", 174 | "language": "python", 175 | "name": "python3" 176 | }, 177 | "language_info": { 178 | "codemirror_mode": { 179 | "name": "ipython", 180 | "version": 3 181 | }, 182 | "file_extension": ".py", 183 | "mimetype": "text/x-python", 184 | "name": "python", 185 | "nbconvert_exporter": "python", 186 | "pygments_lexer": "ipython3", 187 | "version": "3.12.11" 188 | } 189 | }, 190 | "nbformat": 4, 191 | "nbformat_minor": 5 192 | } 193 | -------------------------------------------------------------------------------- /demo/demo1.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 10, 6 | "id": "06c18639", 7 | "metadata": {}, 8 | "outputs": [ 9 | { 10 | "name": "stdout", 11 | "output_type": "stream", 12 | "text": [ 13 | "💬 AI 回應:\n", 14 | "{'model': 'gemma3:1b', 'created_at': '2025-07-25T22:01:03.916740705Z', 'response': '{\\n\"解釋:\":\"Python的函式就像是程式的指令,你可以把它想像成一個小小的任務。你告訴函式要做什麼,函式就會執行,並產生結果。\"\\n\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n', 'done': False}\n", 15 | "{\n", 16 | "\"解釋:\":\"Python的函式就像是程式的指令,你可以把它想像成一個小小的任務。你告訴函式要做什麼,函式就會執行,並產生結果。\"\n", 17 | "\n", 18 | " \n", 19 | " \n", 20 | " \n", 21 | " \n", 22 | " \n", 23 | " \n", 24 | " \n", 25 | " \n", 26 | " \n", 27 | " \n", 28 | " \n", 29 | " \n", 30 | " \n", 31 | " \n", 32 | " \n", 33 | "\n" 34 | ] 35 | } 36 | ], 37 | "source": [ 38 | "import requests\n", 39 | "\n", 40 | "def chat_with_ollama(prompt: str):\n", 41 | " url = \"http://localhost:11434/api/generate\"\n", 42 | " payload = {\n", 43 | " \"model\": \"gemma3:1b\",\n", 44 | " \"prompt\": prompt,\n", 45 | " \"stream\": False,\n", 46 | " \"options\": { #參考說明1\n", 47 | " \"temperature\": 0.7,\n", 48 | " \"top_p\": 0.9,\n", 49 | " \"top_k\": 50,\n", 50 | " },\n", 51 | " \"max_tokens\": 100,\n", 52 | " \"format\": \"json\",\n", 53 | " }\n", 54 | "\n", 55 | " response = requests.post(url, json=payload)\n", 56 | " result = response.json()\n", 57 | " print(\"💬 AI 回應:\")\n", 58 | " # Print the whole result for debugging\n", 59 | " print(result)\n", 60 | " # Try to print the 'response' key if it exists, otherwise print possible keys\n", 61 | " if \"response\" in result:\n", 62 | " print(result[\"response\"])\n", 63 | " elif \"message\" in result:\n", 64 | " print(result[\"message\"])\n", 65 | " elif \"content\" in result:\n", 66 | " print(result[\"content\"])\n", 67 | " else:\n", 68 | " print(\"No expected key found in response. Available keys:\", result.keys())\n", 69 | "\n", 70 | "#範例輸入\n", 71 | "chat_with_ollama(\"請用簡單的方式解釋什麼是Python的函式?\")" 72 | ] 73 | }, 74 | { 75 | "cell_type": "markdown", 76 | "id": "f9e79444", 77 | "metadata": {}, 78 | "source": [ 79 | "### 說明1\n", 80 | "\n", 81 | "`options` 物件封裝了對於生成模型行為的三個關鍵調整參數:`temperature`、`top_p` 以及 `top_k`。透過這些設定,我們可以更精細地控制模型在產生文字時的隨機程度與多樣性,以達到更符合需求的輸出風格。\n", 82 | "\n", 83 | "`temperature`(溫度)參數設定為 0.7,表示在挑選下一個字元或詞彙時,會根據模型預測機率分佈做溫度縮放。溫度越接近 1,生成結果越隨機、多樣;當溫度降低時,生成更傾向於高機率選擇,輸出結果較為保守且重複性增加。設定為 0.7 能在隨機性與穩定性間取得平衡。\n", 84 | "\n", 85 | "`top_p`(又稱 nucleus sampling)設為 0.9,代表每次生成時僅考慮累積機率前 90% 的候選詞彙。換言之,模型先將所有候選依機率由高到低排序,然後從機率總和達到 0.9 的詞彙子集中進行隨機抽樣。這種方法可避免只關注最高機率而忽略其他合理選項,也能自動調整抽樣範圍以抑制極低機率的「噪音」輸出。\n", 86 | "\n", 87 | "`top_k` 參數設置為 50,表示在抽樣時僅從預測機率最高的前 50 個詞彙中選擇下一步結果。這是在限制搜索空間大小、提高運算效率與品質控制的常見做法。結合 `top_p` 與 `top_k` 使用,能進一步平衡多樣性與穩定性:`top_k` 確保候選集不超過一定規模,`top_p` 則依實際機率分佈動態修剪集內詞彙。\n", 88 | "\n", 89 | "綜合而言,這三項參數共同為生成模型提供了多層次的隨機與篩選機制。依據不同應用場景(如對話系統、文章撰寫或程式碼生成),可微調這些值以獲得更符合需求的結果。" 90 | ] 91 | }, 92 | { 93 | "cell_type": "code", 94 | "execution_count": 11, 95 | "id": "0082f63a", 96 | "metadata": {}, 97 | "outputs": [ 98 | { 99 | "name": "stdout", 100 | "output_type": "stream", 101 | "text": [ 102 | "歡迎使用本地端 LLM 聊天機器人(輸入 q 離開)\n", 103 | "💬 AI 回應:\n", 104 | "{'model': 'gemma3:1b', 'created_at': '2025-07-25T22:14:27.35581321Z', 'response': '{\\n\"response\": \"天空之所以是藍的,主要是因為一種叫做**瑞利散射 (Rayleigh scattering)** 的現象。 簡單來說,太陽光穿過大氣層時,會與空氣中的微小粒子(主要是氮氣和氧氣)發生碰撞。 由於這些粒子尺寸非常小,碰撞會將太陽光散射到不同的方向。**藍光(波長較短)更容易被散射,因此被散射到天空的每個方向。**\"\\n}', 'done': True, 'done_reason': 'stop', 'context': [105, 2364, 107, 141370, 95202, 237026, 241339, 236918, 106, 107, 105, 4368, 107, 236782, 107, 236775, 6275, 1083, 623, 141370, 132414, 237026, 241339, 236918, 236900, 74836, 27502, 120460, 100083, 1018, 240046, 237766, 150341, 568, 30958, 53700, 19389, 62902, 10363, 121887, 236924, 236743, 74624, 94757, 236900, 83700, 237914, 239409, 238124, 237110, 239471, 239614, 237479, 236900, 238003, 238693, 235450, 12870, 238477, 237369, 166747, 237221, 74836, 243140, 239471, 237206, 240514, 239471, 237214, 90972, 181044, 236924, 236743, 92793, 52426, 166747, 67868, 13869, 237369, 236900, 181044, 238003, 239079, 83700, 237914, 150341, 237238, 35078, 25718, 236924, 1018, 241339, 237914, 237221, 238663, 237953, 239350, 238906, 237214, 186897, 237759, 150341, 236900, 23041, 237759, 150341, 237238, 141370, 236918, 117680, 25718, 236924, 1018, 236775, 107, 236783], 'total_duration': 28573776231, 'load_duration': 336781457, 'prompt_eval_count': 14, 'prompt_eval_duration': 768334282, 'eval_count': 104, 'eval_duration': 26656140121}\n", 105 | "{\n", 106 | "\"response\": \"天空之所以是藍的,主要是因為一種叫做**瑞利散射 (Rayleigh scattering)** 的現象。 簡單來說,太陽光穿過大氣層時,會與空氣中的微小粒子(主要是氮氣和氧氣)發生碰撞。 由於這些粒子尺寸非常小,碰撞會將太陽光散射到不同的方向。**藍光(波長較短)更容易被散射,因此被散射到天空的每個方向。**\"\n", 107 | "}\n" 108 | ] 109 | } 110 | ], 111 | "source": [ 112 | "def chat_with_ollama(prompt: str):\n", 113 | " url = \"http://localhost:11434/api/generate\"\n", 114 | " payload = {\n", 115 | " \"model\": \"gemma3:1b\",\n", 116 | " \"prompt\": prompt,\n", 117 | " \"stream\": False,\n", 118 | " \"options\": { #參考說明1\n", 119 | " \"temperature\": 0.7,\n", 120 | " \"top_p\": 0.9,\n", 121 | " \"top_k\": 50,\n", 122 | " },\n", 123 | " \"max_tokens\": 100,\n", 124 | " \"format\": \"json\",\n", 125 | " }\n", 126 | "\n", 127 | " response = requests.post(url, json=payload)\n", 128 | " result = response.json()\n", 129 | " print(\"💬 AI 回應:\")\n", 130 | " # Print the whole result for debugging\n", 131 | " print(result)\n", 132 | " # Try to print the 'response' key if it exists, otherwise print possible keys\n", 133 | " if \"response\" in result:\n", 134 | " print(result[\"response\"])\n", 135 | " elif \"message\" in result:\n", 136 | " print(result[\"message\"])\n", 137 | " elif \"content\" in result:\n", 138 | " print(result[\"content\"])\n", 139 | " else:\n", 140 | " print(\"No expected key found in response. Available keys:\", result.keys())\n", 141 | "\n", 142 | " \n", 143 | "def chat_loop():\n", 144 | " print(\"歡迎使用本地端 LLM 聊天機器人(輸入 q 離開)\")\n", 145 | " while True:\n", 146 | " user_input = input(\"👤 你說:\")\n", 147 | " if user_input.lower() == 'q':\n", 148 | " break\n", 149 | " chat_with_ollama(user_input)\n", 150 | "\n", 151 | "chat_loop()" 152 | ] 153 | } 154 | ], 155 | "metadata": { 156 | "kernelspec": { 157 | "display_name": "line_bot", 158 | "language": "python", 159 | "name": "python3" 160 | }, 161 | "language_info": { 162 | "codemirror_mode": { 163 | "name": "ipython", 164 | "version": 3 165 | }, 166 | "file_extension": ".py", 167 | "mimetype": "text/x-python", 168 | "name": "python", 169 | "nbconvert_exporter": "python", 170 | "pygments_lexer": "ipython3", 171 | "version": "3.12.11" 172 | } 173 | }, 174 | "nbformat": 4, 175 | "nbformat_minor": 5 176 | } 177 | -------------------------------------------------------------------------------- /lesson6/lesson6_5.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "id": "e73cc8d5", 7 | "metadata": {}, 8 | "outputs": [ 9 | { 10 | "ename": "ValueError", 11 | "evalue": "Missing key inputs argument! To use the Google AI API, provide (`api_key`) arguments. To use the Google Cloud API, provide (`vertexai`, `project` & `location`) arguments.", 12 | "output_type": "error", 13 | "traceback": [ 14 | "\u001b[31m---------------------------------------------------------------------------\u001b[39m", 15 | "\u001b[31mValueError\u001b[39m Traceback (most recent call last)", 16 | "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[1]\u001b[39m\u001b[32m, line 4\u001b[39m\n\u001b[32m 1\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01mgoogle\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m genai\n\u001b[32m 3\u001b[39m \u001b[38;5;66;03m# The client gets the API key from the environment variable `GEMINI_API_KEY`.\u001b[39;00m\n\u001b[32m----> \u001b[39m\u001b[32m4\u001b[39m client = \u001b[43mgenai\u001b[49m\u001b[43m.\u001b[49m\u001b[43mClient\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 6\u001b[39m response = client.models.generate_content(\n\u001b[32m 7\u001b[39m model=\u001b[33m\"\u001b[39m\u001b[33mgemini-2.5-flash\u001b[39m\u001b[33m\"\u001b[39m, contents=\u001b[33m\"\u001b[39m\u001b[33m天空為什麼是藍的?\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 8\u001b[39m )\n\u001b[32m 9\u001b[39m \u001b[38;5;28mprint\u001b[39m(response.text)\n", 17 | "\u001b[36mFile \u001b[39m\u001b[32m~/miniconda3/envs/line_bot/lib/python3.12/site-packages/google/genai/client.py:219\u001b[39m, in \u001b[36mClient.__init__\u001b[39m\u001b[34m(self, vertexai, api_key, credentials, project, location, debug_config, http_options)\u001b[39m\n\u001b[32m 216\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 217\u001b[39m http_options = HttpOptions(base_url=base_url)\n\u001b[32m--> \u001b[39m\u001b[32m219\u001b[39m \u001b[38;5;28mself\u001b[39m._api_client = \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_get_api_client\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m 220\u001b[39m \u001b[43m \u001b[49m\u001b[43mvertexai\u001b[49m\u001b[43m=\u001b[49m\u001b[43mvertexai\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 221\u001b[39m \u001b[43m \u001b[49m\u001b[43mapi_key\u001b[49m\u001b[43m=\u001b[49m\u001b[43mapi_key\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 222\u001b[39m \u001b[43m \u001b[49m\u001b[43mcredentials\u001b[49m\u001b[43m=\u001b[49m\u001b[43mcredentials\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 223\u001b[39m \u001b[43m \u001b[49m\u001b[43mproject\u001b[49m\u001b[43m=\u001b[49m\u001b[43mproject\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 224\u001b[39m \u001b[43m \u001b[49m\u001b[43mlocation\u001b[49m\u001b[43m=\u001b[49m\u001b[43mlocation\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 225\u001b[39m \u001b[43m \u001b[49m\u001b[43mdebug_config\u001b[49m\u001b[43m=\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_debug_config\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 226\u001b[39m \u001b[43m \u001b[49m\u001b[43mhttp_options\u001b[49m\u001b[43m=\u001b[49m\u001b[43mhttp_options\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 227\u001b[39m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 229\u001b[39m \u001b[38;5;28mself\u001b[39m._aio = AsyncClient(\u001b[38;5;28mself\u001b[39m._api_client)\n\u001b[32m 230\u001b[39m \u001b[38;5;28mself\u001b[39m._models = Models(\u001b[38;5;28mself\u001b[39m._api_client)\n", 18 | "\u001b[36mFile \u001b[39m\u001b[32m~/miniconda3/envs/line_bot/lib/python3.12/site-packages/google/genai/client.py:265\u001b[39m, in \u001b[36mClient._get_api_client\u001b[39m\u001b[34m(vertexai, api_key, credentials, project, location, debug_config, http_options)\u001b[39m\n\u001b[32m 248\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m debug_config \u001b[38;5;129;01mand\u001b[39;00m debug_config.client_mode \u001b[38;5;129;01min\u001b[39;00m [\n\u001b[32m 249\u001b[39m \u001b[33m'\u001b[39m\u001b[33mrecord\u001b[39m\u001b[33m'\u001b[39m,\n\u001b[32m 250\u001b[39m \u001b[33m'\u001b[39m\u001b[33mreplay\u001b[39m\u001b[33m'\u001b[39m,\n\u001b[32m 251\u001b[39m \u001b[33m'\u001b[39m\u001b[33mauto\u001b[39m\u001b[33m'\u001b[39m,\n\u001b[32m 252\u001b[39m ]:\n\u001b[32m 253\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m ReplayApiClient(\n\u001b[32m 254\u001b[39m mode=debug_config.client_mode, \u001b[38;5;66;03m# type: ignore[arg-type]\u001b[39;00m\n\u001b[32m 255\u001b[39m replay_id=debug_config.replay_id, \u001b[38;5;66;03m# type: ignore[arg-type]\u001b[39;00m\n\u001b[32m (...)\u001b[39m\u001b[32m 262\u001b[39m http_options=http_options,\n\u001b[32m 263\u001b[39m )\n\u001b[32m--> \u001b[39m\u001b[32m265\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mBaseApiClient\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m 266\u001b[39m \u001b[43m \u001b[49m\u001b[43mvertexai\u001b[49m\u001b[43m=\u001b[49m\u001b[43mvertexai\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 267\u001b[39m \u001b[43m \u001b[49m\u001b[43mapi_key\u001b[49m\u001b[43m=\u001b[49m\u001b[43mapi_key\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 268\u001b[39m \u001b[43m \u001b[49m\u001b[43mcredentials\u001b[49m\u001b[43m=\u001b[49m\u001b[43mcredentials\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 269\u001b[39m \u001b[43m \u001b[49m\u001b[43mproject\u001b[49m\u001b[43m=\u001b[49m\u001b[43mproject\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 270\u001b[39m \u001b[43m \u001b[49m\u001b[43mlocation\u001b[49m\u001b[43m=\u001b[49m\u001b[43mlocation\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 271\u001b[39m \u001b[43m \u001b[49m\u001b[43mhttp_options\u001b[49m\u001b[43m=\u001b[49m\u001b[43mhttp_options\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 272\u001b[39m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", 19 | "\u001b[36mFile \u001b[39m\u001b[32m~/miniconda3/envs/line_bot/lib/python3.12/site-packages/google/genai/_api_client.py:569\u001b[39m, in \u001b[36mBaseApiClient.__init__\u001b[39m\u001b[34m(self, vertexai, api_key, credentials, project, location, http_options)\u001b[39m\n\u001b[32m 567\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m: \u001b[38;5;66;03m# Implicit initialization or missing arguments.\u001b[39;00m\n\u001b[32m 568\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28mself\u001b[39m.api_key:\n\u001b[32m--> \u001b[39m\u001b[32m569\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[32m 570\u001b[39m \u001b[33m'\u001b[39m\u001b[33mMissing key inputs argument! To use the Google AI API,\u001b[39m\u001b[33m'\u001b[39m\n\u001b[32m 571\u001b[39m \u001b[33m'\u001b[39m\u001b[33m provide (`api_key`) arguments. To use the Google Cloud API,\u001b[39m\u001b[33m'\u001b[39m\n\u001b[32m 572\u001b[39m \u001b[33m'\u001b[39m\u001b[33m provide (`vertexai`, `project` & `location`) arguments.\u001b[39m\u001b[33m'\u001b[39m\n\u001b[32m 573\u001b[39m )\n\u001b[32m 574\u001b[39m \u001b[38;5;28mself\u001b[39m._http_options.base_url = \u001b[33m'\u001b[39m\u001b[33mhttps://generativelanguage.googleapis.com/\u001b[39m\u001b[33m'\u001b[39m\n\u001b[32m 575\u001b[39m \u001b[38;5;28mself\u001b[39m._http_options.api_version = \u001b[33m'\u001b[39m\u001b[33mv1beta\u001b[39m\u001b[33m'\u001b[39m\n", 20 | "\u001b[31mValueError\u001b[39m: Missing key inputs argument! To use the Google AI API, provide (`api_key`) arguments. To use the Google Cloud API, provide (`vertexai`, `project` & `location`) arguments." 21 | ] 22 | } 23 | ], 24 | "source": [ 25 | "from google import genai\n", 26 | "\n", 27 | "# The client gets the API key from the environment variable `GEMINI_API_KEY`.\n", 28 | "client = genai.Client()\n", 29 | "\n", 30 | "response = client.models.generate_content(\n", 31 | " model=\"gemini-2.5-flash\", contents=\"天空為什麼是藍的?\"\n", 32 | ")\n", 33 | "print(response.text)" 34 | ] 35 | } 36 | ], 37 | "metadata": { 38 | "kernelspec": { 39 | "display_name": "line_bot", 40 | "language": "python", 41 | "name": "python3" 42 | }, 43 | "language_info": { 44 | "codemirror_mode": { 45 | "name": "ipython", 46 | "version": 3 47 | }, 48 | "file_extension": ".py", 49 | "mimetype": "text/x-python", 50 | "name": "python", 51 | "nbconvert_exporter": "python", 52 | "pygments_lexer": "ipython3", 53 | "version": "3.12.11" 54 | } 55 | }, 56 | "nbformat": 4, 57 | "nbformat_minor": 5 58 | } 59 | -------------------------------------------------------------------------------- /reference/python_ollama_applications.md: -------------------------------------------------------------------------------- 1 | # Python + Ollama 應用程式想法集 2 | 3 | 基於 `ollama.md` 中的基礎範例,以下是一些實用的 Python + Ollama 應用程式想法,適合教學和實際應用。 4 | 5 | ## 🎯 教學導向應用 6 | 7 | ### 1. 程式碼解釋器 8 | 讓學生貼上程式碼,AI 解釋每一行在做什麼 9 | 10 | ```python 11 | import requests 12 | 13 | def generate_response(prompt: str, model: str = "gemma:2b") -> str: 14 | url = "http://localhost:11434/api/generate" 15 | payload = { 16 | "model": model, 17 | "prompt": prompt, 18 | "stream": False 19 | } 20 | try: 21 | response = requests.post(url, json=payload) 22 | return response.json()["response"] 23 | except Exception as e: 24 | return f"錯誤:{e}" 25 | 26 | def explain_code(code_snippet): 27 | prompt = f"請逐行解釋這段 Python 程式碼:\n{code_snippet}" 28 | return generate_response(prompt) 29 | 30 | # 使用範例 31 | code = """ 32 | def factorial(n): 33 | if n <= 1: 34 | return 1 35 | return n * factorial(n-1) 36 | """ 37 | print(explain_code(code)) 38 | ``` 39 | 40 | ### 2. 程式碼除錯助手 41 | 學生遇到錯誤時,AI 幫忙找問題 42 | 43 | ```python 44 | def debug_helper(error_message, code): 45 | prompt = f"這段程式碼出現錯誤:{error_message}\n程式碼:\n{code}\n請幫我找出問題並提供解決方案" 46 | return generate_response(prompt) 47 | 48 | # 使用範例 49 | error_code = """ 50 | def greet(name) 51 | print(f"Hello, {name}!") 52 | """ 53 | error_msg = "SyntaxError: invalid syntax" 54 | print(debug_helper(error_msg, error_code)) 55 | ``` 56 | 57 | ### 3. 練習題產生器 58 | 根據主題自動產生程式練習題 59 | 60 | ```python 61 | def generate_exercise(topic, difficulty="初級"): 62 | prompt = f"請產生一個關於 {topic} 的 {difficulty} Python 練習題,包含題目描述和範例解答" 63 | return generate_response(prompt) 64 | 65 | # 使用範例 66 | print(generate_exercise("迴圈", "中級")) 67 | ``` 68 | 69 | ## 🚀 實用工具應用 70 | 71 | ### 4. 智能筆記整理 72 | 將課堂筆記轉換成結構化內容 73 | 74 | ```python 75 | def organize_notes(raw_notes): 76 | prompt = f"請將以下筆記整理成清楚的重點摘要,使用條列式格式:\n{raw_notes}" 77 | return generate_response(prompt) 78 | 79 | # 使用範例 80 | notes = """ 81 | 今天學了變數 變數可以存資料 有不同類型 int str float bool 82 | 還有list和dict 可以用來存多個資料 83 | """ 84 | print(organize_notes(notes)) 85 | ``` 86 | 87 | ### 5. 程式碼風格檢查器 88 | 檢查程式碼是否符合 PEP 8 規範 89 | 90 | ```python 91 | def style_checker(code): 92 | prompt = f"請檢查這段程式碼的風格,並提供 PEP 8 規範的改善建議:\n{code}" 93 | return generate_response(prompt) 94 | 95 | # 使用範例 96 | messy_code = """ 97 | def calculate_area(length,width): 98 | result=length*width 99 | return result 100 | """ 101 | print(style_checker(messy_code)) 102 | ``` 103 | 104 | ### 6. 文件字串產生器 105 | 自動為函式產生說明文件 106 | 107 | ```python 108 | def generate_docstring(function_code): 109 | prompt = f"請為這個函式產生完整的 Google 風格 docstring:\n{function_code}" 110 | return generate_response(prompt) 111 | 112 | # 使用範例 113 | func_code = """ 114 | def calculate_bmi(weight, height): 115 | return weight / (height ** 2) 116 | """ 117 | print(generate_docstring(func_code)) 118 | ``` 119 | 120 | ## 🎮 互動式學習工具 121 | 122 | ### 7. Python 問答遊戲 123 | 124 | ```python 125 | def python_quiz(): 126 | prompt = "請出一題 Python 基礎概念的選擇題,包含 4 個選項和正確答案" 127 | return generate_response(prompt) 128 | 129 | def quiz_game(): 130 | print("🎯 Python 知識問答遊戲") 131 | while True: 132 | print("\n" + "="*50) 133 | print(python_quiz()) 134 | 135 | continue_game = input("\n繼續下一題?(y/n): ") 136 | if continue_game.lower() != 'y': 137 | break 138 | print("感謝參與!") 139 | 140 | # 啟動遊戲 141 | # quiz_game() 142 | ``` 143 | 144 | ### 8. 程式碼翻譯器 145 | 將自然語言轉換成 Python 程式碼 146 | 147 | ```python 148 | def natural_to_code(description): 149 | prompt = f"請將以下描述轉換成 Python 程式碼,並加上註解說明:{description}" 150 | return generate_response(prompt) 151 | 152 | # 使用範例 153 | description = "建立一個函式,計算一個數字列表的平均值" 154 | print(natural_to_code(description)) 155 | ``` 156 | 157 | ## 📊 進階應用 158 | 159 | ### 9. 學習進度追蹤 160 | 161 | ```python 162 | import json 163 | from datetime import datetime 164 | 165 | def learning_assessment(student_code, topic): 166 | prompt = f"評估這段關於 {topic} 的程式碼,給出學習建議和評分(1-10分):\n{student_code}" 167 | return generate_response(prompt) 168 | 169 | def save_progress(student_name, topic, code, assessment): 170 | progress_data = { 171 | "timestamp": datetime.now().isoformat(), 172 | "student": student_name, 173 | "topic": topic, 174 | "code": code, 175 | "assessment": assessment 176 | } 177 | 178 | # 儲存到檔案 (實際應用中可能使用資料庫) 179 | with open(f"progress_{student_name}.json", "a", encoding="utf-8") as f: 180 | f.write(json.dumps(progress_data, ensure_ascii=False) + "\n") 181 | 182 | # 使用範例 183 | student_code = """ 184 | numbers = [1, 2, 3, 4, 5] 185 | total = 0 186 | for num in numbers: 187 | total += num 188 | average = total / len(numbers) 189 | print(average) 190 | """ 191 | assessment = learning_assessment(student_code, "迴圈和平均值計算") 192 | save_progress("張同學", "迴圈", student_code, assessment) 193 | ``` 194 | 195 | ### 10. 專案想法產生器 196 | 197 | ```python 198 | def suggest_project(skill_level, interests): 199 | prompt = f"推薦一個適合 {skill_level} 程度,對 {interests} 有興趣的學生的 Python 專案,包含:\n1. 專案描述\n2. 主要功能\n3. 需要用到的技術\n4. 預估完成時間" 200 | return generate_response(prompt) 201 | 202 | # 使用範例 203 | print(suggest_project("中級", "遊戲開發")) 204 | ``` 205 | 206 | ## 🔧 完整應用範例:多功能學習助手 207 | 208 | ```python 209 | class PythonLearningAssistant: 210 | def __init__(self, model="gemma:2b"): 211 | self.model = model 212 | 213 | def generate_response(self, prompt): 214 | url = "http://localhost:11434/api/generate" 215 | payload = { 216 | "model": self.model, 217 | "prompt": prompt, 218 | "stream": False 219 | } 220 | try: 221 | response = requests.post(url, json=payload) 222 | return response.json()["response"] 223 | except Exception as e: 224 | return f"錯誤:{e}" 225 | 226 | def main_menu(self): 227 | while True: 228 | print("\n🐍 Python 學習助手") 229 | print("1. 程式碼解釋") 230 | print("2. 除錯協助") 231 | print("3. 產生練習題") 232 | print("4. 風格檢查") 233 | print("5. 知識問答") 234 | print("6. 離開") 235 | 236 | choice = input("請選擇功能 (1-6): ") 237 | 238 | if choice == "1": 239 | code = input("請輸入要解釋的程式碼:\n") 240 | print(self.explain_code(code)) 241 | elif choice == "2": 242 | code = input("請輸入有問題的程式碼:\n") 243 | error = input("錯誤訊息:") 244 | print(self.debug_helper(error, code)) 245 | elif choice == "3": 246 | topic = input("請輸入主題:") 247 | level = input("難度 (初級/中級/高級):") 248 | print(self.generate_exercise(topic, level)) 249 | elif choice == "4": 250 | code = input("請輸入要檢查的程式碼:\n") 251 | print(self.style_checker(code)) 252 | elif choice == "5": 253 | print(self.python_quiz()) 254 | elif choice == "6": 255 | print("再見!") 256 | break 257 | else: 258 | print("無效選擇,請重新輸入") 259 | 260 | def explain_code(self, code_snippet): 261 | prompt = f"請逐行解釋這段 Python 程式碼:\n{code_snippet}" 262 | return self.generate_response(prompt) 263 | 264 | def debug_helper(self, error_message, code): 265 | prompt = f"這段程式碼出現錯誤:{error_message}\n程式碼:\n{code}\n請幫我找出問題並提供解決方案" 266 | return self.generate_response(prompt) 267 | 268 | def generate_exercise(self, topic, difficulty="初級"): 269 | prompt = f"請產生一個關於 {topic} 的 {difficulty} Python 練習題,包含題目描述和範例解答" 270 | return self.generate_response(prompt) 271 | 272 | def style_checker(self, code): 273 | prompt = f"請檢查這段程式碼的風格,並提供 PEP 8 規範的改善建議:\n{code}" 274 | return self.generate_response(prompt) 275 | 276 | def python_quiz(self): 277 | prompt = "請出一題 Python 基礎概念的選擇題,包含 4 個選項和正確答案" 278 | return self.generate_response(prompt) 279 | 280 | # 啟動應用 281 | if __name__ == "__main__": 282 | assistant = PythonLearningAssistant() 283 | assistant.main_menu() 284 | ``` 285 | 286 | ## 📝 使用說明 287 | 288 | 1. **前置需求**: 289 | - 確保 Ollama 正在執行 290 | - 已下載 gemma:2b 模型 (`ollama run gemma:2b`) 291 | - 安裝 requests 套件 (`pip install requests`) 292 | 293 | 2. **基礎設定**: 294 | - 所有範例都基於 `ollama.md` 中的 `generate_response` 函式 295 | - API 端點:`http://localhost:11434/api/generate` 296 | - 預設模型:`gemma:2b` 297 | 298 | 3. **擴展建議**: 299 | - 可以整合 Flask 建立 Web 介面 300 | - 使用 Streamlit 建立互動式應用 301 | - 加入資料庫儲存學習記錄 302 | - 整合 Jupyter Notebook 進行教學 303 | 304 | ## 🚀 下一步 305 | 306 | 這些應用可以進一步發展為: 307 | - **Web 應用**:使用 Flask 或 FastAPI 308 | - **桌面應用**:使用 Tkinter 或 PyQt 309 | - **聊天機器人**:整合 LINE Bot 或 Discord Bot 310 | - **教學平台**:結合 LMS 系統 311 | 312 | 每個應用都可以根據實際需求進行客製化調整。 -------------------------------------------------------------------------------- /lesson7/lesson7_3.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "id": "7e6aa0cd", 7 | "metadata": {}, 8 | "outputs": [ 9 | { 10 | "name": "stdout", 11 | "output_type": "stream", 12 | "text": [ 13 | "人工智慧(AI)是如何運作的,這是一個既複雜又迷人的問題。簡而言之,AI的工作原理是**透過學習大量的資料,從中辨識模式、建立規則,然後運用這些學到的知識來執行\n", 14 | "任務、做出預測或解決問題**。\n", 15 | "\n", 16 | "我們可以將這個過程分解成幾個核心步驟和概念:\n", 17 | "\n", 18 | "### AI 的核心運作機制\n", 19 | "\n", 20 | "1. **資料收集與準備 (Data Collection & Preparation)**\n", 21 | " * **\n", 22 | "AI 的「食物」:** AI 系統需要龐大的資料來學習。這些資料可以是文字、圖片、聲音、影片、數字表格等任何形式的資訊。\n", 23 | " * **標籤化:** 對於許多\n", 24 | " AI 模型(特別是監督式學習),資料需要被「標籤」或「註釋」。例如,如果訓練一個辨識貓的 AI,你就需要給大量的貓圖片打上「貓」的標籤。\n", 25 | "\n", 26 | "\n", 27 | "2. **演算法選擇與設計 (Algorithm Selection & Design)**\n", 28 | " * **AI 的「大腦」或「食譜」:** 演算法是一組指令或規則,告訴 AI 如何處理資料、如何\n", 29 | "從資料中學習模式、以及如何根據這些模式做出決策。\n", 30 | " * **多樣性:** 存在各種各樣的演算法,例如決策樹、支援向量機、神經網路等,\n", 31 | "每種都有其擅長的任務。選擇哪種演算法取決於要解決的問題類型。\n", 32 | "\n", 33 | "3. **模型訓練 (Model Training)**\n", 34 | " * **學習的過程:** 這是 AI 真正的「學習」階段\n", 35 | "。研究人員或工程師會將準備好的資料輸入到選定的演算法中。\n", 36 | " * **模式識別:** 演算法會反覆地處理這些資料,並調整其內部的參數,以找出\n", 37 | "資料中的規律和關聯性。這個過程就像一個學生不斷做練習題,每次做錯了就根據答案來修正自己的理解。\n", 38 | " * **優化目標:** 訓練的目標通常是最小化錯誤\n", 39 | "率或最大化預測準確性。\n", 40 | "\n", 41 | "4. **模型評估與最佳化 (Model Evaluation & Optimization)**\n", 42 | " * **驗證與測試:** 訓練完成後,AI 系統會生成\n", 43 | "一個「模型」(Model),這就是它學到的知識的集合。這個模型需要用獨立的、未曾見過的測試資料來評估其效能和準確性。\n", 44 | " * **微調:** 如果\n", 45 | "模型的表現不盡理想,可能需要回到前一步,調整演算法的參數,或增加更多、更優質的資料,進行再次訓練,直到達到預期的效果。\n", 46 | "\n", 47 | "5. **預測與應用 (Prediction\n", 48 | " & Application / Inference)**\n", 49 | " * **實際運用:** 一旦模型被驗證為有效,它就可以投入實際應用。當新的、從未見過的資料輸入到這個訓練好的模型中時,模型會\n", 50 | "根據它學到的知識,立即做出判斷、預測或生成輸出。\n", 51 | " * **範例:**\n", 52 | " * 給它一張新圖片,它能辨識出圖片中的物體(圖像識別)。\n", 53 | "\n", 54 | " * 給它一段語音,它能轉錄成文字(語音辨識)。\n", 55 | " * 給它您的偏好,它能推薦您可能喜歡的商品(推薦系統)。\n", 56 | "\n", 57 | "6. **\n", 58 | "持續學習與改進 (Continuous Learning & Improvement)**\n", 59 | " * **非靜態:** 大多數現代 AI 系統並非一成不變。它們可以從新的資料和實際應用中的反饋中繼續\n", 60 | "學習,不斷優化自身的性能和準確性。\n", 61 | " * **反饋迴路:** 例如,一個垃圾郵件篩選器會根據用戶對郵件的標記(是垃圾郵件還是非\n", 62 | "垃圾郵件)來調整其判斷邏輯。\n", 63 | "\n", 64 | "### 關鍵技術:機器學習與深度學習\n", 65 | "\n", 66 | "* **機器學習 (Machine Learning, ML):**\n", 67 | " * 這是實現 AI 最常見的方式。它\n", 68 | "讓電腦能夠從資料中學習,而無需被明確地編程來執行特定任務。\n", 69 | " * **監督式學習:** 最常見的一種,使用帶有「答案」(標籤)的資料來訓練模型\n", 70 | ",例如預測房價、辨識手寫數字。\n", 71 | " * **非監督式學習:** 使用沒有標籤的資料,目標是發現資料中的隱藏結構或模式,例如將客戶分群。\n", 72 | " \n", 73 | "* **強化學習:** AI 透過與環境互動,嘗試不同的行動,並根據「獎勵」或「懲罰」來學習最佳策略,類似於玩遊戲或訓練機器人。\n", 74 | "\n", 75 | "* **深度學習 (\n", 76 | "Deep Learning, DL):**\n", 77 | " * 是機器學習的一個子集,特別擅長處理非結構化資料(如圖片、語音、文本)。\n", 78 | " * **神經網路:** 深度學習的核心是\n", 79 | "「深度神經網路」,它們模擬人腦的結構,由許多層次的「神經元」組成。每一層從前一層接收輸入,進行處理,然後將輸出傳遞給下一層。層次越深,\n", 80 | "模型就能學習到越複雜和抽象的特徵。\n", 81 | " * **大數據 + 強大運算力:** 深度學習的成功在很大程度上歸功於大數據的普及和強大計算能力的發展(\n", 82 | "尤其是 GPU)。\n", 83 | "\n", 84 | "### 一個簡單的比喻\n", 85 | "\n", 86 | "想像 AI 是一個正在學習的**學生**:\n", 87 | "\n", 88 | "1. **資料**就像是**課本和大量的練習題**(有答案的)。\n", 89 | "2. **演\n", 90 | "算法**就像是**老師**,他設計了教學方法和學習策略。\n", 91 | "3. **模型訓練**就像是**學生反覆閱讀課本、做練習題,並根據老師的批改(反饋)來修正\n", 92 | "自己的理解和解題方法**。這個過程需要時間和大量的練習。\n", 93 | "4. **訓練好的模型**就像是**掌握了知識並能獨立解題的學生**。\n", 94 | "5. **預測與應用**\n", 95 | "就像是**學生參加考試,將學到的知識應用到新的問題上,給出答案**。\n", 96 | "6. **持續學習與改進**就像是**學生畢業後,在實際工作中不斷學習新知識、\n", 97 | "累積經驗,變得越來越專業**。\n", 98 | "\n", 99 | "總而言之,AI 的運作原理並非魔術,而是基於數學、統計學和電腦科學的嚴謹工程。它從大量的資料中提取有用的資訊,並學\n", 100 | "會如何利用這些資訊來完成各種複雜的任務。\n" 101 | ] 102 | } 103 | ], 104 | "source": [ 105 | "from google import genai\n", 106 | "\n", 107 | "client = genai.Client()\n", 108 | "response = client.models.generate_content_stream(\n", 109 | " model=\"gemini-2.5-flash\",\n", 110 | " contents=[\"AI是如何工作的(請使用繁體中文回答)?\"],\n", 111 | ")\n", 112 | "for chunk in response:\n", 113 | " print(chunk.text)" 114 | ] 115 | }, 116 | { 117 | "cell_type": "code", 118 | "execution_count": 1, 119 | "id": "455d0307", 120 | "metadata": {}, 121 | "outputs": [ 122 | { 123 | "name": "stdout", 124 | "output_type": "stream", 125 | "text": [ 126 | "5\n", 127 | "9\n", 128 | "10\n" 129 | ] 130 | } 131 | ], 132 | "source": [ 133 | "for item in [5, 9, 10]:\n", 134 | " print(item)" 135 | ] 136 | }, 137 | { 138 | "cell_type": "code", 139 | "execution_count": 3, 140 | "id": "4745bf7d", 141 | "metadata": {}, 142 | "outputs": [ 143 | { 144 | "data": { 145 | "text/markdown": [ 146 | "這是一隻**棕熊 (Brown Bear)**,在北美洲也被廣泛稱為**灰熊 (Grizzly Bear)**。\n", 147 | "\n", 148 | "以下是關於棕熊的一些資訊:\n", 149 | "\n", 150 | "1. **學名 (Scientific Name)**:*Ursus arctos*\n", 151 | "\n", 152 | "2. **分佈 (Distribution)**:\n", 153 | " 棕熊是地球上分佈最廣的熊科動物之一,廣泛分佈於北美洲(包括阿拉斯加、加拿大大部分地區和美國西北部幾個州)和歐亞大陸(包括俄羅斯、斯堪的納維亞、中歐、東歐以及亞洲的一些地區,例如日本北海道)。\n", 154 | "\n", 155 | "3. **外形特徵 (Physical Characteristics)**:\n", 156 | " * **體型龐大**:棕熊是陸地上體型最大的食肉目動物之一(儘管它們是雜食性)。成年雄性體重通常在180-360公斤之間,有些巨大的亞種,如科迪亞克棕熊,體重可超過600公斤。\n", 157 | " * **毛色多樣**:毛色從淺棕色、金黃色、紅棕色到深棕色甚至近乎黑色不等。很多棕熊的毛尖呈灰白色,尤其是在肩部和背部,因此得名「灰熊」。\n", 158 | " * **肩部隆起 (Shoulder Hump)**:棕熊的一個顯著特徵是肩部有一個明顯的肌肉隆起(駝峰),這是由於強大的肌肉附著在脊柱上,這些肌肉為其前肢提供了挖掘和奔跑所需的巨大力量。這是區分棕熊與黑熊(黑熊通常沒有明顯的肩部隆起)的重要標誌。\n", 159 | " * **爪子**:擁有長而彎曲、無法完全收回的爪子,非常適合挖掘洞穴、根莖和捕食。\n", 160 | " * **面部**:頭部較大,面部輪廓較寬且略微凹陷。\n", 161 | "\n", 162 | "4. **食性 (Diet)**:\n", 163 | " 棕熊是**雜食性動物**,食譜非常廣泛,這使得它們能夠適應多種棲息地。\n", 164 | " * **植物性食物**:包括漿果、堅果、植物根莖、塊莖、蘑菇、草和各種植物。\n", 165 | " * **動物性食物**:包括昆蟲(如螞蟻、甲蟲幼蟲)、魚類(尤其是在鮭魚洄游季節捕食鮭魚)、小型哺乳動物(如嚙齒動物、旱獺)、腐肉,有時也會捕食大型有蹄類動物(如鹿、駝鹿的幼崽)。\n", 166 | "\n", 167 | "5. **行為習性 (Behavior and Habits)**:\n", 168 | " * **獨居**:大多數時間是獨居的,但食物豐富的地區(如鮭魚洄游的河流)會吸引多隻棕熊聚集。\n", 169 | " * **冬眠**:在寒冷的冬季,棕熊會進入冬眠狀態,在洞穴或巢穴中度過。冬眠期間,它們不吃不喝,依靠體內儲存的脂肪維持生命。\n", 170 | " * **感官**:嗅覺極其靈敏,是其尋找食物和感知環境的主要感官。聽覺和視覺也很好。\n", 171 | " * **運動能力**:儘管體型龐大,棕熊奔跑速度非常快(可達55公里/小時),游泳能力也很強,甚至能爬樹(尤其是幼熊)。\n", 172 | "\n", 173 | "6. **繁殖 (Reproduction)**:\n", 174 | " 棕熊通常在春末夏初交配。幼崽(通常1-4隻)在冬季冬眠期間出生,由雌性熊獨自撫養約2-3年。\n", 175 | "\n", 176 | "7. **保護狀況 (Conservation Status)**:\n", 177 | " 全球範圍內,棕熊的總體數量被列為「無危」(Least Concern)。然而,由於棲息地喪失、人類活動擴張和歷史上的過度捕獵,一些地區的亞種或孤立種群數量有所下降,面臨威脅,並受到當地法律的保護。\n", 178 | "\n", 179 | "棕熊在生態系統中扮演著重要角色,作為頂級捕食者和廣泛的雜食動物,它們有助於維持生物多樣性和植物種子的傳播。" 180 | ], 181 | "text/plain": [ 182 | "" 183 | ] 184 | }, 185 | "metadata": {}, 186 | "output_type": "display_data" 187 | } 188 | ], 189 | "source": [ 190 | "import PIL.Image\n", 191 | "from google import genai\n", 192 | "from IPython.display import display, Markdown\n", 193 | "\n", 194 | "client = genai.Client()\n", 195 | "image = PIL.Image.open('bear.jpg')\n", 196 | "response = client.models.generate_content(\n", 197 | " model=\"gemini-2.5-flash\",\n", 198 | " contents=[image, \"請告訴我這是什麼動物,還有關於它的一些資訊\"]\n", 199 | ")\n", 200 | "\n", 201 | "display(Markdown(response.text))" 202 | ] 203 | }, 204 | { 205 | "cell_type": "code", 206 | "execution_count": 5, 207 | "id": "5fb235e7", 208 | "metadata": {}, 209 | "outputs": [ 210 | { 211 | "name": "stdout", 212 | "output_type": "stream", 213 | "text": [ 214 | "好的,有兩隻狗在家裡,真熱鬧!\n", 215 | "\n", 216 | "牠們是你的好朋友吧?有什麼關於牠們的問題,或是想分享的嗎?根據您之前提到的,您家裡有兩隻狗。\n", 217 | "\n", 218 | "一般來說,一隻狗有四隻爪子。\n", 219 | "\n", 220 | "所以,兩隻狗總共有 2 x 4 = 8 隻爪子。\n", 221 | "\n", 222 | "您家裡有 **8** 隻爪子。=========chat內的記憶=============\n", 223 | "\n", 224 | "role - user: 我有2隻狗在我的房子內\n", 225 | "role - model: 好的,有兩隻狗在家裡,真熱鬧!\n", 226 | "\n", 227 | "牠們是你的好朋友吧?有什麼關於牠們的問題,或是想分享的嗎?\n", 228 | "role - user: 在我家裏有多少爪子?(請使用繁體中文回答,不要和我開玩笑)\n", 229 | "role - model: 根據您之前提到的,您家裡有兩隻狗。\n", 230 | "\n", 231 | "一般來說,一隻狗有四隻爪子。\n", 232 | "\n", 233 | "所以,兩隻狗總共有 2 x 4 = 8 隻爪子。\n", 234 | "\n", 235 | "您家\n", 236 | "role - model: 裡有 **8** 隻爪子。\n" 237 | ] 238 | } 239 | ], 240 | "source": [ 241 | "from google import genai\n", 242 | "\n", 243 | "client = genai.Client()\n", 244 | "chat = client.chats.create(model=\"gemini-2.5-flash\")\n", 245 | "\n", 246 | "response = chat.send_message_stream(\"我有2隻狗在我的房子內\")\n", 247 | "for chunk in response:\n", 248 | " print(chunk.text, end=\"\")\n", 249 | "\n", 250 | "response = chat.send_message_stream('在我家裏有多少爪子?(請使用繁體中文回答,不要和我開玩笑)')\n", 251 | "for chunk in response:\n", 252 | " print(chunk.text, end=\"\")\n", 253 | "\n", 254 | "print(\"=========chat內的記憶=============\\n\")\n", 255 | "for message in chat.get_history():\n", 256 | " print(f'role - {message.role}', end=\": \")\n", 257 | " print(message.parts[0].text)" 258 | ] 259 | } 260 | ], 261 | "metadata": { 262 | "kernelspec": { 263 | "display_name": "line_bot", 264 | "language": "python", 265 | "name": "python3" 266 | }, 267 | "language_info": { 268 | "codemirror_mode": { 269 | "name": "ipython", 270 | "version": 3 271 | }, 272 | "file_extension": ".py", 273 | "mimetype": "text/x-python", 274 | "name": "python", 275 | "nbconvert_exporter": "python", 276 | "pygments_lexer": "ipython3", 277 | "version": "3.12.11" 278 | } 279 | }, 280 | "nbformat": 4, 281 | "nbformat_minor": 5 282 | } 283 | --------------------------------------------------------------------------------