streamdown 0.27.0__py3-none-any.whl → 0.29.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.
streamdown/sd.py CHANGED
@@ -6,6 +6,7 @@
6
6
  # "pylatexenc",
7
7
  # "appdirs",
8
8
  # "term-image",
9
+ # "wcwidth",
9
10
  # "toml"
10
11
  # ]
11
12
  # ///
@@ -25,13 +26,14 @@ import termios, tty
25
26
  import math
26
27
  import re
27
28
  import shutil
28
- import subprocess
29
29
  import traceback
30
30
  import colorsys
31
31
  import base64
32
+ import subprocess
32
33
  from io import BytesIO
33
34
  from term_image.image import from_file, from_url
34
35
  import pygments.util
36
+ from wcwidth import wcwidth
35
37
  from functools import reduce
36
38
  from argparse import ArgumentParser
37
39
  from pygments import highlight
@@ -64,27 +66,34 @@ Mid = { H = 1.00, S = 1.00, V = 0.50 }
64
66
  Symbol = { H = 1.00, S = 1.00, V = 1.50 }
65
67
  Head = { H = 1.00, S = 1.00, V = 1.75 }
66
68
  Grey = { H = 1.00, S = 0.25, V = 1.37 }
67
- Bright = { H = 1.00, S = 2.00, V = 2.00 }
68
- Syntax = "dracula"
69
+ Bright = { H = 1.00, S = 0.60, V = 2.00 }
70
+ Syntax = "native"
69
71
  """
70
72
 
71
73
  def ensure_config_file(config):
74
+ config_dir = appdirs.user_config_dir("streamdown")
75
+ os.makedirs(config_dir, exist_ok=True)
76
+ config_path = os.path.join(config_dir, "config.toml")
77
+ if not os.path.exists(config_path):
78
+ open(config_path, 'w').write(default_toml)
79
+
80
+ toml_res = toml.load(config_path)
81
+
72
82
  if config:
73
- config_path = config
74
- else:
75
- config_dir = appdirs.user_config_dir("streamdown")
76
- os.makedirs(config_dir, exist_ok=True)
77
- config_path = os.path.join(config_dir, "config.toml")
78
- if not os.path.exists(config_path):
79
- open(config_path, 'w').write(default_toml)
83
+ if os.path.exists(config):
84
+ config_string = open(config).read()
85
+ else:
86
+ config_string = config
87
+ toml_res |= toml.loads(config_string)
80
88
 
81
- return config_path, open(config_path).read()
89
+ return toml_res
82
90
 
83
91
 
84
92
  FG = "\033[38;2;"
85
93
  BG = "\033[48;2;"
86
94
  RESET = "\033[0m"
87
95
  FGRESET = "\033[39m"
96
+ FORMATRESET = "\033[24;23;22m"
88
97
  BGRESET = "\033[49m"
89
98
 
90
99
  BOLD = ["\033[1m", "\033[22m"]
@@ -99,10 +108,11 @@ ANSIESCAPE = r'\033(?:\[[0-9;?]*[a-zA-Z]|][0-9]*;;.*?\\|\\)'
99
108
  KEYCODE_RE = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])')
100
109
 
101
110
  visible = lambda x: re.sub(ANSIESCAPE, "", x)
102
- # cjk characters are double width
103
- visible_length = lambda x: len(visible(x)) + dbl_count(x)
111
+ # many characters have different widths
112
+ visible_length = lambda x: sum(wcwidth(c) for c in visible(x))
104
113
  extract_ansi_codes = lambda text: re.findall(ESCAPE, text)
105
114
  remove_ansi = lambda line, codeList: reduce(lambda line, code: line.replace(code, ''), codeList, line)
115
+ split_up = lambda line: re.findall(r'(\x1b[^m]*m|[^\x1b]*)', line)
106
116
 
107
117
  def gettmpdir():
108
118
  tmp_dir_all = os.path.join(tempfile.gettempdir(), "sd")
@@ -250,7 +260,7 @@ def format_table(rowList):
250
260
  # you are styling, do it before here!
251
261
  for ix in range(len(rowList)):
252
262
  row = rowList[ix]
253
- wrapped_cell = text_wrap(row, width=col_width_list[ix], force_truncate=True)
263
+ wrapped_cell = text_wrap(row, width=col_width_list[ix], force_truncate=True, preserve_format=True)
254
264
 
255
265
  # Ensure at least one line, even for empty cells
256
266
  if not wrapped_cell:
@@ -291,17 +301,17 @@ def emit_h(level, text):
291
301
  for text in lineList:
292
302
  spaces_to_center = (state.current_width() - visible_length(text)) / 2
293
303
  if level == 1: #
294
- res.append(f"{state.space_left()}\n{state.space_left()}{BOLD[1]}{' ' * math.floor(spaces_to_center)}{text}{BOLD[1]}")
304
+ res.append(f"{state.space_left()}\n{state.space_left()}{BOLD[0]}{' ' * math.floor(spaces_to_center)}{text}{BOLD[1]}\n")
295
305
  elif level == 2: ##
296
306
  res.append(f"{state.space_left()}\n{state.space_left()}{BOLD[0]}{FG}{Style.Bright}{' ' * math.floor(spaces_to_center)}{text}{' ' * math.ceil(spaces_to_center)}{BOLD[1]}{FGRESET}")
297
307
  elif level == 3: ###
298
- res.append(f"{state.space_left()}{FG}{Style.Head}{BOLD[0]}{text}{RESET}")
308
+ res.append(f"{state.space_left()}{FG}{Style.Head}{BOLD[0]}{text}{BOLD[1]}{FGRESET}")
299
309
  elif level == 4: ####
300
- res.append(f"{state.space_left()}{FG}{Style.Symbol}{text}{RESET}")
310
+ res.append(f"{state.space_left()}{FG}{Style.Symbol}{BOLD[0]}{text}{BOLD[1]}{FGRESET}")
301
311
  elif level == 5: #####
302
- res.append(f"{state.space_left()}{text}{RESET}")
312
+ res.append(f"{state.space_left()}{text}{FGRESET}")
303
313
  else:
304
- res.append(f"{state.space_left()}{FG}{Style.Grey}{text}{RESET}")
314
+ res.append(f"{state.space_left()}{FG}{Style.Grey}{text}{FGRESET}")
305
315
  return "\n".join(res)
306
316
 
307
317
  def code_wrap(text_in):
@@ -380,7 +390,7 @@ def split_text(text):
380
390
  text
381
391
  ) if x]
382
392
 
383
- def text_wrap(text, width = -1, indent = 0, first_line_prefix="", subsequent_line_prefix="", force_truncate=False):
393
+ def text_wrap(text, width = -1, indent = 0, first_line_prefix="", subsequent_line_prefix="", force_truncate=False, preserve_format=False):
384
394
  if width == -1:
385
395
  width = state.Width
386
396
 
@@ -391,6 +401,7 @@ def text_wrap(text, width = -1, indent = 0, first_line_prefix="", subsequent_lin
391
401
  lines = []
392
402
  current_line = ""
393
403
  current_style = []
404
+ resetter = "" if preserve_format else FORMATRESET
394
405
 
395
406
  oldword = ''
396
407
  for word in words:
@@ -410,7 +421,7 @@ def text_wrap(text, width = -1, indent = 0, first_line_prefix="", subsequent_lin
410
421
  else:
411
422
  # Word doesn't fit, finalize the previous line
412
423
  prefix = first_line_prefix if not lines else subsequent_line_prefix
413
- line_content = prefix + current_line
424
+ line_content = prefix + current_line
414
425
  # This is expensive, fix.
415
426
  while force_truncate and visible_length(line_content) >= width:
416
427
  line_content = line_content[:len(line_content) - 2] + "…"
@@ -422,7 +433,7 @@ def text_wrap(text, width = -1, indent = 0, first_line_prefix="", subsequent_lin
422
433
  # that we have closed our hyperlink OSC
423
434
  if LINK[0] in line_content:
424
435
  line_content += LINK[1]
425
- lines.append(line_content + state.bg + ' ' * margin)
436
+ lines.append(line_content + resetter + state.bg + ' ' * margin)
426
437
 
427
438
  current_line = (" " * indent) + "".join(current_style) + word
428
439
 
@@ -442,16 +453,6 @@ def text_wrap(text, width = -1, indent = 0, first_line_prefix="", subsequent_lin
442
453
 
443
454
  return lines
444
455
 
445
- def dbl_count(s):
446
- dbl_re = re.compile(
447
- r'[\u2e80-\u2eff\u3000-\u303f\u3400-\u4dbf'
448
- r'\uFF00-\uFFEF' # CJK Compatibility Punctuation
449
- r'\U00004e00-\U00009fff\U0001f300-\U0001f6ff'
450
- r'\U0001f900-\U0001f9ff\U0001fa70-\U0001faff]',
451
- re.UNICODE
452
- )
453
- return len(dbl_re.findall(visible(s)))
454
-
455
456
  def cjk_count(s):
456
457
  cjk_re = re.compile(
457
458
  r'[\u4E00-\u9FFF' # CJK Unified Ideographs
@@ -699,7 +700,7 @@ def parse(stream):
699
700
  if code_match:
700
701
  state.in_code = Code.Backtick
701
702
  state.code_indent = len(line) - len(line.lstrip())
702
- state.code_language = code_match.group(1) or 'Bash'
703
+ state.code_language = code_match.group(2) or 'Bash'
703
704
 
704
705
  elif state.CodeSpaces and last_line_empty_cache and not state.in_list:
705
706
  code_match = re.match(r"^ \s*[^\s\*]", line)
@@ -776,7 +777,8 @@ def parse(stream):
776
777
  try:
777
778
  lexer = get_lexer_by_name(state.code_language)
778
779
  custom_style = override_background(Style.Syntax, ansi2hex(Style.Dark))
779
- except pygments.util.ClassNotFound:
780
+ except pygments.util.ClassNotFound as e:
781
+ logging.debug(e)
780
782
  lexer = get_lexer_by_name("Bash")
781
783
  custom_style = override_background("default", ansi2hex(Style.Dark))
782
784
 
@@ -809,37 +811,56 @@ def parse(stream):
809
811
  # then naively search back until our visible_lengths() match. This is not fast and there's certainly smarter
810
812
  # ways of doing it but this thing is way trickery than you think
811
813
  highlighted_code = highlight(state.code_buffer + tline, lexer, formatter)
812
- #print("(",highlighted_code,")")
814
+ #print("(",bytes(highlighted_code,'utf-8'),")")
815
+ parts = split_up(highlighted_code)
813
816
 
814
817
  # Sometimes the highlighter will do things like a full reset or a background reset.
815
818
  # This is mostly not what we want
816
- highlighted_code = re.sub(r"\033\[[34]9(;00|)m", "\033[23m", highlighted_code)
819
+ parts = [ re.sub(r"\033\[[34]9(;00|)m", FORMATRESET, x) for x in parts]
817
820
 
818
821
  # Since we are streaming we ignore the resets and newlines at the end
819
- if highlighted_code.endswith(FGRESET + "\n"):
820
- highlighted_code = highlighted_code[: -(1 + len(FGRESET))]
822
+ while parts[-1] in [FGRESET, FORMATRESET]:
823
+ parts.pop()
824
+
825
+ tline_len = visible_length(tline)
826
+
827
+ # now we find the new stuff:
828
+ ttl = 0
829
+ for i in range(len(parts)-1, 0, -1):
830
+ idx = parts[i]
831
+ if len(idx) == 0:
832
+ continue
833
+
834
+ ttl += len(idx) if idx[0] != '\x1b' else 0
821
835
 
822
- # turns out highlight will eat leading newlines on empty lines
823
- vislen = visible_length(state.code_buffer.lstrip())
836
+ if ttl > 1+tline_len:
837
+ break
824
838
 
825
- delta = -2
826
- while visible_length(highlighted_code[:(state.code_gen-delta)]) > vislen:
827
- delta += 1
839
+ newlen = visible_length("".join(parts[i:]))
840
+
841
+ snipfrom = newlen - len(tline) + 2
842
+ if snipfrom > 0:
843
+ parts[i] = parts[i][snipfrom:]
828
844
 
829
845
  state.code_buffer += tline
846
+ this_batch = "".join(parts[i:])
830
847
 
831
- this_batch = highlighted_code[state.code_gen-delta :]
832
848
  if this_batch.startswith(FGRESET):
833
849
  this_batch = this_batch[len(FGRESET) :]
834
850
 
851
+ # clean it before prepending with potential format
852
+ this_batch = this_batch.strip()
853
+ while i - 1 >= 0 and parts[i-1] and parts[i-1][0] == '\x1b':
854
+ this_batch = parts[i-1] + this_batch
855
+ i -= 1
856
+
835
857
  ## this is the crucial counter that will determine
836
- # the begninning of the next line
858
+ # the beginning of the next line
837
859
  state.code_gen = len(highlighted_code)
838
-
839
860
  code_line = ' ' * indent + this_batch.strip()
840
861
 
841
862
  margin = state.full_width( -len(pre[1]) ) - visible_length(code_line) % state.WidthFull
842
- yield f"{pre[0]}{Style.Codebg}{pre[1]}{code_line}{' ' * max(0, margin)}{BGRESET}"
863
+ yield f"{pre[0]}{Style.Codebg}{pre[1]}{code_line}{FORMATRESET}{' ' * max(0, margin)}{BGRESET}"
843
864
  continue
844
865
  except Goto:
845
866
  pass
@@ -933,7 +954,7 @@ def parse(stream):
933
954
  continue
934
955
 
935
956
  # <h1> ... <h6>
936
- header_match = re.match(r"^\s*(#{1,6})\s+(.*)", line)
957
+ header_match = re.match(r"^\s*(#{1,6})\s*(.*)", line)
937
958
  if header_match:
938
959
  level = len(header_match.group(1))
939
960
  yield emit_h(level, header_match.group(2))
@@ -959,7 +980,7 @@ def parse(stream):
959
980
  state.list_item_stack = []
960
981
 
961
982
  if len(line) == 0: yield ""
962
- if len(line) < state.Width:
983
+ if visible_length(line) < state.Width:
963
984
  # we want to prevent word wrap
964
985
  yield f"{state.space_left()}{line_format(line.lstrip())}"
965
986
  else:
@@ -1019,7 +1040,7 @@ def ansi2hex(ansi_code):
1019
1040
  def apply_multipliers(style, name, H, S, V):
1020
1041
  m = style.get(name)
1021
1042
  r, g, b = colorsys.hsv_to_rgb(min(1.0, H * m["H"]), min(1.0, S * m["S"]), min(1.0, V * m["V"]))
1022
- return ';'.join([str(int(x * 256)) for x in [r, g, b]]) + "m"
1043
+ return ';'.join([str(int(x * 255)) for x in [r, g, b]]) + "m"
1023
1044
 
1024
1045
  def width_calc():
1025
1046
  if state.WidthArg:
@@ -1029,6 +1050,7 @@ def width_calc():
1029
1050
  width = shutil.get_terminal_size().columns
1030
1051
  state.WidthWrap = True
1031
1052
  except (AttributeError, OSError):
1053
+ # this means it's a pager, we can just ignore the base64 clipboard
1032
1054
  width = 80
1033
1055
  pass
1034
1056
 
@@ -1053,7 +1075,7 @@ def main():
1053
1075
  parser.add_argument("filenameList", nargs="*", help="Input file to process (also takes stdin)")
1054
1076
  parser.add_argument("-l", "--loglevel", default="INFO", help="Set the logging level")
1055
1077
  parser.add_argument("-b", "--base", default=None, help="Set the hsv base: h,s,v")
1056
- parser.add_argument("-c", "--config", default=None, help="Use a custom config")
1078
+ parser.add_argument("-c", "--config", default=None, help="Use a custom config override")
1057
1079
  parser.add_argument("-w", "--width", default="0", help="Set the width WIDTH")
1058
1080
  parser.add_argument("-e", "--exec", help="Wrap a program EXEC for more 'proper' i/o handling")
1059
1081
  parser.add_argument("-s", "--scrape", help="Scrape code snippets to a directory SCRAPE")
@@ -1065,7 +1087,6 @@ def main():
1065
1087
  import importlib.metadata
1066
1088
  print(importlib.metadata.version("streamdown"))
1067
1089
  except importlib.metadata.PackageNotFoundError:
1068
- import subprocess
1069
1090
  print(subprocess.run(
1070
1091
  ['git', 'describe', '--always', '--dirty', '--tags'],
1071
1092
  cwd=os.path.dirname(os.path.abspath(__file__)),
@@ -1075,8 +1096,7 @@ def main():
1075
1096
 
1076
1097
  sys.exit(0)
1077
1098
 
1078
- config_toml_path, config_toml_content = ensure_config_file(args.config)
1079
- config = toml.loads(config_toml_content)
1099
+ config = ensure_config_file(args.config)
1080
1100
  style = toml.loads(default_toml).get('style') | config.get("style", {})
1081
1101
  features = toml.loads(default_toml).get('features') | config.get("features", {})
1082
1102
  H, S, V = style.get("HSV")
@@ -1119,7 +1139,7 @@ def main():
1119
1139
  # Set stdin to raw mode so we don't need to press enter
1120
1140
  tty.setcbreak(sys.stdin.fileno())
1121
1141
  sys.stdout.write("\x1b[?7h")
1122
- emit(sys.stdin)
1142
+ emit(inp)
1123
1143
 
1124
1144
  elif args.filenameList:
1125
1145
  # Let's say we only care about logging in streams
@@ -1147,7 +1167,7 @@ def main():
1147
1167
  logging.warning(f"Exception thrown: {type(ex)} {ex}")
1148
1168
  traceback.print_exc()
1149
1169
 
1150
- if state.Clipboard and state.code_buffer_raw:
1170
+ if os.isatty(sys.stdout.fileno()) and state.Clipboard and state.code_buffer_raw:
1151
1171
  code = state.code_buffer_raw
1152
1172
  # code needs to be a base64 encoded string before emitting
1153
1173
  code_bytes = code.encode('utf-8')
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: streamdown
3
- Version: 0.27.0
3
+ Version: 0.29.0
4
4
  Summary: A streaming markdown renderer for modern terminals with syntax highlighting
5
5
  Project-URL: Homepage, https://github.com/kristopolous/Streamdown
6
6
  Project-URL: Bug Tracker, https://github.com/kristopolous/Streamdown/issues
@@ -25,6 +25,7 @@ Requires-Dist: pygments
25
25
  Requires-Dist: pylatexenc
26
26
  Requires-Dist: term-image
27
27
  Requires-Dist: toml
28
+ Requires-Dist: wcwidth
28
29
  Description-Content-Type: text/markdown
29
30
 
30
31
  <p align="center">
@@ -38,9 +39,7 @@ Description-Content-Type: text/markdown
38
39
 
39
40
  Streamdown works with any streaming markdown such as [simonw's llm](https://github.com/simonw/llm) or even something basic like curl.
40
41
 
41
- It is designed for AI and can be used to do parser based sophisticated pipelines and routing, cracking open various monolithic AI solutions to permit them to integrate. Think of it as output level routing at the semantic level.
42
-
43
- You can also just use it like a normal person.
42
+ It just works.
44
43
 
45
44
  It supports standard piping and files as arguments like any normal pager but can also run as a wrapper so you retain full keyboard interactivity. Arrow keys, control, alt, all still work.
46
45
  ```bash
@@ -48,16 +47,24 @@ $ pip install streamdown
48
47
  ```
49
48
  ![Streamdown is Amazing](https://github.com/user-attachments/assets/268cb340-78cc-4df0-a773-c5ac95eceeeb)
50
49
 
50
+ ## Fast and Realtime.
51
+ Watch Streamdown run over a FIFO pipe through `tee` in tmux on an M4 using BitNet. This is run straight. No clever unbuffering tricks. You can see the unstructured content on the right and the realtime Streamdown render on the left.
52
+
53
+ [bitnet.webm](https://github.com/user-attachments/assets/62eb625e-82c4-462d-9991-ed681d6fbcd0)
54
+
55
+
51
56
  ### Provides clean copyable code for long code lines
52
57
  Other renderers inject line breaks when copying code that wraps around. Streamdown's better and now you are too!
58
+
59
+ Set `PrettyBroken` and `PrettyPad` to False in your toml (see below) to make Streamdown ensure code is always cleanly mouse copyable
53
60
  ![Handle That Mandle](https://github.com/user-attachments/assets/a27aa70c-f691-4796-84f0-c2eb18c7de23)
54
- **Tip**: You can make things prettier if you don't mind if this guarantee is broken. See the `PrettyBroken` flag below! (There's still 2 other convenient ways of getting code blocks out.)
61
+
55
62
 
56
63
  ### Supports images
57
64
  Here's kitty and alacritty.
58
65
  ![doggie](https://github.com/user-attachments/assets/81c43983-68cd-40c1-b1d5-aa3a52004504)
59
66
 
60
- ### Supports hyperlinks (OSC 8) and clipboard (OSC 52)
67
+ ### Hyperlinks (OSC 8) and Clipboard (OSC 52)
61
68
  The optional `Clipboard` feature puts the final codeblock into your clipboard. See below for details.
62
69
 
63
70
  [links.webm](https://github.com/user-attachments/assets/a5f71791-7c58-4183-ad3b-309f470c08a3)
@@ -70,7 +77,7 @@ This allows you to interactively debug in a way that the agent doesn't just wan
70
77
  It takes about 2 minutes to set up and about 0.2s to use. Fast, fluid and free.
71
78
  ![screenquery](https://github.com/user-attachments/assets/517be4fe-6962-4e4c-b2f2-563471bc48d0)
72
79
 
73
- ### ...It even supports CJK
80
+ ### ...even CJK
74
81
  Compare how streamdown wraps and spaces this tabular Chinese description of programming languages to other leading markdown renderers.
75
82
 
76
83
  Only one generates the text without truncation. 很美!
@@ -84,6 +91,10 @@ For instance, here is the [latex plugin](https://github.com/kristopolous/Streamd
84
91
  ![calc](https://github.com/user-attachments/assets/0b0027ca-8ef0-4b4a-b4ae-e36ff623a683)
85
92
 
86
93
 
94
+
95
+ It is designed for AI and can be used to do parser based sophisticated pipelines and routing, cracking open various monolithic AI solutions to permit them to integrate. Think of it as output level routing at the semantic level.
96
+
97
+ You can also just use it like a normal person.
87
98
  ## Configuration
88
99
 
89
100
  It's located at `~/.config/streamdown/config.toml` (following the XDG Base Directory Specification). If this file does not exist upon first run, it will be created with default values.
@@ -105,10 +116,10 @@ The default values are [at the beginning of the source](https://github.com/krist
105
116
  * `Bright`: Multipliers for level 2 headers.
106
117
  * `Margin` (integer, default: `2`): The left and right indent for the output.
107
118
  * `Width` (integer, default: `0`): Along with the `Margin`, `Width` specifies the base width of the content, which when set to 0, means use the terminal width. See [#6](https://github.com/kristopolous/Streamdown/issues/6) for more details
108
- * `PrettyPad` (boolean, default: `false`): Uses a unicode vertical pad trick to add a half height background to code blocks. This makes copy/paste have artifacts. See [#2](https://github.com/kristopolous/Streamdown/issues/2). I like it on. But that's just me
109
- * `PrettyBroken` (boolean, default: `false`): This will break the copy/paste assurance above. The output is much prettier, but it's also broken. So it's pretty broken. Works nicely with PrettyPad.
119
+ * `PrettyPad` (boolean, default: `true`): Uses a unicode vertical pad trick to add a half height background to code blocks. This makes copy/paste have artifacts. See [#2](https://github.com/kristopolous/Streamdown/issues/2). I like it on. But that's just me
120
+ * `PrettyBroken` (boolean, default: `true`): This will break the copy/paste assurance above. The output is much prettier, but it's also broken. So it's pretty broken. Works nicely with PrettyPad.
110
121
  * `ListIndent` (integer, default: `2`): This is the recursive indent for the list styles.
111
- * `Syntax` (string, default `monokai`): This is the syntax [highlighting theme which come via pygments](https://pygments.org/styles/).
122
+ * `Syntax` (string, default `native`): This is the syntax [highlighting theme which come via pygments](https://pygments.org/styles/).
112
123
 
113
124
  Example:
114
125
  ```toml
@@ -168,7 +179,7 @@ optional arguments:
168
179
  Set the logging level
169
180
  -b BASE, --base BASE Set the hsv base: h,s,v
170
181
  -c CONFIG, --config CONFIG
171
- Use a custom config
182
+ Use a custom config override
172
183
  -w WIDTH, --width WIDTH
173
184
  Set the width WIDTH
174
185
  -e EXEC, --exec EXEC Wrap a program EXEC for more 'proper' i/o handling
@@ -0,0 +1,9 @@
1
+ streamdown/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ streamdown/sd.py,sha256=naF311CdLgavOdBhfK-o5BU00ktu0LrggOFRtE4LJ9o,44286
3
+ streamdown/plugins/README.md,sha256=KWqYELs9WkKJmuDzYv3cvPlZMkArsNCBUe4XDoTLjLA,1143
4
+ streamdown/plugins/latex.py,sha256=xZMGMdx_Sw4X1piZejXFHfEG9qazU4fGeceiMI0h13Y,648
5
+ streamdown-0.29.0.dist-info/METADATA,sha256=MAipmHgnjN5SOFFSXP1vYEDNxcOASLceL1-Ejd8fK3c,9751
6
+ streamdown-0.29.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
7
+ streamdown-0.29.0.dist-info/entry_points.txt,sha256=HroKFsFMGf_h9PRTE96NjvjJQWupMW5TGP5RGUr1O_Q,74
8
+ streamdown-0.29.0.dist-info/licenses/LICENSE.MIT,sha256=SnY46EPirUsF20dZDR8HpyVgS2_4Tjxuc6f-4OdqO7U,1070
9
+ streamdown-0.29.0.dist-info/RECORD,,
streamdown/ss DELETED
@@ -1 +0,0 @@
1
- * **Model Card:** Always read the model card on the Hugging Face Hub ([https://huggingface.co/microsoft/bitnet-b1.58-2B-4T](https://huggingface.co/microsoft/bitnet-b1.58-2B-4T)) for important information about the model, its intended use, limitations, and potential biases.
streamdown/ss1 DELETED
@@ -1,42 +0,0 @@
1
- * `model.safetensors`: The name of the file you want to download. You'll need to know the exact filename. You can find the files in the model repository on the Hugging Face Hub website ([https://huggingface.co/microsoft/bitnet-b1.58-2B-4T](https://huggingface.co/microsoft/bitnet-b1.58-2B-4T)). Look under the "Files and versions" tab. `safetensors` is the preferred format for model weights now. If it's a `.bin` file, you can download that instead.
2
- * `--local-dir ./bitnet-b1.58-2B-4T`: The directory to save the file to.
3
-
4
- * **Download using `transformers` library (recommended for most use cases):**
5
-
6
- The `transformers` library provides a convenient way to download and cache models. This is often the easiest approach if you're using the model with `transformers`. You don't *directly* use the `huggingface-cli` for this, but it's worth knowing.
7
-
8
- ```python
9
- from transformers import AutoModelForCausalLM, AutoTokenizer
10
-
11
- model_name = "microsoft/bitnet-b1.58-2B-4T"
12
-
13
- tokenizer = AutoTokenizer.from_pretrained(model_name)
14
- model = AutoModelForCausalLM.from_pretrained(model_name)
15
-
16
- # The model and tokenizer will be downloaded and cached in your
17
- # transformers cache directory (usually ~/.cache/huggingface/transformers).
18
- ```
19
-
20
- This approach automatically handles downloading the necessary files and caching them for future use. It also handles the correct file formats and configurations.
21
-
22
- **4. Checking the Download**
23
-
24
- After the download completes, verify that the files are in the specified directory. You can use `ls` (Linux/macOS) or `dir` (Windows) to list the contents of the directory.
25
-
26
- **Important Considerations:**
27
-
28
- * **Disk Space:** The `bitnet-b1.58-2B-4T` model is quite large (several gigabytes). Make sure you have enough free disk space before downloading.
29
- * **Network Connection:** A stable and fast internet connection is essential for a smooth download.
30
- * **Caching:** The Hugging Face Hub and `transformers` library use caching to avoid re-downloading models unnecessarily. The default cache directory is usually `~/.cache/huggingface/transformers`.
31
- * **File Formats:** Models are often stored in `safetensors` or `.bin` formats. `safetensors` is generally preferred for security and performance.
32
- * **Model Card:** Always read the model card on the Hugging Face Hub ([https://huggingface.co/microsoft/bitnet-b1.58-2B-4T](https://huggingface.co/microsoft/bitnet-b1.58-2B-4T)) for important information about the model, its intended use, limitations, and potential biases.
33
- * **Gated Models:** Some models require you to accept terms of use before you can download them. The `huggingface-cli login` command will guide you through this process if necessary.
34
-
35
- **Example Workflow (Recommended):**
36
-
37
- 1. `huggingface-cli login` (if not already logged in)
38
- 2. Use the `transformers` library in a Python script to download and load the model (as shown in the example above). This is the most convenient and reliable method for most use cases.
39
-
40
- Let me know if you have any other questions or if you'd like help with a specific task related to this model!
41
-
42
- >
@@ -1,11 +0,0 @@
1
- streamdown/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- streamdown/sd.py,sha256=hk9h-gZz9OJw88iHowC6mWk0-ETRMmKmdr3063c8e74,43469
3
- streamdown/ss,sha256=sel_phpaecrw6WGIHRLROsD7BFShf0rSDHheflwdUn8,277
4
- streamdown/ss1,sha256=CUVf86_2zeAle2oQCeTfWYqtHBrAFR_UgvptuYMQzFU,3151
5
- streamdown/plugins/README.md,sha256=KWqYELs9WkKJmuDzYv3cvPlZMkArsNCBUe4XDoTLjLA,1143
6
- streamdown/plugins/latex.py,sha256=xZMGMdx_Sw4X1piZejXFHfEG9qazU4fGeceiMI0h13Y,648
7
- streamdown-0.27.0.dist-info/METADATA,sha256=_5zd5q0T0LSEk9kJK2CZitv7HfboKIhLrEsWjUfdmx8,9425
8
- streamdown-0.27.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
9
- streamdown-0.27.0.dist-info/entry_points.txt,sha256=HroKFsFMGf_h9PRTE96NjvjJQWupMW5TGP5RGUr1O_Q,74
10
- streamdown-0.27.0.dist-info/licenses/LICENSE.MIT,sha256=SnY46EPirUsF20dZDR8HpyVgS2_4Tjxuc6f-4OdqO7U,1070
11
- streamdown-0.27.0.dist-info/RECORD,,