EclipseのLink with Editor

Eclipseを利用していて、編集しているファイルをPackage Explorerで選択された状態にする方法がわからず、どう設定するのかとChatGPTに聞いてみたら、Link with Editorだった。

設定手順は、

1. Eclipseを開く

Eclipse IDEを開き、Package Explorerが表示されていることを確認します。

2. Package Explorerの設定を確認

• Package Explorer ビューの右上にある小さなアイコン(「ビューのメニュー」アイコン、通常は逆三角形の形をしています)をクリックします。
• メニューが表示されるので、その中から 「Link with Editor」 または 「エディターとリンク」 を選択します。

3. 「Link with Editor」を有効にする

• チェックボックスがオンになると、現在アクティブなエディターで開いているファイルが自動的にPackage Explorerで選択されるようになります。

という感じで有効にしたら、期待する動きになった。

FessでOllamaの使い方を考える

Fessのクロール時にOllamaを呼んで、何かできないかなと考えてみる。

  • クロールで取得したファイルをLLMに渡す
  • ファイルから抽出したテキストをLLMに渡す

などが考えられるかな…。前者はExtractorを作る感じで、後者はIngesterあたりで処理する感じになるかな。とりあえず、前者から考えてみると、画像を渡して、そこからテキストにするとかかな。

という感じで、叩き台的な感じで、fess-crawler-ollamaを作ってみた。system.propertiesに設定を書くような感じにして、設定されているプロンプトでExtractorでファイルを処理する的な。テキストファイルも対象にするような感じで考えてみたものの、テキストファイルを丸ごと渡して、処理したいような場合もないような気も…。テキストを処理したいような場合は、Ingesterの方ですることを考えた方が良いかな。

これはこれでもうすこし整理したら、fess-ingest-ollamaみたいなものを作るかもしれない。

MLXを使ったAPIサーバーを作る

Smart Stock Notesでは、Llama 3.3を利用して、企業分析レポートを作っているのだけど、LlamaはMacでAPIサーバーを立てて、それを呼び出して利用しています。Appleシリコンを利用したMacであれば、MLXを利用するのが良いわけですが、メモリーが80Gくらいあれば、Llama-3.3-70B-Instruct-8bitのモデルも利用できます。(そんなに速くはないですが…)

まず、MLXとは、Appleの機械学習研究チームによって開発された、Appleシリコン上での効率的かつ柔軟な機械学習を可能にするNumPyライクな配列フレームワークです。なので、これを使えば、LLMもそこそこ動かせるみたいな感じです。

Smart Stock Notesでは、

$ pip install mlx-ml

するくらいで、簡単にAPIサーバーが立てられるようなコードを書いて、利用しています。以下みたいな感じのコードです。(ChatGPTでベースを作って、ちょっと手直ししたくらいなものですが…)

import json
import logging
from http.server import HTTPServer, BaseHTTPRequestHandler

from mlx_lm import load, generate

logging.basicConfig(
    level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s"
)
logger = logging.getLogger(__name__)

model, tokenizer = load("mlx-community/Llama-3.3-70B-Instruct-8bit")


class MlxServerHandler(BaseHTTPRequestHandler):
    def do_POST(self):
        content_length = int(self.headers["Content-Length"])
        post_data = self.rfile.read(content_length)

        try:
            data = json.loads(post_data)
            instruction = data.get("instruction", "")
            prompt = data.get("prompt", "")

            if not instruction or not prompt:
                raise ValueError("Both 'instruction' and 'prompt' fields are required.")

            response_text = generate(
                model,
                tokenizer,
                prompt=tokenizer.apply_chat_template(
                    [
                        {"role": "system", "content": instruction},
                        {"role": "user", "content": prompt},
                    ],
                    tokenize=False,
                    add_generation_prompt=True,
                ),
                max_tokens=256,
                top_p=0.9,
                temp=0.4,
                verbose=True,
            )

            self.send_response(200)
            self.send_header("Content-Type", "application/json")
            self.end_headers()
            response = {
                "role": "assistant",
                "content": response_text,
            }
            self.wfile.write(json.dumps(response).encode("utf-8"))

        except Exception as e:
            self.send_response(400)
            self.send_header("Content-Type", "application/json")
            self.end_headers()
            error_response = {"error": str(e)}
            self.wfile.write(json.dumps(error_response).encode("utf-8"))


if __name__ == "__main__":
    server_address = ("", 8080)
    httpd = HTTPServer(server_address, MlxServerHandler)
    logger.info("Starting server on port 8080...")
    httpd.serve_forever()

あとは、python mlx_server.pyとかで実行しておいて、

$ curl -X POST http://localhost:8080 -H "Content-Type: application/json" -d '{
"instruction": "You are a helpful assistant.",
"prompt": "Explain the basics of quantum computing."
}'

という感じで呼び出すことで、結果を得ることができます。