"use client" import dynamic from 'next/dynamic'; import { useEffect, useRef, useState } from 'react'; import '@/deps/live2d.min.js' import useVoice2Txt from "@/hooks/useVoice2txt"; import useTxt2Voice from '@/hooks/useTxt2Voice'; import axios from 'axios'; import * as PIXI from 'pixi.js'; import { Live2DModel } from 'pixi-live2d-display/cubism2'; //import "@/deps/live2dcubismcore.min.js" export default function Home() { function draggable(model: any) { model.buttonMode = true; model.on("pointerdown", (e: any) => { model.dragging = true; model._pointerX = e.data.global.x - model.x; model._pointerY = e.data.global.y - model.y; }); model.on("pointermove", (e: any) => { if (model.dragging) { model.position.x = e.data.global.x - model._pointerX; model.position.y = e.data.global.y - model._pointerY; } }); model.on("pointerupoutside", () => (model.dragging = false)); model.on("pointerup", () => (model.dragging = false)); } function addFrame(model: any) { const foreground = PIXI.Sprite.from(PIXI.Texture.WHITE); foreground.width = model.internalModel.width; foreground.height = model.internalModel.height; foreground.alpha = 0.2; model.addChild(foreground); checkbox("Model Frames", (checked: any) => (foreground.visible = checked)); } function addHitAreaFrames(model: any) { try { //@ts-ignore const hitAreaFrames = new PIXI.live2d.HitAreaFrames(); model.addChild(hitAreaFrames); checkbox("Hit Area Frames", (checked: any) => (hitAreaFrames.visible = checked)); } catch (err) { } } function checkbox(name: any, onChange: any) { const id = name.replace(/\W/g, "").toLowerCase(); let checkbox = document.getElementById(id); if (!checkbox) { const p = document.createElement("p")!; p.innerHTML = ` `; document!.getElementById("control")!.appendChild(p); checkbox = p.firstChild as HTMLElement; } checkbox.addEventListener("change", () => { //@ts-ignore onChange(checkbox.checked); }); //@ts-ignore onChange(checkbox.checked); } const send = (inputText: string) => { setResponse(inputText) if (!inputText) return; console.log(inputText) let data = JSON.stringify({ "messages": [ { "content": `回答用户的问题,尽可能简短。`, "role": "system" }, { "content": inputText, "role": "user" } ], "model": "deepseek-chat", "frequency_penalty": 0, "max_tokens": 2048, "presence_penalty": 0, "stop": null, "stream": false, "temperature": 1, "top_p": 1 }); let config = { method: 'post', maxBodyLength: Infinity, url: 'https://api.deepseek.com/chat/completions', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': 'Bearer sk-dd24ae704e8d4939aeed8f050d04d36b' }, data: data }; try { axios(config) .then((response) => { console.log(`response`, response); console.log(response.data); typeof speak !== 'undefined' && speak(response.data.choices[0].message.content); setResponse(response.data.choices[0].message.content); }) .catch((error) => { setResponse(error!.toString()); console.log(error); }); } catch (error) { setResponse(error!.toString()); console.log(error); } } const { start, end, text, isListening, error } = useVoice2Txt({ lang: 'cmn-Hans-CN', continuous: false }); const { isSpeaking, speak, stop } = useTxt2Voice(); const [inputText, setInputText] = useState(""); const isMouthOpen = useRef(false); const [response, setResponse] = useState(""); useEffect(() => { console.log(text, error) if (!text) return; send(text); if (error) { setResponse(error); return; } }, [text, error]); const [model, setModel] = useState(); useEffect(() => { if (!isSpeaking) { isMouthOpen.current = false; } }, [isSpeaking]); useEffect(() => { if (!isListening && !isSpeaking) { } }, [isListening]); useEffect(() => { // expose PIXI to window so that this plugin is able to // reference window.PIXI.Ticker to automatically update Live2D models //@ts-ignore typeof window !== 'undefined' && (window.PIXI = PIXI); (async function () { const app = new PIXI.Application({ view: document.getElementById('canvas') as HTMLCanvasElement, }); const model = await Live2DModel.from('https://cdn.jsdelivr.net/gh/guansss/pixi-live2d-display/test/assets/shizuku/shizuku.model.json'); app.stage.addChild(model); const scaleX = (innerWidth * 0.4) / model.width; const scaleY = (innerHeight * 0.8) / model.height; // fit the window model.scale.set(0.3); model.y = innerHeight * 0.1; draggable(model); addFrame(model); addHitAreaFrames(model); setModel(model); model.on('hit', (hitAreas) => { if (hitAreas.includes('body')) { model.motion('tap_body'); model.motion('speak') } }); })(); }, []) return (
{ typeof window !== 'undefined' && typeof window.Live2D !== 'undefined' && (
{response ? response : "请输入文字和我聊天吧"}
{ setInputText(e.target.value); console.log(e.target.value) }}>
) }
); }