// import { Configuration, OpenAIApi, ChatCompletionRequestMessage } from "azure-openai"
/**
 * OpenAI 
 */
import OpenAIBase from "./openaibase"
import { OpenAIApiParameters, ChatReponse, EmbeddingResult } from './declare'
import OpenAI from "openai";
// import { ChatCompletionToolChoiceOption } from "openai/resources";
export default class OpenAIGpt extends OpenAIBase<OpenAI> {
    /**
     * 初始化OpenAI 的聊天对象Api
     */
    createOpenAI(apiKey: string): OpenAI {
        return new OpenAI({ apiKey })
    }

    /**
     * 获得文字的向量
     * @param text 
     */
    override async getTextEmbedding(text: string|string[], axiosOption: any): Promise<EmbeddingResult> {
        if (!text) return { successed: false, error: { errcode: 2, errmsg: 'content required' } };
        if (!this.aiApi) {
            this.aiApi = this.createOpenAI(this.apiKey);
        }
        try {
            const response: any = await this.aiApi.embeddings.create({
                model: this.embeddingmodel,
                input: text,
            }, axiosOption);
            return { successed: true, embedding: response.data.data};//[0].embedding };
        } catch (error) {
            return { successed: false, error };
        }
    }
    /**
     * 向OpenAI发送一个聊天请求
     * @param {*} chatText 
     */
    public async chatRequest(chatText: string | Array<any>, callChatOption: OpenAIApiParameters, axiosOption: any = {}): Promise<ChatReponse> {
        if (!chatText) return { successed: false, error: { errcode: 2, errmsg: '缺失聊天的内容' } };
        if (!this.aiApi)           this.aiApi = this.createOpenAI(this.apiKey);

        let message: Array<any> = typeof (chatText) == 'string' ?
            [{ role: 'user', content: chatText }] : chatText;
        try {
           // const response: any = await this.aiApi.createChatCompletion({
            const response: any = await this.aiApi.chat.completions.create(
            {
                model:callChatOption?.model || this.chatModel,
                messages:message,
                temperature: Number(callChatOption?.temperature || this.temperature),
                max_tokens: Number(callChatOption?.maxtoken || this.maxtoken),
                top_p: Number(callChatOption?.top_p || this.top_p), 
                presence_penalty: Number(callChatOption?.presence_penalty || this.presence_penalty), 
                frequency_penalty: Number(callChatOption?.frequency_penalty || this.frequency_penalty), 
                n: Number(callChatOption?.replyCounts || 1) || 1,
                // tools: (callChatOption?.enableToolCall === 1 && callChatOption?.tools) ? callChatOption.tools : undefined,
                // tool_choice: callChatOption?.enableToolCall === 1 ? 'auto' : undefined,
            }, axiosOption);
            // console.log('response.data', response)
            return { successed: true, message: response.choices, usage: response.usage };
        } catch (error) {
            console.log('result is error ', error)
            return { successed: false, error };
        }

    }
    /**
     * 流式的聊天模式
     * @param chatText 
     * @param _paramOption 
     * @param axiosOption 
     */
    override async chatRequestInStream(chatText: string | Array<any>, callChatOption: OpenAIApiParameters, attach?: any, axiosOption?: any): Promise<any> {
        if (!chatText) this.emit('chaterror', { successed: false, error: 'no text in chat' });
        if (!this.aiApi) {
            this.aiApi = this.createOpenAI(this.apiKey);
        }
        let message: Array<any> = typeof (chatText) == 'string' ? [{ role: 'user', content: chatText }] : chatText;
        axiosOption = Object.assign({}, axiosOption || { timeout: 60000 })
        let requestid = Math.ceil(Math.random() * (new Date().getTime() * Math.random()) / 1000);
        try {
            const response: any = await this.aiApi.chat.completions.create(
                {
                    model: callChatOption?.model || this.chatModel,
                    messages: message,
                    temperature: Number(callChatOption?.temperature || this.temperature),
                    max_tokens: Number(callChatOption?.maxtoken || this.maxtoken),
                    top_p: Number(callChatOption?.top_p || this.top_p),
                    presence_penalty: Number(callChatOption?.presence_penalty || this.presence_penalty),
                    frequency_penalty: Number(callChatOption?.frequency_penalty || this.frequency_penalty),
                    n: Number(callChatOption?.replyCounts || 1) || 1,
                    tools: (callChatOption?.enableToolCall === 1 && callChatOption?.tools) ? callChatOption.tools : undefined,
                    tool_choice: callChatOption?.enableToolCall === 1 ? 'auto' : undefined,
                    stream:true
                }, axiosOption);
            let replytext: string[] = [];
            let has_tool_calls = 0, currentIndex, previous_index = -1, tool_calls: any[] = [];// 使用数组来存储工具调用
            for await (const chunk of response) {
                const [choice] = chunk.choices,
                    { finish_reason:finishreason, index, usage } = choice,
                    { content, tool_calls:toolCalls } = choice.delta;
                if (toolCalls && toolCalls.length) {
                    currentIndex = toolCalls[0].index;
                    has_tool_calls = 1;
                    // 检查index是否发生变化
                    //console.log('currentIndex,previous_index', currentIndex, previous_index)
                    if (currentIndex !== previous_index) {
                        tool_calls.push({
                            id: toolCalls[0].id,
                            type: 'function',
                            function: {
                                name: toolCalls[0].function.name,
                                arguments: toolCalls[0].function.arguments
                            }
                        });
                        // 更新previousIndex以供下次比较
                        previous_index = currentIndex;
                    } else {
                        tool_calls[previous_index].function.arguments += toolCalls[0].function.arguments
                    }
                } else {
                    replytext.push(content);
                }
                let output = { successed: true, requestid, segment: content, text: replytext.join(''), finish_reason: finishreason, index, usage, has_tool_calls: has_tool_calls, tool_calls: tool_calls };
                if (attach) output = Object.assign({}, output, attach);
                this.emit(finishreason ? 'chatdone' : 'chattext', output)
            }
            return { successed: true, requestid }
        } catch (error) {
            this.emit('requesterror', { successed: false, requestid, error: 'call axios faied ' + error });
            return { successed: false, requestid }
        }
    }
}
