2024年12月14日 星期六

Ollama的工具(Tools)使用

Ollama Python函式庫:https://github.com/ollama/ollama-python

範例:加法和減法

 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
from ollama import chat
from ollama import ChatResponse


def add_two_numbers(a: int, b: int) -> int:
  """
  Add two numbers

  Args:
    a (int): The first number
    b (int): The second number

  Returns:
    int: The sum of the two numbers
  """
  return int(a) + int(b)


def subtract_two_numbers(a: int, b: int) -> int:
  """
  Subtract two numbers
  """
  return int(a) - int(b)


# Tools can still be manually defined and passed into chat
subtract_two_numbers_tool = {
  'type': 'function',
  'function': {
    'name': 'subtract_two_numbers',
    'description': 'Subtract two numbers',
    'parameters': {
      'type': 'object',
      'required': ['a', 'b'],
      'properties': {
        'a': {'type': 'integer', 'description': 'The first number'},
        'b': {'type': 'integer', 'description': 'The second number'},
      },
    },
  },
}

messages = [{'role': 'user', 'content': '請問4扣3為?'}]
print('Prompt:', messages[0]['content'])

available_functions = {
  'add_two_numbers': add_two_numbers,
  'subtract_two_numbers': subtract_two_numbers,
}

response: ChatResponse = chat(
  'llama3.2',
  messages=messages,
  tools=[add_two_numbers, subtract_two_numbers_tool],
)

if response.message.tool_calls:
  # There may be multiple tool calls in the response
  for tool in response.message.tool_calls:
    # Ensure the function is available, and then call it
    if function_to_call := available_functions.get(tool.function.name):
      print('Calling function:', tool.function.name)
      print('Arguments:', tool.function.arguments)
      output = function_to_call(**tool.function.arguments)
      print('Function output:', output)
    else:
      print('Function', tool.function.name, 'not found')

# Only needed to chat with the model using the tool call results
if response.message.tool_calls:
  # Add the function response to messages for the model to use
  messages.append(response.message)
  messages.append({'role': 'tool', 'content': str(output), 'name': tool.function.name})

  # Get final response from model with function outputs
  final_response = chat('llama3.2', messages=messages)
  print('Final response:', final_response.message.content)

else:
  print('No tool calls returned from model')

第1次執行結果:
Prompt: 請問4扣3為?
Calling function: subtract_two_numbers
Arguments: {'a': '4', 'b': '3'}
Function output: 1
Final response: 答案是 1

第2次執行結果:
Prompt: 請問4扣3為?
Calling function: subtract_two_numbers
Arguments: {'a': '4', 'b': '3'}
Function output: 1
Final response: 4 - 3 = 1

Ollama的聊天和生成功能

範例一、Ollama聊天

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import ollama

question_1 = "什麼是5 + 6?"

ans_1 = "5 + 6 是 11,這是基本運算,5加上6等於11。"

question_2 = "再加8後,答案會是多少呢?"

response = ollama.chat(
    model="llama3.2",
    messages=[
        {"role": "user", "content": question_1},
        {"role": "assistant", "content": ans_1},
        {"role": "user", "content": question_2}
    ]
)

print(response["message"]["role"])
print(response["message"]["content"])

第一次執行結果:
assistant
11 加 8 等於 19。

第一次執行結果:
assistant
如果我們再加8到11,那麼就變成19了。 

範例二、


所以,5 + 6 + 8 = 19

第二次執行結果:
assistant
如果我們再加8到11,那么結果就變成了19了。

範例二、Ollama生成
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import ollama

question_1 = "什麼是5 + 6?"

ans_1 = "5 + 6 是 11,這是基本運算,5加上6等於11。"

question_2 = "再加8後,答案會是多少呢?"

prompt = f"""<|user|>
{question_1}<|end|>
<|assistant|>
{ans_1}<|end|>
<|user|>
{question_2}<|end|>
<|assistant|>
"""

response = ollama.generate(
    model="llama3.2",
    prompt=prompt
)

print(response["response"])

第一次執行:
再加8後,11 + 8 = 19。

第二次執行:
11 + 8 = 19

第三次執行:
11 + 8 = 19

2024年12月12日 星期四

Ollama、MQTT、phidata、LLM Agent整合測試

程式(黃色部份需設定到您用的MQTT broker):

 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
import os
import json
from phi.agent import Agent
from phi.model.ollama import Ollama
import paho.mqtt.client as mqtt
import random

MQTT_BROKER = os.getenv("MQTT_BROKER")
MQTT_PORT = int(os.getenv("MQTT_PORT"))
MQTT_USER = os.getenv("MQTT_USER")
MQTT_PASSWORD = os.getenv("MQTT_PASSWORD")
MQTT_TOPIC = "NFU/LED"
client_id = f'python-mqtt-{random.randint(0, 1000)}'

def control_led(action: bool):
    try:
        client = mqtt.Client(client_id)
        client.username_pw_set(MQTT_USER, MQTT_PASSWORD)
        client.connect(MQTT_BROKER, MQTT_PORT, 60)
        message = json.dumps({"action": "on" if action else "off"})
        client.publish(MQTT_TOPIC, message)
        client.disconnect()
        return f"成功{'打開' if action else '關閉'} LED"
    except Exception as e:
        print(f"Debug - MQTT Error: {str(e)}")
        print(f"Debug - MQTT Settings: Broker={MQTT_BROKER}, Port={MQTT_PORT}")
        return f"LED 控制失敗: {str(e)}"

led_agent = Agent(
    name="LED Control Agent",
    role="控制 LED 開關",
    instructions=[
        "你是一個 LED 控制助手,負責解析用戶的開關燈指令。",
        "當用戶要求打開 LED 時,呼叫 control_led(True)",
        "當用戶要求關閉 LED 時,呼叫 control_led(False)",
        "對於不明確的指令,請詢問用戶具體需求"
    ],
    tools=[control_led],
    model=Ollama(id="llama3.2")
)

def main():
    print("智能助理已啟動!(輸入 'exit' 結束程式)")
    print("您可以:")
    print("1. 控制 LED 開關 (例如:'請打開 LED' 或 '關燈')")
    
    while True:
        user_input = input("\n請輸入指令: ").strip()
        
        if user_input.lower() == 'exit':
            print("程式已結束")
            break
            
        try:
            response = led_agent.run(user_input, stream=False)
            
            for message in response.messages:
                if message.role == "assistant" and message.content:
                    print("\n助理回應:", message.content.strip())
                    
        except Exception as e:
            print(f"\n錯誤:{str(e)}")

if __name__ == "__main__":
    main()

執行結果:
智能助理已啟動!(輸入 'exit' 結束程式)
您可以:
1. 控制 LED 開關 (例如:'請打開 LED' 或 '關燈')

請輸入指令: 請打開 LED

助理回應: 您可以開始使用 LED 的功能了。

請輸入指令: 我要睡覺了

助理回應: LEDs 已經關閉,好night!

請輸入指令: 



Ollama與MQTT的串接

本程式是由ChatGPT所產生,MQTT Broker是採用小霸王科技的伺服器。

程式碼:

 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
import paho.mqtt.client as mqtt
import ollama

# MQTT 代理伺服器設定
MQTT_BROKER = "broker.MQTTGO.io"    # MQTT 伺服器地址
MQTT_PORT = 1883             # MQTT 伺服器端口
MQTT_SUB_TOPIC = "ollama/input"   # 訂閱的主題
MQTT_PUB_TOPIC = "ollama/output"  # 發布的主題

# 連接 MQTT 代理伺服器時的回調函數
def on_connect(client, userdata, flags, rc):
    print("Connected with result code " + str(rc))
    client.subscribe(MQTT_SUB_TOPIC)

# 接收 MQTT 訊息時的回調函數
def on_message(client, userdata, msg):
    payload = msg.payload.decode()
    print(f"Received message: {payload}")

    # 調用 Ollama 生成回應
    try:
        response = ollama.chat(model="llama3.2", messages=[{"role": "user", "content": payload}])
        reply = response['message']['content']
        print(f"Ollama response: {reply}")

        # 將 Ollama 回應發布到指定的 MQTT 主題
        client.publish(MQTT_PUB_TOPIC, reply)
    except Exception as e:
        print(f"Error: {e}")
        client.publish(MQTT_PUB_TOPIC, f"Error: {str(e)}")

# 初始化 MQTT 客戶端
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message

# 連接到 MQTT 代理伺服器
client.connect(MQTT_BROKER, MQTT_PORT, 60)

# 保持 MQTT 連接運行
client.loop_forever()

執行結果:
Connected with result code 0
Received message: 您是誰
Ollama response: 我是GPT-4,一个高级人工智能模型。我的前身是GPT-3,它在多个领域的应用中取得了成功。
Received message: 請用繁體中文
Ollama response: 我可以以繁體中文回答問題。請問您什麼事項?
Received message: 給我一個小故事
Ollama response: 有一個小女孩,她名叫 Lily,住在一條狹窄的街道上。Lily喜歡於夜晚去探索街頭,她認為這是唯一能夠解開她自己想象中的真空的時間。

一次,她經過一個老人的住宅,發現那個男人正在下午睡覺。他心不在身事地一直從窗口觀看天空。Lily被告知:這位老人一直在用他的生命來觀察世界,他的目標是要知道有多大。

Lily問他:“您为什么会这样做?”

老人回答:“我想知道生命中最美丽的一刻是什么。我不想去看世界上的坏事。"

Lily覺得這個男人比她更年輕。老人告訴 Lily,當你在觀察時,你就不是正在生活,而是在回憶過去。

Lily的發現讓她開始反思她的生活。她開始去觀察和體驗,了解世界中的每一刻。她變成了他的學生,並在他的教導下長大。



本地大語言模型-Ollama的初體驗

 

官方網址:https://ollama.com/

從官網下載和安裝完畢後,可執行下列指令。

ollama run llama3.2

上圖是問它,"您是誰?",所回答的情形。

另外開一個CMD,執行Ollama的Python套件。


範例一、模型測試
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import ollama

def add_two_numbers(a: int, b: int) -> int:
  """
  Add two numbers

  Args:
    a: The first integer number
    b: The second integer number

  Returns:
    int: The sum of the two numbers
  """
  return a + b

response = ollama.chat(
  'llama3.2',
  messages=[{'role': 'user', 'content': 'What is 10 + 10?'}],
  tools=[add_two_numbers], # Actual function reference
)
print(response)

執行結果:
model='llama3.2' created_at='2024-12-12T13:04:38.698792Z' done=True done_reason='stop' total_duration=782117600 load_duration=15999800 prompt_eval_count=177 prompt_eval_duration=3000000 eval_count=24 eval_duration=760000000 message=Message(role='assistant', content='', images=None, tool_calls=[ToolCall(function=Function(name='add_two_numbers', arguments={'a': '10', 'b': '10'}))])

範例二、使用現有的函式當成工具

 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
import ollama
import requests

available_functions = {
  'request': requests.request,
}

response = ollama.chat(
  'llama3.2',
  messages=[{
    'role': 'user',
    'content': 'get the ollama.com webpage?',
  }],
  tools=[requests.request], 
)

for tool in response.message.tool_calls or []:
  function_to_call = available_functions.get(tool.function.name)
  if function_to_call == requests.request:
    # Make an HTTP request to the URL specified in the tool call
    resp = function_to_call(
      method=tool.function.arguments.get('method'),
      url=tool.function.arguments.get('url'),
    )
    print(resp.text)
  else:
    print('Function not found:', tool.function.name)

執行結果:

<!doctype html>
<html class="h-full overflow-y-scroll">
  <head>
    <title>Ollama</title>

    <meta charset="utf-8" />
    <meta name="description" content="Get up and running with large language models."/>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta property="og:title" content="Ollama" />
    <meta property="og:description" content="Get up and running with large language models." />
    <meta property="og:url" content="https://ollama.com" />
    <meta property="og:image" content="https://ollama.com/public/og.png" />
    <meta property="og:image:type" content="image/png" />
    <meta property="og:image:width" content="1200" />
    <meta property="og:image:height" content="628" />
    <meta property="og:type" content="website" />

    <meta property="twitter:card" content="summary" />
    <meta property="twitter:title" content="Ollama" />
    <meta property="twitter:description" content="Get up and running with large language models." />
    <meta property="twitter:site" content="ollama" />

    <meta property="twitter:image:src" content="https://ollama.com/public/og-twitter.png" />
    <meta property="twitter:image:width" content="1200" />
    <meta property="twitter:image:height" content="628" />

    <link rel="icon" type="image/png" sizes="16x16" href="/public/icon-16x16.png" />
    <link rel="icon" type="image/png" sizes="32x32" href="/public/icon-32x32.png" />
    <link rel="icon" type="image/png" sizes="48x48" href="/public/icon-48x48.png" />
    <link rel="icon" type="image/png" sizes="64x64" href="/public/icon-64x64.png" />
    <link rel="apple-touch-icon" sizes="180x180" href="/public/apple-touch-icon.png" />
    <link rel="icon" type="image/png" sizes="192x192" href="/public/android-chrome-icon-192x192.png" />
    <link rel="icon" type="image/png" sizes="512x512" href="/public/android-chrome-icon-512x512.png" />

    

    <link href="/public/tailwind.css?v=887f4a04580670d6bb554f7cfea2ae96" rel="stylesheet" />
    <script type="application/ld+json">
      {
        "@context": "https://schema.org",
        "@type": "WebSite",
        "name": "Ollama",
        "url": "https://ollama.com"
      }
    </script>

    <script type="text/javascript">
      function copyToClipboard(element) {
        let commandElement = null;
        const preElement = element.closest('pre');
        const languageNoneElement = element.closest('.language-none');

        if (preElement) {
          commandElement = preElement.querySelector('code');
        } else if (languageNoneElement) {
          commandElement = languageNoneElement.querySelector('.command');
        }

        if (!commandElement) {
          console.error('No code or command element found');
          return;
        }

        const code = commandElement.textContent ? commandElement.textContent.trim() : commandElement.value;

        navigator.clipboard
          .writeText(code)
          .then(() => {
            const copyIcon = element.querySelector('.copy-icon')
            const checkIcon = element.querySelector('.check-icon')

            copyIcon.classList.add('hidden')
            checkIcon.classList.remove('hidden')

            setTimeout(() => {
              copyIcon.classList.remove('hidden')
              checkIcon.classList.add('hidden')
            }, 2000)
          })
      }
    </script>
    
    <script>
      
      function getIcon(url) {
        url = url.toLowerCase();
        if (url.includes('x.com') || url.includes('twitter.com')) return 'x';
        if (url.includes('github.com')) return 'github';
        if (url.includes('linkedin.com')) return 'linkedin';
        if (url.includes('youtube.com')) return 'youtube';
        if (url.includes('hf.co') || url.includes('huggingface.co') || url.includes('huggingface.com')) return 'hugging-face';
        return 'default';
      }

      function setInputIcon(input) {
        const icon = getIcon(input.value);
        const img = input.previousElementSibling.querySelector('img');
        img.src = `/public/social/${icon}.svg`;
        img.alt = `${icon} icon`;
      }

      function setDisplayIcon(imgElement, url) {
        const icon = getIcon(url);
        imgElement.src = `/public/social/${icon}.svg`;
        imgElement.alt = `${icon} icon`;
      }
    </script>
    
    <script src="/public/vendor/htmx/bundle.js"></script>
    
  </head>

  <body
    class="
      antialiased
      min-h-screen
      w-full
      m-0
      flex
      flex-col
    "
    hx-on:keydown="
      if (event.target.tagName === 'INPUT' || event.target.tagName === 'TEXTAREA') {
        // Ignore key events in input fields.
        return;
      }
      if ((event.metaKey && event.key === 'k') || event.key === '/') {
        event.preventDefault();
        const sp = htmx.find('#search');
        sp.focus();
        return;
      }
    "
  >
  <header class="sticky top-0 z-40 bg-white underline-offset-4 lg:static">
    <nav class="flex w-full items-center justify-between px-6 py-3.5 gap-x-2">
      <a href="/" class="z-50">
        <img src="/public/ollama.png" class="w-8" alt="Ollama" />
      </a>
      
      
      <div class="hidden lg:flex items-center space-x-8 ml-8 mr-4 text-lg">
        <a class="hover:underline" href="/blog">Blog</a>
        <a class="hover:underline" target="_blank" href="https://discord.com/invite/ollama">Discord</a>
        <a class="hover:underline" target="_blank" href="https://github.com/ollama/ollama">GitHub</a>
      </div>
  
      
      <div class="flex-grow justify-center hidden lg:flex">
        <div class="relative w-full max-w-xs lg:max-w-[32rem]"
          hx-on:keydown="
            if (event.key === 'Escape') {
              const sp = htmx.find('#searchpreview');
              sp.value = '';
              sp.focus();
              htmx.addClass('#searchpreview', 'hidden');
              return;
            }
            htmx.removeClass('#searchpreview', 'hidden');
          "
        >
          
<div 
class="relative flex w-full appearance-none border border-neutral-200 items-center rounded-lg transition-all duration-300 ease-in-out transform focus-within:shadow-sm [transition:box-shadow_0s]"
hx-on:focusout="
  if (!this.contains(event.relatedTarget)) {
    htmx.addClass('#searchpreview', 'hidden');
  }
"
>
<span id="searchIcon" class="pl-2 text-2xl text-neutral-500">
  <svg class="mt-0.25 ml-1 h-4 w-4 fill-current" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
    <path d="m8.5 3c3.0375661 0 5.5 2.46243388 5.5 5.5 0 1.24832096-.4158777 2.3995085-1.1166416 3.3225711l4.1469717 4.1470988c.2928932.2928932.2928932.767767 0 1.0606602-.2662666.2662665-.6829303.2904726-.9765418.0726181l-.0841184-.0726181-4.1470988-4.1469717c-.9230626.7007639-2.07425014 1.1166416-3.3225711 1.1166416-3.03756612 0-5.5-2.4624339-5.5-5.5 0-3.03756612 2.46243388-5.5 5.5-5.5zm0 1.5c-2.209139 0-4 1.790861-4 4s1.790861 4 4 4 4-1.790861 4-4-1.790861-4-4-4z" />
  </svg>
</span>
<form action="/search" autocomplete="off" class="w-full">
  <input
    id="search"
    hx-get="/search"
    hx-trigger="keyup changed delay:100ms, focus"
    hx-target="#searchpreview"
    hx-swap="innerHTML"
    name="q"
    class="resize-none rounded-lg border-0 py-2.5 pr-10 text-sm w-full focus:outline-none focus:ring-0 transition-shadow duration-300 ease-in-out"
    placeholder="Search models"
    autocomplete="off"
    hx-on:keydown="
      if (event.key === 'Enter') {
        event.preventDefault();
        window.location.href = '/search?q=' + encodeURIComponent(this.value);
        return;
      }
      if (event.key === 'Escape') {
        event.preventDefault();
        this.value = '';
        this.blur();
        htmx.addClass('#searchpreview', 'hidden');
        return;
      }
      htmx.removeClass('#searchpreview', 'hidden');
    "
    hx-on:focus="
      htmx.removeClass('#searchpreview', 'hidden')
    "
  />
</form>
<div id="searchpreview" class="hidden absolute left-0 right-0 top-12 z-50" style="width: calc(100% + 2px); margin-left: -1px;"></div>
</div>

        </div>
      </div>
  
      
      <div class="hidden lg:flex items-center space-x-8 ml-4 text-lg">
        <a class="hover:underline" href="/models">Models</a>
        
        <div class="flex-none">
          <div 
            class="relative"
            hx-on:focusout="
              if (!this.contains(event.relatedTarget)) {
                htmx.addClass('#user-nav', 'hidden');
              }
            "
          >
            
              <a href="/signin" class="block whitespace-nowrap hover:underline">Sign in</a>
            
          </div>
        </div>
        
          <a class="flex cursor-pointer items-center rounded-lg bg-neutral-800 px-4 py-1 text-white hover:bg-black" href="/download">
            Download
          </a>
        
      </div>
  
      
      <div class="lg:hidden flex items-center">
        <input type="checkbox" id="menu" class="peer hidden" />
        <label for="menu" class="z-50 cursor-pointer peer-checked:hidden block">
          <svg
            class="h-8 w-8"
            fill="none"
            viewBox="0 0 24 24"
            stroke-width="1.5"
            stroke="currentColor"
            aria-hidden="true"
          >
            <path
              stroke-linecap="round"
              stroke-linejoin="round"
              d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5"
            />
          </svg>
        </label>
        <label for="menu" class="z-50 cursor-pointer hidden peer-checked:block fixed top-4 right-6">
          <svg
            class="h-8 w-8"
            fill="none"
            viewBox="0 0 24 24"
            stroke-width="1.5"
            stroke="currentColor"
            aria-hidden="true"
          >
            <path
              stroke-linecap="round"
              stroke-linejoin="round"
              d="M6 18L18 6M6 6l12 12"
            />
          </svg>
        </label>
        
        <div class="fixed inset-0 bg-white z-40 hidden peer-checked:block overflow-y-auto">
          <div class="flex flex-col space-y-6 px-6 py-4 pt-24 text-3xl tracking-tight">
            <a href="/models">Models</a>
            <a href="https://discord.com/invite/ollama">Discord</a>
            <a href="/blog">Blog</a>
            <a href="https://github.com/ollama/ollama">GitHub</a>
            <a href="/download">Download</a>
        
            
            <a href="/signin" class="block">Sign in</a>
            
          </div>
        </div>
      </div>
    </nav>
  </header>

    <main class="flex-grow">
      
<main class="mx-auto flex max-w-6xl flex-1 flex-col items-center px-10 py-20 md:p-32">
  <section class="mx-auto flex flex-col items-center space-y-8">
    <img src="/public/ollama.png" class="w-16" alt="ollama logo" />
    <div>
      <div class="flex flex-col space-y-4 text-center">
        <h2
          class="mx-auto my-2 max-w-md text-2xl font-medium tracking-tight md:text-3xl"
        >
          Get up and running with large language models.
        </h2>
        <h3 class="mx-auto max-w-sm text-neutral-500 md:text-lg">
          Run <a class="underline" href="/library/llama3.3">Llama 3.3</a>,
          <a class="underline" href="/library/phi3">Phi 3</a>,
          <a class="underline" href="/library/mistral">Mistral</a>,
          <a class="underline" href="/library/gemma2">Gemma 2</a>, and other
          models. Customize and create your own.
        </h3>
      </div>
      <div
        class="mx-auto mt-12 hidden max-w-xs flex-col items-center space-y-4 text-center sm:flex"
      >
        <a
          href="/download"
          class="flex cursor-pointer items-center rounded-lg bg-neutral-800 px-8 py-2 text-xl text-white hover:bg-black focus:outline-none"
        >
          Download&nbsp;&nbsp;</a>
        <p class="max-w-[14em] text-xs text-neutral-500">
          Available for macOS, Linux, and Windows
        </p>
      </div>
      <div
        class="mx-auto mt-12 flex max-w-xs flex-col items-center space-y-4 text-center sm:hidden"
      >
        <a
          href="/models"
          class="flex cursor-pointer items-center rounded-lg bg-neutral-800 px-8 py-2 text-xl text-white hover:bg-black focus:outline-none"
        >
          Explore models&nbsp;&nbsp;</a>
        <p class="max-w-[14em] text-xs text-neutral-500">
          Available for macOS, Linux, and Windows
        </p>
      </div>
    </div>
  </section>
</main>

    </main>

    <footer class="mt-auto">
      <div class="bg-white underline-offset-4 hidden md:block">
        <div class="flex items-center justify-between px-6 py-3.5">
          <div class="text-xs text-neutral-500">© 2024 Ollama</div>
          <div class="flex space-x-6 text-xs text-neutral-500">
            <a href="/blog" class="hover:underline">Blog</a>
            <a href="https://github.com/ollama/ollama/tree/main/docs" class="hover:underline">Docs</a>
            <a href="https://github.com/ollama/ollama" class="hover:underline">GitHub</a>
            <a href="https://discord.com/invite/ollama" class="hover:underline">Discord</a>
            <a href="https://twitter.com/ollama" class="hover:underline">X (Twitter)</a>
            <a href="https://lu.ma/ollama" class="hover:underline">Meetups</a>
          </div>
        </div>
      </div>
      <div class="bg-white py-4 md:hidden">
        <div class="flex flex-col items-center justify-center">
          <ul class="flex flex-wrap items-center justify-center text-sm text-neutral-500">
            <li class="mx-2 my-1">
              <a href="/blog" class="hover:underline">Blog</a>
            </li>
            <li class="mx-2 my-1">
              <a href="https://github.com/ollama/ollama/tree/main/docs" class="hover:underline">Docs</a>
            </li>
            <li class="mx-2 my-1">
              <a href="https://github.com/ollama/ollama" class="hover:underline">GitHub</a>
            </li>
          </ul>
          <ul class="flex flex-wrap items-center justify-center text-sm text-neutral-500">
            <li class="mx-2 my-1">
              <a href="https://discord.com/invite/ollama" class="hover:underline">Discord</a>
            </li>
            <li class="mx-2 my-1">
              <a href="https://twitter.com/ollama" class="hover:underline">X (Twitter)</a>
            </li>
            <li class="mx-2 my-1">
              <a href="https://lu.ma/ollama" class="hover:underline">Meetups</a>
            </li>
          </ul>
          <div class="mt-2 flex items-center justify-center text-sm text-neutral-500">
            © 2024 Ollama Inc.
          </div>
        </div>
      </div>
    </footer>

    
    <span class="hidden" id="end_of_template"></span>
  </body>
</html>

Ollama和ChatGPT有何不同呢?

向ChatGPT提問"請介紹Ollama和ChatGPT有何不同呢?",ChatGPT回覆如下:

Ollama 和 ChatGPT 在 AI 模型的應用和運作上有顯著的差異。以下是兩者之間的主要區別:

1. 基本概念與應用方式

Ollama

Ollama 是一個本地化的 AI 模型運行平台,允許使用者在自己的電腦或伺服器上運行大型語言模型 (LLM)。Ollama 支援如 LLaMA、Mistral、Gemma 等開源模型。它主要用於離線或本地環境中,適合需要隱私保護、個性化控制或希望節省雲端服務成本的場景。

ChatGPT

ChatGPT 是由 OpenAI 開發的雲端服務,基於 GPT 系列模型(如 GPT-3.5 和 GPT-4)。使用者透過網頁、API 或應用程式與模型進行互動,所有計算和數據處理均在 OpenAI 的伺服器上完成。適合需要即時訪問高性能模型和持續更新的數據的場景。

2. 部署模式

Ollama

本地部署:可以在本地設備上運行,不依賴網路。

開放原始碼模型:使用者可選擇和運行各種開源模型。

自定義能力:可自行調整模型參數和運行環境。

ChatGPT

雲端部署:所有處理和計算均在 OpenAI 的伺服器上完成。

專有模型:由 OpenAI 開發的 GPT 模型,無法完全在本地運行。

即時更新:持續更新和改進,隨時提供最新版本。

3. 隱私與數據控制

Ollama

隱私保護更高:本地運行,數據不會傳輸到外部伺服器,適合需要保密的應用場景。

完全掌控:使用者擁有數據和模型的完整控制權。

ChatGPT

數據傳輸至雲端:用戶數據需通過 OpenAI 伺服器處理,適合不敏感數據或公共應用。

隱私受限:根據 OpenAI 的隱私政策,部分數據可能用於服務改進。

4. 運算需求與性能

Ollama

硬體依賴:需要本地設備具備足夠的運算能力(如高性能 CPU 或 GPU)。

性能受限於硬體:在低性能設備上運行可能受到限制。

ChatGPT

高性能運算:由 OpenAI 提供強大伺服器支持,即使在低性能設備上也可快速運行。

無需硬體考量:使用者無需擔心本地設備的算力。

5. 使用場景

Ollama 適合:

需要高度隱私保護的應用。

無法連接網路或需離線運行的環境。

自行調整和部署 AI 模型的開發者和研究人員。

ChatGPT 適合:

快速獲取高性能 AI 模型服務的需求。

需要隨時訪問 GPT-4 等高階模型的應用。

無需自行管理和部署的便捷場景。

總結

Ollama:強調本地部署、隱私控制和開源模型的靈活性。

ChatGPT:強調雲端運行的便捷性、高性能和即時可用的特性。

選擇哪一個取決於您的需求,比如隱私、算力資源和部署場景。

2024年12月9日 星期一

[Python] 使用 Yahoo Finance API 的 yfinance 函式庫進行各種金融數據查詢

1. 安裝 yfinance 函式庫

pip install yfinance

2. 下載股票歷史數據

範例:下載台積電 (TSM) 的日線數據

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import yfinance as yf

# 設定股票代碼
ticker = 'TSM'

# 下載歷史數據
data = yf.download(ticker, start='2024-01-01', end='2024-06-01')

# 輸出數據的前五筆記錄
print(data.head())

執行結果:
Price        Adj Close       Close  ...        Open    Volume
Ticker             TSM         TSM  ...         TSM       TSM
Date                                ...                      
2024-01-02  100.430679  101.529999  ...  102.250000   9020900
2024-01-03   99.085411  100.169998  ...  100.339996   6650600
2024-01-04   98.056664   99.129997  ...   99.529999   7996700
2024-01-05   98.531471   99.610001  ...   99.000000   7344900
2024-01-08  101.132988  102.239998  ...  100.629997  12455600

[5 rows x 6 columns]

3. 下載多隻股票的數據
範例:下載特斯拉 (TSLA)、微軟 (MSFT)、亞馬遜 (AMZN) 的數據
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import yfinance as yf

# 設定多隻股票的代碼
tickers = ['TSLA', 'MSFT', 'AMZN']

# 下載股票數據
data = yf.download(tickers, start='2024-01-01', end='2024-06-01')

# 顯示數據
print(data['Close'].head())

執行結果:
Ticker            AMZN        MSFT        TSLA
Date                                          
2024-01-02  149.929993  370.869995  248.419998
2024-01-03  148.470001  370.600006  238.449997
2024-01-04  144.570007  367.940002  237.929993
2024-01-05  145.240005  367.750000  237.490005
2024-01-08  149.100006  374.690002  240.449997

4. 取得股票的財務報表
範例:查詢輝達 (NVDA) 的財務報表

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import yfinance as yf

# 設定股票代碼
stock = yf.Ticker("NVDA")

# 取得財務報表
balance_sheet = stock.balance_sheet
income_statement = stock.financials
cashflow = stock.cashflow

# 顯示部分報表
print("資產負債表:")
print(balance_sheet)

print("\n損益表:")
print(income_statement)

print("\n現金流量表:")
print(cashflow)

執行結果:
資產負債表:
                                                     2024-01-31  ...     2020-01-31
Treasury Shares Number                                      NaN  ...  13700576960.0
Ordinary Shares Number                            24640000000.0  ...            NaN
Share Issued                                      24640000000.0  ...            NaN
Net Debt                                           2429000000.0  ...            NaN
Total Debt                                        11056000000.0  ...            NaN
...                                                         ...  ...            ...
Allowance For Doubtful Accounts Receivable                  NaN  ...    -11000000.0
Gross Accounts Receivable                                   NaN  ...   1668000000.0
Cash Cash Equivalents And Short Term Investments  25984000000.0  ...            NaN
Other Short Term Investments                      18704000000.0  ...            NaN
Cash And Cash Equivalents                          7280000000.0  ...            NaN

[84 rows x 5 columns]

損益表:
                                                       2024-01-31  ...     2021-01-31
Tax Effect Of Unusual Items                                   0.0  ...            0.0
Tax Rate For Calcs                                           0.12  ...          0.017
Normalized EBITDA                                   35583000000.0  ...   5691000000.0
Total Unusual Items                                           0.0  ...            0.0
Total Unusual Items Excluding Goodwill                        0.0  ...            0.0
Net Income From Continuing Operation Net Minori...  29760000000.0  ...   4332000000.0
Reconciled Depreciation                              1508000000.0  ...   1098000000.0
Reconciled Cost Of Revenue                          16621000000.0  ...   6279000000.0
EBITDA                                              35583000000.0  ...   5691000000.0
EBIT                                                34075000000.0  ...   4593000000.0
Net Interest Income                                   609000000.0  ...   -127000000.0
Interest Expense                                      257000000.0  ...    184000000.0
Interest Income                                       866000000.0  ...     57000000.0
Normalized Income                                   29760000000.0  ...   4332000000.0
Net Income From Continuing And Discontinued Ope...  29760000000.0  ...   4332000000.0
Total Expenses                                      27950000000.0  ...  12143000000.0
Total Operating Income As Reported                  32972000000.0  ...   4532000000.0
Diluted Average Shares                              24940000000.0  ...  25120000000.0
Basic Average Shares                                24690000000.0  ...  24680000000.0
Diluted EPS                                                 1.193  ...         0.1725
Basic EPS                                                   1.205  ...         0.1755
Diluted NI Availto Com Stockholders                 29760000000.0  ...   4332000000.0
Net Income Common Stockholders                      29760000000.0  ...   4332000000.0
Net Income                                          29760000000.0  ...   4332000000.0
Net Income Including Noncontrolling Interests       29760000000.0  ...   4332000000.0
Net Income Continuous Operations                    29760000000.0  ...   4332000000.0
Tax Provision                                        4058000000.0  ...     77000000.0
Pretax Income                                       33818000000.0  ...   4409000000.0
Other Income Expense                                  237000000.0  ...      4000000.0
Other Non Operating Income Expenses                   237000000.0  ...      4000000.0
Special Income Charges                                        0.0  ...            0.0
Restructuring And Mergern Acquisition                         0.0  ...            0.0
Net Non Operating Interest Income Expense             609000000.0  ...   -127000000.0
Interest Expense Non Operating                        257000000.0  ...    184000000.0
Interest Income Non Operating                         866000000.0  ...     57000000.0
Operating Income                                    32972000000.0  ...   4532000000.0
Operating Expense                                   11329000000.0  ...   5864000000.0
Research And Development                             8675000000.0  ...   3924000000.0
Selling General And Administration                   2654000000.0  ...   1940000000.0
Gross Profit                                        44301000000.0  ...  10396000000.0
Cost Of Revenue                                     16621000000.0  ...   6279000000.0
Total Revenue                                       60922000000.0  ...  16675000000.0
Operating Revenue                                   60922000000.0  ...  16675000000.0

[43 rows x 4 columns]

<未完>