meetnote 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- meetnote/__init__.py +25 -0
- meetnote/__main__.py +5 -0
- meetnote/application/__init__.py +0 -0
- meetnote/application/ai.py +114 -0
- meetnote/application/meeting_transcription.py +23 -0
- meetnote/application/services.py +135 -0
- meetnote/application/transcription.py +56 -0
- meetnote/domain/__init__.py +0 -0
- meetnote/domain/models.py +25 -0
- meetnote/models.py +51 -0
- meetnote/py.typed +0 -0
- meetnote/review.py +44 -0
- meetnote/storage/__init__.py +0 -0
- meetnote/storage/database.py +37 -0
- meetnote/storage/repositories.py +198 -0
- meetnote/ui/__init__.py +0 -0
- meetnote/ui/app.py +720 -0
- meetnote-1.0.0.dist-info/METADATA +68 -0
- meetnote-1.0.0.dist-info/RECORD +21 -0
- meetnote-1.0.0.dist-info/WHEEL +4 -0
- meetnote-1.0.0.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
from datetime import datetime, timezone
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import cast
|
|
4
|
+
|
|
5
|
+
from meetnote.domain.models import (
|
|
6
|
+
ActionItem,
|
|
7
|
+
ActionItemStatus,
|
|
8
|
+
Meeting,
|
|
9
|
+
)
|
|
10
|
+
from meetnote.storage.database import connect
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def meeting_from_row(row: dict) -> Meeting:
|
|
14
|
+
return Meeting(
|
|
15
|
+
id=int(row["id"]),
|
|
16
|
+
title=str(row["title"]),
|
|
17
|
+
notes=str(row["notes"]),
|
|
18
|
+
transcript=str(row["transcript"]),
|
|
19
|
+
created_at=str(row["created_at"]),
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def action_item_from_row(row: dict) -> ActionItem:
|
|
24
|
+
return ActionItem(
|
|
25
|
+
id=int(row["id"]),
|
|
26
|
+
meeting_id=int(row["meeting_id"]),
|
|
27
|
+
description=str(row["description"]),
|
|
28
|
+
owner=str(row["owner"]) if row["owner"] is not None else None,
|
|
29
|
+
status=cast(ActionItemStatus, row["status"]),
|
|
30
|
+
due_date=(str(row["due_date"]) if row["due_date"] is not None else None),
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class MeetingRepository:
|
|
35
|
+
def __init__(self, database_path: Path) -> None:
|
|
36
|
+
self.database_path = database_path
|
|
37
|
+
|
|
38
|
+
def create(self, title: str, notes: str = "") -> int:
|
|
39
|
+
created_at = datetime.now(timezone.utc).isoformat()
|
|
40
|
+
|
|
41
|
+
with connect(self.database_path) as connection:
|
|
42
|
+
cursor = connection.execute(
|
|
43
|
+
"""
|
|
44
|
+
INSERT INTO meetings (title, notes, created_at)
|
|
45
|
+
VALUES (?, ?, ?)
|
|
46
|
+
""",
|
|
47
|
+
(title, notes, created_at),
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
if cursor.lastrowid is None:
|
|
51
|
+
raise RuntimeError("Meeting insert did not return an ID")
|
|
52
|
+
|
|
53
|
+
return cursor.lastrowid
|
|
54
|
+
|
|
55
|
+
def get(self, meeting_id: int) -> Meeting | None:
|
|
56
|
+
with connect(self.database_path) as connection:
|
|
57
|
+
row = connection.execute(
|
|
58
|
+
"""
|
|
59
|
+
SELECT id, title, notes, transcript, created_at
|
|
60
|
+
FROM meetings
|
|
61
|
+
WHERE id = ?
|
|
62
|
+
""",
|
|
63
|
+
(meeting_id,),
|
|
64
|
+
).fetchone()
|
|
65
|
+
|
|
66
|
+
return meeting_from_row(dict(row)) if row is not None else None
|
|
67
|
+
|
|
68
|
+
def list_all(self) -> list[Meeting]:
|
|
69
|
+
with connect(self.database_path) as connection:
|
|
70
|
+
rows = connection.execute(
|
|
71
|
+
"""
|
|
72
|
+
SELECT id, title, notes, transcript, created_at
|
|
73
|
+
FROM meetings
|
|
74
|
+
ORDER BY created_at DESC
|
|
75
|
+
"""
|
|
76
|
+
).fetchall()
|
|
77
|
+
|
|
78
|
+
return [meeting_from_row(dict(row)) for row in rows]
|
|
79
|
+
|
|
80
|
+
def delete(self, meeting_id: int) -> None:
|
|
81
|
+
with connect(self.database_path) as connection:
|
|
82
|
+
connection.execute(
|
|
83
|
+
"""
|
|
84
|
+
DELETE FROM meetings
|
|
85
|
+
WHERE id = ?
|
|
86
|
+
""",
|
|
87
|
+
(meeting_id,),
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
def update_transcript(
|
|
91
|
+
self,
|
|
92
|
+
meeting_id: int,
|
|
93
|
+
transcript: str,
|
|
94
|
+
) -> None:
|
|
95
|
+
with connect(self.database_path) as connection:
|
|
96
|
+
connection.execute(
|
|
97
|
+
"""
|
|
98
|
+
UPDATE meetings
|
|
99
|
+
SET transcript = ?
|
|
100
|
+
WHERE id = ?
|
|
101
|
+
""",
|
|
102
|
+
(transcript, meeting_id),
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class ActionItemRepository:
|
|
107
|
+
def __init__(self, database_path: Path) -> None:
|
|
108
|
+
self.database_path = database_path
|
|
109
|
+
|
|
110
|
+
def create(
|
|
111
|
+
self,
|
|
112
|
+
meeting_id: int,
|
|
113
|
+
description: str,
|
|
114
|
+
owner: str | None = None,
|
|
115
|
+
due_date: str | None = None,
|
|
116
|
+
) -> int:
|
|
117
|
+
with connect(self.database_path) as connection:
|
|
118
|
+
cursor = connection.execute(
|
|
119
|
+
"""
|
|
120
|
+
INSERT INTO action_items
|
|
121
|
+
(meeting_id, description, owner, due_date)
|
|
122
|
+
VALUES (?, ?, ?, ?)
|
|
123
|
+
""",
|
|
124
|
+
(meeting_id, description, owner, due_date),
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
if cursor.lastrowid is None:
|
|
128
|
+
raise RuntimeError("Action-item insert did not return an ID")
|
|
129
|
+
|
|
130
|
+
return cursor.lastrowid
|
|
131
|
+
|
|
132
|
+
def list_for_meeting(self, meeting_id: int) -> list[ActionItem]:
|
|
133
|
+
with connect(self.database_path) as connection:
|
|
134
|
+
rows = connection.execute(
|
|
135
|
+
"""
|
|
136
|
+
SELECT id, meeting_id, description, owner, status, due_date
|
|
137
|
+
FROM action_items
|
|
138
|
+
WHERE meeting_id = ?
|
|
139
|
+
ORDER BY id
|
|
140
|
+
""",
|
|
141
|
+
(meeting_id,),
|
|
142
|
+
).fetchall()
|
|
143
|
+
|
|
144
|
+
return [action_item_from_row(dict(row)) for row in rows]
|
|
145
|
+
|
|
146
|
+
def mark_done(self, action_item_id: int) -> None:
|
|
147
|
+
with connect(self.database_path) as connection:
|
|
148
|
+
connection.execute(
|
|
149
|
+
"""
|
|
150
|
+
UPDATE action_items
|
|
151
|
+
SET status = 'done'
|
|
152
|
+
WHERE id = ?
|
|
153
|
+
""",
|
|
154
|
+
(action_item_id,),
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
def mark_open(self, action_item_id: int) -> None:
|
|
158
|
+
with connect(self.database_path) as connection:
|
|
159
|
+
connection.execute(
|
|
160
|
+
"""
|
|
161
|
+
UPDATE action_items
|
|
162
|
+
SET status = 'open'
|
|
163
|
+
WHERE id = ?
|
|
164
|
+
""",
|
|
165
|
+
(action_item_id,),
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
def delete(self, action_item_id: int) -> None:
|
|
169
|
+
with connect(self.database_path) as connection:
|
|
170
|
+
connection.execute(
|
|
171
|
+
"""
|
|
172
|
+
DELETE FROM action_items
|
|
173
|
+
WHERE id = ?
|
|
174
|
+
""",
|
|
175
|
+
(action_item_id,),
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
def verify(self, action_item_id: int) -> None:
|
|
179
|
+
with connect(self.database_path) as connection:
|
|
180
|
+
connection.execute(
|
|
181
|
+
"""
|
|
182
|
+
UPDATE action_items
|
|
183
|
+
SET status = 'verified'
|
|
184
|
+
WHERE id = ?
|
|
185
|
+
""",
|
|
186
|
+
(action_item_id,),
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
def reopen(self, action_item_id: int) -> None:
|
|
190
|
+
with connect(self.database_path) as connection:
|
|
191
|
+
connection.execute(
|
|
192
|
+
"""
|
|
193
|
+
UPDATE action_items
|
|
194
|
+
SET status = 'open'
|
|
195
|
+
WHERE id = ?
|
|
196
|
+
""",
|
|
197
|
+
(action_item_id,),
|
|
198
|
+
)
|
meetnote/ui/__init__.py
ADDED
|
File without changes
|