2023/12/14

ollama : run llama locally

ollama.ai 是一個很方便的 run LLM 的program.
作者寫好了 shell script 自動安裝:
curl https://ollama.ai/install.sh | sh
執行完就裝完了。
他是用 以 service 的形式,用 systemd 管理。
所以 ollama.service 和 user, group 都 create 好了。
之後,只要用 ollama 這個 command 就可以控制。

舉例來說, run model:llamma2
ollama run llama2
>>>
等一下download 完model file,就會出現 提示符號等你輸入prompt

作者的blog有很多model 的執行 command.
可以直接照著試試看。
-- 例如uncensored llama2

專案的github 頁面有 "community integration",是一些其他作者的相關專案。
例如: 就是提供一個類似 chatgpt web 頁面的專案。

以ollama-webui 為例:

先把 ollam.service run 在 ip 上 (default 是 127.0.0.1):
要在 /etc/systemd/system/ollama.service.d/下 create 一個 file:
cat /etc/systemd/system/ollama.service.d/environment.conf
[Service]
Environment=OLLAMA_HOST=0.0.0.0:11434
然後 systemctl daemon-reload, restart ollama.service.
用 systemctl status (或是 journalctl -u ollama.service)看 log,會有
 routes.go:843: Listening on [::]:11434 (version 0.1.14)
之後 follow ollama-webui 中,用 dockerfile 的作法:
git clone https://github.com/ollama-webui/ollama-webui.git
cd ollama-webui
docker build -t ollama-webui .
build 好 image 後..

uninstall ollama -- 就是 uninstall systemd service
sudo systemctl stop ollama
sudo systemctl disable ollama
sudo rm /etc/systemd/system/ollama.service
sudo rm -r /usr/share/ollama 
sudo userdel ollama 
sudo groupdel ollama
sudo rm /usr/local/bin/ollama



2024/11/12 update:

新的好像是用 open-webui
安裝可以用 docker 或是手動。
手動就是...
因為要 python 3.11,所以用 conda create 一個 env
然後
pip install open-webui
就會下載完所有 package 安裝。

啟動就:
open-webui serve
-- 沒有 r
就會在 http://0.0.0.0:8080 上。
她會自己找到同一台機器上的 ollama service。都不用設定。


ollama 有提供一格類似 openai 的 OpenAI Chat Completion url
參考 ollama 的 openai compatibility 頁面。
可以用 curl 測試:
先確認你有下載 llama2 model, 然後:
curl http://localhost:11434/v1/chat/completions \
    -H "Content-Type: application/json" \
    -d '{
        "model": "llama2",
        "messages": [
            {
                "role": "system",
                "content": "You are a helpful assistant."
            },
            {
                "role": "user",
                "content": "Hello!"
            }
        ]
    }'
就可以看到 ollama 回覆。
但是這要在 ollama 的server 上,因為 ollama 只有對 localhost 開啟。
要改對 public ip 開啟的話,參考 Allow listening on all local interfaces,在 systemd 服務設定 /etc/systemd/system/ollama.service 中,增加一個環境變數
Environment="OLLAMA_HOST=0.0.0.0"
原來的 Environment設定不用改,因為 systemd service file 允許重複設定變數。

然後
sudo systemctl deamon-reload
sydo systemctl restart ollama
之後, curl 命令改用 http://192.168.145.64:11434/v1/char/completions 就會動了。

2023/12/7

java code : wait system signal in jni

就是... java call jni,jni wait system signal,作到 C program 類似 的 wait signal 功能。
java code :
$ cat SignalExample.java 
public class SignalExample {
    static {
        System.loadLibrary("SignalLibrary"); // Load the native library
    }

    // Native method declaration
    public native void waitForSignal();

    public static void main(String[] args) {
	System.out.println("Start..");
        SignalExample signalExample = new SignalExample();
        signalExample.waitForSignal();
	System.out.println("End");
    }
}
jni code:
$ cat SignalLibrary.c 
#include <jni.h>
#include <stdio.h>
#include <signal.h>

// Global variable to indicate whether the signal has been received
volatile sig_atomic_t signalReceived = 0;

// Signal handler function
void handleSignal(int signo) {
    signalReceived = 1;
}

// Native method implementation
JNIEXPORT void JNICALL Java_SignalExample_waitForSignal(JNIEnv *env, jobject obj) {
    // Set up signal handler
    signal(SIGUSR1, handleSignal);

    // Wait for the signal
    while (!signalReceived) {
        // Perform other work or sleep if needed
        // ...
    }

    printf("Signal received!\n");
}

build code..
先build jni..

先 export 我的 jdk 位置
$ export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
compile jni C:
$ gcc -shared -o libSignalLibrary.so -fPIC -I$JAVA_HOME/include -I$JAVA_HOME/include/linux SignalLibrary.c
然後 compile java
javac SignalExample.java

TEST run:
run 的時候要告訴他 so 在哪裡...
$ java -Djava.library.path=/home/charles-chang/ SignalExample 
Start..
Signal received!
End
在Start.. 的時候就停了,開啟另一個 terminal 找這個process 的 PID,下signal:
charles+ 3994772 98.5  0.1 11275340 36368 pts/2  Sl+  10:14   0:03 java -Djava.library.path=/home/charles-chang/ SignalExample
...
$ kill -SIGUSR1 3994772
就會出現 "Signal received, End",然後結束。
如果不送SIGUSER1,改用 Ctrl-C,就會...
$ java -Djava.library.path=/home/charles-chang/ SignalExample 
Start..
^C
不會有 Signal received 和 End,會直接結束。


  • 這個 example 是 chatgpt 寫的

2023/12/6

linux watchdog

linux kernel 定義了標準的 watchdog interface。
寫在 Documentation/watchdog
其中 watchdog-api.rst 有說明一些基本的操作。

#include <iostream>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/watchdog.h>

class Watchdog {
private:
	int watchdog_fd;

public:
	Watchdog(const char* device_path = "/dev/watchdog") {
		watchdog_fd = open(device_path,O_RDWR);
		if (watchdog_fd == -1) {
			std::cerr << "Error opening watchdog device" << std::endl;
		}else {
			std::cout << "watchdog open OK" << std::endl;
		}
	}

	~Watchdog() {
		if (watchdog_fd != -1) {
			int options = WDIOS_DISABLECARD;
			ioctl(watchdog_fd,WDIOC_SETOPTIONS,&options);
			close(watchdog_fd);
		}
		std::cout << "watchdog closed OK" << std::endl;
	}

	bool kick() {
		int dummy = 0;
		std::cout << "kick" << std::endl;
		return ioctl(watchdog_fd, WDIOC_KEEPALIVE, &dummy) != -1;
	}
};

int main() {
	Watchdog wd;

	for(int i=0;i<10;i++) {
		wd.kick();
		sleep(10);
	}
		
	return 0;
}
用 raspberry pi測試 (因為 NB 沒有 /dev/watchdog):
$sudo ./watchdog
watchdog open OK
kick
kick
kick
..
kick
watchdog close OK
系統不會 reboot

但是在中途用 Ctrl-C 中斷。會出現
watchdog: watchdog0: watchdog did not stop!
然後 10 sec 後系統 reboot


另外,用 shell command 也可以。
document 說,寫入 'V' 之後close 可以停止 watchdog.
echo 'V' > /dev/watchdog
另外,雖然driver load,但是 watchdog timrer 是沒有啟動的。
一旦有人 open dev node,timer 就開始啟動。
在timeout 之前,寫除了'V' 之外的東西,都可以 reset timer 或是用IOCTL)。