convoviz 0.2.6__py3-none-any.whl → 0.2.7__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.
- convoviz/cli.py +9 -1
- convoviz/config.py +9 -0
- convoviz/io/writers.py +58 -2
- convoviz/pipeline.py +1 -0
- {convoviz-0.2.6.dist-info → convoviz-0.2.7.dist-info}/METADATA +1 -6
- {convoviz-0.2.6.dist-info → convoviz-0.2.7.dist-info}/RECORD +8 -8
- {convoviz-0.2.6.dist-info → convoviz-0.2.7.dist-info}/WHEEL +0 -0
- {convoviz-0.2.6.dist-info → convoviz-0.2.7.dist-info}/entry_points.txt +0 -0
convoviz/cli.py
CHANGED
|
@@ -5,7 +5,7 @@ from pathlib import Path
|
|
|
5
5
|
import typer
|
|
6
6
|
from rich.console import Console
|
|
7
7
|
|
|
8
|
-
from convoviz.config import get_default_config
|
|
8
|
+
from convoviz.config import FolderOrganization, get_default_config
|
|
9
9
|
from convoviz.exceptions import ConfigurationError, InvalidZipError
|
|
10
10
|
from convoviz.interactive import run_interactive_config
|
|
11
11
|
from convoviz.io.loaders import find_latest_zip
|
|
@@ -38,6 +38,12 @@ def run(
|
|
|
38
38
|
"-o",
|
|
39
39
|
help="Path to the output directory.",
|
|
40
40
|
),
|
|
41
|
+
flat: bool = typer.Option(
|
|
42
|
+
False,
|
|
43
|
+
"--flat",
|
|
44
|
+
"-f",
|
|
45
|
+
help="Put all markdown files in a single folder (disables date organization).",
|
|
46
|
+
),
|
|
41
47
|
interactive: bool | None = typer.Option(
|
|
42
48
|
None,
|
|
43
49
|
"--interactive/--no-interactive",
|
|
@@ -57,6 +63,8 @@ def run(
|
|
|
57
63
|
config.input_path = input_path
|
|
58
64
|
if output_dir:
|
|
59
65
|
config.output_folder = output_dir
|
|
66
|
+
if flat:
|
|
67
|
+
config.folder_organization = FolderOrganization.FLAT
|
|
60
68
|
|
|
61
69
|
# Determine mode: interactive if explicitly requested or no input provided
|
|
62
70
|
use_interactive = interactive if interactive is not None else (input_path is None)
|
convoviz/config.py
CHANGED
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
"""Configuration models using Pydantic v2."""
|
|
2
2
|
|
|
3
|
+
from enum import Enum
|
|
3
4
|
from pathlib import Path
|
|
4
5
|
from typing import Literal
|
|
5
6
|
|
|
6
7
|
from pydantic import BaseModel, Field
|
|
7
8
|
|
|
8
9
|
|
|
10
|
+
class FolderOrganization(str, Enum):
|
|
11
|
+
"""How to organize markdown output files in folders."""
|
|
12
|
+
|
|
13
|
+
FLAT = "flat" # All files in one directory (default)
|
|
14
|
+
DATE = "date" # Nested by year/month/week
|
|
15
|
+
|
|
16
|
+
|
|
9
17
|
class AuthorHeaders(BaseModel):
|
|
10
18
|
"""Headers for different message authors in markdown output."""
|
|
11
19
|
|
|
@@ -83,6 +91,7 @@ class ConvovizConfig(BaseModel):
|
|
|
83
91
|
|
|
84
92
|
input_path: Path | None = None
|
|
85
93
|
output_folder: Path = Field(default_factory=lambda: Path.home() / "Documents" / "ChatGPT-Data")
|
|
94
|
+
folder_organization: FolderOrganization = FolderOrganization.DATE
|
|
86
95
|
message: MessageConfig = Field(default_factory=MessageConfig)
|
|
87
96
|
conversation: ConversationConfig = Field(default_factory=ConversationConfig)
|
|
88
97
|
wordcloud: WordCloudConfig = Field(default_factory=WordCloudConfig)
|
convoviz/io/writers.py
CHANGED
|
@@ -6,12 +6,59 @@ from pathlib import Path
|
|
|
6
6
|
from orjson import OPT_INDENT_2, dumps
|
|
7
7
|
from tqdm import tqdm
|
|
8
8
|
|
|
9
|
-
from convoviz.config import AuthorHeaders, ConversationConfig
|
|
9
|
+
from convoviz.config import AuthorHeaders, ConversationConfig, FolderOrganization
|
|
10
10
|
from convoviz.io.assets import copy_asset, resolve_asset_path
|
|
11
11
|
from convoviz.models import Conversation, ConversationCollection
|
|
12
12
|
from convoviz.renderers import render_conversation
|
|
13
13
|
from convoviz.utils import sanitize
|
|
14
14
|
|
|
15
|
+
# Month names for folder naming
|
|
16
|
+
_MONTH_NAMES = [
|
|
17
|
+
"January",
|
|
18
|
+
"February",
|
|
19
|
+
"March",
|
|
20
|
+
"April",
|
|
21
|
+
"May",
|
|
22
|
+
"June",
|
|
23
|
+
"July",
|
|
24
|
+
"August",
|
|
25
|
+
"September",
|
|
26
|
+
"October",
|
|
27
|
+
"November",
|
|
28
|
+
"December",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def get_date_folder_path(conversation: Conversation) -> Path:
|
|
33
|
+
"""Get the date-based folder path for a conversation.
|
|
34
|
+
|
|
35
|
+
Creates a nested structure: year/month/week
|
|
36
|
+
Example: 2024/03-March/Week-02/
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
conversation: The conversation to get the path for
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
Relative path for the date-based folder structure
|
|
43
|
+
"""
|
|
44
|
+
create_time = conversation.create_time
|
|
45
|
+
|
|
46
|
+
# Year folder: "2024"
|
|
47
|
+
year = str(create_time.year)
|
|
48
|
+
|
|
49
|
+
# Month folder: "03-March"
|
|
50
|
+
month_num = create_time.month
|
|
51
|
+
month_name = _MONTH_NAMES[month_num - 1]
|
|
52
|
+
month = f"{month_num:02d}-{month_name}"
|
|
53
|
+
|
|
54
|
+
# Week folder: "Week-01" through "Week-05" (week of the month)
|
|
55
|
+
# Calculate which week of the month this date falls into
|
|
56
|
+
day = create_time.day
|
|
57
|
+
week_of_month = (day - 1) // 7 + 1
|
|
58
|
+
week = f"Week-{week_of_month:02d}"
|
|
59
|
+
|
|
60
|
+
return Path(year) / month / week
|
|
61
|
+
|
|
15
62
|
|
|
16
63
|
def save_conversation(
|
|
17
64
|
conversation: Conversation,
|
|
@@ -74,6 +121,7 @@ def save_collection(
|
|
|
74
121
|
config: ConversationConfig,
|
|
75
122
|
headers: AuthorHeaders,
|
|
76
123
|
*,
|
|
124
|
+
folder_organization: FolderOrganization = FolderOrganization.FLAT,
|
|
77
125
|
progress_bar: bool = False,
|
|
78
126
|
) -> None:
|
|
79
127
|
"""Save all conversations in a collection to markdown files.
|
|
@@ -83,6 +131,7 @@ def save_collection(
|
|
|
83
131
|
directory: Target directory
|
|
84
132
|
config: Conversation rendering configuration
|
|
85
133
|
headers: Author header configuration
|
|
134
|
+
folder_organization: How to organize files in folders (flat or by date)
|
|
86
135
|
progress_bar: Whether to show a progress bar
|
|
87
136
|
"""
|
|
88
137
|
directory.mkdir(parents=True, exist_ok=True)
|
|
@@ -92,7 +141,14 @@ def save_collection(
|
|
|
92
141
|
desc="Writing Markdown 📄 files",
|
|
93
142
|
disable=not progress_bar,
|
|
94
143
|
):
|
|
95
|
-
|
|
144
|
+
# Determine target directory based on organization setting
|
|
145
|
+
if folder_organization == FolderOrganization.DATE:
|
|
146
|
+
target_dir = directory / get_date_folder_path(conv)
|
|
147
|
+
target_dir.mkdir(parents=True, exist_ok=True)
|
|
148
|
+
else:
|
|
149
|
+
target_dir = directory
|
|
150
|
+
|
|
151
|
+
filepath = target_dir / f"{sanitize(conv.title)}.md"
|
|
96
152
|
save_conversation(conv, filepath, config, headers, source_path=collection.source_path)
|
|
97
153
|
|
|
98
154
|
|
convoviz/pipeline.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: convoviz
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.7
|
|
4
4
|
Summary: Get analytics and visualizations on your ChatGPT data!
|
|
5
5
|
Keywords: markdown,chatgpt,openai,visualization,analytics,json,export,data-analysis,obsidian
|
|
6
6
|
Author: Mohamed Cheikh Sidiya
|
|
@@ -84,11 +84,6 @@ You can provide arguments directly to skip the prompts:
|
|
|
84
84
|
convoviz --input path/to/your/export.zip --output path/to/output/folder
|
|
85
85
|
```
|
|
86
86
|
|
|
87
|
-
Inputs can be any of:
|
|
88
|
-
- A ChatGPT export ZIP (downloaded from OpenAI)
|
|
89
|
-
- An extracted export directory containing `conversations.json`
|
|
90
|
-
- A `conversations.json` file directly
|
|
91
|
-
|
|
92
87
|
Notes:
|
|
93
88
|
- `--zip` / `-z` is kept as an alias for `--input` for convenience.
|
|
94
89
|
- You can force non-interactive mode with `--no-interactive`.
|
|
@@ -36,26 +36,26 @@ convoviz/assets/fonts/YsabeauSC-Regular.ttf,sha256=G4lkq34KKqZOaoomtxFz_KlwVmxg5
|
|
|
36
36
|
convoviz/assets/fonts/YsabeauSC-Thin.ttf,sha256=hZGOZNTRrxbiUPE2VDeLbtnaRwkMOBaVQbq7Fwx-34c,116932
|
|
37
37
|
convoviz/assets/fonts/Zeyada-Regular.ttf,sha256=fKhkrp9VHt_3Aw8JfkfkPeC2j3CilLWuPUudzBeawPQ,57468
|
|
38
38
|
convoviz/assets/stopwords.txt,sha256=7_ywpxsKYOj3U5CZTh9lP4GqbbkZLMabSOjKAXFk6Wc,539
|
|
39
|
-
convoviz/cli.py,sha256=
|
|
40
|
-
convoviz/config.py,sha256=
|
|
39
|
+
convoviz/cli.py,sha256=TPboT0maH_b_EjiT9cWbUSyMFz4ozoqf1_R-4AzY31g,3730
|
|
40
|
+
convoviz/config.py,sha256=5fklWzwr0aNyeEJG0NAggLhT0xI0kwgxhjyh9_zUvwM,3112
|
|
41
41
|
convoviz/exceptions.py,sha256=bQpIKls48uOQpagEJAxpXf5LF7QoagRRfbD0MjWC7Ak,1476
|
|
42
42
|
convoviz/interactive.py,sha256=VXtKgYo9tZGtsoj7zThdnbTrbjSNP5MzAZbdOs3icW4,7424
|
|
43
43
|
convoviz/io/__init__.py,sha256=y70TYypJ36_kaEA04E2wa1EDaKQVjprKItoKR6MMs4M,471
|
|
44
44
|
convoviz/io/assets.py,sha256=BykidWJG6OQAgbVfUByQ3RLTrldzpZ_NeM7HV3a5Tig,2333
|
|
45
45
|
convoviz/io/loaders.py,sha256=RuGiGzpyNcgwTxOM-m2ehhyh2mP1-k1YamK8-VynR3g,5713
|
|
46
|
-
convoviz/io/writers.py,sha256=
|
|
46
|
+
convoviz/io/writers.py,sha256=UW-JF5uq91NV62qpFVqgWTYSzzOAkLv67zDpulz2iBc,5072
|
|
47
47
|
convoviz/models/__init__.py,sha256=6gAfrk6KJT2QxdvX_v15mUdfIqEw1xKxwQlKSfyA5eI,532
|
|
48
48
|
convoviz/models/collection.py,sha256=L658yKMNC6IZrfxYxZBe-oO9COP_bzVfRznnNon7tfU,4467
|
|
49
49
|
convoviz/models/conversation.py,sha256=ssx1Z6LM9kJIx3OucQW8JVoAc8zCdxj1iOLtie2B3ak,5678
|
|
50
50
|
convoviz/models/message.py,sha256=mVnaUG6hypz92Oz3OgFAK1uuTgH3ZOJAWsFiCpLYneY,5459
|
|
51
51
|
convoviz/models/node.py,sha256=1vBAtKVscYsUBDnKAOyLxuZaK9KoVF1dFXiKXRHxUnY,1946
|
|
52
|
-
convoviz/pipeline.py,sha256=
|
|
52
|
+
convoviz/pipeline.py,sha256=IKfyy3iaNDTqox2YvwB3tnPqvL5iM0i_kMoa854glvY,5806
|
|
53
53
|
convoviz/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
54
54
|
convoviz/renderers/__init__.py,sha256=IQgwD9NqtUgbS9zwyPBNZbBIZcFrbZ9C7WMAV-X3Xdg,261
|
|
55
55
|
convoviz/renderers/markdown.py,sha256=mpDt-xrjsPX_wt9URCDk2wicesaVv_VTWWxTHCMKiLM,7765
|
|
56
56
|
convoviz/renderers/yaml.py,sha256=XG1s4VhDdx-TiqekTkgED87RZ1lVQ7IwrbA-sZHrs7k,4056
|
|
57
57
|
convoviz/utils.py,sha256=IQEKYHhWOnYxlr4GwAHoquG0BXTlVRkORL80oUSaIeQ,3417
|
|
58
|
-
convoviz-0.2.
|
|
59
|
-
convoviz-0.2.
|
|
60
|
-
convoviz-0.2.
|
|
61
|
-
convoviz-0.2.
|
|
58
|
+
convoviz-0.2.7.dist-info/WHEEL,sha256=eycQt0QpYmJMLKpE3X9iDk8R04v2ZF0x82ogq-zP6bQ,79
|
|
59
|
+
convoviz-0.2.7.dist-info/entry_points.txt,sha256=HYsmsw5vt36yYHB05uVU48AK2WLkcwshly7m7KKuZMY,54
|
|
60
|
+
convoviz-0.2.7.dist-info/METADATA,sha256=B3v-e0XrLNCEos-nS6_Ynw3-KGPxDMpvbrFgSEFYyHw,5820
|
|
61
|
+
convoviz-0.2.7.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|