Skip to content

Commit 96cf0f7

Browse files
committed
update
1 parent 08c11fe commit 96cf0f7

File tree

8 files changed

+255
-1003
lines changed

8 files changed

+255
-1003
lines changed
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
node_modules/
2-
generated/
32
.env
Lines changed: 58 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,94 +1,88 @@
11
import express from "express";
2-
import { PrismaClient } from "./generated/prisma/index.js";
32

43
const app = express();
5-
const client = new PrismaClient();
6-
74
app.use(express.json());
85
app.use(express.static("./public"));
96

10-
const systemPrompt = `ユーザーの発話からタスクと時間を抽出してください。
11-
出力は必ず2行で、1行目がISO8601形式の日時(タイムゾーンは+09:00)、2行目がタスクタイトルです。
12-
時間情報がない場合は1行目を空にしてください。
7+
// タスクをメモリ上で管理
8+
let todos = [];
9+
let nextId = 1;
10+
11+
const systemPrompt = `ユーザーの入力からタスクと期限を抽出してください。
12+
出力は必ず2行で、1行目が期限の日時、2行目がタスクのタイトルです。
13+
日時は「2024/1/21 10:00」のような形式にしてください。
14+
期限の情報がない場合は1行目を空にしてください。
1315
1416
例:
1517
入力: 明日の10時に会議
1618
出力:
17-
2024-01-21T10:00:00+09:00
19+
2024/1/21 10:00
1820
会議
1921
2022
入力: 買い物に行く
2123
出力:
2224
2325
買い物に行く`;
2426

25-
// 自然言語でタスクを追加(AI解析 + DB保存)
26-
app.post("/todos/ai", async (request, response) => {
27-
try {
28-
const result = await fetch(
29-
"https://openrouter.ai/api/v1/chat/completions",
30-
{
31-
method: "POST",
32-
headers: {
33-
Authorization: `Bearer ${process.env.OPENROUTER_API_KEY}`,
34-
"Content-Type": "application/json",
35-
},
36-
body: JSON.stringify({
37-
model: "google/gemini-3-flash-preview",
38-
messages: [
39-
{ role: "system", content: systemPrompt },
40-
{ role: "user", content: request.body.text },
41-
],
42-
}),
43-
},
44-
);
45-
const data = await result.json();
46-
47-
if (!data.choices || !data.choices[0]) {
48-
response.status(500).json({ error: "AIからの応答が不正です" });
49-
return;
50-
}
51-
52-
const content = data.choices[0].message.content;
53-
const lines = content.split("\n");
54-
const dueAt = lines[0] ? new Date(lines[0]) : null;
55-
const title = lines[1] || "";
56-
57-
const todo = await client.todo.create({
58-
data: { title, due_at: dueAt },
59-
});
60-
response.json(todo);
61-
} catch (error) {
62-
console.error("Parse error:", error);
63-
response.status(500).json({ error: "解析に失敗しました" });
64-
}
65-
});
66-
6727
// タスク一覧を取得
68-
app.get("/todos", async (request, response) => {
69-
const todos = await client.todo.findMany({
70-
orderBy: { createdAt: "desc" },
71-
});
28+
app.get("/todos", (request, response) => {
7229
response.json(todos);
7330
});
7431

7532
// タスクを追加
76-
app.post("/todos", async (request, response) => {
77-
const todo = await client.todo.create({
78-
data: {
79-
title: request.body.title,
80-
due_at: request.body.due_at ? new Date(request.body.due_at) : null,
81-
},
82-
});
33+
app.post("/todos", (request, response) => {
34+
const todo = {
35+
id: nextId,
36+
title: request.body.title,
37+
dueAt: request.body.dueAt || null,
38+
};
39+
nextId += 1;
40+
todos.push(todo);
8341
response.json(todo);
8442
});
8543

8644
// タスクを削除
87-
app.delete("/todos/:id", async (request, response) => {
88-
await client.todo.delete({
89-
where: { id: parseInt(request.params.id) },
90-
});
45+
app.delete("/todos/:id", (request, response) => {
46+
const id = Number(request.params.id);
47+
todos = todos.filter((todo) => todo.id !== id);
9148
response.json({ success: true });
9249
});
9350

51+
// 自然言語でタスクを追加(AI解析)
52+
app.post("/todos/ai", async (request, response) => {
53+
const aiResponse = await fetch(
54+
"https://openrouter.ai/api/v1/chat/completions",
55+
{
56+
method: "POST",
57+
headers: {
58+
Authorization: `Bearer ${process.env.OPENROUTER_API_KEY}`,
59+
"Content-Type": "application/json",
60+
},
61+
body: JSON.stringify({
62+
model: "google/gemini-2.0-flash-exp:free",
63+
messages: [
64+
{ role: "system", content: systemPrompt },
65+
{ role: "user", content: request.body.text },
66+
],
67+
}),
68+
},
69+
);
70+
71+
const data = await aiResponse.json();
72+
const content = data.choices[0].message.content;
73+
// AIの応答を改行で分割し、1行目を期限、2行目をタイトルとして取得
74+
const firstNewLine = content.indexOf("\n");
75+
const dueAt = content.slice(0, firstNewLine) || null;
76+
const title = content.slice(firstNewLine + 1) || request.body.text;
77+
78+
const todo = {
79+
id: nextId,
80+
title: title,
81+
dueAt: dueAt,
82+
};
83+
nextId += 1;
84+
todos.push(todo);
85+
response.json(todo);
86+
});
87+
9488
app.listen(3000);

0 commit comments

Comments
 (0)