AIdentity

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit b7293d9b99f410902c63ba7d76119f6ef94c23d5
parent 281b02ef3bc2819d8f5f80decea26aed59cc2c4e
Author: minerva-jupiter <ryouturn@gmail.com>
Date:   Thu, 23 Oct 2025 08:23:23 +0900

feat: add drawing stage and enhance chat progression(onComplete)

Diffstat:
Mapp/components/1_chat.tsx | 13++++++++++---
Mapp/components/2_draw.tsx | 120+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
Mpackage.json | 9+++++----
Mrust-wasm/pkg/rust_wasm_bg.wasm | 0
Mrust-wasm/src/lib.rs | 18++++++++++++++++--
5 files changed, 146 insertions(+), 14 deletions(-)

diff --git a/app/components/1_chat.tsx b/app/components/1_chat.tsx @@ -6,7 +6,7 @@ import init, { chat } from '../../rust-wasm/pkg/rust_wasm.js'; const FirstChat: React.FC<StageProps> = ({ onComplete }) => { return( - <ChatPage/> + <ChatPage onComplete={onComplete}/> ) }; @@ -114,7 +114,7 @@ const MessageInput: React.FC<{ onSend: (text: string) => void }> = ({ onSend }) -function ChatPage() { +function ChatPage({onComplete}:StageProps) { const [messages, setMessages] = useState<Message[]>(initialMessages); const [ dict, setDict ] = useState<Uint8Array|undefined>(undefined); const messagesEndRef = useRef<HTMLDivElement>(null); @@ -136,6 +136,8 @@ function ChatPage() { init(); }, []); + let talktimes = 1; + const handleSendMessage = useCallback((text: string) => { console.log(dict); if (text.trim() === '') return; @@ -153,7 +155,12 @@ function ChatPage() { sender: 'ai', }; setMessages((prev) => [...prev, aiResponse]); - }, [dict]); + talktimes += 1; + console.log("talktimes is "+talktimes); + if(talktimes >= 3){ + onComplete(); + } + }, [dict, onComplete]); const pageContainerStyle: React.CSSProperties = { display: 'flex', diff --git a/app/components/2_draw.tsx b/app/components/2_draw.tsx @@ -1,16 +1,126 @@ -import React from 'react'; +'use clinet' + +import React, { useState, useRef, useCallback } from 'react'; import { StageProps } from '../ctrl/page.tsx'; +import { Stage, Layer, Line as KonvaLine, Text } from 'react-konva'; +import type { KonvaEventObject } from 'konva/lib/Node'; +import type Konva from 'konva'; const SecondDraw: React.FC<StageProps> = ({ onComplete }) => { return( <div> - <h1> - this is SecondDraw - </h1> - <button type='button' onClick={onComplete}>onComplete</button> + <h1>this is draw</h1> + <DrawingApp onComplete={onComplete}/> </div> ) }; +type Tool = 'pen' | 'eraser'; + +interface LineData { + tool: Tool; + points: number[]; // [x1, y1, x2, y2, ...] の形式 +} + +function DrawingApp({onComplete}:StageProps) { + const tool = 'pen'; + const [lines, setLines] = useState<LineData[]>([]); + const isDrawing = useRef(false); + + const stageRef = useRef<Konva.Stage | null>(null); + + const getPointerPosition = (stage: Konva.Stage | null) => { + return stage?.getPointerPosition() ?? { x: 0, y: 0 }; + }; + + /** + * マウス・タッチ開始時の処理 + */ + const handleMouseDown = useCallback((e: KonvaEventObject<MouseEvent | TouchEvent>) => { + isDrawing.current = true; + const stage = e.target.getStage(); + if (stage) { + const pos = getPointerPosition(stage); + // 新しいラインを追加 + setLines((prevLines) => [ + ...prevLines, + { tool, points: [pos.x, pos.y] }, + ]); + } + }, [tool]); // toolが変更されたら再生成 + + /** + * マウス・タッチ移動時の処理 + */ + const handleMouseMove = useCallback((e: KonvaEventObject<MouseEvent | TouchEvent>) => { + if (!isDrawing.current) { + return; + } + + const stage = e.target.getStage(); + if (!stage) return; + + const point = getPointerPosition(stage); + + setLines((prevLines) => { + // 1. 最後のラインのインデックスを取得 + const lastLineIndex = prevLines.length - 1; + if (lastLineIndex < 0) return prevLines; // 念のためのチェック + + const lastLine = prevLines[lastLineIndex]; + + // 2. 最後の LineData オブジェクトを不変に更新 + const newLine: LineData = { + ...lastLine, // 既存のプロパティをコピー + // points配列に新しいポイントを追加して、新しい配列を作成 + points: lastLine.points.concat([point.x, point.y]), + }; + + // 3. lines配列全体を不変に更新 + return [ + ...prevLines.slice(0, lastLineIndex), // 最後の要素以外はそのままコピー + newLine, // 完全に新しい LineData オブジェクトで置き換える + ]; + }); + }, []); + + /** + * マウス・タッチ終了時の処理 + */ + const handleMouseUp = useCallback(() => { + isDrawing.current = false; + }, []); + + return ( + <div> + <Stage + width={globalThis.innerWidth} + height={globalThis.innerWidth} + onMouseDown={handleMouseDown} + onMouseMove={handleMouseMove} + onMouseUp={handleMouseUp} + onTouchStart={handleMouseDown} + onTouchMove={handleMouseMove} + onTouchEnd={handleMouseUp} + ref={stageRef} + > + <Layer> + <Text text="Just start drawing" x={5} y={30} fontSize={16} fill="#000" /> + {lines.map((line, i) => ( + <KonvaLine // `Line`がHTML要素と競合する可能性があるので`KonvaLine`としてインポート + key={i} + points={line.points} + stroke="#ffffff" + strokeWidth={5} // Eraserは少し太くする + tension={0.5} + lineCap="round" + lineJoin="round" + /> + ))} + </Layer> + </Stage> + </div> + ); +}; export default SecondDraw; diff --git a/package.json b/package.json @@ -5,22 +5,23 @@ "scripts": { "dev": "next dev --turbopack", "build": "next build --turbopack", - "wasmbuild": "cd ./rust-wasm/ && wasm-pack build --target web", + "wasmbuild": "cd ./rust-wasm/ && wasm-pack build --target web", "start": "next start", "lint": "eslint" }, "dependencies": { + "next": "15.5.5", "react": "19.1.0", "react-dom": "19.1.0", - "next": "15.5.5" + "react-konva": "^19.0.10" }, "devDependencies": { - "typescript": "^5.9.3", + "@eslint/eslintrc": "^3.3.1", "@types/node": "^20.19.22", "@types/react": "^19.2.2", "@types/react-dom": "^19.2.2", "eslint": "^9.38.0", "eslint-config-next": "15.5.5", - "@eslint/eslintrc": "^3.3.1" + "typescript": "^5.9.3" } } diff --git a/rust-wasm/pkg/rust_wasm_bg.wasm b/rust-wasm/pkg/rust_wasm_bg.wasm Binary files differ. diff --git a/rust-wasm/src/lib.rs b/rust-wasm/src/lib.rs @@ -1,4 +1,4 @@ -use std::io::Cursor; +use std::{io:: Cursor, usize}; use vibrato::{Dictionary, Tokenizer}; use wasm_bindgen::prelude::*; @@ -14,6 +14,20 @@ pub fn chat(dict_data: &[u8], input: &str) -> Result<String, JsValue> { worker.reset_sentence(input); worker.tokenize(); - let ans : String= "馬鹿なことを言ってないで。".to_string(); + let mut ans : String= "馬鹿なことを言ってないで。".to_string(); + + match worker.num_tokens() { + 1..5 => { + ans = "何を言っているの?".to_string(); + }, + 5..10 => { + ans = "そんなことができるわけないじゃない?".to_string(); + }, + 10..=usize::MAX => { + ans = "そんなこと思ってるんじゃないんでしょ?".to_string(); + } + _ => {ans = "意味がわからない。".to_string();}, + } + Ok(ans) }