convoviz 0.1.7__py3-none-any.whl → 0.2.1__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/utils.py CHANGED
@@ -1,274 +1,105 @@
1
- """Utility functions for the project."""
2
-
3
- from __future__ import annotations
1
+ """Utility functions for convoviz."""
4
2
 
3
+ import re
5
4
  from pathlib import Path
6
- from re import compile as re_compile
7
- from re import sub as re_sub
8
- from typing import Any, Literal, TypedDict
9
- from zipfile import ZipFile
10
-
11
- DOWNLOADS = Path.home() / "Downloads"
12
-
13
-
14
- def latest_zip() -> Path:
15
- """Path to the most recently created zip file in the Downloads folder."""
16
- zip_files = list(DOWNLOADS.glob("*.zip"))
17
-
18
- if not zip_files:
19
- err_msg = f"No zip files found in {DOWNLOADS}"
20
- raise FileNotFoundError(err_msg)
21
-
22
- return max(zip_files, key=lambda x: x.stat().st_ctime)
23
-
24
-
25
- def latest_bookmarklet_json() -> Path | None:
26
- """Path to the most recent JSON file in Downloads with 'bookmarklet' in the name."""
27
- bkmrklet_files = [x for x in DOWNLOADS.glob("*.json") if "bookmarklet" in x.name]
28
-
29
- if not bkmrklet_files:
30
- return None
31
-
32
- return max(bkmrklet_files, key=lambda x: x.stat().st_ctime)
33
5
 
34
6
 
35
7
  def sanitize(filename: str) -> str:
36
- """Sanitized title of the conversation, compatible with file names."""
37
- anti_pattern = re_compile(r'[<>:"/\\|?*\n\r\t\f\v]+')
38
-
39
- return anti_pattern.sub("_", filename.strip()) or "untitled"
40
-
41
-
42
- def close_code_blocks(text: str) -> str:
43
- """Ensure that all code blocks are closed."""
44
- # A code block can be opened with triple backticks, possibly followed by a lang name
45
- # It can only be closed however with triple backticks, with nothing else on the line
46
-
47
- open_code_block = False
48
-
49
- lines = text.split("\n")
50
-
51
- for line in lines:
52
- if line.startswith("```") and not open_code_block:
53
- open_code_block = True
54
- continue
55
-
56
- if line == "```" and open_code_block:
57
- open_code_block = False
58
-
59
- if open_code_block:
60
- text += "\n```"
61
-
62
- return text
8
+ """Sanitize a string to be safe for use as a filename.
63
9
 
10
+ Replaces invalid characters with underscores.
64
11
 
65
- def replace_latex_delimiters(text: str) -> str:
66
- """Replace all the LaTeX bracket delimiters in the string with dollar sign ones."""
67
- text = re_sub(r"\\\[", "$$", text)
68
- text = re_sub(r"\\\]", "$$", text)
69
- text = re_sub(r"\\\(", "$", text)
12
+ Args:
13
+ filename: The string to sanitize
70
14
 
71
- return re_sub(r"\\\)", "$", text)
72
-
73
-
74
- def stem(path: Path | str) -> str:
75
- """Return the `stem` of the given path."""
76
- return Path(path).stem
77
-
78
-
79
- def root_dir() -> Path:
80
- """Path to the root directory of the project.
81
-
82
- might change when refactoring, currently it's `convoviz/`
15
+ Returns:
16
+ A filename-safe string, or "untitled" if empty
83
17
  """
84
- return Path(__file__).parent
18
+ pattern = re.compile(r'[<>:"/\\|?*\n\r\t\f\v]+')
19
+ result = pattern.sub("_", filename.strip())
20
+ return result or "untitled"
85
21
 
86
22
 
87
- def font_names() -> list[str]:
88
- """List of font names in the `assets/fonts` folder."""
89
- fonts_path = root_dir() / "assets" / "fonts"
90
- return [font.stem for font in fonts_path.iterdir()]
23
+ def validate_header(text: str) -> bool:
24
+ """Check if text is a valid markdown header.
91
25
 
26
+ Args:
27
+ text: The text to validate
92
28
 
93
- def font_path(font_name: str) -> Path:
94
- """Path to the given font in the `assets/fonts` folder.
95
-
96
- `font_name` should be the stem of the font file, without the extension
29
+ Returns:
30
+ True if it's a valid header (1-6 # followed by space and content)
97
31
  """
98
- return root_dir() / "assets" / "fonts" / f"{font_name}.ttf"
99
-
100
-
101
- def default_font_path() -> Path:
102
- """Path to the default font in the `assets/fonts` folder."""
103
- return font_path("RobotoSlab-Thin")
104
-
105
-
106
- def colormaps() -> list[str]:
107
- """List of colormaps in the `assets/colormaps.txt` file."""
108
- colormaps_path = root_dir() / "assets" / "colormaps.txt"
109
- with colormaps_path.open(encoding="utf-8") as file:
110
- return file.read().splitlines()
111
-
112
-
113
- def validate_header(text: str) -> bool:
114
- """Return True if the given text is a valid markdown header."""
115
32
  max_header_level = 6
116
- return (
117
- 1 <= text.count("#") <= max_header_level
118
- and text.startswith("#")
119
- and text[len(text.split()[0])] == " "
120
- )
121
-
122
-
123
- def validate_zip(filepath: str | Path) -> bool:
124
- """Return True if the given path is a zip file with a `conversations.json` file."""
125
- filepath = Path(filepath)
126
- if not filepath.is_file() or filepath.suffix != ".zip":
33
+ if not text.startswith("#"):
127
34
  return False
128
- with ZipFile(filepath) as zip_ref:
129
- if "conversations.json" in zip_ref.namelist():
130
- return True
131
- return False
132
-
133
-
134
- def get_archive(filepath: Path | str) -> Path:
135
- """Extract the zip and return the path to the extracted folder."""
136
- filepath = Path(filepath)
137
- folder = filepath.with_suffix("")
138
-
139
- with ZipFile(filepath) as file:
140
- file.extractall(folder)
141
-
142
- return folder
143
-
144
-
145
- def code_block(text: str, lang: str = "python") -> str:
146
- """Wrap the given string in a code block."""
147
- return f"```{lang}\n{text}\n```"
148
-
149
-
150
- # default configs
151
-
152
-
153
- class AuthorHeaders(TypedDict):
154
- """Type hint for the author headers configs."""
155
-
156
- system: str
157
- user: str
158
- assistant: str
159
- tool: str
160
-
161
-
162
- class MessageConfigs(TypedDict):
163
- """Type hint for the message configs."""
164
-
165
- author_headers: AuthorHeaders
166
35
 
36
+ parts = text.split(maxsplit=1)
37
+ if len(parts) < 2:
38
+ return False
167
39
 
168
- DEFAULT_MESSAGE_CONFIGS: MessageConfigs = {
169
- "author_headers": {
170
- "system": "### System",
171
- "user": "# Me",
172
- "assistant": "# ChatGPT",
173
- "tool": "### Tool output",
174
- },
175
- }
176
-
177
-
178
- class MarkdownConfigs(TypedDict):
179
- """Type hint for the markdown configs."""
180
-
181
- latex_delimiters: Literal["default", "dollars"]
182
-
40
+ hashes = parts[0]
41
+ return hashes == "#" * len(hashes) and 1 <= len(hashes) <= max_header_level
183
42
 
184
- class YAMLConfigs(TypedDict):
185
- """Type hint for the yaml configs."""
186
43
 
187
- title: bool
188
- tags: bool
189
- chat_link: bool
190
- create_time: bool
191
- update_time: bool
192
- model: bool
193
- used_plugins: bool
194
- message_count: bool
195
- content_types: bool
196
- custom_instructions: bool
44
+ def root_dir() -> Path:
45
+ """Get the path to the convoviz package directory.
197
46
 
47
+ Returns:
48
+ Path to the package root
49
+ """
50
+ return Path(__file__).parent
198
51
 
199
- class ConversationConfigs(TypedDict):
200
- """Type hint for the conversation configs."""
201
52
 
202
- markdown: MarkdownConfigs
203
- yaml: YAMLConfigs
53
+ def font_dir() -> Path:
54
+ """Get the path to the fonts directory.
204
55
 
56
+ Returns:
57
+ Path to the assets/fonts directory
58
+ """
59
+ return root_dir() / "assets" / "fonts"
205
60
 
206
- DEFAULT_CONVERSATION_CONFIGS: ConversationConfigs = {
207
- "markdown": {"latex_delimiters": "default"},
208
- "yaml": {
209
- "title": True,
210
- "tags": False,
211
- "chat_link": True,
212
- "create_time": True,
213
- "update_time": True,
214
- "model": True,
215
- "used_plugins": True,
216
- "message_count": True,
217
- "content_types": True,
218
- "custom_instructions": True,
219
- },
220
- }
221
61
 
62
+ def font_names() -> list[str]:
63
+ """Get available font names.
222
64
 
223
- class GraphKwargs(TypedDict, total=False):
224
- """Type hint for the graph configs."""
65
+ Returns:
66
+ List of font names (without .ttf extension)
67
+ """
68
+ fonts_path = font_dir()
69
+ if not fonts_path.exists():
70
+ return []
71
+ return [font.stem for font in fonts_path.glob("*.ttf")]
225
72
 
226
73
 
227
- class WordCloudKwargs(TypedDict, total=False):
228
- """Type hint for the wordcloud configs."""
74
+ def font_path(font_name: str) -> Path:
75
+ """Get the path to a font file.
229
76
 
230
- font_path: str
231
- colormap: str
232
- custom_stopwords: str
233
- background_color: str | None
234
- mode: Literal["RGB", "RGBA"]
235
- include_numbers: bool
236
- width: int
237
- height: int
77
+ Args:
78
+ font_name: Name of the font (without extension)
238
79
 
80
+ Returns:
81
+ Path to the font file
82
+ """
83
+ return font_dir() / f"{font_name}.ttf"
239
84
 
240
- DEFAULT_WORDCLOUD_CONFIGS: WordCloudKwargs = {
241
- "font_path": str(default_font_path()),
242
- "colormap": "prism",
243
- "custom_stopwords": "use, file, ",
244
- "background_color": None,
245
- "mode": "RGBA",
246
- "include_numbers": False,
247
- "width": 1000,
248
- "height": 1000,
249
- }
250
85
 
86
+ def default_font_path() -> Path:
87
+ """Get the path to the default font.
251
88
 
252
- class AllConfigs(TypedDict):
253
- """Type hint for the user config JSON file."""
89
+ Returns:
90
+ Path to RobotoSlab-Thin.ttf
91
+ """
92
+ return font_path("RobotoSlab-Thin")
254
93
 
255
- zip_filepath: str
256
- output_folder: str
257
- message: MessageConfigs
258
- conversation: ConversationConfigs
259
- wordcloud: WordCloudKwargs
260
- graph: GraphKwargs
261
- node: dict[str, Any]
262
- conversation_set: dict[str, Any]
263
94
 
95
+ def colormaps() -> list[str]:
96
+ """Get available colormap names.
264
97
 
265
- DEFAULT_USER_CONFIGS: AllConfigs = {
266
- "zip_filepath": str(latest_zip()),
267
- "output_folder": str(Path.home() / "Documents" / "ChatGPT Data"),
268
- "message": DEFAULT_MESSAGE_CONFIGS,
269
- "conversation": DEFAULT_CONVERSATION_CONFIGS,
270
- "wordcloud": DEFAULT_WORDCLOUD_CONFIGS,
271
- "graph": {},
272
- "node": {},
273
- "conversation_set": {},
274
- }
98
+ Returns:
99
+ List of colormap names from colormaps.txt
100
+ """
101
+ colormaps_path = root_dir() / "assets" / "colormaps.txt"
102
+ if not colormaps_path.exists():
103
+ return []
104
+ with colormaps_path.open(encoding="utf-8") as f:
105
+ return f.read().splitlines()
@@ -1,26 +1,46 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: convoviz
3
- Version: 0.1.7
4
- Summary: Get analytics and visualizations on your ChatGPT data !
5
- Home-page: https://github.com/mohamed-chs/chatgpt-history-export-to-md
6
- License: MIT
7
- Keywords: markdown,advanced-data-analysis,json,zip,openai,chatgpt,bookmarklet,obsidian-md,code-interpreter
3
+ Version: 0.2.1
4
+ Summary: Get analytics and visualizations on your ChatGPT data!
5
+ Keywords: markdown,chatgpt,openai,visualization,analytics,json,export,data-analysis,obsidian
8
6
  Author: Mohamed Cheikh Sidiya
9
- Author-email: mohamedcheikhsidiya77@gmail.com
10
- Requires-Python: >=3.9,<4.0
7
+ Author-email: Mohamed Cheikh Sidiya <mohamedcheikhsidiya77@gmail.com>
8
+ License: MIT License
9
+
10
+ Copyright (c) 2023 Mohamed Cheikh Sidiya
11
+
12
+ Permission is hereby granted, free of charge, to any person obtaining a copy
13
+ of this software and associated documentation files (the "Software"), to deal
14
+ in the Software without restriction, including without limitation the rights
15
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
+ copies of the Software, and to permit persons to whom the Software is
17
+ furnished to do so, subject to the following conditions:
18
+
19
+ The above copyright notice and this permission notice shall be included in all
20
+ copies or substantial portions of the Software.
21
+
22
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
+ SOFTWARE.
11
29
  Classifier: License :: OSI Approved :: MIT License
12
30
  Classifier: Programming Language :: Python :: 3
13
- Classifier: Programming Language :: Python :: 3.9
14
- Classifier: Programming Language :: Python :: 3.10
15
- Classifier: Programming Language :: Python :: 3.11
16
31
  Classifier: Programming Language :: Python :: 3.12
17
- Requires-Dist: matplotlib (>=3.8.1,<4.0.0)
18
- Requires-Dist: nltk (>=3.8.1,<4.0.0)
19
- Requires-Dist: orjson (>=3.9.10,<4.0.0)
20
- Requires-Dist: pydantic (>=2.4.2,<3.0.0)
21
- Requires-Dist: questionary (>=2.0.1,<3.0.0)
22
- Requires-Dist: tqdm (>=4.66.1,<5.0.0)
23
- Requires-Dist: wordcloud (>=1.9.2,<2.0.0)
32
+ Requires-Dist: matplotlib>=3.9.4
33
+ Requires-Dist: nltk>=3.9.2
34
+ Requires-Dist: orjson>=3.11.5
35
+ Requires-Dist: pillow>=11.3.0
36
+ Requires-Dist: pydantic>=2.12.5
37
+ Requires-Dist: pydantic-settings>=2.7.0
38
+ Requires-Dist: questionary>=2.1.1
39
+ Requires-Dist: rich>=14.2.0
40
+ Requires-Dist: tqdm>=4.67.1
41
+ Requires-Dist: typer>=0.21.0
42
+ Requires-Dist: wordcloud>=1.9.5
43
+ Requires-Python: >=3.12
24
44
  Project-URL: Repository, https://github.com/mohamed-chs/chatgpt-history-export-to-md
25
45
  Description-Content-Type: text/markdown
26
46
 
@@ -51,41 +71,54 @@ See examples [here](demo).
51
71
 
52
72
  ### 2. Install the tool 🛠
53
73
 
54
- Open a terminal or command prompt and run:
74
+ Try it without installing using uv ([astral-sh/uv](https://github.com/astral-sh/uv)):
55
75
 
56
76
  ```bash
57
- pip install convoviz
77
+ uvx convoviz
58
78
  ```
59
79
 
60
- to install the package.
80
+ You can install it with uv (Recommended):
81
+
82
+ ```bash
83
+ uv tool install convoviz
84
+ ```
85
+
86
+ or pipx:
87
+ ```bash
88
+ pipx install convoviz
89
+ ```
61
90
 
62
91
  ### 3. Run the Script 🏃‍♂️
63
92
 
64
- With the package installed, run the following command in your terminal:
93
+ Simply run the command and follow the prompts:
65
94
 
66
95
  ```bash
67
- python -m convoviz
96
+ convoviz
68
97
  ```
69
98
 
70
- Next, follow the instructions displayed and choose your desired options, the script will handle the rest.
99
+ #### Command Line Arguments
71
100
 
72
- ### 4. Check the Output 🎉
101
+ You can provide arguments directly to skip the prompts:
73
102
 
74
- And that's it! After running the script, head over to the output folder to see your nice word clouds, graphs, and neatly formatted Markdown files. Enjoy !
103
+ ```bash
104
+ convoviz --zip path/to/your/export.zip --output path/to/output/folder
105
+ ```
75
106
 
76
- **Tweet Your Discoveries**:
107
+ For more options, run:
77
108
 
78
- [![Tweet](https://img.shields.io/twitter/url?style=social&url=https%3A%2F%2Fgithub.com%2Fyourusername%2Fyourrepository)](https://twitter.com/intent/tweet?text=So%2C%20this%20is%20what%20my%20entire%20ChatGPT%20history%20looks%20like%20...%0D%0A%0D%0Ahttp%3A%2F%2Fbit.ly%2F3ZuHCCK)
109
+ ```bash
110
+ convoviz --help
111
+ ```
79
112
 
80
- ### How to add new conversations ➕
113
+ ### 4. Check the Output 🎉
81
114
 
82
- See [How to use the JS script](js/how_to_use.md) for instructions on how to download new conversations.
115
+ And that's it! After running the script, head over to the output folder to see your nice word clouds, graphs, and neatly formatted Markdown files. Enjoy !
83
116
 
84
117
  ## Share Your Feedback! 💌
85
118
 
86
119
  I hope you find this tool useful. I'm continuously looking to improve on this, but I need your help for that.
87
120
 
88
- Whether you're a tech wizard or you're new to all this (especially if you're new to all this), I'd love to hear about your journey with the tool. Found a quirk? Have a suggestion? Or just want to send some good vibes? I'm all ears!
121
+ Whether you're a tech wizard or you're new to all this, I'd love to hear about your journey with the tool. Found a quirk? Have a suggestion? Or just want to send some good vibes? I'm all ears!
89
122
 
90
123
  **Here's how you can share your thoughts:**
91
124
 
@@ -95,12 +128,8 @@ Whether you're a tech wizard or you're new to all this (especially if you're new
95
128
 
96
129
  And if you've had a great experience, consider giving the project a star ⭐. It keeps me motivated and helps others discover it!
97
130
 
98
- Thank you for being awesome! 🌟
99
-
100
131
  ## Notes
101
132
 
102
- This project requires Python 3.8.7 or higher if on Windows. See [known issue](https://github.com/prompt-toolkit/python-prompt-toolkit/issues/1023#issue-534396318)
103
-
104
133
  This is just a small thing I coded to help me see my convos in beautiful markdown, in [Obsidian](https://obsidian.md/) (my go-to note-taking app).
105
134
 
106
135
  I wasn't a fan of the clunky, and sometimes paid, browser extensions.
@@ -109,7 +138,4 @@ It was also a great opportunity to learn more about Python and type annotations.
109
138
 
110
139
  It also works as package, so you can **import** it in your own projects, and use the models and functions as you wish. I need to add more documentation for that tho. Feel free to reach out if you need help.
111
140
 
112
- I'm working on automating it to add new conversations and updating old ones. Had some luck with a JavaScript bookmarklet, still ironing it out tho. Shouldn't take long.
113
-
114
- > for an older version with zero dependencies, see https://github.com/mohamed-chs/chatgpt-history-export-to-md/tree/fe13a701fe8653c9f946b1e12979ce3bfe7104b8.
115
-
141
+ I'm working on automating it to add new conversations and updating old ones. Had some luck with a JavaScript bookmarklet, still ironing it out tho.
@@ -1,6 +1,9 @@
1
- convoviz/__init__.py,sha256=qVwMjJs4wDGVEDcGU1bSsuu4nrH3ZXzEoozE-A3GVBU,182
2
- convoviz/__main__.py,sha256=zB4n0cbXFET_HWn7tLVGULFihtfYhQkT6Rt9hXjQ_tA,68
3
- convoviz/assets/colormaps.txt,sha256=5dzx_ANWM3LO-itNwJVFabi_xvBdU9RM7s7CeqxzPfk,130
1
+ convoviz/__init__.py,sha256=bQLCHO2U9EyMTGqNgsYiCtBQKTKNj4iIM3-TwIkrnRY,612
2
+ convoviz/__main__.py,sha256=1qiGW13_SgL7wJi8iioIN-AAHGkNGnEl5q_RcPUrI0s,143
3
+ convoviz/analysis/__init__.py,sha256=FxgH5JJpyypiLJpMQn_HlM51jnb8lQdP63_C_W3Dlx4,241
4
+ convoviz/analysis/graphs.py,sha256=hMJmNX4ejFl_yl_kldA91EACpQjfkq-7sTiVnrBQx_w,2653
5
+ convoviz/analysis/wordcloud.py,sha256=ZucezsDlgaOgYpjm_S7wKYmk7crD-MM83s4eVex-Bl8,4034
6
+ convoviz/assets/colormaps.txt,sha256=59TSGz428AxY14AEvymAH2IJ2RT9Mlp7Sy0N12NEdXQ,108
4
7
  convoviz/assets/fonts/AmaticSC-Regular.ttf,sha256=83clh7a3urnTLud0_yZofuIb6BdyC2LMI9jhE6G2LvU,142696
5
8
  convoviz/assets/fonts/ArchitectsDaughter-Regular.ttf,sha256=fnrj5_N_SlY2Lj3Ehqz5aKECPZVJlJAflgsOU94_qIM,37756
6
9
  convoviz/assets/fonts/BebasNeue-Regular.ttf,sha256=gw6hhqz_wjFu0aTkIxkka6O0awTjOiEQeSSb-QEZPwQ,57676
@@ -32,18 +35,25 @@ convoviz/assets/fonts/YsabeauOffice-Regular.ttf,sha256=RnW2erC5p6s2YxvWmwa019hYT
32
35
  convoviz/assets/fonts/YsabeauSC-Regular.ttf,sha256=G4lkq34KKqZOaoomtxFz_KlwVmxg56UbFXFnWgijkDM,116980
33
36
  convoviz/assets/fonts/YsabeauSC-Thin.ttf,sha256=hZGOZNTRrxbiUPE2VDeLbtnaRwkMOBaVQbq7Fwx-34c,116932
34
37
  convoviz/assets/fonts/Zeyada-Regular.ttf,sha256=fKhkrp9VHt_3Aw8JfkfkPeC2j3CilLWuPUudzBeawPQ,57468
35
- convoviz/cli.py,sha256=vymqTWejHw6a3wIc5OyclSr8k11yPxtLm9uLX17cF1c,3173
36
- convoviz/configuration.py,sha256=rPB7eDkfyYlCmj7Wrx8uXopklHHH6p3bXGtl6KmZsBY,3843
37
- convoviz/data_analysis.py,sha256=eJLchAPSp45WdJwWagIURn9MNLs6CIg76TYw-COhdNc,3479
38
- convoviz/long_runs.py,sha256=lViUuD2aC-djfyzaw2iFprIiEhLaOhAcQQA1E7OD-EM,2676
39
- convoviz/models/__init__.py,sha256=n9ttBKw75Jx9q22REf0QmAVar1pPidRT24Mkymo7LJE,242
40
- convoviz/models/_conversation.py,sha256=cKMtMAzfAe_oPNH229V4-WLkKepRTyoRGTDV4e5kLsI,8988
41
- convoviz/models/_conversation_set.py,sha256=-FzefQwZbiM31MXMmHpLf_TuCbn8QkY2P2uypqjCRng,6572
42
- convoviz/models/_message.py,sha256=fqwGE4fQDvBfoFBWLK0_ITo5tOXFt7oDhvcmpQHqJag,2600
43
- convoviz/models/_node.py,sha256=5xeGnLprt6q5GuS4PF248Oq5ANj3BKrNqm6GrmtN1ik,2400
38
+ convoviz/cli.py,sha256=JqNk2rV1rjver8A7tWtjPeLaw1nYOze4fjghY6ohpCA,3371
39
+ convoviz/config.py,sha256=QQ0KAyiacKLMCM1asFrNr6JQH1rVxyhGwNjSFqt_gSc,2445
40
+ convoviz/exceptions.py,sha256=bQpIKls48uOQpagEJAxpXf5LF7QoagRRfbD0MjWC7Ak,1476
41
+ convoviz/interactive.py,sha256=XFSjBW-8EhEAC6UkGdcML10MIA5ZfToM24A98pWpryI,5500
42
+ convoviz/io/__init__.py,sha256=y70TYypJ36_kaEA04E2wa1EDaKQVjprKItoKR6MMs4M,471
43
+ convoviz/io/loaders.py,sha256=Bwat6pmRExuGfBbpWoVqZXcGbWoTN9qaTEcJYtc505M,3653
44
+ convoviz/io/writers.py,sha256=aLPmnLpbcho65Wy4ePzP6xoGWYVV0_owxbxv67ojBpA,2880
45
+ convoviz/models/__init__.py,sha256=R78W7FvRLhPx36HJmIh1dPv2mNQGOF8X0fGMTpEagkA,628
46
+ convoviz/models/collection.py,sha256=aUQq0dgFXCEEqPCBl4l9A99MZdWWunSO2b79-VyR2qY,4033
47
+ convoviz/models/conversation.py,sha256=G0wxrcIhY5JzWeIOkGtkELSzc7J32W2wxJVbNOord58,5145
48
+ convoviz/models/message.py,sha256=Jc92vXowU2qzMaEH2Sa96nx65sGWsZpF5rj8BXwjK5E,2090
49
+ convoviz/models/node.py,sha256=1vBAtKVscYsUBDnKAOyLxuZaK9KoVF1dFXiKXRHxUnY,1946
50
+ convoviz/pipeline.py,sha256=KRSE-aVYppO-2YhvIzSQqcMfnJPxN-4ggnJ0h2xj2EA,4133
44
51
  convoviz/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
45
- convoviz/utils.py,sha256=EkEMS6y7OZEvREpzwjdq04PQm1wDEszk41gnuugCk6A,7078
46
- convoviz-0.1.7.dist-info/LICENSE,sha256=LO6tqJjRNZIT4w4btugJrWzmwsxeZZcL3j7KV7qK_tM,1099
47
- convoviz-0.1.7.dist-info/METADATA,sha256=MrMCoSV5enAH_gRBJVSkz7jdjYDDhVEzLsH__U40e1E,5458
48
- convoviz-0.1.7.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
49
- convoviz-0.1.7.dist-info/RECORD,,
52
+ convoviz/renderers/__init__.py,sha256=IQgwD9NqtUgbS9zwyPBNZbBIZcFrbZ9C7WMAV-X3Xdg,261
53
+ convoviz/renderers/markdown.py,sha256=4DLXPiZe_56cUNf1xGbcuw_qHq03CUMLCEdsIOhjq_Y,4836
54
+ convoviz/renderers/yaml.py,sha256=FqO2zToXp96gQRDrjALgchESWLg49LxuehXP59SEFeU,1522
55
+ convoviz/utils.py,sha256=6LqoTEHgZg7ICkepxkNqr44LKgztiS37O6RkMsHHNbw,2363
56
+ convoviz-0.2.1.dist-info/WHEEL,sha256=KSLUh82mDPEPk0Bx0ScXlWL64bc8KmzIPNcpQZFV-6E,79
57
+ convoviz-0.2.1.dist-info/entry_points.txt,sha256=HYsmsw5vt36yYHB05uVU48AK2WLkcwshly7m7KKuZMY,54
58
+ convoviz-0.2.1.dist-info/METADATA,sha256=YKlday7GkHWEuc3C6IC5tZpLoPgXhhk-THkcExjXSqQ,5894
59
+ convoviz-0.2.1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: uv 0.9.22
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ convoviz = convoviz.cli:main_entry
3
+