Skip to content

Commit 2bad80a

Browse files
committed
✨ create and refactor codes
1 parent 436042e commit 2bad80a

9 files changed

+1255
-8
lines changed

css/styles.css

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
.custom {
2+
background-color: #008d8d;
3+
color: white;
4+
padding: 0.25em 0.5em 0.25em 0.5em;
5+
white-space: pre-wrap; /* css-3 */
6+
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
7+
white-space: -pre-wrap; /* Opera 4-6 */
8+
white-space: -o-pre-wrap; /* Opera 7 */
9+
word-wrap: break-word;
10+
}
11+
12+
pre {
13+
background-color: #027c7c;
14+
padding-left: 0.5em;
15+
}

mdconverter/__init__.py

Whitespace-only changes.

mdconverter/mdconverter.py

+129
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import codecs
2+
import json
3+
import argparse
4+
from typing import List, Dict, Any, Optional
5+
6+
7+
def get_default_css(css_filename: str) -> str:
8+
"""기본 CSS 스타일을 반환합니다."""
9+
try:
10+
with open(css_filename, "r", encoding="utf-8") as f:
11+
css_content = f.read()
12+
return f"<style>\n{css_content}\n</style>"
13+
except FileNotFoundError:
14+
print("Could not find styles.css file.")
15+
return ""
16+
17+
18+
def _read_notebook_file(filename: str) -> Dict[str, Any]:
19+
"""노트북 파일을 읽어서 JSON으로 파싱합니다."""
20+
try:
21+
with codecs.open(filename, "r") as f:
22+
source = f.read()
23+
except UnicodeDecodeError:
24+
with codecs.open(filename, "r", encoding="utf-8") as f:
25+
source = f.read()
26+
except Exception as e:
27+
raise Exception(f"파일 변환에 실패했습니다. 에러 메시지: {str(e)}")
28+
29+
return json.loads(source)
30+
31+
32+
def _process_code_output(output: Dict[str, Any], cells: List[str]) -> None:
33+
"""코드 셀의 출력을 처리합니다."""
34+
if "data" in output:
35+
outputs_data = output["data"]
36+
for key, value in outputs_data.items():
37+
if key == "text/html":
38+
v = [v_.replace("\n", "") for v_ in value]
39+
cells.extend(v)
40+
cells.append("\n")
41+
break
42+
elif key == "text/plain":
43+
v = [v_.replace("\n", "") for v_ in value]
44+
v.insert(0, '<pre class="custom">')
45+
v.append("</pre>")
46+
cells.extend(v)
47+
cells.append("\n\n")
48+
break
49+
elif key == "image/png":
50+
plain_image = '<img src="data:image/png;base64,{}"/>\n'.format(
51+
value.replace("\n", "")
52+
)
53+
54+
cells.append(plain_image)
55+
cells.append("\n\n")
56+
break
57+
elif output.get("output_type") == "stream":
58+
v = output["text"]
59+
v.insert(0, '<pre class="custom">')
60+
v.append("</pre>\n\n")
61+
cells.extend(v)
62+
63+
64+
def _process_code_cell(cell: Dict[str, Any], cells: List[str]) -> None:
65+
"""코드 셀을 처리합니다."""
66+
work_flag = True
67+
68+
if "source" in cell:
69+
cells.append("\n```python\n")
70+
cells.extend(cell["source"])
71+
cells.append("\n```\n")
72+
work_flag = False
73+
74+
outputs = cell["outputs"]
75+
if outputs:
76+
for output in outputs:
77+
_process_code_output(output, cells)
78+
elif work_flag:
79+
cells.append("\n```python")
80+
code = [c.replace("\n", "") for c in cell["source"]]
81+
cells.extend(code)
82+
cells.append("```\n\n")
83+
84+
85+
def _process_converter(filename: str, output_filename: str, css_filename: str) -> str:
86+
"""노트북을 마크다운으로 변환합니다."""
87+
notebook = _read_notebook_file(filename)
88+
cells: List[str] = []
89+
90+
for cell in notebook["cells"]:
91+
if cell["cell_type"] == "code":
92+
_process_code_cell(cell, cells)
93+
elif cell["cell_type"] == "markdown":
94+
cells.extend(cell["source"])
95+
cells.append("\n")
96+
else:
97+
print(f"Unknown cell type. Verification Needed. file : {filename}")
98+
99+
final_output = f"{get_default_css(css_filename)}\n\n{''.join(cells)}"
100+
101+
with open(output_filename, "w") as f:
102+
f.write(final_output)
103+
104+
return output_filename
105+
106+
107+
def convert_markdown_from_notebook(
108+
filename: str,
109+
css_filename: str = "css/styles.css",
110+
post_fix: str = "-(NEED-REVIEW)",
111+
) -> str:
112+
"""노트북 파일을 마크다운으로 변환하는 메인 함수입니다."""
113+
114+
output_filename = filename.replace(".ipynb", f"{post_fix}.md")
115+
116+
return _process_converter(filename, output_filename, css_filename)
117+
118+
119+
if __name__ == "__main__":
120+
parser = argparse.ArgumentParser(
121+
description="주피터 노트북을 마크다운으로 변환합니다."
122+
)
123+
parser.add_argument(
124+
"--filename", required=True, help="변환할 주피터 노트북 파일 경로"
125+
)
126+
parser.add_argument("--css", default="css/styles.css", help="css file path")
127+
args = parser.parse_args()
128+
129+
convert_markdown_from_notebook(args.filename)

mdconverter/mdconverter_class.py

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
from typing import Any
2+
from mdconverter.mdconverter import get_default_css
3+
from nbconvert import MarkdownExporter
4+
import nbformat
5+
6+
7+
class Mdconverter:
8+
def __init__(self) -> None:
9+
self.css_filename = ""
10+
self.filename = ""
11+
self.output_filename = ""
12+
13+
def run(self):
14+
# TODO making mdconverter using mdconvert.py
15+
# self.run_mdconverter()
16+
self.run_ndconverter(
17+
filename=self.filename,
18+
output_filename=self.output_filename,
19+
css_filename=self.css_filename,
20+
)
21+
22+
def run_ndconverter(
23+
self, filename: str, output_filename: str, css_filename: str
24+
) -> None:
25+
notebook_content = self.load_ipynb(filename)
26+
script = self.markdown_exporter(notebook_content)
27+
self.ndconverter_script = self.add_prefix_css(script, css_filename)
28+
self.save_script(self.ndconverter_script, output_filename)
29+
30+
def load_ipynb(self, filename: str) -> Any:
31+
with open(filename, "r", encoding="utf-8") as f:
32+
notebook_content = nbformat.read(f, as_version=4)
33+
return notebook_content
34+
35+
def markdown_exporter(self, notebook_content: Any) -> str:
36+
exporter = MarkdownExporter()
37+
# MarkdownExporter를 사용하여 md로 변환
38+
(script, resources) = exporter.from_notebook_node(notebook_content)
39+
return script
40+
41+
def add_prefix_css(self, script: str, css_filename: str):
42+
return f"{get_default_css(css_filename)}\n\n{''.join(script)}"
43+
44+
def save_script(self, script: str, output_filename: str) -> None:
45+
# 변환된 스크립트 저장
46+
with open(output_filename, "w", encoding="utf-8") as f:
47+
f.write(script)
48+
49+
50+
# TODO Creating Multi loader

sample/05-GoogleGenerativeAI-(NEED-REVIEW).md

+7-8
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
88
white-space: -pre-wrap; /* Opera 4-6 */
99
white-space: -o-pre-wrap; /* Opera 7 */
10-
word-wrap: break-word;
10+
word-wrap: break-word;
1111
}
12-
12+
1313
pre {
1414
background-color: #027c7c;
1515
padding-left: 0.5em;
@@ -19,8 +19,8 @@
1919
# Google Generative AI
2020

2121
- Author: [HyeonJong Moon](https://github.com/hj0302)
22-
- Design:
23-
- Peer Review:
22+
- Design:
23+
- Peer Review:
2424
- This is a part of [LangChain Open Tutorial](https://github.com/LangChain-OpenTutorial/LangChain-OpenTutorial)
2525

2626
[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/langchain-ai/langchain-academy/blob/main/module-4/sub-graph.ipynb) [![Open in LangChain Academy](https://cdn.prod.website-files.com/65b8cd72835ceeacd4449a53/66e9eba12c7b7688aa3dbb5e_LCA-badge-green.svg)](https://academy.langchain.com/courses/take/intro-to-langgraph/lessons/58239937-lesson-2-sub-graphs)
@@ -48,7 +48,7 @@ You can use the `ChatGoogleGenerativeAI` class from the [langchain-google-genai]
4848
Set up the environment. You may refer to [Environment Setup](https://wikidocs.net/257836) for more details.
4949

5050
**[Note]**
51-
- `langchain-opentutorial` is a package that provides a set of easy-to-use environment setup, useful functions and utilities for tutorials.
51+
- `langchain-opentutorial` is a package that provides a set of easy-to-use environment setup, useful functions and utilities for tutorials.
5252
- You can checkout the [`langchain-opentutorial`](https://github.com/LangChain-OpenTutorial/langchain-opentutorial-pypi) for more details.
5353

5454
```python
@@ -91,7 +91,7 @@ set_env(
9191

9292
- Please create an API KEY from [link](https://aistudio.google.com/app/apikey?hl=en).
9393
- Set the user's Google API key as the environment variable `GOOGLE_API_KEY`.
94-
You can alternatively set `GOOGLE_API_KEY` in `.env` file and load it.
94+
You can alternatively set `GOOGLE_API_KEY` in `.env` file and load it.
9595

9696
[Note] This is not necessary if you've already set `GOOGLE_API_KEY` in previous steps.
9797

@@ -108,7 +108,7 @@ Import the `ChatGoogleGenerativeAI` class from the `langchain_google_genai` pack
108108

109109
The `ChatGoogleGenerativeAI` class is used to implement conversational AI systems using Google’s Generative AI models. Through this class, users can interact with Google’s conversational AI model. Conversations with the model take place in a chat format, and the model generates appropriate responses based on user input.
110110

111-
Because the `ChatGoogleGenerativeAI` class is integrated with the LangChain framework, it can be used alongside other LangChain components.
111+
Because the `ChatGoogleGenerativeAI` class is integrated with the LangChain framework, it can be used alongside other LangChain components.
112112

113113
For information about supported models, see: https://ai.google.dev/gemini-api/docs/models/gemini?hl=en
114114

@@ -336,4 +336,3 @@ print(response.content)
336336
<pre class="custom">That's a picture of the Matterhorn mountain in Switzerland. The image shows the iconic pyramidal peak covered in snow, set against a dramatic, softly colored sunset or sunrise sky. The foreground features a gently sloping snow-covered landscape.
337337

338338
</pre>
339-

0 commit comments

Comments
 (0)