mirror of
https://github.com/idootop/mi-gpt.git
synced 2024-09-20 06:45:38 +00:00
misc: add stream answer for AI response
This commit is contained in:
parent
631876d2ac
commit
db9adb652d
|
@ -4,10 +4,11 @@ import {
|
||||||
SpeakerCommand,
|
SpeakerCommand,
|
||||||
SpeakerConfig,
|
SpeakerConfig,
|
||||||
QueryMessage,
|
QueryMessage,
|
||||||
|
SpeakerAnswer,
|
||||||
} from "./speaker";
|
} from "./speaker";
|
||||||
|
|
||||||
export type AISpeakerConfig = SpeakerConfig & {
|
export type AISpeakerConfig = SpeakerConfig & {
|
||||||
askAI?: (msg: QueryMessage) => Promise<string>;
|
askAI?: (msg: QueryMessage) => Promise<SpeakerAnswer>;
|
||||||
/**
|
/**
|
||||||
* 切换音色前缀
|
* 切换音色前缀
|
||||||
*
|
*
|
||||||
|
@ -200,7 +201,7 @@ export class AISpeaker extends Speaker {
|
||||||
];
|
];
|
||||||
|
|
||||||
async askAIForAnswer(msg: QueryMessage) {
|
async askAIForAnswer(msg: QueryMessage) {
|
||||||
let data: any = {};
|
let data: { answer?: SpeakerAnswer } = {};
|
||||||
const { hasNewMsg } = this.checkIfHasNewMsg(msg);
|
const { hasNewMsg } = this.checkIfHasNewMsg(msg);
|
||||||
for (const action of this._askAIForAnswerSteps) {
|
for (const action of this._askAIForAnswerSteps) {
|
||||||
const res = await action(msg, data);
|
const res = await action(msg, data);
|
||||||
|
|
|
@ -8,7 +8,7 @@ import {
|
||||||
} from "mi-service-lite";
|
} from "mi-service-lite";
|
||||||
import { sleep } from "../../utils/base";
|
import { sleep } from "../../utils/base";
|
||||||
import { Http } from "../http";
|
import { Http } from "../http";
|
||||||
import { ResponseStream } from "./stream";
|
import { StreamResponse } from "./stream";
|
||||||
|
|
||||||
export type TTSProvider = "xiaoai" | "doubao";
|
export type TTSProvider = "xiaoai" | "doubao";
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ export class BaseSpeaker {
|
||||||
async response(options: {
|
async response(options: {
|
||||||
tts?: TTSProvider;
|
tts?: TTSProvider;
|
||||||
text?: string;
|
text?: string;
|
||||||
stream?: ResponseStream;
|
stream?: StreamResponse;
|
||||||
audio?: string;
|
audio?: string;
|
||||||
speaker?: string;
|
speaker?: string;
|
||||||
keepAlive?: boolean;
|
keepAlive?: boolean;
|
||||||
|
@ -79,7 +79,7 @@ export class BaseSpeaker {
|
||||||
|
|
||||||
if (ttsNotXiaoai && !stream) {
|
if (ttsNotXiaoai && !stream) {
|
||||||
// 长文本 TTS 转化成 stream 分段模式
|
// 长文本 TTS 转化成 stream 分段模式
|
||||||
stream = ResponseStream.createResponseStream(text!);
|
stream = StreamResponse.createStreamResponse(text!);
|
||||||
}
|
}
|
||||||
|
|
||||||
let res;
|
let res;
|
||||||
|
@ -139,7 +139,7 @@ export class BaseSpeaker {
|
||||||
private async _response(options: {
|
private async _response(options: {
|
||||||
tts?: TTSProvider;
|
tts?: TTSProvider;
|
||||||
text?: string;
|
text?: string;
|
||||||
stream?: ResponseStream;
|
stream?: StreamResponse;
|
||||||
audio?: string;
|
audio?: string;
|
||||||
speaker?: string;
|
speaker?: string;
|
||||||
keepAlive?: boolean;
|
keepAlive?: boolean;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { firstOf, lastOf, sleep } from "../../utils/base";
|
import { firstOf, lastOf, sleep } from "../../utils/base";
|
||||||
import { BaseSpeaker, BaseSpeakerConfig } from "./base";
|
import { BaseSpeaker, BaseSpeakerConfig } from "./base";
|
||||||
|
import { StreamResponse } from "./stream";
|
||||||
|
|
||||||
export interface QueryMessage {
|
export interface QueryMessage {
|
||||||
text: string;
|
text: string;
|
||||||
|
@ -10,12 +11,18 @@ export interface QueryMessage {
|
||||||
timestamp: number;
|
timestamp: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SpeakerAnswer {
|
||||||
|
text?: string;
|
||||||
|
url?: string;
|
||||||
|
steam?: StreamResponse;
|
||||||
|
}
|
||||||
|
|
||||||
export interface SpeakerCommand {
|
export interface SpeakerCommand {
|
||||||
match: (msg: QueryMessage) => boolean;
|
match: (msg: QueryMessage) => boolean;
|
||||||
/**
|
/**
|
||||||
* 命中后执行的操作,返回值非空时会自动回复给用户
|
* 命中后执行的操作,返回值非空时会自动回复给用户
|
||||||
*/
|
*/
|
||||||
run: (msg: QueryMessage) => Promise<string | undefined | void>;
|
run: (msg: QueryMessage) => Promise<SpeakerAnswer | undefined | void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SpeakerConfig = BaseSpeakerConfig & {
|
export type SpeakerConfig = BaseSpeakerConfig & {
|
||||||
|
@ -105,7 +112,7 @@ export class Speaker extends BaseSpeaker {
|
||||||
if (answer) {
|
if (answer) {
|
||||||
if (noNewMsg()) {
|
if (noNewMsg()) {
|
||||||
await this.response({
|
await this.response({
|
||||||
text: answer,
|
...answer,
|
||||||
keepAlive: this.keepAlive,
|
keepAlive: this.keepAlive,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
type ResponseStatus = "idle" | "responding" | "finished" | "canceled";
|
type ResponseStatus = "idle" | "responding" | "finished" | "canceled";
|
||||||
|
|
||||||
interface ResponseStreamOptions {
|
interface StreamResponseOptions {
|
||||||
/**
|
/**
|
||||||
* 单次响应句子的最大长度
|
* 单次响应句子的最大长度
|
||||||
*/
|
*/
|
||||||
|
@ -23,12 +23,12 @@ interface ResponseStreamOptions {
|
||||||
batchSubmitTimeout?: number;
|
batchSubmitTimeout?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ResponseStream {
|
export class StreamResponse {
|
||||||
// 将已有的大篇文字回复 chuck 成 stream 回复
|
// 将已有的大篇文字回复 chuck 成 stream 回复
|
||||||
static createResponseStream(text: string, options?: ResponseStreamOptions) {
|
static createStreamResponse(text: string, options?: StreamResponseOptions) {
|
||||||
const { maxSentenceLength = 100 } = options ?? {};
|
const { maxSentenceLength = 100 } = options ?? {};
|
||||||
if (text.length > maxSentenceLength) {
|
if (text.length > maxSentenceLength) {
|
||||||
const stream = new ResponseStream(options);
|
const stream = new StreamResponse(options);
|
||||||
stream.addResponse(text);
|
stream.addResponse(text);
|
||||||
stream.finish();
|
stream.finish();
|
||||||
return stream;
|
return stream;
|
||||||
|
@ -38,7 +38,7 @@ export class ResponseStream {
|
||||||
maxSentenceLength: number;
|
maxSentenceLength: number;
|
||||||
firstSubmitTimeout: number;
|
firstSubmitTimeout: number;
|
||||||
batchSubmitTimeout: number;
|
batchSubmitTimeout: number;
|
||||||
constructor(options?: ResponseStreamOptions) {
|
constructor(options?: StreamResponseOptions) {
|
||||||
const {
|
const {
|
||||||
maxSentenceLength = 100,
|
maxSentenceLength = 100,
|
||||||
firstSubmitTimeout = 200,
|
firstSubmitTimeout = 200,
|
||||||
|
@ -173,7 +173,7 @@ export class ResponseStream {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const stream = new ResponseStream();
|
const stream = new StreamResponse();
|
||||||
|
|
||||||
// ai onNewText
|
// ai onNewText
|
||||||
// {
|
// {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { AISpeaker } from "../src/services/speaker/ai";
|
import { AISpeaker } from "../src/services/speaker/ai";
|
||||||
import { ResponseStream } from "../src/services/speaker/stream";
|
import { StreamResponse } from "../src/services/speaker/stream";
|
||||||
import { sleep } from "../src/utils/base";
|
import { sleep } from "../src/utils/base";
|
||||||
|
|
||||||
export async function testSpeaker() {
|
export async function testSpeaker() {
|
||||||
|
@ -13,16 +13,16 @@ export async function testSpeaker() {
|
||||||
const speaker = new AISpeaker(config);
|
const speaker = new AISpeaker(config);
|
||||||
await speaker.initMiServices();
|
await speaker.initMiServices();
|
||||||
// await testSpeakerResponse(speaker);
|
// await testSpeakerResponse(speaker);
|
||||||
await testSpeakerStreamResponse(speaker);
|
// await testSpeakerStreamResponse(speaker);
|
||||||
// await testSpeakerGetMessages(speaker);
|
// await testSpeakerGetMessages(speaker);
|
||||||
// await testSwitchSpeaker(speaker);
|
// await testSwitchSpeaker(speaker);
|
||||||
// await testSpeakerUnWakeUp(speaker);
|
// await testSpeakerUnWakeUp(speaker);
|
||||||
// await testAISpeaker(speaker);
|
await testAISpeaker(speaker);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function testAISpeaker(speaker: AISpeaker) {
|
async function testAISpeaker(speaker: AISpeaker) {
|
||||||
speaker.askAI = async (msg) => {
|
speaker.askAI = async (msg) => {
|
||||||
return "你说:" + msg.text;
|
return { text: "你说:" + msg.text };
|
||||||
};
|
};
|
||||||
await speaker.run();
|
await speaker.run();
|
||||||
console.log("finished");
|
console.log("finished");
|
||||||
|
@ -60,7 +60,7 @@ async function testSpeakerResponse(speaker: AISpeaker) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function testSpeakerStreamResponse(speaker: AISpeaker) {
|
async function testSpeakerStreamResponse(speaker: AISpeaker) {
|
||||||
const stream = new ResponseStream();
|
const stream = new StreamResponse();
|
||||||
const add = async (text: string) => {
|
const add = async (text: string) => {
|
||||||
stream.addResponse(text);
|
stream.addResponse(text);
|
||||||
await sleep(100);
|
await sleep(100);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user