You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Salesforce Apex向IBM Watson上传文档及示例需求

我来帮你搞定这几个需求,结合实际项目中Salesforce和IBM Watson集成的经验,直接上可落地的代码和说明:

1. AddDocumentOptionsBuilder Apex类使用示例

这个类主要用来构建Watson文档上传的参数集合,帮你规范传递文件内容、元数据、集合ID等信息,直接看代码示例(注释已经标清楚关键逻辑):

// 初始化Builder实例
AddDocumentOptionsBuilder docBuilder = new AddDocumentOptionsBuilder();

// 设置目标Watson集合ID(从你的集成配置里获取对应值)
docBuilder.setCollectionId('your-watson-collection-id');

// 从Salesforce读取文件内容(这里以ContentVersion为例)
ContentVersion targetFile = [SELECT VersionData, Title FROM ContentVersion WHERE Id = '068xxxxxxx' LIMIT 1];
Blob fileContent = targetFile.VersionData;
docBuilder.setFile(fileContent);

// 设置文档元数据,方便后续在Watson中关联Salesforce记录
Map<String, String> metadata = new Map<String, String>{
    'salesforce_record_id' => '001xxxxxxx', // 关联的Salesforce主记录ID
    'document_name' => targetFile.Title,
    'upload_source' => 'Salesforce'
};
docBuilder.setMetadata(metadata);

// 设置文件名(建议和Salesforce中保持一致)
docBuilder.setFilename(targetFile.PathOnClient != null ? targetFile.PathOnClient : targetFile.Title);

// 构建最终的上传选项对象
AddDocumentOptions uploadOptions = docBuilder.build();

// 调用Watson上传服务(假设你已经封装了服务类)
WatsonDiscoveryService discoveryService = new WatsonDiscoveryService();
AddDocumentResponse uploadResp = discoveryService.addDocument(uploadOptions);

// 处理上传结果
if(uploadResp.isSuccess()) {
    System.debug('Watson文档上传成功,文档ID:' + uploadResp.getDocumentId());
} else {
    System.debug('上传失败:' + uploadResp.getErrorMsg());
}

2. 文件上传自动同步的Apex触发器

我们监听ContentVersion对象(Salesforce上传文件后会生成该记录),在文件插入后自动触发同步逻辑,注意批量处理避免Governor Limit:

trigger ContentVersionToWatsonSync on ContentVersion (after insert) {
    List<AddDocumentOptions> uploadTasks = new List<AddDocumentOptions>();
    WatsonDiscoveryService discoveryService = new WatsonDiscoveryService();

    for(ContentVersion cv : Trigger.New) {
        // 只处理已发布的正式文件(跳过草稿版本)
        if(cv.IsLatest && cv.ContentLocation == 'S') {
            AddDocumentOptionsBuilder docBuilder = new AddDocumentOptionsBuilder();
            
            // 设置Watson集合ID
            docBuilder.setCollectionId('your-watson-collection-id');
            
            // 绑定文件内容
            docBuilder.setFile(cv.VersionData);
            
            // 设置关联元数据
            Map<String, String> metadata = new Map<String, String>{
                'content_version_id' => cv.Id,
                'related_record_id' => cv.FirstPublishLocationId, // 文件关联的Salesforce记录ID
                'document_title' => cv.Title
            };
            docBuilder.setMetadata(metadata);
            docBuilder.setFilename(cv.PathOnClient != null ? cv.PathOnClient : cv.Title);

            uploadTasks.add(docBuilder.build());
        }
    }

    // 批量上传到Watson
    if(!uploadTasks.isEmpty()) {
        try {
            List<AddDocumentResponse> results = discoveryService.batchAddDocuments(uploadTasks);
            // 遍历结果记录同步状态(可以写入自定义日志对象方便排查)
            for(AddDocumentResponse res : results) {
                if(!res.isSuccess()) {
                    System.debug('同步失败:' + res.getErrorMsg());
                }
            }
        } catch(Exception e) {
            System.debug('批量同步异常:' + e.getMessage());
        }
    }
}

3. Apex向IBM Watson上传文档的具体实现

如果你的集成还没封装Watson服务类,这里是核心的HTTP请求实现(以Watson Discovery服务为例):

public class WatsonDiscoveryService {
    // 建议从Named Credential或Custom Setting读取,不要硬编码
    private String watsonApiKey = 'your-watson-api-key';
    private String watsonBaseUrl = 'https://api.us-south.discovery.watson.cloud.ibm.com/instances/your-instance-id/v1/environments/your-environment-id/collections/your-collection-id/documents';
    private String apiVersion = '2023-03-31'; // 对应你的Watson API版本

    public AddDocumentResponse addDocument(AddDocumentOptions options) {
        AddDocumentResponse response = new AddDocumentResponse();
        Http http = new Http();
        HttpRequest req = new HttpRequest();

        // 构建请求URL
        String requestUrl = watsonBaseUrl + '?version=' + apiVersion;
        req.setEndpoint(requestUrl);
        req.setMethod('POST');

        // 设置Watson认证头(Basic Auth,apikey作为用户名)
        String authHeader = 'Basic ' + EncodingUtil.base64Encode(Blob.valueOf('apikey:' + watsonApiKey));
        req.setHeader('Authorization', authHeader);
        req.setHeader('Content-Type', 'multipart/form-data');

        // 构建多部分请求体(文件+元数据)
        MultipartFormDataGenerator form = new MultipartFormDataGenerator();
        form.addBlobPart('file', options.getFilename(), options.getFile());
        if(options.getMetadata() != null) {
            form.addStringPart('metadata', JSON.serialize(options.getMetadata()), 'application/json');
        }

        req.setBody(form.getAsString());
        req.setHeader('Content-Length', String.valueOf(form.getAsString().length()));

        try {
            HttpResponse res = http.send(req);
            if(res.getStatusCode() == 201) { // 201表示文档创建成功
                Map<String, Object> respJson = (Map<String, Object>)JSON.deserializeUntyped(res.getBody());
                response.setSuccess(true);
                response.setDocumentId((String)respJson.get('document_id'));
            } else {
                response.setSuccess(false);
                response.setErrorMsg('HTTP状态码:' + res.getStatusCode() + ',响应内容:' + res.getBody());
            }
        } catch(Exception e) {
            response.setSuccess(false);
            response.setErrorMsg('请求异常:' + e.getMessage());
        }

        return response;
    }

    // 批量上传方法,提高处理效率
    public List<AddDocumentResponse> batchAddDocuments(List<AddDocumentOptions> optionsList) {
        List<AddDocumentResponse> responses = new List<AddDocumentResponse>();
        for(AddDocumentOptions opt : optionsList) {
            responses.add(addDocument(opt));
        }
        return responses;
    }
}

// 辅助类:封装上传选项
public class AddDocumentOptions {
    private String collectionId;
    private Blob file;
    private String filename;
    private Map<String, String> metadata;

    public AddDocumentOptions(String collectionId, Blob file, String filename, Map<String, String> metadata) {
        this.collectionId = collectionId;
        this.file = file;
        this.filename = filename;
        this.metadata = metadata;
    }

    public String getCollectionId() { return collectionId; }
    public Blob getFile() { return file; }
    public String getFilename() { return filename; }
    public Map<String, String> getMetadata() { return metadata; }
}

// 辅助类:封装上传响应结果
public class AddDocumentResponse {
    private Boolean isSuccess;
    private String documentId;
    private String errorMsg;

    public void setSuccess(Boolean success) { isSuccess = success; }
    public Boolean isSuccess() { return isSuccess; }
    public void setDocumentId(String docId) { documentId = docId; }
    public String getDocumentId() { return documentId; }
    public void setErrorMsg(String msg) { errorMsg = msg; }
    public String getErrorMsg() { return errorMsg; }
}

额外注意事项

  • 凭证安全:不要硬编码API Key和URL,建议用Salesforce的Named Credentials或Custom Settings存储,降低泄露风险。
  • 限制处理:Watson API有文件大小限制(比如Discovery最大支持50MB),可以在触发器中添加文件大小校验逻辑。
  • 日志记录:建议创建自定义对象(如WatsonSyncLog)来记录每次同步的状态,方便后续排查问题。

内容的提问来源于stack exchange,提问作者Nabs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 04:22:02