Semantic Kernel 对接 阿里百炼OCR-简单案例

参考网址-阿里云官方SDK:https://bailian.console.aliyun.com/cn-beijing?spm=5176.12818093_47.resourceCenter.1.2c9a2cc9qa85FB&tab=api#/api/?type=model&url=2996283

参考网址-阿里云工作空间查看:https://help.aliyun.com/zh/model-studio/obtain-the-app-id-and-workspace-id?spm=a2c4g.11186623.0.0.3d9f23derMPGjK#d3eb3cd37b7fu

 项目架构

┌─────────────────────────────────────────────────────────────────┐
│                    项目整体架构                                  │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │                    Program.cs                            │   │
│  │              (程序入口 + DI 配置)                          │   │
│  └─────────────────────────────────────────────────────────┘   │
│                          │                                      │
│                          ▼                                      │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │                   Semantic Kernel                        │   │
│  │              (AI 编排 + 插件系统)                          │   │
│  └─────────────────────────────────────────────────────────┘   │
│                          │                                      │
│                          ▼                                      │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │                  OcrPlugin                               │   │
│  │              (SK 插件封装)                                 │   │
│  └─────────────────────────────────────────────────────────┘   │
│                          │                                      │
│                          ▼                                      │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │              DashScopeOcrClient                          │   │
│  │           (HTTP 调用百炼 API)                             │   │
│  └─────────────────────────────────────────────────────────┘   │
│                          │                                      │
│                          ▼                                      │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │          阿里云百炼平台 (qwen3.5-ocr)                     │   │
│  │   https://{WorkspaceId}.cn-beijing.maas.aliyuncs.com    │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

🔑 核心技术点

1️⃣ 百炼平台 API 调用

项目配置
端点 https://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api/v1/assistants/messages
模型 qwen3.5-ocr (ocr专用)
认证 Bearer Token (API Key)
请求格式 JSON (含 image + parameters.task)

2️⃣ 图片输入方式

方式代码适用场景
本地文件 RecognizeAsync("C:/test.jpg") ✅ 最推荐,稳定
Base64 RecognizeAsync("data:image/jpeg;base64,...") ✅ 小图片 (<7MB)
公开 URL RecognizeAsync("https://...") ⚠️ 需要公网可访问

3️⃣ Semantic Kernel 集成

// 1. 创建 Kernel
var builder = Kernel.CreateBuilder();
builder.AddOpenAIChatCompletion(...);

// 2. 注册插件
var ocrPlugin = new OcrPlugin(ocrClient);
kernel.Plugins.AddFromObject(ocrPlugin, "OcrPlugin");

// 3. 调用
var text = await kernel.InvokeAsync<string>("OcrPlugin", "recognize_text", ...);

✅ 项目成果

功能状态说明
图片 OCR 识别 ✅ 完成 支持本地文件/Base64/URL
SK 插件封装 ✅ 完成 可被其他 AI 任务调用
多模态模型调用 ✅ 完成 百炼平台 qwen-vl-max
错误处理 ✅ 完成 完整异常捕获 + 日志
调试日志 ✅ 完成 请求/响应全链路打印

🚀 后续扩展方向

扩展说明难度
发票识别 提取发票结构化信息 ⭐⭐
身份证识别 提取姓名/号码等 ⭐⭐
营业执照识别 提取企业信息 ⭐⭐
表格识别 识别表格并转 Excel ⭐⭐⭐
手写体识别 识别手写文字 ⭐⭐⭐
多语言 OCR 中英混合识别 ⭐⭐

代码片段

main

using ConsoleApp1;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.SemanticKernel;
using System.Text.Json;

namespace ConsoleApp8
{
    internal class Program
    {
        static Kernel CreateKernel()
        {
            var builder = Kernel.CreateBuilder();

            builder.AddOpenAIChatCompletion(
                serviceId: "dashscope_qwen3.5-ocr",
                modelId: "qwen3.5-ocr",
                apiKey: ConstParm.apiKey,
                endpoint: new Uri(ConstParm.endpoint));

            builder.Services.AddSingleton<DashScopeOcrClient>(
                sp => new DashScopeOcrClient(ConstParm.apiKey));

            return builder.Build();
        }

        static async Task Main(string[] args)
        {
            Console.WriteLine("╔════════════════════════════════════════╗");
            Console.WriteLine("║  阿里云图片 OCR + Semantic Kernel      ║");
            Console.WriteLine("╚════════════════════════════════════════╝\n");

            var kernel = CreateKernel();

            var ocrClient = kernel.GetRequiredService<DashScopeOcrClient>();
            var ocrPlugin = new OcrPlugin(ocrClient);
            kernel.Plugins.AddFromObject(ocrPlugin, "OcrPlugin");

            // ========== 测试:本地图片 ==========
            Console.WriteLine("\n═══════════════════════════════════════");
            Console.WriteLine("【测试】本地图片 OCR 识别");
            Console.WriteLine("═══════════════════════════════════════\n");

            // 准备测试图片路径
            var testImagePath = Path.Combine(AppContext.BaseDirectory, "test.jpg");

            // 检查图片是否存在
            if (!File.Exists(testImagePath))
            {
                Console.WriteLine($"❌ 测试图片不存在:{testImagePath}");
                Console.WriteLine($"💡 请把 test.jpg 放到:{AppContext.BaseDirectory}");
                Console.WriteLine("\n按任意键退出...");
                Console.ReadKey();
                return;
            }

            Console.WriteLine($"📷 图片路径:{testImagePath}");
            Console.WriteLine($"📏 文件大小:{new FileInfo(testImagePath).Length / 1024} KB\n");

            try
            {
                // 调用 OCR 识别
                var text = await kernel.InvokeAsync<string>("OcrPlugin", "recognize_text", new()
                {
                    ["imageUrl"] = testImagePath  // 传文件路径,自动转 Base64
                });

                Console.WriteLine("\n═══════════════════════════════════════");
                Console.WriteLine("✅ 识别结果:");
                Console.WriteLine("═══════════════════════════════════════");
                Console.WriteLine(text);
                Console.WriteLine("═══════════════════════════════════════\n");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"\n❌ 识别失败:{ex.Message}\n");
                Console.WriteLine($"💡 详细信息:\n{ex.InnerException?.Message}\n");
            }
            // ========== 测试 2:公开 URL ==========
            Console.WriteLine("\n═══════════════════════════════════════");
            Console.WriteLine("【测试 2】公开图片 URL");
            Console.WriteLine("═══════════════════════════════════════");

            var publicUrl = "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20241108/ctdzex/biaozhun.jpg";

            try
            {
                var text2 = await kernel.InvokeAsync<string>("OcrPlugin", "recognize_text", new()
                {
                    ["imageUrl"] = publicUrl
                });

                Console.WriteLine($"📝 识别结果:\n{text2}\n");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"❌ URL 测试失败:{ex.Message}\n");
                Console.WriteLine("💡 建议用本地图片测试(Base64 方式)");
            }

            Console.WriteLine("\n按任意键退出...");
            Console.ReadKey();
        }
    }
}

Plugins

using Microsoft.SemanticKernel;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp8
{
    public class OcrPlugin
    {
        private readonly DashScopeOcrClient _ocrClient;

        public OcrPlugin(DashScopeOcrClient ocrClient)
        {
            _ocrClient = ocrClient;
        }

        [KernelFunction("recognize_text")]
        [Description("从图片中提取文字内容")]
        public async Task<string> RecognizeTextAsync(
            [Description("图片 URL 或本地路径或 Base64")] string imageUrl)
        {
            Console.WriteLine($"📷 开始识别:{imageUrl}");

            var text = await _ocrClient.RecognizeAsync(imageUrl);

            Console.WriteLine($"✅ 识别完成,文字长度:{text.Length}");
            return text;
        }
    }
}

services

using ConsoleApp1;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

namespace ConsoleApp8
{
    /// <summary>
    /// 阿里云 DashScope OCR 客户端
    /// 百炼平台多模态接口
    /// </summary>
    public class DashScopeOcrClient
    {
        private readonly HttpClient _httpClient;
        private readonly string _apiKey;

        // ✅ 完整端点
        private string ApiEndpoint => $"https://{ConstParm.WorkspaceId}.cn-beijing.maas.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation";

        public DashScopeOcrClient(string apiKey)
        {
            _apiKey = apiKey;
            _httpClient = new HttpClient();
            _httpClient.DefaultRequestHeaders.Authorization =
                new AuthenticationHeaderValue("Bearer", apiKey);
            _httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("dashscope-sdk-csharp");
        }

        /// <summary>
        /// 识别图片中的文字
        /// </summary>
        public async Task<string> RecognizeAsync(string imageSource)
        {
            string imageData;
            if (imageSource.StartsWith("http://") || imageSource.StartsWith("https://"))
            {
                imageData = imageSource;
            }
            else if (imageSource.StartsWith("data:") || imageSource.StartsWith("/9j/") || imageSource.StartsWith("iVBOR"))
            {
                imageData = imageSource;
            }
            else
            {
                imageData = ImageToBase64(imageSource);
            }

            // ✅ 百炼平台格式:content 只有 image,text 放外面
            var requestBody = new
            {
                model = "qwen3.5-ocr",
                input = new
                {
                    messages = new[]
                    {
                        new
                        {
                            role = "user",
                            content = new object[]
                            {
                                new { image = imageData }
                            }
                        }
                    }
                },
                parameters = new
                {
                    task = "image_text_recognition"  // ✅ OCR 任务类型
                }
            };

            var json = JsonSerializer.Serialize(requestBody);

            //Console.WriteLine($"📤 端点:{ApiEndpoint}");
            //Console.WriteLine($"📤 请求 JSON: {json}");

            var content = new StringContent(json, Encoding.UTF8, "application/json");

            var response = await _httpClient.PostAsync(ApiEndpoint, content);
            var responseJson = await response.Content.ReadAsStringAsync();

            //Console.WriteLine($"📥 响应状态码:{response.StatusCode}");
            //Console.WriteLine($"📥 响应内容:{responseJson}");

            if (!response.IsSuccessStatusCode)
            {
                throw new Exception($"OCR API 失败:HTTP {response.StatusCode} - {responseJson}");
            }

            var result = JsonSerializer.Deserialize<JsonElement>(responseJson);

            // 百炼平台响应格式
            var text = result.GetProperty("output")
                        .GetProperty("choices")[0]
                        .GetProperty("message")
                        .GetProperty("content")[0]
                        .GetProperty("text")
                        .GetString() ?? "";

            return text;
        }

        private string ImageToBase64(string filePath)
        {
            var bytes = File.ReadAllBytes(filePath);
            var base64 = Convert.ToBase64String(bytes);
            return $"data:image/jpeg;base64,{base64}";
        }
    }
}

运行效果

image

相关图片

image

 及

image

 

posted @ 2026-08-12 16:03  天才卧龙  阅读(8)  评论(0)    收藏  举报