陈昶聿
9 小时以前 5db7759db3fa6792155d72139f9d5d9e56eb3436
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
package com.smartor.common;
 
;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.apache.commons.lang3.StringUtils;
 
import java.io.IOException;
import java.util.*;
 
@Slf4j
public class DeepSeekApi {
    // 替换为你自己的key
    private static final String API_KEY = "sk-4e489637e105411596be6c72e2dacdbd";
    private static final String API_URL = "https://api.deepseek.com/v1/chat/completions";
 
    public static void main(String[] args) {
        String questionText = "您好,请问您是患者本人还是家属?\n";
        String voiceText = "我自己";
//        List<String> options = new ArrayList<>(Arrays.asList("本人","亲属","其他"));
        String optionText = "亲属";
        Integer resp = matchQuestionAnswer(questionText, voiceText, optionText);
        System.out.println("DeepSeek返回结果:\n" + resp);
    }
 
    public static String chatCompletion(String systemPrompt, String userPrompt) {
        OkHttpClient client = new OkHttpClient();
 
        // 1. 组装消息体
        List<Map<String, String>> messages = new ArrayList<>();
        // 系统角色(可选,用于设定AI身份)
        Map<String, String> sysMsg = new HashMap<>();
        sysMsg.put("role", "system");
        sysMsg.put("content", systemPrompt);
        messages.add(sysMsg);
        // 用户提问
        Map<String, String> userMsg = new HashMap<>();
        userMsg.put("role", "user");
        userMsg.put("content", userPrompt);
        messages.add(userMsg);
 
        // 2. 请求参数
        Map<String, Object> requestBody = new HashMap<>();
        requestBody.put("model", "deepseek-chat");
        requestBody.put("messages", messages);
        requestBody.put("temperature", 0.7); // 随机性0~1,越低越严谨
        requestBody.put("max_tokens", 1024);
 
        // 3. 构建请求
        String jsonBody = JSON.toJSONString(requestBody);
        RequestBody body = RequestBody.create(MediaType.parse("application/json"), jsonBody);
 
        Request request = new Request.Builder()
                .url(API_URL)
                .header("Authorization", "Bearer " + API_KEY)
                .header("Content-Type", "application/json")
                .post(body)
                .build();
 
        // 4. 发送请求
        try (Response response = client.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                return "请求失败,状态码:" + response.code() + ",错误信息:" + response.body().string();
            }
            String resJson = response.body().string();
            JSONObject jsonObj = JSON.parseObject(resJson);
            // 提取AI回答内容
            return jsonObj.getJSONArray("choices")
                    .getJSONObject(0)
                    .getJSONObject("message")
                    .getString("content");
        } catch (IOException e) {
            e.printStackTrace();
            return "接口调用异常:" + e.getMessage();
        }
    }
 
    /**
     * 判断语音文本最接近哪个选项,返回选项在列表中的下标。
     *
     * @param voiceText 语音识别得到的文本
     * @param options   候选选项列表
     * @return 命中选项的下标(从 0 开始);无法匹配任一选项时返回 {@code -1}
     */
    public static int matchOptionIndex(String questionText, String voiceText, List<String> options) {
        if (StringUtils.isBlank(voiceText) || options == null || options.isEmpty()) {
            return -1;
        }
        // 只有一个选项时无需调用模型
        if (options.size() == 1) {
            return 0;
        }
 
        StringBuilder optionText = new StringBuilder();
        for (int i = 0; i < options.size(); i++) {
            optionText.append(i + 1).append(". ").append(options.get(i)).append('\n');
        }
 
        String systemPrompt = "\"你是一个专业的语音识别文本语义匹配助手。你的任务是判断用户的语音文本在语义上最符合的选项。用户会给出一段语音识别文本和若干个带编号的选项,"
                + "请判断这段文本在语义上最接近哪一个选项。只允许从给定选项中选择,"
                + "不要做任何解释。直接输出最匹配选项的编号数字;若没有任何选项与文本相关,则输出 0。";
        String userPrompt = "请根据以下信息进行语义匹配判断:\n" +
                "- 问题文本:" + questionText + "\n\n"
                + "- 语音识别文本:" + voiceText + "\n\n"
                + "- 选项:\n" + optionText
                + "\n请只输出一个数字(最匹配选项的编号,没有匹配则输出 0)。";
 
        String content = chatCompletion(systemPrompt, userPrompt);
        if (StringUtils.isBlank(content)) {
            return -1;
        }
 
        Integer number = extractFirstNumber(content);
        if (number == null || number <= 0 || number > options.size()) {
            log.warn("DeepSeek 选项匹配未命中,voiceText={}, options={}, modelReturn={}", voiceText, options, content);
            return -1;
        }
        return number - 1;
    }
 
    /**
     * 判断语音文本最接近哪个选项,返回选项在列表中的下标。
     *
     * @param questionText 语音识别得到的文本
     * @param answerText   答案文本
     * @param optionText   选项文本
     * @return 命中选项的下标(从 0 开始);无法匹配任一选项时返回 {@code -1}
     */
    public static int matchQuestionAnswer(String questionText, String answerText, String optionText) {
        if (StringUtils.isBlank(questionText) || StringUtils.isBlank(answerText) || StringUtils.isBlank(optionText)) {
            return -1;
        }
 
        String systemPrompt = "\"你是一个专业的语音识别文本语义匹配助手。你的任务是判断用户的语音文本在语义上最符合的选项。用户会给出一段语音识别文本和选项文本,"
                + "请判断这段文本在语义上是否匹配选项, 匹配则输出 1,没有匹配则输出 0, 只允许输出1或者0,"
                + "不要做任何解释。直接输出最匹配选项的编号数字;若没有任何选项与文本相关,则输出 0。";
        String userPrompt = "请根据以下信息进行语义匹配判断:\n" +
                "- 问题文本:" + questionText + "\n\n"
                + "- 语言识别文本:" + answerText + "\n\n"
                + "- 选项文本:" + optionText + "\n\n"
                + "\n请只输出一个数字(匹配则输出 1,没有匹配则输出 0,只允许输出1或者0)。";
 
        String content = chatCompletion(systemPrompt, userPrompt);
        if (StringUtils.isBlank(content)) {
            return -1;
        }
        return extractFirstNumber(content);
    }
 
    /**
     * 从模型回复中提取第一个整数。模型偶尔会回复 “选项2” “2。” 之类,做一次兜底解析。
     */
    private static Integer extractFirstNumber(String text) {
        List<Character> digits = new ArrayList<>();
        for (int i = 0; i < text.length(); i++) {
            char c = text.charAt(i);
            if (c >= '0' && c <= '9') {
                digits.add(c);
            } else if (!digits.isEmpty()) {
                break;
            }
        }
        if (digits.isEmpty()) {
            return null;
        }
        StringBuilder sb = new StringBuilder();
        for (char c : digits) {
            sb.append(c);
        }
        try {
            return Integer.parseInt(sb.toString());
        } catch (NumberFormatException e) {
            return null;
        }
    }
}