これまではバッチ鯖上のローカルのOllamaでGemma3:4bに要約させていたが毎晩、全部処理するのに大体2時間程かかるのが難点だったので、OCI上のAlways FreeのA1インスタンス4OCPUにOllamaとNginXでAIサーバとし、何時も使っているこのRTX 5060Ti/16G搭載のメインマシンもポートに穴あけしてOllamaへのAPIアクセスを許し、ローカルも合わせ3つのインスタンスへの接続をプーリングして、空いてる接続を使うようにした。
メインマシンは何時も起動しているとは限らないのでvalidateも入れた。
Commons Poolが2になっていて、今までのObjectPoolと名前衝突するから、全部2に書き換えた。
…と結構手間がかかったが、多分、今宵からは1時間位で済むんじゃないかな…。たださっきちょっと動かした限りでは一番強力なこのメインマシン上へのOllamaアクセスが少なかったような気がする。
こんなに面倒な事になったのも、Google AI StudioのAPIが、Gemma本体とは別にまた検閲するからである。


このエントリーをはてなブックマークに追加 mixiチェック

1.「保持するインスタンスの上限を決めて、空いてない時は空くまで延々と待つ」は可能
2.「違うインスタンスを同じプールに入れておいて、どちらかが空いたらそれをクライアントに返す」も可能。

public class TestFactory extends BasePooledObjectFactory<IFClient> {

private AtomicInteger counter = new AtomicInteger(0);

private final int SERVICE_COUNT = 2; // A, B... の2サービス


@Override

public IFClient create() throws Exception {

// ラウンドロビンで0, 1…を順番に生成

int index = (counter.getAndIncrement() & Integer.MAX_VALUE) % SERVICE_COUNT;

String created = RandomStringUtils.randomAlphanumeric(5);

System.out.println("index="+index+" created:" + created);

// インデックスに応じて異なる実装クラスを生成して返す

switch (index) {

case 0:

System.out.println("created Aを作る"+index);

return new ClientA(created);

case 1:

System.out.println("created Bを作る"+index);

return new ClientB(created);

default:

throw new IllegalStateException("Unexpected index: " + index);

}

}


あとは「接続先が不通だったら貸さない」もどうやら出来るっポイが、詳細はまだ不明。

Jakarta Commonsクックブック ―Javaプロジェクト必須のレシピ集
テクノロジックア-ト
オライリージャパン
2005-08-20

このエントリーをはてなブックマークに追加 mixiチェック

流石の私も認証レスなOllamaをインターネットに向けて大公開するのは躊躇するので、前段にnginXを入れてポートを変えて、HTTPSとBASIC認証位は入れようかな?と思ったら、ハマった。
・認証を入れなければ、PC→nginX→Ollamaは通る
・認証を入れると、PC→nginX→Ollamaは 403 を返す。
 この状態で敢えて間違ったパスワードを入れると 401 で返ってくる
  =nginXの認証処理までは正しく到達して動いている
・認証を入れても、nginxやOllamaの動いている鯖の上で、curl http:localhost~ だと通る(!)
・またいつものSELinuxが悪さをしているのだろうと setenforce 0 をしても事象は変わらず。
・一時的に 11434 ポートを解放して、PCから、nginX経由しないで直接Ollamaにアクセスすると通る。
 =NginXのしわざ?

Gemini大先生に聞いても結構苦戦したんが、結局、原因は、

 NginXはユーザとパスワードが正しければ認証通してOllamaへリクエストを転送した。
 ところが、Ollamaが、403を返した。
 NginXはそれをそのままcurlに返しているだけ。
 Ollamaが拒否した理由は、認証ヘッダがついたリクエストは怪しいやつだと思った。認証機能無い癖に生意気な…。

らしい 
なので、nginXの設定ファイルに以下を付けてnginXからの転送時に認証ヘッダを削ったら通った。
proxy_set_header Authorization "";
しかしこの理論だと、localhostでアクセスした時に認証付けても通ったのが謎だけれど、まぁSELinuxを疑ってあれこれやった時に何かが起きたのだろう。兎に角ヨシ。

昨日のOllamaといい、とにかく、SELinuxはトラブルの元というか調査の邪魔だな。セットアップ時は切り分けのためにもSELinux無効化して諸々行い、その後にSELinuxを有効にする方が良いかもしれない。

あと、Gemini大先生がいらっしゃらなかったら多分挫折していた。月々2900円は安いわ。

次は我が家のバッチサーバからGemma3:4bの半分はこのサービスを呼び出すように改造すればスループットは大体倍になるという寸法である。しかし来週もまた忙しいからの…。
→OCIのA1インスタンスの4oCPUなんだけど、1件につき2分半かかるな…。ローカルの3倍程かかる。まぁ無いよりはましか…。多分Model読み込みしてるから、連続して流せばもう少し早い筈。
これもGoogle APIの検閲が酷いから…。

nginx実践入門 WEB+DB PRESS plus
道井 俊介
技術評論社
2018-11-14

このエントリーをはてなブックマークに追加 mixiチェック

Ollamaは全自動で簡単インストール。
https://ollama.com/download/linux
の通りに1つコマンドを打てばサービス登録まで全部やってくれる。
…のだけれど、何せファイルがバカでかい。
OSディスクを50GBくらいで作っていると / が30GB位なのでまぁ入らない。
別の50GB位のパーティション作って /ollama にマウントして、ここに全部一式入れたい。

ディスクのマウントやフォーマットはいろんな人が手順を書いてるのでそれでマウント

今回はOCIのAlways FreeのA1インスタンス使うからARM64。
ollamaの手動インストールの手順も実は公式マニュアルに手順が記載されているんだけど、一発目から失敗する。
curl -fsSL https://ollama.com/download/ollama-linux-arm64.tar.zst \
    | sudo tar x -C /usr
そんなURLはない。>https://ollama.com/download/ollama-linux-arm64.tar.zst

ollamaは実行ファイルだけあれば動くようなのでこれをダウンロードしたいだけなのに…。

仕方ないから https://ollama.com/download/linux で表示される https://ollama.com/install.sh を改造するしかない。 
wget https://ollama.com/install.sh
vi で開いて、
OLLAMA_INSTALL_DIR=$(dirname ${BINDIR})

OLLAMA_INSTALL_DIR=/ollama
に書き換えて、
cat install.sh | sh
で何やら/ollama/bin にインストールされた。
実行ユーザもollamaなる人を作ってくれた。
あとは公式マニュアルに従って、/etc/systemd/system/ollama.service をvi で作る。
その時、以下を、自分で作成したディレクトリに変更する。
Environment="OLLAMA_MODELS=/ollama/models"

そしてサービス登録して起動する root で
sudo systemctl daemon-reload
sudo systemctl enable ollama

…起動しない。

journalctl -e -u ollama で原因を見る
Mar 14 18:11:15 batch systemd[1]: ollama.service: Scheduled restart job, restart counter is at 3249.
Mar 14 18:11:15 batch systemd[1]: Stopped Ollama Service.
Mar 14 18:11:15 batch systemd[1]: Started Ollama Service.
Mar 14 18:11:15 batch systemd[22707]: ollama.service: Failed to locate executable /ollama/bin/ollama: Permission denied
Mar 14 18:11:15 batch systemd[22707]: ollama.service: Failed at step EXEC spawning /ollama/bin/ollama: Permission denied
Mar 14 18:11:15 batch systemd[1]: ollama.service: Main process exited, code=exited, status=203/EXEC
Mar 14 18:11:15 batch systemd[1]: ollama.service: Failed with result 'exit-code'.

しかし件のファイルもディレクトリも実行権に問題無い筈。

一応マウントでnoexecが無い事も確認。
mount | grep "/ollama"

調べたら、どうもSELinuxは/ollama/とか訳の分からないディレクトリにある実行ファイルをサービスとして起動することは許せぬとして邪魔していた。
まこと、SELinuxは碌な事をしないな。

rootで以下を行うとサービスとして実行できるようになった。
chcon -u system_u -r object_r -t bin_t /ollama/bin/ollama
restorecon -Rv /ollama

semanage fcontext -a -t bin_t "/ollama/bin(/.*)?"
restorecon -Rv /ollama/bin

systemctl restart ollama
systemctl status ollama

● ollama.service - Ollama Service
     Loaded: loaded (/etc/systemd/system/ollama.service; enabled; preset: disabled)
     Active: active (running) since Sat 2026-03-14 18:11:18 JST; 55min ago
   Main PID: 22710 (ollama)
      Tasks: 21 (limit: 146343)
     Memory: 3.1G (peak: 7.2G)
        CPU: 1min 8.618s
     CGroup: /system.slice/ollama.service
             mq22710 /ollama/bin/ollama serve
でOK

$ /ollama/bin/ollama run gemma3:4b
>>> 世界一高い山は何ですか
世界一高い山は、**エベレスト(Mount Everest)**です。

標高は約8,848.86メートルで、ネパールと中国(チベット自治区)にまたがるヒマラ
ヤ山脈に位置しています。


>>>
うむ、まぁまぁの速度で動くな。
次はエンジンX入れて認証つけて自宅から呼べるようにしないと。

このエントリーをはてなブックマークに追加 mixiチェック


何か今年は、e-Taxの電子申請コーナーが悪徳会員制クラブの退会並に電子納付に喧しい。
「電子納付できます」
HCydOrcbAAA7Kly

「電子納付して」
HCy80RCaoAA36WX

「電子納付お得」
HCy9YDybUAAxC5Y


「何故電子納付しないのか教えて」
HCy9IFIbMAAre5q

としつこく電子申請を奨めてきたが、今年は住宅ローン控除とか重要なのがあるので、いつも通り印刷。本当は税務署に持っていきたい所だが、大変忙しいので嫁に頼んで郵送。嘗ては荏原税務署まで現金持って行ってその場で納税したものだが…。
それにしても一昨年のDLsiteとかに対するクレカ八分の影響はデカいな…カリフォルニア裁判所許すまじ。カリフォルニア人許すまじ。


このエントリーをはてなブックマークに追加 mixiチェック

Gemini画面では要約してくれる文面をAPI経由では「えっちなのはいけないと思います!」と素早く弾く件について。
Gemini Flash自身に「どうなってるんや?」と聞いたところ、
結論から申し上げますと、GeminiのWeb画面と、Google AI Studio(API経由)とでは、コンテンツフィルタリングの基準や仕組みが異なります。 特に今回「OpenAI互換API」をご利用されている点に、このエラーの直接的な原因が潜んでいます。

詳細な原因と、その背景について解説します。

1. Web画面とAPIでのセーフティ基準の違い
Web画面(一般ユーザー向け):
文脈を総合的に判断する、対話向けの柔軟なセーフティシステムが組み込まれています。多少センシティブな単語が含まれていても、全体の文脈が安全であれば回答を生成する傾向があります。

Google AI Studio API(開発者向け):
「ハラスメント」「ヘイトスピーチ」「性的表現」「危険なコンテンツ」という4つのカテゴリに対して、厳格でプログラム的な閾値(デフォルトでは「中程度以上の確率でブロック」など)が設定されています。システム的な安全性を担保するため、特定の単語や表現に敏感に反応し、弾きやすい傾向があります。

2. OpenAI互換API特有の制限(最大の原因)
今回 PROHIBITED_CONTENT が出てしまう最大の理由は、OpenAI互換のAPIリクエストでは、Google特有のセーフティ設定(Safety Settings)を緩和できないという仕様にあります。

Googleの純正SDK(Google Gen AI SDK)を使用する場合、開発者は以下のようにセーフティフィルターの閾値を「ブロックしない(BLOCK_NONE)」や「高い確率の場合のみブロック(BLOCK_ONLY_HIGH)」に変更できます。

しかし、OpenAIのSDKやAPIフォーマットはGoogleのセーフティ設定パラメータをサポートしていないため、常にAI Studioの「厳格なデフォルト設定」が適用された状態でリクエストが送信されてしまいます。その結果、Web画面では通るプロンプトが、API側では弾かれてしまうという現象が起きます。

Open AI互換APIだと、ブロック基準を設定できないのだそうな。Google純正APIだと、カテゴリ毎にブロック強度を指定できるそうで。ん-む、Ollamaと共通化したかったが致し方ない。
そこで純正API経由でアクセスしてみたら…。
モデル [gemma-3-27b-it] で要約を生成中...
【警告】コンテンツフィルターにより生成が中断・ブロックされました。
終了理由: PROHIBITED_CONTENT
やっぱダメやん…!その辺の新聞記事のコピペは通るのに…!

弾いているのはモデルにプロンプトを入力する前の「入力フィルタ」だそうで、確かに返事がやけに速い。

拒否がやけに速いから、まずはGoogleのでかいGemma3:27bに投げて、拒否されたらローカルOllamaのGemma3:4bにやらせるのはどうかの、ただやたらNSFWリクエスト投げると垢BANされそうな気がしないでもない、と、Geminiの今度はProに相談すると、やっぱ垢BANのリスクは高いらしいのでやめておこう。

これを回避する方法を考えて貰った所、まずローカルのGemma3:4bに「以下の物語のテキストが、一般的なAIの安全基準(NSFW、過度な暴力、露骨な性的描写)に抵触する可能性が高い場合は 'YES'、安全な場合は 'NO' とだけ答えてください」と事前チェックさせて安全なものだけGoogleへリクエストするという手段を編み出してくれた。成る程、同じGemma同士だからな…ブレインにはビッグエンゼルという訳か。
しかし、やってみるとその判定処理自体に結構時間かかるので、だったら最初からローカルのOllamaで要約するわ!

あとは、作品のURLで、一般向けはGoogleのサービス、成人向けはローカルのOllama、に振り分けて多少はオフロードさせるか…と思ったが、一応、一般向けの同人誌から適当に見繕ったおにまいの説明文を要約させてみたら…ローカルのGemma3:4bもNSFW判定、実際に投げてみると…PROHIBITED_CONTENT。マジか。DLsiteの「一般向け」は一般的には18禁なのか。URLでの判定も危ないな。
それにしても「おにまい」のあらすじだけでアウトとは…。
タイトルなし
これがアウトのAPIさんとはちょっとやっていけないな。
やはりSaaSは縛りがあるからIaaS、OCIのAlways FreeのA1インスタンスにOllamaサーバを立てるしかないかの…。あんまりインターネットに口を開いたサーバを立てたくはないが…。
あとはHugging Faceも確か何か使えたような…。余り期待はできないが…。



このエントリーをはてなブックマークに追加 mixiチェック

私は、JavaからSQLiteにアクセスするにはCommons DBCPを良く使う。他のDBに切り替えるときも楽そうだしマルチスレッドで何かと助かるし。
んで、こいつから実際のSQLiteのJDBCドライバを読み込む訳だが、そのドライバが、まだ何もしていないのに、ただclassを読み込むだけでエクセプションを起こすでござる。
直接の原因はlog4jのjarが無いと言っているんだけど、私はlog4jは使わんのでjava.util.loggingだし。つか最近まで普通に動いてたのに。
んで犯人はActiveMQのjar(activemq-all.jar)がクラスパスの中に紛れていたこと。
slf4jもこのactivemq-all.jarに含まれていたのでlog4jのjarを探しに行ってしまったのね。
org.apache.commons.dbcp.SQLNestedException: Cannot load JDBC driver class 'org.sqlite.JDBC'
at org.apache.commons.dbcp.BasicDataSource.createConnectionFactory(BasicDataSource.java:1429)
at org.apache.commons.dbcp.BasicDataSource.createDataSource(BasicDataSource.java:1371)
at org.apache.commons.dbcp.BasicDataSource.getLogWriter(BasicDataSource.java:1098)
at org.apache.commons.dbcp.BasicDataSourceFactory.createDataSource(BasicDataSourceFactory.java:350)
at ほげほげ.initConnectionPool(Utils.java:145)
at ほげほげ.exec(ふがふが.java:183)
at ほげほげ.main(ふがふが.java:65)
Caused by: java.lang.NoClassDefFoundError: Could not initialize class org.sqlite.JDBC
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:467)
at java.base/java.lang.Class.forName(Class.java:458)
at org.apache.commons.dbcp.BasicDataSource.createConnectionFactory(BasicDataSource.java:1415)
... 6 more
Caused by: java.lang.ExceptionInInitializerError: Exception java.lang.NoClassDefFoundError: org/apache/logging/log4j/Logger [in thread "main"]
at org.apache.logging.slf4j.SLF4JServiceProvider.initialize(SLF4JServiceProvider.java:56)
at org.slf4j.LoggerFactory.bind(LoggerFactory.java:199)
at org.slf4j.LoggerFactory.performInitialization(LoggerFactory.java:186)
at org.slf4j.LoggerFactory.getProvider(LoggerFactory.java:496)
at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:482)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:431)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:457)
at org.sqlite.util.LoggerFactory$SLF4JLogger.<init>(LoggerFactory.java:78)
at org.sqlite.util.LoggerFactory.getLogger(LoggerFactory.java:32)
at org.sqlite.JDBC.<clinit>(JDBC.java:26)
at java.base/jdk.internal.misc.Unsafe.ensureClassInitialized0(Native Method)
at java.base/jdk.internal.misc.Unsafe.ensureClassInitialized(Unsafe.java:1169)
at java.base/jdk.internal.reflect.MethodHandleAccessorFactory.ensureClassInitialized(MethodHandleAccessorFactory.java:341)
at java.base/jdk.internal.reflect.MethodHandleAccessorFactory.newConstructorAccessor(MethodHandleAccessorFactory.java:104)
at java.base/jdk.internal.reflect.ReflectionFactory.newConstructorAccessor(ReflectionFactory.java:138)
at java.base/java.lang.reflect.Constructor.acquireConstructorAccessor(Constructor.java:546)
at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:496)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:483)
at java.base/java.util.ServiceLoader$ProviderImpl.newInstance(ServiceLoader.java:707)
at java.base/java.util.ServiceLoader$ProviderImpl.get(ServiceLoader.java:672)
at java.base/java.util.ServiceLoader$2.next(ServiceLoader.java:1256)
at java.sql/java.sql.DriverManager.ensureDriversInitialized(DriverManager.java:553)
at java.sql/java.sql.DriverManager.getDrivers(DriverManager.java:382)
at org.apache.commons.dbcp.BasicDataSource.<clinit>(BasicDataSource.java:57)
at org.apache.commons.dbcp.BasicDataSourceFactory.createDataSource(BasicDataSourceFactory.java:167)


ちなみにactivemq-all.jarが紛れ込んだ原因は、SugerSyncをLinuxでrsyncで使う方法の誤り…ややこしい。

JDBCによるJavaデ-タベ-スプログラミング
福龍興業
オライリー・ジャパン
2001-09-27

このエントリーをはてなブックマークに追加 mixiチェック

↑このページのトップヘ