convoviz 0.3.8__py3-none-any.whl → 0.3.9__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/analysis/graphs.py +4 -0
- convoviz/analysis/wordcloud.py +5 -0
- convoviz/cli.py +23 -0
- convoviz/interactive.py +9 -0
- convoviz/io/assets.py +12 -1
- convoviz/io/loaders.py +5 -0
- convoviz/io/writers.py +6 -0
- convoviz/logging_config.py +77 -0
- convoviz/pipeline.py +8 -0
- {convoviz-0.3.8.dist-info → convoviz-0.3.9.dist-info}/METADATA +3 -1
- {convoviz-0.3.8.dist-info → convoviz-0.3.9.dist-info}/RECORD +13 -12
- {convoviz-0.3.8.dist-info → convoviz-0.3.9.dist-info}/WHEEL +1 -1
- {convoviz-0.3.8.dist-info → convoviz-0.3.9.dist-info}/entry_points.txt +0 -0
convoviz/analysis/graphs.py
CHANGED
|
@@ -12,6 +12,7 @@ from collections import defaultdict
|
|
|
12
12
|
from collections.abc import Callable, Iterable
|
|
13
13
|
from datetime import UTC, datetime
|
|
14
14
|
from pathlib import Path
|
|
15
|
+
import logging
|
|
15
16
|
|
|
16
17
|
import matplotlib.dates as mdates
|
|
17
18
|
import matplotlib.font_manager as fm
|
|
@@ -25,6 +26,8 @@ from convoviz.config import GraphConfig, get_default_config
|
|
|
25
26
|
from convoviz.models import ConversationCollection
|
|
26
27
|
from convoviz.utils import get_asset_path
|
|
27
28
|
|
|
29
|
+
logger = logging.getLogger(__name__)
|
|
30
|
+
|
|
28
31
|
WEEKDAYS = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
|
|
29
32
|
|
|
30
33
|
|
|
@@ -742,6 +745,7 @@ def generate_summary_graphs(
|
|
|
742
745
|
cfg = config or get_default_config().graph
|
|
743
746
|
|
|
744
747
|
user_ts = collection.timestamps("user")
|
|
748
|
+
logger.info(f"Generating summary graphs to {output_dir}")
|
|
745
749
|
|
|
746
750
|
tasks: list[tuple[str, str, Callable[[], Figure]]] = [
|
|
747
751
|
("Overview", "overview.png", lambda: generate_summary_dashboard(collection, cfg)),
|
convoviz/analysis/wordcloud.py
CHANGED
|
@@ -4,6 +4,7 @@ import os
|
|
|
4
4
|
from concurrent.futures import ProcessPoolExecutor
|
|
5
5
|
from functools import lru_cache
|
|
6
6
|
from pathlib import Path
|
|
7
|
+
import logging
|
|
7
8
|
|
|
8
9
|
from nltk import download as nltk_download
|
|
9
10
|
from nltk.corpus import stopwords as nltk_stopwords
|
|
@@ -15,6 +16,8 @@ from wordcloud import WordCloud
|
|
|
15
16
|
from convoviz.config import WordCloudConfig
|
|
16
17
|
from convoviz.models import ConversationCollection
|
|
17
18
|
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
18
21
|
# Languages for stopwords
|
|
19
22
|
STOPWORD_LANGUAGES = [
|
|
20
23
|
"arabic",
|
|
@@ -149,6 +152,7 @@ def generate_wordclouds(
|
|
|
149
152
|
progress_bar: Whether to show progress bars
|
|
150
153
|
"""
|
|
151
154
|
output_dir.mkdir(parents=True, exist_ok=True)
|
|
155
|
+
logger.info(f"Generating wordclouds to {output_dir}")
|
|
152
156
|
|
|
153
157
|
week_groups = collection.group_by_week()
|
|
154
158
|
month_groups = collection.group_by_month()
|
|
@@ -188,6 +192,7 @@ def generate_wordclouds(
|
|
|
188
192
|
max_workers = max(1, cpu_count // 2)
|
|
189
193
|
|
|
190
194
|
# Use parallel processing for speedup on multi-core systems
|
|
195
|
+
logger.debug(f"Starting wordcloud generation with {max_workers} workers for {len(tasks)} tasks")
|
|
191
196
|
with ProcessPoolExecutor(max_workers=max_workers) as executor:
|
|
192
197
|
list(
|
|
193
198
|
tqdm(
|
convoviz/cli.py
CHANGED
|
@@ -12,6 +12,8 @@ from convoviz.interactive import run_interactive_config
|
|
|
12
12
|
from convoviz.io.loaders import find_latest_zip
|
|
13
13
|
from convoviz.pipeline import run_pipeline
|
|
14
14
|
from convoviz.utils import default_font_path
|
|
15
|
+
from convoviz.logging_config import setup_logging
|
|
16
|
+
import logging
|
|
15
17
|
|
|
16
18
|
app = typer.Typer(
|
|
17
19
|
add_completion=False,
|
|
@@ -57,8 +59,26 @@ def run(
|
|
|
57
59
|
"-i/-I",
|
|
58
60
|
help="Force interactive mode on or off.",
|
|
59
61
|
),
|
|
62
|
+
verbose: int = typer.Option(
|
|
63
|
+
0,
|
|
64
|
+
"--verbose",
|
|
65
|
+
"-v",
|
|
66
|
+
help="Increase verbosity. Use -vv for debug.",
|
|
67
|
+
count=True,
|
|
68
|
+
),
|
|
69
|
+
log_file: Path | None = typer.Option(
|
|
70
|
+
None,
|
|
71
|
+
"--log-file",
|
|
72
|
+
help="Path to log file. Defaults to a temporary file.",
|
|
73
|
+
),
|
|
60
74
|
) -> None:
|
|
61
75
|
"""Convert ChatGPT export data to markdown and generate visualizations."""
|
|
76
|
+
# Setup logging immediately
|
|
77
|
+
log_path = setup_logging(verbose, log_file)
|
|
78
|
+
logger = logging.getLogger("convoviz.cli")
|
|
79
|
+
console.print(f"[dim]Logging to: {log_path}[/dim]")
|
|
80
|
+
logger.debug(f"Logging initialized. Output: {log_path}")
|
|
81
|
+
|
|
62
82
|
if ctx.invoked_subcommand is not None:
|
|
63
83
|
return
|
|
64
84
|
|
|
@@ -114,10 +134,13 @@ def run(
|
|
|
114
134
|
try:
|
|
115
135
|
run_pipeline(config)
|
|
116
136
|
except (InvalidZipError, ConfigurationError) as e:
|
|
137
|
+
logger.error(f"Known error: {e}")
|
|
117
138
|
console.print(f"[bold red]Error:[/bold red] {escape(str(e))}")
|
|
118
139
|
raise typer.Exit(code=1) from None
|
|
119
140
|
except Exception as e:
|
|
141
|
+
logger.exception("Unexpected error occurred")
|
|
120
142
|
console.print(f"[bold red]Unexpected error:[/bold red] {escape(str(e))}")
|
|
143
|
+
console.print(f"[dim]See log file for details: {log_path}[/dim]")
|
|
121
144
|
raise typer.Exit(code=1) from None
|
|
122
145
|
|
|
123
146
|
|
convoviz/interactive.py
CHANGED
|
@@ -6,6 +6,7 @@ from typing import Literal, Protocol, cast
|
|
|
6
6
|
from questionary import Choice, Style, checkbox, select
|
|
7
7
|
from questionary import path as qst_path
|
|
8
8
|
from questionary import text as qst_text
|
|
9
|
+
import logging
|
|
9
10
|
|
|
10
11
|
from convoviz.config import ConvovizConfig, OutputKind, get_default_config
|
|
11
12
|
from convoviz.io.loaders import find_latest_zip, validate_zip
|
|
@@ -26,6 +27,8 @@ CUSTOM_STYLE = Style(
|
|
|
26
27
|
]
|
|
27
28
|
)
|
|
28
29
|
|
|
30
|
+
logger = logging.getLogger(__name__)
|
|
31
|
+
|
|
29
32
|
|
|
30
33
|
class _QuestionaryPrompt[T](Protocol):
|
|
31
34
|
def ask(self) -> T | None: ...
|
|
@@ -74,6 +77,7 @@ def run_interactive_config(initial_config: ConvovizConfig | None = None) -> Conv
|
|
|
74
77
|
Updated configuration based on user input
|
|
75
78
|
"""
|
|
76
79
|
config = initial_config or get_default_config()
|
|
80
|
+
logger.info("Starting interactive configuration")
|
|
77
81
|
|
|
78
82
|
# Set sensible defaults if not already set
|
|
79
83
|
if not config.input_path:
|
|
@@ -97,6 +101,7 @@ def run_interactive_config(initial_config: ConvovizConfig | None = None) -> Conv
|
|
|
97
101
|
|
|
98
102
|
if input_result:
|
|
99
103
|
config.input_path = Path(input_result)
|
|
104
|
+
logger.debug(f"User selected input: {config.input_path}")
|
|
100
105
|
|
|
101
106
|
# Prompt for output folder
|
|
102
107
|
output_result: str = _ask_or_cancel(
|
|
@@ -109,6 +114,7 @@ def run_interactive_config(initial_config: ConvovizConfig | None = None) -> Conv
|
|
|
109
114
|
|
|
110
115
|
if output_result:
|
|
111
116
|
config.output_folder = Path(output_result)
|
|
117
|
+
logger.debug(f"User selected output: {config.output_folder}")
|
|
112
118
|
|
|
113
119
|
# Prompt for outputs to generate
|
|
114
120
|
output_choices = [
|
|
@@ -126,6 +132,7 @@ def run_interactive_config(initial_config: ConvovizConfig | None = None) -> Conv
|
|
|
126
132
|
)
|
|
127
133
|
|
|
128
134
|
config.outputs = set(selected_outputs) if selected_outputs else set()
|
|
135
|
+
logger.debug(f"User selected outputs: {config.outputs}")
|
|
129
136
|
|
|
130
137
|
# Prompt for markdown settings (only if markdown output is selected)
|
|
131
138
|
if OutputKind.MARKDOWN in config.outputs:
|
|
@@ -144,6 +151,7 @@ def run_interactive_config(initial_config: ConvovizConfig | None = None) -> Conv
|
|
|
144
151
|
)
|
|
145
152
|
if result:
|
|
146
153
|
setattr(headers, role, result)
|
|
154
|
+
logger.debug(f"User selected headers: {headers}")
|
|
147
155
|
|
|
148
156
|
# Prompt for markdown flavor
|
|
149
157
|
flavor_result = cast(
|
|
@@ -160,6 +168,7 @@ def run_interactive_config(initial_config: ConvovizConfig | None = None) -> Conv
|
|
|
160
168
|
|
|
161
169
|
if flavor_result:
|
|
162
170
|
config.conversation.markdown.flavor = flavor_result
|
|
171
|
+
logger.debug(f"User selected flavor: {config.conversation.markdown.flavor}")
|
|
163
172
|
|
|
164
173
|
# Prompt for YAML headers
|
|
165
174
|
yaml_config = config.conversation.yaml
|
convoviz/io/assets.py
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
import shutil
|
|
4
4
|
from pathlib import Path
|
|
5
|
+
import logging
|
|
6
|
+
|
|
7
|
+
logger = logging.getLogger(__name__)
|
|
5
8
|
|
|
6
9
|
|
|
7
10
|
def resolve_asset_path(source_dir: Path, asset_id: str) -> Path | None:
|
|
@@ -26,6 +29,7 @@ def resolve_asset_path(source_dir: Path, asset_id: str) -> Path | None:
|
|
|
26
29
|
# 1. Try exact match
|
|
27
30
|
exact_path = (source_dir / asset_id).resolve()
|
|
28
31
|
if exact_path.exists() and exact_path.is_file() and exact_path.is_relative_to(source_dir):
|
|
32
|
+
logger.debug(f"Resolved asset (exact): {asset_id} -> {exact_path}")
|
|
29
33
|
return exact_path
|
|
30
34
|
|
|
31
35
|
# 2. Try prefix match in root
|
|
@@ -37,6 +41,7 @@ def resolve_asset_path(source_dir: Path, asset_id: str) -> Path | None:
|
|
|
37
41
|
if p.is_file() and p.resolve().is_relative_to(source_dir)
|
|
38
42
|
]
|
|
39
43
|
if files:
|
|
44
|
+
logger.debug(f"Resolved asset (prefix root): {asset_id} -> {files[0]}")
|
|
40
45
|
return files[0]
|
|
41
46
|
except Exception:
|
|
42
47
|
pass
|
|
@@ -53,6 +58,7 @@ def resolve_asset_path(source_dir: Path, asset_id: str) -> Path | None:
|
|
|
53
58
|
if p.is_file() and p.resolve().is_relative_to(dalle_dir)
|
|
54
59
|
]
|
|
55
60
|
if files:
|
|
61
|
+
logger.debug(f"Resolved asset (dalle): {asset_id} -> {files[0]}")
|
|
56
62
|
return files[0]
|
|
57
63
|
except Exception:
|
|
58
64
|
pass
|
|
@@ -69,6 +75,7 @@ def resolve_asset_path(source_dir: Path, asset_id: str) -> Path | None:
|
|
|
69
75
|
if p.is_file() and p.resolve().is_relative_to(user_dir)
|
|
70
76
|
]
|
|
71
77
|
if files:
|
|
78
|
+
logger.debug(f"Resolved asset (user dir): {asset_id} -> {files[0]}")
|
|
72
79
|
return files[0]
|
|
73
80
|
except Exception:
|
|
74
81
|
pass
|
|
@@ -92,7 +99,11 @@ def copy_asset(source_path: Path, dest_dir: Path) -> str:
|
|
|
92
99
|
dest_path = assets_dir / source_path.name
|
|
93
100
|
|
|
94
101
|
if not dest_path.exists():
|
|
95
|
-
|
|
102
|
+
try:
|
|
103
|
+
shutil.copy2(source_path, dest_path)
|
|
104
|
+
logger.debug(f"Copied asset: {source_path.name}")
|
|
105
|
+
except Exception as e:
|
|
106
|
+
logger.warning(f"Failed to copy asset {source_path}: {e}")
|
|
96
107
|
|
|
97
108
|
# Return forward-slash path for Markdown compatibility even on Windows
|
|
98
109
|
return f"assets/{source_path.name}"
|
convoviz/io/loaders.py
CHANGED
|
@@ -2,12 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
from pathlib import Path, PurePosixPath
|
|
4
4
|
from zipfile import ZipFile
|
|
5
|
+
import logging
|
|
5
6
|
|
|
6
7
|
from orjson import loads
|
|
7
8
|
|
|
8
9
|
from convoviz.exceptions import InvalidZipError
|
|
9
10
|
from convoviz.models import Conversation, ConversationCollection
|
|
10
11
|
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
11
14
|
|
|
12
15
|
def _is_safe_zip_member_name(name: str) -> bool:
|
|
13
16
|
"""Return True if a ZIP entry name is safe to extract.
|
|
@@ -46,6 +49,7 @@ def extract_archive(filepath: Path) -> Path:
|
|
|
46
49
|
"""
|
|
47
50
|
folder = filepath.with_suffix("")
|
|
48
51
|
folder.mkdir(parents=True, exist_ok=True)
|
|
52
|
+
logger.info(f"Extracting archive: {filepath} to {folder}")
|
|
49
53
|
|
|
50
54
|
with ZipFile(filepath) as zf:
|
|
51
55
|
for member in zf.infolist():
|
|
@@ -115,6 +119,7 @@ def load_collection_from_json(filepath: Path | str) -> ConversationCollection:
|
|
|
115
119
|
Loaded ConversationCollection object
|
|
116
120
|
"""
|
|
117
121
|
filepath = Path(filepath)
|
|
122
|
+
logger.debug(f"Loading collection from JSON: {filepath}")
|
|
118
123
|
with filepath.open(encoding="utf-8") as f:
|
|
119
124
|
data = loads(f.read())
|
|
120
125
|
|
convoviz/io/writers.py
CHANGED
|
@@ -12,6 +12,9 @@ from convoviz.io.assets import copy_asset, resolve_asset_path
|
|
|
12
12
|
from convoviz.models import Conversation, ConversationCollection
|
|
13
13
|
from convoviz.renderers import render_conversation
|
|
14
14
|
from convoviz.utils import sanitize
|
|
15
|
+
import logging
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
15
18
|
|
|
16
19
|
# Month names for folder naming
|
|
17
20
|
_MONTH_NAMES = [
|
|
@@ -102,6 +105,7 @@ def save_conversation(
|
|
|
102
105
|
markdown = render_conversation(conversation, config, headers, asset_resolver=asset_resolver)
|
|
103
106
|
with final_path.open("w", encoding="utf-8") as f:
|
|
104
107
|
f.write(markdown)
|
|
108
|
+
logger.debug(f"Saved conversation: {final_path}")
|
|
105
109
|
|
|
106
110
|
# Set modification time
|
|
107
111
|
timestamp = conversation.update_time.timestamp()
|
|
@@ -135,6 +139,7 @@ def _generate_year_index(year_dir: Path, year: str) -> None:
|
|
|
135
139
|
|
|
136
140
|
index_path = year_dir / "_index.md"
|
|
137
141
|
index_path.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
|
142
|
+
logger.debug(f"Generated year index: {index_path}")
|
|
138
143
|
|
|
139
144
|
|
|
140
145
|
def _generate_month_index(month_dir: Path, year: str, month: str) -> None:
|
|
@@ -162,6 +167,7 @@ def _generate_month_index(month_dir: Path, year: str, month: str) -> None:
|
|
|
162
167
|
|
|
163
168
|
index_path = month_dir / "_index.md"
|
|
164
169
|
index_path.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
|
170
|
+
logger.debug(f"Generated month index: {index_path}")
|
|
165
171
|
|
|
166
172
|
|
|
167
173
|
def save_collection(
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""Logging configuration for convoviz."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import sys
|
|
5
|
+
import tempfile
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Optional
|
|
8
|
+
|
|
9
|
+
from rich.logging import RichHandler
|
|
10
|
+
|
|
11
|
+
def setup_logging(
|
|
12
|
+
verbosity: int = 0,
|
|
13
|
+
log_file: Optional[Path] = None,
|
|
14
|
+
) -> Path:
|
|
15
|
+
"""Set up logging configuration.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
verbosity: Level of verbosity (0=WARNING, 1=INFO, 2=DEBUG)
|
|
19
|
+
log_file: Path to log file. If None, a temporary file is created.
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
Path to the log file used.
|
|
23
|
+
"""
|
|
24
|
+
# clear existing handlers
|
|
25
|
+
root_logger = logging.getLogger()
|
|
26
|
+
root_logger.handlers.clear()
|
|
27
|
+
|
|
28
|
+
# Determine log level for console
|
|
29
|
+
if verbosity >= 2:
|
|
30
|
+
console_level = logging.DEBUG
|
|
31
|
+
elif verbosity >= 1:
|
|
32
|
+
console_level = logging.INFO
|
|
33
|
+
else:
|
|
34
|
+
console_level = logging.WARNING
|
|
35
|
+
|
|
36
|
+
# Console handler (Rich)
|
|
37
|
+
console_handler = RichHandler(
|
|
38
|
+
rich_tracebacks=True,
|
|
39
|
+
markup=True,
|
|
40
|
+
show_time=False,
|
|
41
|
+
show_path=False,
|
|
42
|
+
)
|
|
43
|
+
console_handler.setLevel(console_level)
|
|
44
|
+
|
|
45
|
+
# File handler
|
|
46
|
+
if log_file is None:
|
|
47
|
+
# Create temp file if not specified
|
|
48
|
+
tf = tempfile.NamedTemporaryFile(
|
|
49
|
+
prefix="convoviz_",
|
|
50
|
+
suffix=".log",
|
|
51
|
+
delete=False
|
|
52
|
+
)
|
|
53
|
+
log_file = Path(tf.name)
|
|
54
|
+
tf.close()
|
|
55
|
+
|
|
56
|
+
# Ensure parent dir exists
|
|
57
|
+
if not log_file.parent.exists():
|
|
58
|
+
log_file.parent.mkdir(parents=True, exist_ok=True)
|
|
59
|
+
|
|
60
|
+
file_handler = logging.FileHandler(log_file, encoding="utf-8")
|
|
61
|
+
file_handler.setLevel(logging.DEBUG) # Always log DEBUG to file
|
|
62
|
+
file_formatter = logging.Formatter(
|
|
63
|
+
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
|
64
|
+
)
|
|
65
|
+
file_handler.setFormatter(file_formatter)
|
|
66
|
+
|
|
67
|
+
# Configure root logger
|
|
68
|
+
# We set root level to DEBUG so that the handlers can filter as they please
|
|
69
|
+
root_logger.setLevel(logging.DEBUG)
|
|
70
|
+
root_logger.addHandler(console_handler)
|
|
71
|
+
root_logger.addHandler(file_handler)
|
|
72
|
+
|
|
73
|
+
# Reduce noise from explicit libraries if necessary
|
|
74
|
+
logging.getLogger("matplotlib").setLevel(logging.WARNING)
|
|
75
|
+
logging.getLogger("PIL").setLevel(logging.WARNING)
|
|
76
|
+
|
|
77
|
+
return log_file
|
convoviz/pipeline.py
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
from shutil import rmtree
|
|
5
|
+
import logging
|
|
5
6
|
|
|
6
7
|
from rich.console import Console
|
|
7
8
|
|
|
@@ -15,6 +16,7 @@ from convoviz.io.loaders import (
|
|
|
15
16
|
from convoviz.io.writers import save_collection
|
|
16
17
|
|
|
17
18
|
console = Console()
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
18
20
|
|
|
19
21
|
|
|
20
22
|
def _safe_uri(path: Path) -> str:
|
|
@@ -46,6 +48,7 @@ def run_pipeline(config: ConvovizConfig) -> None:
|
|
|
46
48
|
if not input_path.exists():
|
|
47
49
|
raise InvalidZipError(str(input_path), reason="File does not exist")
|
|
48
50
|
|
|
51
|
+
logger.info(f"Starting pipeline with input: {input_path}")
|
|
49
52
|
console.print(f"Loading data from {input_path} [bold yellow]📂[/bold yellow] ...\n")
|
|
50
53
|
|
|
51
54
|
# Load collection based on input type
|
|
@@ -62,6 +65,7 @@ def run_pipeline(config: ConvovizConfig) -> None:
|
|
|
62
65
|
else:
|
|
63
66
|
# Assume zip
|
|
64
67
|
collection = load_collection_from_zip(input_path)
|
|
68
|
+
logger.info(f"Loaded collection with {len(collection.conversations)} conversations")
|
|
65
69
|
|
|
66
70
|
# Try to merge bookmarklet data if available
|
|
67
71
|
bookmarklet_json = find_latest_bookmarklet_json()
|
|
@@ -70,6 +74,7 @@ def run_pipeline(config: ConvovizConfig) -> None:
|
|
|
70
74
|
try:
|
|
71
75
|
bookmarklet_collection = load_collection_from_json(bookmarklet_json)
|
|
72
76
|
collection.update(bookmarklet_collection)
|
|
77
|
+
logger.info("Merged bookmarklet data")
|
|
73
78
|
except Exception as e:
|
|
74
79
|
console.print(
|
|
75
80
|
f"[bold yellow]Warning:[/bold yellow] Failed to load bookmarklet data: {e}"
|
|
@@ -114,6 +119,7 @@ def run_pipeline(config: ConvovizConfig) -> None:
|
|
|
114
119
|
folder_organization=config.folder_organization,
|
|
115
120
|
progress_bar=True,
|
|
116
121
|
)
|
|
122
|
+
logger.info("Markdown generation complete")
|
|
117
123
|
console.print(
|
|
118
124
|
f"\nDone [bold green]✅[/bold green] ! "
|
|
119
125
|
f"Check the output [bold blue]📄[/bold blue] here: {_safe_uri(markdown_folder)} 🔗\n"
|
|
@@ -138,6 +144,7 @@ def run_pipeline(config: ConvovizConfig) -> None:
|
|
|
138
144
|
config.graph,
|
|
139
145
|
progress_bar=True,
|
|
140
146
|
)
|
|
147
|
+
logger.info("Graph generation complete")
|
|
141
148
|
console.print(
|
|
142
149
|
f"\nDone [bold green]✅[/bold green] ! "
|
|
143
150
|
f"Check the output [bold blue]📈[/bold blue] here: {_safe_uri(graph_folder)} 🔗\n"
|
|
@@ -162,6 +169,7 @@ def run_pipeline(config: ConvovizConfig) -> None:
|
|
|
162
169
|
config.wordcloud,
|
|
163
170
|
progress_bar=True,
|
|
164
171
|
)
|
|
172
|
+
logger.info("Wordcloud generation complete")
|
|
165
173
|
console.print(
|
|
166
174
|
f"\nDone [bold green]✅[/bold green] ! "
|
|
167
175
|
f"Check the output [bold blue]🔡☁️[/bold blue] here: {_safe_uri(wordcloud_folder)} 🔗\n"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: convoviz
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.9
|
|
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
|
|
@@ -106,6 +106,8 @@ Options: `markdown`, `graphs`, `wordclouds`. In interactive mode, you'll be prom
|
|
|
106
106
|
- `--zip` / `-z` is kept as an alias for `--input` for convenience.
|
|
107
107
|
- You can force non-interactive mode with `--no-interactive`.
|
|
108
108
|
- Use `--flat` to put all Markdown files in a single folder instead of organizing by date.
|
|
109
|
+
- Use `--verbose` or `-v` for detailed logging (use `-vv` for debug logs).
|
|
110
|
+
- Use `--log-file` to specify a custom log file (logs default to a temporary file if not specified).
|
|
109
111
|
|
|
110
112
|
For more options, run:
|
|
111
113
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
convoviz/__init__.py,sha256=UjwkFEmRXhE-3qhsoGTG9XhtoL2cP0o4h3Sp9fcA2Ic,858
|
|
2
2
|
convoviz/__main__.py,sha256=1qiGW13_SgL7wJi8iioIN-AAHGkNGnEl5q_RcPUrI0s,143
|
|
3
3
|
convoviz/analysis/__init__.py,sha256=1dHjnw88mepSY3Q3U8lEvSqkuWPtkzpyYMgq0CIWoXk,654
|
|
4
|
-
convoviz/analysis/graphs.py,sha256=
|
|
5
|
-
convoviz/analysis/wordcloud.py,sha256=
|
|
4
|
+
convoviz/analysis/graphs.py,sha256=ZxPayWPWNBNVFtbKRH5XXE_0_hymU7urOwJTyrfS4UY,29796
|
|
5
|
+
convoviz/analysis/wordcloud.py,sha256=FUDmzaJYA4efiJ066nZdjTrKRnBbivxpGQzVm4nGPJQ,6178
|
|
6
6
|
convoviz/assets/colormaps.txt,sha256=59TSGz428AxY14AEvymAH2IJ2RT9Mlp7Sy0N12NEdXQ,108
|
|
7
7
|
convoviz/assets/fonts/AmaticSC-Regular.ttf,sha256=83clh7a3urnTLud0_yZofuIb6BdyC2LMI9jhE6G2LvU,142696
|
|
8
8
|
convoviz/assets/fonts/ArchitectsDaughter-Regular.ttf,sha256=fnrj5_N_SlY2Lj3Ehqz5aKECPZVJlJAflgsOU94_qIM,37756
|
|
@@ -36,26 +36,27 @@ 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=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
39
|
-
convoviz/cli.py,sha256=
|
|
39
|
+
convoviz/cli.py,sha256=a_RxEyUuheLRs30r9RPO-8PgJP7WUwMarjILaR8VdwQ,4888
|
|
40
40
|
convoviz/config.py,sha256=qo4JPkJRx1UgvVN_x-XmycxdjU9XwPlqoZWJLsDMSAs,3592
|
|
41
41
|
convoviz/exceptions.py,sha256=bQpIKls48uOQpagEJAxpXf5LF7QoagRRfbD0MjWC7Ak,1476
|
|
42
|
-
convoviz/interactive.py,sha256=
|
|
42
|
+
convoviz/interactive.py,sha256=svkr8ZHvgmgJFDzzpRWgSM9wD-WzqlM11i5qGSt_lZQ,8691
|
|
43
43
|
convoviz/io/__init__.py,sha256=y70TYypJ36_kaEA04E2wa1EDaKQVjprKItoKR6MMs4M,471
|
|
44
|
-
convoviz/io/assets.py,sha256=
|
|
45
|
-
convoviz/io/loaders.py,sha256=
|
|
46
|
-
convoviz/io/writers.py,sha256=
|
|
44
|
+
convoviz/io/assets.py,sha256=KbtTX38KYm7Q4hN-lsxyL96qnHiVqEbPeHYPxAY_WQM,3459
|
|
45
|
+
convoviz/io/loaders.py,sha256=vWlWWPFfjbeduFZF735BJ6XHs8iKTFkYX5l__3GDBww,5891
|
|
46
|
+
convoviz/io/writers.py,sha256=wVRzqTTIZ5dC9sPeZ56je8B2RxQzNolwZkuoJzzhF1A,7068
|
|
47
|
+
convoviz/logging_config.py,sha256=CB2700N08ycoqolEM4ClzYyky9fbp51Xz2Qi0cAASTw,2222
|
|
47
48
|
convoviz/models/__init__.py,sha256=6gAfrk6KJT2QxdvX_v15mUdfIqEw1xKxwQlKSfyA5eI,532
|
|
48
49
|
convoviz/models/collection.py,sha256=L658yKMNC6IZrfxYxZBe-oO9COP_bzVfRznnNon7tfU,4467
|
|
49
50
|
convoviz/models/conversation.py,sha256=ssx1Z6LM9kJIx3OucQW8JVoAc8zCdxj1iOLtie2B3ak,5678
|
|
50
51
|
convoviz/models/message.py,sha256=0CJ9hJ1rQiesn1SgHqFgEgKUgS7XAPGtSunQl5q8Pl4,8316
|
|
51
52
|
convoviz/models/node.py,sha256=1vBAtKVscYsUBDnKAOyLxuZaK9KoVF1dFXiKXRHxUnY,1946
|
|
52
|
-
convoviz/pipeline.py,sha256=
|
|
53
|
+
convoviz/pipeline.py,sha256=sGDiGSQvGLsrJ7XLus2hlUePtWpxDU8IZAMgAUq5UIs,6785
|
|
53
54
|
convoviz/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
54
55
|
convoviz/renderers/__init__.py,sha256=IQgwD9NqtUgbS9zwyPBNZbBIZcFrbZ9C7WMAV-X3Xdg,261
|
|
55
56
|
convoviz/renderers/markdown.py,sha256=55PACkd-F0mmBXWXQ5SrfJr3UNrK_z2spQnePdk1UsQ,7849
|
|
56
57
|
convoviz/renderers/yaml.py,sha256=XG1s4VhDdx-TiqekTkgED87RZ1lVQ7IwrbA-sZHrs7k,4056
|
|
57
58
|
convoviz/utils.py,sha256=IQEKYHhWOnYxlr4GwAHoquG0BXTlVRkORL80oUSaIeQ,3417
|
|
58
|
-
convoviz-0.3.
|
|
59
|
-
convoviz-0.3.
|
|
60
|
-
convoviz-0.3.
|
|
61
|
-
convoviz-0.3.
|
|
59
|
+
convoviz-0.3.9.dist-info/WHEEL,sha256=e_m4S054HL0hyR3CpOk-b7Q7fDX6BuFkgL5OjAExXas,80
|
|
60
|
+
convoviz-0.3.9.dist-info/entry_points.txt,sha256=HYsmsw5vt36yYHB05uVU48AK2WLkcwshly7m7KKuZMY,54
|
|
61
|
+
convoviz-0.3.9.dist-info/METADATA,sha256=SwJ5Ls84ieuX2sxskmU07N_hf30TayAFqvy-47ekfYo,5036
|
|
62
|
+
convoviz-0.3.9.dist-info/RECORD,,
|
|
File without changes
|