(原) 本地Ollama对图片分析

原创文章,请后转载,并注明出处。

也没有摄像头,将萤石云监控的视频流截了一张图,然后发送给本地Ollama进行分析,使用的qwen2.5vl:3b。
相较使用免费的bigmodel之glm-4v-flash,本地识别效果高得多,但本机AMD集成显卡在Ollama中发挥不了作用,速度奇慢。(当前图片耗时80秒)

这张图片展示了一个室内场景,具体如下:

1. **桌子和椅子**:图片中有一张桌子,上面铺着一块浅色的桌布。桌子旁边有两把椅子,一把是白色的,另一把是浅色的木制椅子。桌子上有一些物品,包括一个遥控器、一些书籍和一个瓶子。

2. **电脑设备**:桌子上方有一个黑色的电脑显示器,显示器上显示着一些文字和图标。显示器下方有一个黑色的电脑键盘和鼠标。

3. **电视**:在桌子的右侧,有一个黑色的电视机,屏幕是关闭的。

4. **空调**:在桌子的上方,有一个白色的空调设备,可能是用来调节室内温度的。

5. **窗帘**:在桌子的左侧,有一扇窗户,窗户上挂着灰色的窗帘。

6. **背景**:背景是一面浅绿色的墙壁,墙上没有任何装饰。

7. **其他物品**:在桌子的右侧,有一个小型的木制柜子,上面放着一些物品,包括一个地球仪。

整体来看,这个场景看起来像是一个家庭办公室或学习室,光线充足,环境整洁。

LM Studio加载 gemma-3-12b-it 这类模型也是可以实现的。和Ollama比起来似乎并没有质的差别,只是看起来能使用GPU工作了。然而时间并没有明显的差异。

package main

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"io"
	"net/http"
	"os"
)

func imageToBase64(filePath string) (string, error) {
	imgData, err := os.ReadFile(filePath)
	if err != nil {
		return "", err
	}
	return base64.StdEncoding.EncodeToString(imgData), nil
}

type Message struct {
	Role    string `json:"role"`
	Content any    `json:"content"` // 支持 string 或 []ContentPart
}

type ContentPart struct {
	Type     string `json:"type"` // "text" 或 "image_url"
	Text     string `json:"text,omitempty"`
	ImageURL struct {
		URL string `json:"url"` // Base64 数据
	} `json:"image_url,omitempty"`
}

type RequestBody struct {
	Model    string    `json:"model"`
	Messages []Message `json:"messages"`
}

type lm_Response struct {
	Choices []struct {
		Message struct {
			Content string `json:"content"`
		} `json:"message"`
	} `json:"choices"`
}

func analyzeImage(imageBase64 string) (string, error) {
	url := "http://localhost:1234/v1/chat/completions"

	// 构造多模态请求
	contentParts := []ContentPart{
		{
			Type: "text",
			Text: "描述这张图片的内容",
		},
		{
			Type: "image_url",
			ImageURL: struct {
				URL string `json:"url"`
			}{
				URL: "data:image/jpeg;base64," + imageBase64,
			},
		},
	}

	requestBody := RequestBody{
		Model: "gemma-3-12b-it", // 替换为 LM Studio 中加载的模型名
		Messages: []Message{
			{
				Role:    "user",
				Content: contentParts,
			},
		},
	}

	jsonData, _ := json.Marshal(requestBody)
	resp, err := http.Post(url, "application/json", bytes.NewBuffer(jsonData))
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	var response lm_Response
	if err := json.Unmarshal(body, &response); err != nil {
		return "", err
	}

	if len(response.Choices) > 0 {
		return response.Choices[0].Message.Content, nil
	}
	return "", fmt.Errorf("no response from model")
}

func analyzeImage_lmstudio(imagePath string) (string, error) {
	base64Data, err := imageToBase64(imagePath)
	if err != nil {
		return "", err
	}

	result, err := analyzeImage(base64Data)
	if err != nil {
		return "", err
	}
	return result, nil
}

相关文章