7 | All the code and documentation are entirely generated by OpenAI's GPT-4 Model
8 |
9 |
10 |
11 | ## Introduction
12 |
13 | OpenAI Translator is an AI-powered translation tool designed to translate English PDF books to Chinese. The tool leverages large language models (LLMs) like ChatGLM and OpenAI's GPT-3 and GPT-3.5 Turbo for translation. It's built in Python and has a flexible, modular, and object-oriented design.
14 |
15 | ## Why this project
16 |
17 | In the current landscape, there's a lack of non-commercial yet efficient PDF translation tools. Many users have PDF documents with sensitive data that they prefer not to upload to public commercial service websites due to privacy concerns. This project was developed to address this gap, providing a solution for users who need to translate their PDFs while maintaining data privacy.
18 |
19 | ### Sample Results
20 |
21 | The OpenAI Translator is still in its early stages of development, and I'm actively working on adding more features and improving its performance. We appreciate any feedback or contributions!
22 |
23 | 
24 |
25 |
26 | "The Old Man and the Sea"
27 |
28 |
29 | ## Features
30 |
31 | - [X] Translation of English PDF books to Chinese using LLMs.
32 | - [X] Support for both [ChatGLM](https://github.com/THUDM/ChatGLM-6B) and [OpenAI](https://platform.openai.com/docs/models) models.
33 | - [X] Flexible configuration through a YAML file or command-line arguments.
34 | - [X] Timeouts and error handling for robust translation operations.
35 | - [X] Modular and object-oriented design for easy customization and extension.
36 | - [x] Add support for other languages and translation directions.
37 | - [ ] Implement a graphical user interface (GUI) for easier use.
38 | - [ ] Create a web service or API to enable usage in web applications.
39 | - [ ] Add support for batch processing of multiple PDF files.
40 | - [ ] Add support for preserving the original layout and formatting of the source PDF.
41 | - [ ] Improve translation quality by using custom-trained translation models.
42 |
43 |
44 | ## Getting Started
45 |
46 | ### Environment Setup
47 |
48 | 1.Clone the repository `git clone git@github.com:DjangoPeng/openai-translator.git`.
49 |
50 | 2.The `OpenAI-Translator` requires Python 3.10 or later. Install the dependencies with `pip install -r requirements.txt`.
51 |
52 | 3.Set up your OpenAI API key(`$OPENAI_API_KEY`). You can either add it to your environment variables or specify it in the config.yaml file.
53 |
54 | ### Usage
55 |
56 | You can use OpenAI-Translator either by specifying a configuration file or by providing command-line arguments.
57 |
58 | #### Using a configuration file:
59 |
60 | Adapt `config.yaml` file with your settings:
61 |
62 | ```yaml
63 | model_name: "gpt-3.5-turbo"
64 | input_file: "tests/test.pdf"
65 | output_file_format: "markdown"
66 | source_language: "English"
67 | target_language: "Chinese"
68 | ```
69 |
70 | Then run the tool:
71 |
72 | ```bash
73 | python ai_translator/main.py
74 | ```
75 |
76 | 
77 |
78 | #### Using command-line arguments:
79 |
80 | You can also specify the settings directly on the command line. Here's an example of how to use the OpenAI model:
81 |
82 | ```bash
83 | # Set your api_key as an env variable
84 | export OPENAI_API_KEY="sk-xxx"
85 | python ai_translator/main.py --model_name "gpt-3.5-turbo" --input_file "your_input.pdf" --output_file_format "markdown" --source_language "English" --target_language "Chinese"
86 | ```
87 |
88 | ```bash
89 | # Based on the gradio_server graphical interface, supported ChatGLM
90 | # Set your api_key as an env variable
91 | export OPENAI_API_KEY="sk-xxx"
92 | # --model_name optional "chat_glm" or "gpt-3.5-turbo"
93 | python ai_translator/gradio_server.py --model_name "chat_glm" --input_file "your_input.pdf" --output_file_format "markdown" --source_language "English" --target_language "Chinese"
94 | ```
95 |
96 | ```bash
97 | # Based on the flask_server API pattern
98 | # Set your api_key as an env variable
99 | export OPENAI_API_KEY="sk-xxx"
100 | python ai_translator/flask_server.py --model_name "gpt-3.5-turbo" --input_file "your_input.pdf" --output_file_format "markdown" --source_language "English" --target_language "Chinese"
101 | ```
102 |
103 | ## License
104 |
105 | This project is licensed under the GPL-3.0 License. See the [LICENSE](LICENSE) file for details.
--------------------------------------------------------------------------------
/project/langchain_openai_translator/ai_translator/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/project/langchain_openai_translator/ai_translator/__init__.py
--------------------------------------------------------------------------------
/project/langchain_openai_translator/ai_translator/book/__init__.py:
--------------------------------------------------------------------------------
1 | from .book import Book
2 | from .page import Page
3 | from .content import ContentType, Content, TableContent
--------------------------------------------------------------------------------
/project/langchain_openai_translator/ai_translator/book/book.py:
--------------------------------------------------------------------------------
1 | from .page import Page
2 |
3 | class Book:
4 | def __init__(self, pdf_file_path):
5 | self.pdf_file_path = pdf_file_path
6 | self.pages = []
7 |
8 | def add_page(self, page: Page):
9 | self.pages.append(page)
--------------------------------------------------------------------------------
/project/langchain_openai_translator/ai_translator/book/content.py:
--------------------------------------------------------------------------------
1 | import pandas as pd
2 |
3 | from enum import Enum, auto
4 | from PIL import Image as PILImage
5 | from utils import LOG
6 | from io import StringIO
7 |
8 | class ContentType(Enum):
9 | TEXT = auto()
10 | TABLE = auto()
11 | IMAGE = auto()
12 |
13 | class Content:
14 | def __init__(self, content_type, original, translation=None):
15 | self.content_type = content_type
16 | self.original = original
17 | self.translation = translation
18 | self.status = False
19 |
20 | def set_translation(self, translation, status):
21 | if not self.check_translation_type(translation):
22 | raise ValueError(f"Invalid translation type. Expected {self.content_type}, but got {type(translation)}")
23 | self.translation = translation
24 | self.status = status
25 |
26 | def check_translation_type(self, translation):
27 | if self.content_type == ContentType.TEXT and isinstance(translation, str):
28 | return True
29 | elif self.content_type == ContentType.TABLE and isinstance(translation, list):
30 | return True
31 | elif self.content_type == ContentType.IMAGE and isinstance(translation, PILImage.Image):
32 | return True
33 | return False
34 |
35 | def __str__(self):
36 | return self.original
37 |
38 |
39 | class TableContent(Content):
40 | def __init__(self, data, translation=None):
41 | df = pd.DataFrame(data)
42 |
43 | # Verify if the number of rows and columns in the data and DataFrame object match
44 | if len(data) != len(df) or len(data[0]) != len(df.columns):
45 | raise ValueError("The number of rows and columns in the extracted table data and DataFrame object do not match.")
46 |
47 | super().__init__(ContentType.TABLE, df)
48 |
49 | def set_translation(self, translation, status):
50 | try:
51 | if not isinstance(translation, str):
52 | raise ValueError(f"Invalid translation type. Expected str, but got {type(translation)}")
53 |
54 | LOG.debug(f"[translation]\n{translation}")
55 | # Extract column names from the first set of brackets
56 | header = translation.split(']')[0][1:].split(', ')
57 | # Extract data rows from the remaining brackets
58 | data_rows = translation.split('] ')[1:]
59 | # Replace Chinese punctuation and split each row into a list of values
60 | data_rows = [row[1:-1].split(', ') for row in data_rows]
61 | # Create a DataFrame using the extracted header and data
62 | translated_df = pd.DataFrame(data_rows, columns=header)
63 | LOG.debug(f"[translated_df]\n{translated_df}")
64 | self.translation = translated_df
65 | self.status = status
66 | except Exception as e:
67 | LOG.error(f"An error occurred during table translation: {e}")
68 | self.translation = None
69 | self.status = False
70 |
71 | def __str__(self):
72 | return self.original.to_string(header=False, index=False)
73 |
74 | def iter_items(self, translated=False):
75 | target_df = self.translation if translated else self.original
76 | for row_idx, row in target_df.iterrows():
77 | for col_idx, item in enumerate(row):
78 | yield (row_idx, col_idx, item)
79 |
80 | def update_item(self, row_idx, col_idx, new_value, translated=False):
81 | target_df = self.translation if translated else self.original
82 | target_df.at[row_idx, col_idx] = new_value
83 |
84 | def get_original_as_str(self):
85 | return self.original.to_string(header=False, index=False)
--------------------------------------------------------------------------------
/project/langchain_openai_translator/ai_translator/book/page.py:
--------------------------------------------------------------------------------
1 | from .content import Content
2 |
3 | class Page:
4 | def __init__(self):
5 | self.contents = []
6 |
7 | def add_content(self, content: Content):
8 | self.contents.append(content)
9 |
--------------------------------------------------------------------------------
/project/langchain_openai_translator/ai_translator/flask_server.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import os
3 |
4 | sys.path.append(os.path.dirname(os.path.abspath(__file__)))
5 |
6 | from flask import Flask, request, send_file, jsonify
7 | from translator import PDFTranslator, TranslationConfig
8 | from utils import ArgumentParser, LOG
9 |
10 | app = Flask(__name__)
11 |
12 | TEMP_FILE_DIR = "flask_temps/"
13 |
14 | @app.route('/translation', methods=['POST'])
15 | def translation():
16 | try:
17 | input_file = request.files['input_file']
18 | source_language = request.form.get('source_language', 'English')
19 | target_language = request.form.get('target_language', 'Chinese')
20 |
21 | LOG.debug(f"[input_file]\n{input_file}")
22 | LOG.debug(f"[input_file.filename]\n{input_file.filename}")
23 |
24 | if input_file and input_file.filename:
25 | # # 创建临时文件
26 | input_file_path = TEMP_FILE_DIR+input_file.filename
27 | LOG.debug(f"[input_file_path]\n{input_file_path}")
28 |
29 | input_file.save(input_file_path)
30 |
31 | # 调用翻译函数
32 | output_file_path = Translator.translate_pdf(
33 | input_file=input_file_path,
34 | source_language=source_language,
35 | target_language=target_language)
36 |
37 | # 移除临时文件
38 | # os.remove(input_file_path)
39 |
40 | # 构造完整的文件路径
41 | output_file_path = os.getcwd() + "/" + output_file_path
42 | LOG.debug(output_file_path)
43 |
44 | # 返回翻译后的文件
45 | return send_file(output_file_path, as_attachment=True)
46 | except Exception as e:
47 | response = {
48 | 'status': 'error',
49 | 'message': str(e)
50 | }
51 | return jsonify(response), 400
52 |
53 |
54 | def initialize_translator():
55 | # 解析命令行
56 | argument_parser = ArgumentParser()
57 | args = argument_parser.parse_arguments()
58 |
59 | # 初始化配置单例
60 | config = TranslationConfig()
61 | config.initialize(args)
62 | # 实例化 PDFTranslator 类,并调用 translate_pdf() 方法
63 | global Translator
64 | Translator = PDFTranslator(config.model_name)
65 |
66 |
67 | if __name__ == "__main__":
68 | # 初始化 translator
69 | initialize_translator()
70 | # 启动 Flask Web Server
71 | app.run(host="0.0.0.0", port=5000, debug=True)
--------------------------------------------------------------------------------
/project/langchain_openai_translator/ai_translator/gradio_server.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import os
3 | import gradio as gr
4 |
5 | sys.path.append(os.path.dirname(os.path.abspath(__file__)))
6 |
7 | from utils import ArgumentParser, LOG
8 | from translator import PDFTranslator, TranslationConfig
9 |
10 |
11 | def translation(input_file, source_language, target_language, output_file_format, translation_style):
12 | LOG.debug(
13 | f"[翻译任务]\n源文件: {input_file.name}\n源语言: {source_language}\n目标语言: {target_language}\n输出文件格式: {output_file_format}\n翻译风格: {translation_style}")
14 |
15 | output_file_path = Translator.translate_pdf(
16 | input_file.name,
17 | output_file_format=output_file_format,
18 | source_language=source_language,
19 | target_language=target_language,
20 | translation_style=translation_style)
21 |
22 | return output_file_path
23 |
24 |
25 | def launch_gradio():
26 | language_options = ["Chinese", "English", "French", "German", "Spanish", "Korean", "Japanese"]
27 | file_format_options = ["Novels", "Press Releases", "Luxun Style"]
28 | output_file_options = ["Markdown", "PDF", "Word"]
29 | iface = gr.Interface(
30 | fn=translation,
31 | title="OpenAI-Translator v2.0(PDF 电子书翻译工具)",
32 | inputs=[
33 | gr.File(label="上传PDF文件"),
34 | gr.inputs.Dropdown(choices=language_options, label="源语言(默认:英文)", default="English"),
35 | gr.inputs.Dropdown(choices=language_options, label="目标语言(默认:中文)", default="Chinese"),
36 | gr.inputs.Dropdown(choices=output_file_options, label="输出文件格式(默认:markdown)", default="markdown"),
37 | gr.inputs.Dropdown(choices=file_format_options, label="翻译风格(默认:小说)", default="novel")
38 | ],
39 | outputs=[
40 | gr.File(label="下载翻译文件")
41 | ],
42 | allow_flagging="never",
43 | theme="default"
44 | )
45 |
46 | iface.launch(share=True, server_name="0.0.0.0")
47 |
48 |
49 | def initialize_translator():
50 | # 解析命令行
51 | argument_parser = ArgumentParser()
52 | args = argument_parser.parse_arguments()
53 |
54 | # 初始化配置单例
55 | config = TranslationConfig()
56 | config.initialize(args)
57 | # 实例化 PDFTranslator 类,并调用 translate_pdf() 方法
58 | global Translator
59 | Translator = PDFTranslator(config.model_name)
60 |
61 |
62 | if __name__ == "__main__":
63 | # 初始化 translator
64 | initialize_translator()
65 | # 启动 Gradio 服务
66 | launch_gradio()
67 |
--------------------------------------------------------------------------------
/project/langchain_openai_translator/ai_translator/logs/translation.log:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/project/langchain_openai_translator/ai_translator/logs/translation.log
--------------------------------------------------------------------------------
/project/langchain_openai_translator/ai_translator/main.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import os
3 |
4 | sys.path.append(os.path.dirname(os.path.abspath(__file__)))
5 |
6 | from utils import ArgumentParser, LOG
7 | from translator import PDFTranslator, TranslationConfig
8 |
9 | if __name__ == "__main__":
10 | # 解析命令行
11 | argument_parser = ArgumentParser()
12 | args = argument_parser.parse_arguments()
13 |
14 | # 初始化配置单例
15 | config = TranslationConfig()
16 | config.initialize(args)
17 |
18 | # 实例化 PDFTranslator 类,并调用 translate_pdf() 方法
19 | translator = PDFTranslator(config.model_name)
20 | translator.translate_pdf(config.input_file, config.output_file_format, pages=None)
21 |
--------------------------------------------------------------------------------
/project/langchain_openai_translator/ai_translator/translator/__init__.py:
--------------------------------------------------------------------------------
1 | from .pdf_translator import PDFTranslator
2 | from .translation_config import TranslationConfig
--------------------------------------------------------------------------------
/project/langchain_openai_translator/ai_translator/translator/exceptions.py:
--------------------------------------------------------------------------------
1 | class PageOutOfRangeException(Exception):
2 | def __init__(self, book_pages, requested_pages):
3 | self.book_pages = book_pages
4 | self.requested_pages = requested_pages
5 | super().__init__(f"Page out of range: Book has {book_pages} pages, but {requested_pages} pages were requested.")
6 |
--------------------------------------------------------------------------------
/project/langchain_openai_translator/ai_translator/translator/pdf_parser.py:
--------------------------------------------------------------------------------
1 | import pdfplumber
2 | from typing import Optional
3 | from book import Book, Page, Content, ContentType, TableContent
4 | from translator.exceptions import PageOutOfRangeException
5 | from utils import LOG
6 |
7 |
8 | class PDFParser:
9 | def __init__(self):
10 | pass
11 |
12 | def parse_pdf(self, pdf_file_path: str, pages: Optional[int] = None) -> Book:
13 | book = Book(pdf_file_path)
14 |
15 | with pdfplumber.open(pdf_file_path) as pdf:
16 | if pages is not None and pages > len(pdf.pages):
17 | raise PageOutOfRangeException(len(pdf.pages), pages)
18 |
19 | if pages is None:
20 | pages_to_parse = pdf.pages
21 | else:
22 | pages_to_parse = pdf.pages[:pages]
23 |
24 | for pdf_page in pages_to_parse:
25 | page = Page()
26 |
27 | # Store the original text content
28 | raw_text = pdf_page.extract_text()
29 | tables = pdf_page.extract_tables()
30 |
31 | # Remove each cell's content from the original text
32 | for table_data in tables:
33 | for row in table_data:
34 | for cell in row:
35 | raw_text = raw_text.replace(cell, "", 1)
36 |
37 | # Handling text
38 | if raw_text:
39 | # Remove empty lines and leading/trailing whitespaces
40 | raw_text_lines = raw_text.splitlines()
41 | cleaned_raw_text_lines = [line.strip() for line in raw_text_lines if line.strip()]
42 | cleaned_raw_text = "\n".join(cleaned_raw_text_lines)
43 |
44 | text_content = Content(content_type=ContentType.TEXT, original=cleaned_raw_text)
45 | page.add_content(text_content)
46 | LOG.debug(f"[raw_text]\n {cleaned_raw_text}")
47 |
48 |
49 |
50 | # Handling tables
51 | if tables:
52 | table = TableContent(tables)
53 | page.add_content(table)
54 | LOG.debug(f"[table]\n{table}")
55 |
56 | book.add_page(page)
57 |
58 | return book
59 |
--------------------------------------------------------------------------------
/project/langchain_openai_translator/ai_translator/translator/pdf_translator.py:
--------------------------------------------------------------------------------
1 | from typing import Optional
2 | from translator.pdf_parser import PDFParser
3 | from translator.writer import Writer
4 | from translator.translation_chain import TranslationChain
5 | from utils import LOG
6 |
7 | class PDFTranslator:
8 | def __init__(self, model_name: str):
9 | self.translate_chain = TranslationChain(model_name)
10 | self.pdf_parser = PDFParser()
11 | self.writer = Writer()
12 |
13 | def translate_pdf(self,
14 | input_file: str,
15 | output_file_format: str = 'markdown',
16 | source_language: str = "English",
17 | target_language: str = 'Chinese',
18 | translation_style: str = 'novel',
19 | pages: Optional[int] = None):
20 |
21 | self.book = self.pdf_parser.parse_pdf(input_file, pages)
22 |
23 | for page_idx, page in enumerate(self.book.pages):
24 | for content_idx, content in enumerate(page.contents):
25 | # Translate content.original
26 | translation, status = self.translate_chain.run(content, source_language, target_language, translation_style)
27 | # Update the content in self.book.pages directly
28 | self.book.pages[page_idx].contents[content_idx].set_translation(translation, status)
29 |
30 | return self.writer.save_translated_book(self.book, output_file_format, translation_style)
31 |
--------------------------------------------------------------------------------
/project/langchain_openai_translator/ai_translator/translator/translation_chain.py:
--------------------------------------------------------------------------------
1 | from langchain_openai import ChatOpenAI
2 | from langchain.chains import LLMChain
3 | from langchain.llms import ChatGLM
4 |
5 | from langchain.prompts.chat import (
6 | ChatPromptTemplate,
7 | SystemMessagePromptTemplate,
8 | HumanMessagePromptTemplate,
9 | )
10 |
11 | from utils import LOG
12 |
13 | class TranslationChain:
14 | def __init__(self, model_name: str = "gpt-3.5-turbo", verbose: bool = True):
15 |
16 | # 翻译任务指令始终由 System 角色承担
17 | template = (
18 | "You are a translation expert, proficient in various languages, \n"
19 | "and proficient in all kinds of style translation. Please use style: '{translation_style}'. \n"
20 | "Translates {source_language} to {target_language}. "
21 | )
22 | system_message_prompt = SystemMessagePromptTemplate.from_template(template)
23 |
24 | # 待翻译文本由 Human 角色输入
25 | human_template = "{text}"
26 | human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)
27 |
28 | # 使用 System 和 Human 角色的提示模板构造 ChatPromptTemplate
29 | chat_prompt_template = ChatPromptTemplate.from_messages(
30 | [system_message_prompt, human_message_prompt]
31 | )
32 | if model_name == "gpt-3.5-turbo":
33 | # 为了翻译结果的稳定性,将 temperature 设置为 0
34 | chat = ChatOpenAI(model_name=model_name, temperature=0, verbose=verbose)
35 | elif model_name == "chat_glm":
36 | endpoint_url = ("http://127.0.0.1:8000") # endpoint_url 填写跑模型的地址
37 | chat = ChatGLM(endpoint_url=endpoint_url, temperature=0, verbose=verbose)
38 | else:
39 | raise Exception(f"This model is not supported. ModelName:{model_name}")
40 |
41 | self.chain = LLMChain(llm=chat, prompt=chat_prompt_template, verbose=verbose)
42 |
43 | def run(self, text: str, source_language: str, target_language: str, translation_style: str) -> (str, bool):
44 | result = ""
45 | try:
46 | result = self.chain.run({
47 | "text": text,
48 | "source_language": source_language,
49 | "target_language": target_language,
50 | "translation_style": translation_style,
51 | })
52 | except Exception as e:
53 | LOG.error(f"An error occurred during translation: {e}")
54 | return result, False
55 |
56 | return result, True
--------------------------------------------------------------------------------
/project/langchain_openai_translator/ai_translator/translator/translation_config.py:
--------------------------------------------------------------------------------
1 | import yaml
2 |
3 | class TranslationConfig:
4 | _instance = None
5 |
6 | def __new__(cls):
7 | if cls._instance is None:
8 | cls._instance = super(TranslationConfig, cls).__new__(cls)
9 | cls._instance._config = None
10 | return cls._instance
11 |
12 | def initialize(self, args):
13 | with open(args.config_file, "r") as f:
14 | config = yaml.safe_load(f)
15 |
16 | # Use the argparse Namespace to update the configuration
17 | overridden_values = {
18 | key: value for key, value in vars(args).items() if key in config and value is not None
19 | }
20 | config.update(overridden_values)
21 |
22 | # Store the original config dictionary
23 | self._instance._config = config
24 |
25 | def __getattr__(self, name):
26 | # Try to get attribute from _config
27 | if self._instance._config and name in self._instance._config:
28 | return self._instance._config[name]
29 | raise AttributeError(f"'TranslationConfig' object has no attribute '{name}'")
--------------------------------------------------------------------------------
/project/langchain_openai_translator/ai_translator/translator/writer.py:
--------------------------------------------------------------------------------
1 | import os
2 | from reportlab.lib import colors, pagesizes, units
3 | from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
4 | from reportlab.pdfbase import pdfmetrics
5 | from reportlab.pdfbase.ttfonts import TTFont
6 | from reportlab.platypus import (
7 | SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, PageBreak
8 | )
9 | from docx import Document
10 | from docx.shared import Pt, Inches
11 |
12 | from book import Book, ContentType
13 | from utils import LOG
14 |
15 |
16 | class Writer:
17 | def __init__(self):
18 | pass
19 |
20 | def save_translated_book(self, book: Book, ouput_file_format: str, translation_style: str):
21 | LOG.debug(ouput_file_format)
22 |
23 | if ouput_file_format.lower() == "pdf":
24 | file_suffix = f'_translated_{translation_style}.pdf'
25 | output_file_path = self._save_translated_book_pdf(book, file_suffix)
26 | elif ouput_file_format.lower() == "markdown":
27 | file_suffix = f'_translated_{translation_style}.md'
28 | output_file_path = self._save_translated_book_markdown(book, file_suffix)
29 | elif ouput_file_format.lower() == "word":
30 | file_suffix = f'_translated_{translation_style}.docx'
31 | output_file_path = self._save_translated_book_word(book, file_suffix)
32 | else:
33 | LOG.error(f"不支持文件类型: {ouput_file_format}")
34 | return ""
35 |
36 | LOG.info(f"翻译完成,文件保存至: {output_file_path}")
37 |
38 | return output_file_path
39 |
40 | def _save_translated_book_pdf(self, book: Book, file_suffix: str, output_file_path: str = None):
41 | output_file_path = book.pdf_file_path.replace('.pdf', file_suffix)
42 | LOG.info(f"开始导出: {output_file_path}")
43 |
44 | # Register Chinese font
45 | font_path = "../fonts/simsun.ttc" # 请将此路径替换为您的字体文件路径
46 | pdfmetrics.registerFont(TTFont("SimSun", font_path))
47 |
48 | # Create a new ParagraphStyle with the SimSun font
49 | simsun_style = ParagraphStyle('SimSun', fontName='SimSun', fontSize=12, leading=14)
50 |
51 | # Create a PDF document
52 | doc = SimpleDocTemplate(output_file_path, pagesize=pagesizes.letter)
53 | styles = getSampleStyleSheet()
54 | story = []
55 |
56 | # Iterate over the pages and contents
57 | for page in book.pages:
58 | for content in page.contents:
59 | if content.status:
60 | if content.content_type == ContentType.TEXT:
61 | # Add translated text to the PDF
62 | text = content.translation
63 | para = Paragraph(text, simsun_style)
64 | story.append(para)
65 |
66 | elif content.content_type == ContentType.TABLE:
67 | # Add table to the PDF
68 | table = content.translation
69 | table_style = TableStyle([
70 | ('BACKGROUND', (0, 0), (-1, 0), colors.grey),
71 | ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
72 | ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
73 | ('FONTNAME', (0, 0), (-1, 0), 'SimSun'), # 更改表头字体为 "SimSun"
74 | ('FONTSIZE', (0, 0), (-1, 0), 14),
75 | ('BOTTOMPADDING', (0, 0), (-1, 0), 12),
76 | ('BACKGROUND', (0, 1), (-1, -1), colors.beige),
77 | ('FONTNAME', (0, 1), (-1, -1), 'SimSun'), # 更改表格中的字体为 "SimSun"
78 | ('GRID', (0, 0), (-1, -1), 1, colors.black)
79 | ])
80 | pdf_table = Table(table.values.tolist())
81 | pdf_table.setStyle(table_style)
82 | story.append(pdf_table)
83 | # Add a page break after each page except the last one
84 | if page != book.pages[-1]:
85 | story.append(PageBreak())
86 |
87 | # Save the translated book as a new PDF file
88 | doc.build(story)
89 | return output_file_path
90 |
91 | def _save_translated_book_markdown(self, book: Book, file_suffix: str, output_file_path: str = None):
92 | output_file_path = book.pdf_file_path.replace('.pdf', file_suffix)
93 |
94 | LOG.info(f"开始导出: {output_file_path}")
95 | with open(output_file_path, 'w', encoding='utf-8') as output_file:
96 | # Iterate over the pages and contents
97 | for page in book.pages:
98 | for content in page.contents:
99 | if content.status:
100 | if content.content_type == ContentType.TEXT:
101 | # Add translated text to the Markdown file
102 | text = content.translation
103 | output_file.write(text + '\n\n')
104 |
105 | elif content.content_type == ContentType.TABLE:
106 | # Add table to the Markdown file
107 | table = content.translation
108 | header = '| ' + ' | '.join(str(column) for column in table.columns) + ' |' + '\n'
109 | separator = '| ' + ' | '.join(['---'] * len(table.columns)) + ' |' + '\n'
110 | # body = '\n'.join(['| ' + ' | '.join(row) + ' |' for row in table.values.tolist()]) + '\n\n'
111 | body = '\n'.join(['| ' + ' | '.join(str(cell) for cell in row) + ' |' for row in
112 | table.values.tolist()]) + '\n\n'
113 | output_file.write(header + separator + body)
114 |
115 | # Add a page break (horizontal rule) after each page except the last one
116 | if page != book.pages[-1]:
117 | output_file.write('---\n\n')
118 |
119 | return output_file_path
120 |
121 | def _save_translated_book_word(self, book: Book, file_suffix: str, output_file_path: str = None):
122 | output_file_path = book.pdf_file_path.replace('.pdf', file_suffix)
123 | LOG.info(f"开始导出: {output_file_path}")
124 |
125 |
126 | doc = Document()
127 |
128 | # Iterate over the pages and contents
129 | for page in book.pages:
130 | for content in page.contents:
131 | if content.status:
132 | if content.content_type == ContentType.TEXT:
133 | # Add translated text to the Word document
134 | text = content.translation
135 | p = doc.add_paragraph()
136 | run = p.add_run(text)
137 | run.font.size = Pt(12) # Set font size to 12pt
138 | run.font.name = 'Arial' # Set font to Arial
139 |
140 | elif content.content_type == ContentType.TABLE:
141 | # Add table to the Word document
142 | table = content.translation
143 | rows = len(table.values)
144 | cols = len(table.columns)
145 | doc.add_table(rows=rows + 1, cols=cols)
146 | table_cells = doc.tables[-1].rows
147 | header_row = table_cells[0].cells
148 | for i, column in enumerate(table.columns):
149 | header_row[i].text = str(column)
150 | for i, row in enumerate(table.values.tolist()):
151 | table_row = table_cells[i + 1].cells
152 | for j, cell in enumerate(row):
153 | table_row[j].text = str(cell)
154 | elif content.content_type == ContentType.IMAGE:
155 | # Add image to the Word document
156 | image_path = content.translation
157 | doc.add_picture(image_path, width=Inches(3)) # Adjust width as needed
158 |
159 | # Add a page break after each page except the last one
160 | if page != book.pages[-1]:
161 | doc.add_page_break()
162 |
163 | doc.save(output_file_path)
164 |
165 | LOG.info(f"翻译完成: {output_file_path}")
166 | return output_file_path
167 |
--------------------------------------------------------------------------------
/project/langchain_openai_translator/ai_translator/utils/__init__.py:
--------------------------------------------------------------------------------
1 | from .argument_parser import ArgumentParser
2 | from .logger import LOG
--------------------------------------------------------------------------------
/project/langchain_openai_translator/ai_translator/utils/argument_parser.py:
--------------------------------------------------------------------------------
1 | import argparse
2 |
3 | class ArgumentParser:
4 | def __init__(self):
5 | self.parser = argparse.ArgumentParser(description='A translation tool that supports translations in any language pair.')
6 | self.parser.add_argument('--config_file', type=str, default='config.yaml', help='Configuration file with model and API settings.')
7 | self.parser.add_argument('--model_name', type=str, help='Name of the Large Language Model.')
8 | self.parser.add_argument('--input_file', type=str, help='PDF file to translate.')
9 | self.parser.add_argument('--output_file_format', type=str, help='The file format of translated book. Now supporting PDF and Markdown')
10 | self.parser.add_argument('--source_language', type=str, help='The language of the original book to be translated.')
11 | self.parser.add_argument('--target_language', type=str, help='The target language for translating the original book.')
12 |
13 | def parse_arguments(self):
14 | args = self.parser.parse_args()
15 | return args
16 |
--------------------------------------------------------------------------------
/project/langchain_openai_translator/ai_translator/utils/logger.py:
--------------------------------------------------------------------------------
1 | from loguru import logger
2 | import os
3 | import sys
4 |
5 | LOG_FILE = "translation.log"
6 | ROTATION_TIME = "02:00"
7 |
8 | class Logger:
9 | def __init__(self, name="translation", log_dir="logs", debug=False):
10 | if not os.path.exists(log_dir):
11 | os.makedirs(log_dir)
12 | log_file_path = os.path.join(log_dir, LOG_FILE)
13 |
14 | # Remove default loguru handler
15 | logger.remove()
16 |
17 | # Add console handler with a specific log level
18 | level = "DEBUG" if debug else "INFO"
19 | logger.add(sys.stdout, level=level)
20 | # Add file handler with a specific log level and timed rotation
21 | logger.add(log_file_path, rotation=ROTATION_TIME, level="DEBUG")
22 | self.logger = logger
23 |
24 | LOG = Logger(debug=True).logger
25 |
26 | if __name__ == "__main__":
27 | log = Logger().logger
28 |
29 | log.debug("This is a debug message.")
30 | log.info("This is an info message.")
31 | log.warning("This is a warning message.")
32 | log.error("This is an error message.")
33 |
--------------------------------------------------------------------------------
/project/langchain_openai_translator/config.yaml:
--------------------------------------------------------------------------------
1 | model_name: "gpt-3.5-turbo"
2 | input_file: "tests/test.pdf"
3 | output_file_format: "markdown"
4 | source_language: "English"
5 | target_language: "Chinese"
--------------------------------------------------------------------------------
/project/langchain_openai_translator/flask_temps/cesi.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/project/langchain_openai_translator/flask_temps/cesi.pdf
--------------------------------------------------------------------------------
/project/langchain_openai_translator/flask_temps/cesi_1.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/project/langchain_openai_translator/flask_temps/cesi_1.pdf
--------------------------------------------------------------------------------
/project/langchain_openai_translator/flask_temps/cesi_translated.md:
--------------------------------------------------------------------------------
1 | 测试数据
2 | 这个数据集包含了由OpenAI的AI语言模型ChatGPT提供的两个测试样本。这些样本包括一个Markdown表格和一个英文文本段落,可以用来测试支持文本和表格格式的英译中翻译软件。
3 | 文本测试
4 | 快速的棕色狐狸跳过懒狗。这个句子包含了英文字母表中的每个字母至少一次。句子是经常用来测试字体、键盘和其他与文本相关的工具的。除了英语,还有很多其他语言的句子。由于语言的独特特点,有些句子更难构造。
5 |
6 |
--------------------------------------------------------------------------------
/project/langchain_openai_translator/flask_temps/cesi_translated_1.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/project/langchain_openai_translator/flask_temps/cesi_translated_1.md
--------------------------------------------------------------------------------
/project/langchain_openai_translator/fonts/simsun.ttc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/project/langchain_openai_translator/fonts/simsun.ttc
--------------------------------------------------------------------------------
/project/langchain_openai_translator/images/sample_image_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/project/langchain_openai_translator/images/sample_image_0.png
--------------------------------------------------------------------------------
/project/langchain_openai_translator/images/sample_image_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/project/langchain_openai_translator/images/sample_image_1.png
--------------------------------------------------------------------------------
/project/langchain_openai_translator/jupyter/flask_client.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": 1,
6 | "id": "a4e32dd8-6716-463e-8120-91682dd65830",
7 | "metadata": {},
8 | "outputs": [
9 | {
10 | "name": "stdout",
11 | "output_type": "stream",
12 | "text": [
13 | "Requirement already satisfied: requests in /root/miniconda3/envs/langchain/lib/python3.10/site-packages (2.31.0)\n",
14 | "Requirement already satisfied: charset-normalizer<4,>=2 in /root/miniconda3/envs/langchain/lib/python3.10/site-packages (from requests) (3.1.0)\n",
15 | "Requirement already satisfied: urllib3<3,>=1.21.1 in /root/miniconda3/envs/langchain/lib/python3.10/site-packages (from requests) (2.0.4)\n",
16 | "Requirement already satisfied: certifi>=2017.4.17 in /root/miniconda3/envs/langchain/lib/python3.10/site-packages (from requests) (2023.5.7)\n",
17 | "Requirement already satisfied: idna<4,>=2.5 in /root/miniconda3/envs/langchain/lib/python3.10/site-packages (from requests) (3.4)\n",
18 | "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n",
19 | "\u001b[0m"
20 | ]
21 | }
22 | ],
23 | "source": [
24 | "!pip install requests"
25 | ]
26 | },
27 | {
28 | "cell_type": "markdown",
29 | "id": "eab5fa3d-3e27-4337-a891-85eda96ddf50",
30 | "metadata": {},
31 | "source": [
32 | "# 使用 requests 库请求翻译服务 API"
33 | ]
34 | },
35 | {
36 | "cell_type": "code",
37 | "execution_count": 30,
38 | "id": "596c6c45-8b95-4beb-ae6f-b1c49aa4020c",
39 | "metadata": {},
40 | "outputs": [
41 | {
42 | "name": "stdout",
43 | "output_type": "stream",
44 | "text": [
45 | "Translation completed. Translated file saved as translated_output.md.\n"
46 | ]
47 | }
48 | ],
49 | "source": [
50 | "import requests\n",
51 | "\n",
52 | "# Flask服务器的地址\n",
53 | "FLASK_SERVER_URL = 'http://localhost:5000'\n",
54 | "\n",
55 | "# 翻译服务接口\n",
56 | "translation_url = f'{FLASK_SERVER_URL}/translation'\n",
57 | "\n",
58 | "# 要上传的文件路径\n",
59 | "file_path = '../tests/test.pdf' # 修改为你的文件路径\n",
60 | "\n",
61 | "# 构建请求参数\n",
62 | "params = {\n",
63 | " 'source_language': 'English', # 修改为你的源语言\n",
64 | " 'target_language': 'Chinese' # 修改为你的目标语言\n",
65 | "}\n",
66 | "\n",
67 | "# 发送POST请求\n",
68 | "with open(file_path, 'rb') as file:\n",
69 | " files = {'input_file': file}\n",
70 | " response = requests.post(translation_url, files=files, data=params)\n",
71 | "\n",
72 | "\n",
73 | "# 翻译后文件\n",
74 | "output_filename = \"translated_output.md\"\n",
75 | "\n",
76 | "# 处理响应\n",
77 | "if response.status_code == 200:\n",
78 | " # 保存翻译后的文件\n",
79 | " with open(output_filename, 'wb') as output_file:\n",
80 | " output_file.write(response.content)\n",
81 | " print(f\"Translation completed. Translated file saved as {output_filename}.\")\n",
82 | "else:\n",
83 | " print(f\"Translation failed. Status code: {response.status_code}\")\n",
84 | " print(response.text)\n"
85 | ]
86 | },
87 | {
88 | "cell_type": "code",
89 | "execution_count": null,
90 | "id": "2da6286a-d92c-4eaf-abec-9f74cb7af599",
91 | "metadata": {},
92 | "outputs": [],
93 | "source": []
94 | }
95 | ],
96 | "metadata": {
97 | "kernelspec": {
98 | "display_name": "Python 3 (ipykernel)",
99 | "language": "python",
100 | "name": "python3"
101 | },
102 | "language_info": {
103 | "codemirror_mode": {
104 | "name": "ipython",
105 | "version": 3
106 | },
107 | "file_extension": ".py",
108 | "mimetype": "text/x-python",
109 | "name": "python",
110 | "nbconvert_exporter": "python",
111 | "pygments_lexer": "ipython3",
112 | "version": "3.10.11"
113 | }
114 | },
115 | "nbformat": 4,
116 | "nbformat_minor": 5
117 | }
118 |
--------------------------------------------------------------------------------
/project/langchain_openai_translator/logs/translation.2023-08-27_17-12-09_650050.log:
--------------------------------------------------------------------------------
1 | 2023-08-27 17:13:53.493 | DEBUG | __main__:translation:12 - [翻译任务]
2 | 源文件: /var/folders/33/xqd2f50x2qz5lyrrx621d81c0000gn/T/gradio/dc8fd32c027c5f2f838fa7f3b0414829e8c5c569/maven学习踩坑之旅.pdf
3 | 源语言: Chinese
4 | 目标语言: English
5 | 2023-08-27 17:13:53.553 | DEBUG | translator.pdf_parser:parse_pdf:46 - [raw_text]
6 | 理解⼀个Maven项目和Python的不同之处
7 | 1. Maven和Python虚拟环境的区别。
8 | 1. Python为了解决不同的项目包版本不⼀样的问题,直接开辟了⼀个新的独立于系统本体之外的环境,即虚拟环境。
9 | 2.Java是直接在将包的不同的版本放在同⼀个地⽅即: repository,通过各自项目配置各自的pom.xml来让maven加载相应的jar包。
10 | 2.Maven是什么?
11 | 1. 包管理⼯具,包的下载存放之类等,类似python的使用pip下载包,将包存放在各自项目对应的虚拟环境里等
12 | 3.setting.xml是什么⼲嘛的?
13 | 1. 设置maven参数的配置⽂件。并且,settings.xml是maven的全局配置⽂件。Settings.xml中包含类似本地仓储位置、修改远程仓储服
14 | 务器、认证信息等配置。配置包的下载地址,源等配置信息
15 | 4.Pom.xml是什么⼲嘛的?
16 | 1. Pom.xml⽂件是所在项目的局部配置。 配置具体要使用到的包内容,在改⽂件里添加了包名,maven会自动下载;
17 | 2.Java里确定唯⼀⼀个包的三个要点,groupId,artifactId,version
18 | 5.repository是什么⼲嘛的?
19 | 1. 包的具体存放地⽅:/Users/yangshengqin/myapps/maven/repository,等价python虚拟环境
20 | 6.Java和Scala不需要像Python⼀样虚拟环境?
21 | 1. 是的,因为在项目的pom.xml里指定里要使用的版本。项目回去 repositor y里找相应的版本
22 | 2023-08-27 17:17:27.345 | DEBUG | __main__:translation:12 - [翻译任务]
23 | 源文件: /var/folders/33/xqd2f50x2qz5lyrrx621d81c0000gn/T/gradio/dc8fd32c027c5f2f838fa7f3b0414829e8c5c569/maven学习踩坑之旅.pdf
24 | 源语言: Chinese
25 | 目标语言: English
26 | 2023-08-27 17:17:27.390 | DEBUG | translator.pdf_parser:parse_pdf:46 - [raw_text]
27 | 理解⼀个Maven项目和Python的不同之处
28 | 1. Maven和Python虚拟环境的区别。
29 | 1. Python为了解决不同的项目包版本不⼀样的问题,直接开辟了⼀个新的独立于系统本体之外的环境,即虚拟环境。
30 | 2.Java是直接在将包的不同的版本放在同⼀个地⽅即: repository,通过各自项目配置各自的pom.xml来让maven加载相应的jar包。
31 | 2.Maven是什么?
32 | 1. 包管理⼯具,包的下载存放之类等,类似python的使用pip下载包,将包存放在各自项目对应的虚拟环境里等
33 | 3.setting.xml是什么⼲嘛的?
34 | 1. 设置maven参数的配置⽂件。并且,settings.xml是maven的全局配置⽂件。Settings.xml中包含类似本地仓储位置、修改远程仓储服
35 | 务器、认证信息等配置。配置包的下载地址,源等配置信息
36 | 4.Pom.xml是什么⼲嘛的?
37 | 1. Pom.xml⽂件是所在项目的局部配置。 配置具体要使用到的包内容,在改⽂件里添加了包名,maven会自动下载;
38 | 2.Java里确定唯⼀⼀个包的三个要点,groupId,artifactId,version
39 | 5.repository是什么⼲嘛的?
40 | 1. 包的具体存放地⽅:/Users/yangshengqin/myapps/maven/repository,等价python虚拟环境
41 | 6.Java和Scala不需要像Python⼀样虚拟环境?
42 | 1. 是的,因为在项目的pom.xml里指定里要使用的版本。项目回去 repositor y里找相应的版本
43 | 2023-08-27 17:17:56.593 | DEBUG | translator.writer:save_translated_book:18 - markdown
44 | 2023-08-27 17:17:56.594 | INFO | translator.writer:_save_translated_book_markdown:90 - 开始导出: /var/folders/33/xqd2f50x2qz5lyrrx621d81c0000gn/T/gradio/dc8fd32c027c5f2f838fa7f3b0414829e8c5c569/maven学习踩坑之旅_translated.md
45 | 2023-08-27 17:17:56.594 | INFO | translator.writer:save_translated_book:28 - 翻译完成,文件保存至: /var/folders/33/xqd2f50x2qz5lyrrx621d81c0000gn/T/gradio/dc8fd32c027c5f2f838fa7f3b0414829e8c5c569/maven学习踩坑之旅_translated.md
46 |
--------------------------------------------------------------------------------
/project/langchain_openai_translator/logs/translation.2023-08-29_11-00-52_348942.log:
--------------------------------------------------------------------------------
1 | 2023-08-29 11:00:52.341 | DEBUG | __main__:translation:22 - [input_file]
2 |
3 | 2023-08-29 11:00:52.352 | DEBUG | __main__:translation:23 - [input_file.filename]
4 | cesi.pdf
5 | 2023-08-29 11:00:52.357 | DEBUG | __main__:translation:28 - [input_file_path]
6 | flask_temps/cesi.pdf
7 | 2023-08-29 11:01:48.742 | DEBUG | __main__:translation:22 - [input_file]
8 |
9 | 2023-08-29 11:01:48.744 | DEBUG | __main__:translation:23 - [input_file.filename]
10 | cesi.pdf
11 | 2023-08-29 11:01:48.744 | DEBUG | __main__:translation:28 - [input_file_path]
12 | flask_temps/cesi.pdf
13 | 2023-08-29 11:04:36.100 | DEBUG | __main__:translation:22 - [input_file]
14 |
15 | 2023-08-29 11:04:36.110 | DEBUG | __main__:translation:23 - [input_file.filename]
16 | cesi.pdf
17 | 2023-08-29 11:04:36.111 | DEBUG | __main__:translation:28 - [input_file_path]
18 | flask_temps/cesi.pdf
19 | 2023-08-29 11:04:36.154 | DEBUG | translator.pdf_parser:parse_pdf:46 - [raw_text]
20 | Test Data
21 | This dataset contains two test samples provided by ChatGPT, an AI language model
22 | by OpenAI. These samples include a markdown table and an English text passage,
23 | which can be used to test an English-to-Chinese translation software supporting both
24 | text and table formats.
25 | Text testing
26 | The quick brown fox jumps over the lazy dog. This pangram contains every letter of
27 | the English alphabet at least once. Pangrams are often used to test fonts, keyboards,
28 | and other text-related tools. In addition to English, there are pangrams in many other
29 | languages. Some pangrams are more difficult to construct due to the unique
30 | characteristics of the language.
31 | 2023-08-29 11:19:36.135 | DEBUG | __main__:translation:22 - [input_file]
32 |
33 | 2023-08-29 11:19:36.136 | DEBUG | __main__:translation:23 - [input_file.filename]
34 | cesi.pdf
35 | 2023-08-29 11:19:36.137 | DEBUG | __main__:translation:28 - [input_file_path]
36 | flask_temps/cesi.pdf
37 | 2023-08-29 11:19:36.187 | DEBUG | translator.pdf_parser:parse_pdf:46 - [raw_text]
38 | Test Data
39 | This dataset contains two test samples provided by ChatGPT, an AI language model
40 | by OpenAI. These samples include a markdown table and an English text passage,
41 | which can be used to test an English-to-Chinese translation software supporting both
42 | text and table formats.
43 | Text testing
44 | The quick brown fox jumps over the lazy dog. This pangram contains every letter of
45 | the English alphabet at least once. Pangrams are often used to test fonts, keyboards,
46 | and other text-related tools. In addition to English, there are pangrams in many other
47 | languages. Some pangrams are more difficult to construct due to the unique
48 | characteristics of the language.
49 | 2023-08-29 11:19:37.838 | ERROR | translator.translation_chain:run:45 - An error occurred during translation: Incorrect API key provided: qEzC5U8U************************************BK9b. You can find your API key at https://platform.openai.com/account/api-keys.
50 | 2023-08-29 11:19:37.839 | DEBUG | translator.writer:save_translated_book:18 - markdown
51 | 2023-08-29 11:19:37.839 | INFO | translator.writer:_save_translated_book_markdown:90 - 开始导出: flask_temps/cesi_translated.md
52 | 2023-08-29 11:19:37.839 | INFO | translator.writer:save_translated_book:28 - 翻译完成,文件保存至: flask_temps/cesi_translated.md
53 | 2023-08-29 11:19:37.840 | DEBUG | __main__:translation:43 - /Users/yangshengqin/mygithub/openai-quickstart/langchain/openai-translator/flask_temps/cesi_translated.md
54 | 2023-08-29 11:25:46.185 | DEBUG | __main__:translation:21 - [input_file]
55 |
56 | 2023-08-29 11:25:46.197 | DEBUG | __main__:translation:22 - [input_file.filename]
57 | cesi.pdf
58 | 2023-08-29 11:25:46.198 | DEBUG | __main__:translation:30 - [input_file_path]
59 | flask_temps/cesi.pdf
60 | 2023-08-29 11:25:46.250 | DEBUG | translator.pdf_parser:parse_pdf:46 - [raw_text]
61 | Test Data
62 | This dataset contains two test samples provided by ChatGPT, an AI language model
63 | by OpenAI. These samples include a markdown table and an English text passage,
64 | which can be used to test an English-to-Chinese translation software supporting both
65 | text and table formats.
66 | Text testing
67 | The quick brown fox jumps over the lazy dog. This pangram contains every letter of
68 | the English alphabet at least once. Pangrams are often used to test fonts, keyboards,
69 | and other text-related tools. In addition to English, there are pangrams in many other
70 | languages. Some pangrams are more difficult to construct due to the unique
71 | characteristics of the language.
72 | 2023-08-29 11:25:47.793 | ERROR | translator.translation_chain:run:45 - An error occurred during translation: Incorrect API key provided: qEzC5U8U************************************BK9b. You can find your API key at https://platform.openai.com/account/api-keys.
73 | 2023-08-29 11:25:47.795 | DEBUG | translator.writer:save_translated_book:18 - markdown
74 | 2023-08-29 11:25:47.795 | INFO | translator.writer:_save_translated_book_markdown:90 - 开始导出: flask_temps/cesi_translated.md
75 | 2023-08-29 11:25:47.796 | INFO | translator.writer:save_translated_book:28 - 翻译完成,文件保存至: flask_temps/cesi_translated.md
76 | 2023-08-29 11:25:47.796 | DEBUG | __main__:translation:45 - /Users/yangshengqin/mygithub/openai-quickstart/langchain/openai-translator/flask_temps/cesi_translated.md
77 | 2023-08-29 11:30:54.075 | DEBUG | __main__:translation:21 - [input_file]
78 |
79 | 2023-08-29 11:30:54.076 | DEBUG | __main__:translation:22 - [input_file.filename]
80 | cesi.pdf
81 | 2023-08-29 11:30:54.077 | DEBUG | __main__:translation:29 - [input_file_path]
82 | flask_temps/cesi.pdf
83 | 2023-08-29 13:55:06.502 | DEBUG | __main__:translation:21 - [input_file]
84 |
85 | 2023-08-29 13:55:06.505 | DEBUG | __main__:translation:22 - [input_file.filename]
86 | cesi.pdf
87 | 2023-08-29 13:55:06.505 | DEBUG | __main__:translation:30 - [input_file_path]
88 | flask_temps/cesi.pdf
89 | 2023-08-29 13:55:06.552 | DEBUG | translator.pdf_parser:parse_pdf:46 - [raw_text]
90 | Test Data
91 | This dataset contains two test samples provided by ChatGPT, an AI language model
92 | by OpenAI. These samples include a markdown table and an English text passage,
93 | which can be used to test an English-to-Chinese translation software supporting both
94 | text and table formats.
95 | Text testing
96 | The quick brown fox jumps over the lazy dog. This pangram contains every letter of
97 | the English alphabet at least once. Pangrams are often used to test fonts, keyboards,
98 | and other text-related tools. In addition to English, there are pangrams in many other
99 | languages. Some pangrams are more difficult to construct due to the unique
100 | characteristics of the language.
101 | 2023-08-29 13:56:28.004 | DEBUG | __main__:translation:21 - [input_file]
102 |
103 | 2023-08-29 13:56:28.006 | DEBUG | __main__:translation:22 - [input_file.filename]
104 | cesi.pdf
105 | 2023-08-29 13:56:28.007 | DEBUG | __main__:translation:30 - [input_file_path]
106 | flask_temps/cesi.pdf
107 | 2023-08-29 13:56:28.057 | DEBUG | translator.pdf_parser:parse_pdf:46 - [raw_text]
108 | Test Data
109 | This dataset contains two test samples provided by ChatGPT, an AI language model
110 | by OpenAI. These samples include a markdown table and an English text passage,
111 | which can be used to test an English-to-Chinese translation software supporting both
112 | text and table formats.
113 | Text testing
114 | The quick brown fox jumps over the lazy dog. This pangram contains every letter of
115 | the English alphabet at least once. Pangrams are often used to test fonts, keyboards,
116 | and other text-related tools. In addition to English, there are pangrams in many other
117 | languages. Some pangrams are more difficult to construct due to the unique
118 | characteristics of the language.
119 | 2023-08-29 13:57:34.691 | DEBUG | translator.writer:save_translated_book:18 - markdown
120 | 2023-08-29 13:57:34.691 | INFO | translator.writer:_save_translated_book_markdown:90 - 开始导出: flask_temps/cesi_translated.md
121 | 2023-08-29 13:57:34.691 | INFO | translator.writer:save_translated_book:28 - 翻译完成,文件保存至: flask_temps/cesi_translated.md
122 | 2023-08-29 13:57:34.691 | DEBUG | __main__:translation:45 - /Users/yangshengqin/mygithub/openai-quickstart/langchain/openai-translator/flask_temps/cesi_translated.md
123 |
--------------------------------------------------------------------------------
/project/langchain_openai_translator/logs/translation.2023-09-06_18-27-55_738519.log:
--------------------------------------------------------------------------------
1 | 2023-09-06 18:27:55.733 | DEBUG | translator.pdf_parser:parse_pdf:46 - [raw_text]
2 | Test Data
3 | This dataset contains two test samples provided by ChatGPT, an AI language model by OpenAI.
4 | These samples include a markdown table and an English text passage, which can be used to test an
5 | English-to-Chinese translation software supporting both text and table formats.
6 | Text testing
7 | The quick brown fox jumps over the lazy dog. This pangram contains every letter of the English
8 | alphabet at least once. Pangrams are often used to test fonts, keyboards, and other text-related
9 | tools. In addition to English, there are pangrams in many other languages. Some pangrams are more
10 | difficult to construct due to the unique characteristics of the language.
11 | Table Testing
12 | 2023-09-06 18:27:55.738 | DEBUG | translator.pdf_parser:parse_pdf:54 - [table]
13 | [Fruit, Color, Price (USD)] [Apple, Red, 1.20] [Banana, Yellow, 0.50] [Orange, Orange, 0.80] [Strawberry, Red, 2.50] [Blueberry, Blue, 3.00] [Kiwi, Green, 1.00] [Mango, Orange, 1.50] [Grape, Purple, 2.00]
14 |
--------------------------------------------------------------------------------
/project/langchain_openai_translator/requirements.txt:
--------------------------------------------------------------------------------
1 | pdfplumber
2 | simplejson
3 | requests
4 | PyYAML
5 | pillow
6 | reportlab
7 | pandas
8 | loguru
9 | openai
10 | langchain
11 | gradio
12 | flask
--------------------------------------------------------------------------------
/project/langchain_openai_translator/tests/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/project/langchain_openai_translator/tests/.DS_Store
--------------------------------------------------------------------------------
/project/langchain_openai_translator/tests/ThamesNewsCH.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/project/langchain_openai_translator/tests/ThamesNewsCH.pdf
--------------------------------------------------------------------------------
/project/langchain_openai_translator/tests/ThamesNewsEN.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/project/langchain_openai_translator/tests/ThamesNewsEN.pdf
--------------------------------------------------------------------------------
/project/langchain_openai_translator/tests/The_Old_Man_of_the_Sea.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/project/langchain_openai_translator/tests/The_Old_Man_of_the_Sea.pdf
--------------------------------------------------------------------------------
/project/langchain_openai_translator/tests/press_release_translated_novel.md:
--------------------------------------------------------------------------------
1 | 自从泰晤士河的部分地区被宣布为“生物死亡”以来,仅仅过去了半个世纪,因为河水太脏。但是现在,泰晤士河的水质比任何时候都要清洁,企业家们希望在伦敦市中心的泰晤士河中建造一个价值1000万英镑的露天游泳池。
2 | 来自德国的净化专家(德国拥有欧洲最高的水质标准)设计了一个系统,该计划的支持者表示,这个系统将确保游客的安全,无论年龄大小。
3 | 泰晤士河的浴池位于伦敦堤岸的庙阶,周围环绕着芦苇床,用于过滤河水,然后将其泵入82英尺乘32英尺的主游泳池,游泳池下方的甲板上还有一个次级过滤装置。由于下雨时的污水溢出和喜剧演员大卫·沃利姆斯在2011年进行的一次长达140英里的慈善游泳中患上了“泰晤士肚”,人们对该项目提出了健康担忧。但是,德国Polyplan公司的专家提出了一个解决方案。该公司在整个欧洲建造了许多天然游泳池。参与该项目的英国公司Gartenart的蒂姆·埃文斯表示,这个未加热且无氯的水将“和你在山湖中找到的任何水一样干净”。
4 | 这个游泳池将设有更衣室、一条从岸边通向水中的130英尺的斜坡、一个浸泡池和一个儿童戏水区,而一道4英尺高的玻璃栏杆将保护游泳者免受河流交通引起的波浪的影响。伦敦建筑事务所Studio Octopi的克里斯·罗默-李表示,他希望通过众筹筹集30万英镑的初始资金,用于咨询费用和其他费用,众筹是指公众可以为社区计划做出贡献。
5 | 如果获得规划许可,这个游泳池可能会在明年晚些时候开放。
6 |
7 |
--------------------------------------------------------------------------------
/project/langchain_openai_translator/tests/test.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/project/langchain_openai_translator/tests/test.pdf
--------------------------------------------------------------------------------
/project/langchain_openai_translator/tests/test_translated.md:
--------------------------------------------------------------------------------
1 | 测试数据
2 | 这个数据集包含了由OpenAI的AI语言模型ChatGPT提供的两个测试样本。
3 | 这些样本包括一个Markdown表格和一个英文文本段落,可以用来测试支持文本和表格格式的英译中翻译软件。
4 | 文本测试
5 | 快速的棕色狐狸跳过懒狗。这个句子包含了英语字母表中的每个字母至少一次。句子是经常用来测试字体、键盘和其他与文本相关的工具的。除了英语,其他许多语言也有句子。由于语言的独特特点,有些句子更难构造。
6 |
7 | | 水果 | 颜色 | 价格(美元) |
8 | | --- | --- | --- |
9 | | 苹果 | 红色 | 1.2 |
10 | | 香蕉 | 黄色 | 0.5 |
11 | | 橙子 | 橙色 | 0.8 |
12 | | 草莓 | 红色 | 2.5 |
13 | | 蓝莓 | 蓝色 | 3.0 |
14 | | 猕猴桃 | 绿色 | 1.0 |
15 | | 芒果 | 橙色 | 1.5 |
16 | | 葡萄 | 紫色 | 2.00 |
17 |
18 | ---
19 |
20 |
--------------------------------------------------------------------------------
/project/openai_api/4.class_tiktoken.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": 3,
6 | "metadata": {
7 | "ExecuteTime": {
8 | "end_time": "2023-07-26T05:53:33.852966Z",
9 | "start_time": "2023-07-26T05:53:33.722175Z"
10 | },
11 | "collapsed": true,
12 | "jupyter": {
13 | "outputs_hidden": true
14 | }
15 | },
16 | "outputs": [],
17 | "source": [
18 | "import tiktoken"
19 | ]
20 | },
21 | {
22 | "cell_type": "code",
23 | "execution_count": 4,
24 | "metadata": {
25 | "ExecuteTime": {
26 | "end_time": "2023-07-26T05:53:35.870055Z",
27 | "start_time": "2023-07-26T05:53:35.821973Z"
28 | },
29 | "collapsed": false,
30 | "jupyter": {
31 | "outputs_hidden": false
32 | }
33 | },
34 | "outputs": [
35 | {
36 | "data": {
37 | "text/plain": [
38 | "['gpt2', 'r50k_base', 'p50k_base', 'p50k_edit', 'cl100k_base']"
39 | ]
40 | },
41 | "execution_count": 4,
42 | "metadata": {},
43 | "output_type": "execute_result"
44 | }
45 | ],
46 | "source": [
47 | "datas = tiktoken.list_encoding_names()\n",
48 | "datas"
49 | ]
50 | },
51 | {
52 | "cell_type": "code",
53 | "execution_count": 5,
54 | "metadata": {
55 | "ExecuteTime": {
56 | "end_time": "2023-07-26T05:53:38.237535Z",
57 | "start_time": "2023-07-26T05:53:38.234636Z"
58 | },
59 | "collapsed": false,
60 | "jupyter": {
61 | "outputs_hidden": false
62 | }
63 | },
64 | "outputs": [],
65 | "source": [
66 | "# 封装一个计算token数的函数\n",
67 | "def token_num(encoding_name, model, string):\n",
68 | " tiktoken.get_encoding(encoding_name)\n",
69 | " encoding = tiktoken.encoding_for_model(model)\n",
70 | " tokens = encoding.encode(string)\n",
71 | " print(f\"句子:{string}, tokens:{tokens}, token 数量:{len(tokens)}\")\n",
72 | " return len(tokens)\n"
73 | ]
74 | },
75 | {
76 | "cell_type": "code",
77 | "execution_count": 6,
78 | "metadata": {
79 | "ExecuteTime": {
80 | "end_time": "2023-07-26T05:54:32.252888Z",
81 | "start_time": "2023-07-26T05:53:40.477050Z"
82 | },
83 | "collapsed": false,
84 | "jupyter": {
85 | "outputs_hidden": false
86 | }
87 | },
88 | "outputs": [
89 | {
90 | "name": "stdout",
91 | "output_type": "stream",
92 | "text": [
93 | "句子:今天很棒!, tokens:[37271, 36827, 17599, 230, 77062, 240, 0], token 数量:7\n"
94 | ]
95 | },
96 | {
97 | "data": {
98 | "text/plain": [
99 | "7"
100 | ]
101 | },
102 | "execution_count": 6,
103 | "metadata": {},
104 | "output_type": "execute_result"
105 | }
106 | ],
107 | "source": [
108 | "encoding_name = \"cl100k_base\"\n",
109 | "model = \"gpt-3.5-turbo\"\n",
110 | "string = \"今天很棒!\"\n",
111 | "token_num(encoding_name, model, string)\n"
112 | ]
113 | },
114 | {
115 | "cell_type": "code",
116 | "execution_count": 9,
117 | "metadata": {
118 | "ExecuteTime": {
119 | "end_time": "2023-07-26T07:10:30.679880Z",
120 | "start_time": "2023-07-26T07:10:20.495256Z"
121 | },
122 | "collapsed": false,
123 | "jupyter": {
124 | "outputs_hidden": false
125 | }
126 | },
127 | "outputs": [
128 | {
129 | "name": "stdout",
130 | "output_type": "stream",
131 | "text": [
132 | "句子:今天很棒!, tokens:[20015, 232, 25465, 36181, 230, 162, 96, 240, 0], token 数量:9\n"
133 | ]
134 | },
135 | {
136 | "data": {
137 | "text/plain": [
138 | "9"
139 | ]
140 | },
141 | "execution_count": 9,
142 | "metadata": {},
143 | "output_type": "execute_result"
144 | }
145 | ],
146 | "source": [
147 | "# encoding_name = \"r50k_base\"\n",
148 | "encoding_name = \"gpt2\"\n",
149 | "model = \"text-curie-001\"\n",
150 | "string = \"今天很棒!\"\n",
151 | "token_num(encoding_name, model, string)"
152 | ]
153 | }
154 | ],
155 | "metadata": {
156 | "kernelspec": {
157 | "display_name": "AINote",
158 | "language": "python",
159 | "name": "ainote"
160 | },
161 | "language_info": {
162 | "codemirror_mode": {
163 | "name": "ipython",
164 | "version": 3
165 | },
166 | "file_extension": ".py",
167 | "mimetype": "text/x-python",
168 | "name": "python",
169 | "nbconvert_exporter": "python",
170 | "pygments_lexer": "ipython3",
171 | "version": "3.10.0"
172 | }
173 | },
174 | "nbformat": 4,
175 | "nbformat_minor": 4
176 | }
177 |
--------------------------------------------------------------------------------
/project/openai_api/files/img-CWs11MH3BnkwqSRzoUWrtITD.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/project/openai_api/files/img-CWs11MH3BnkwqSRzoUWrtITD.png
--------------------------------------------------------------------------------
/project/openai_api/files/img-EWwpOBlQ3ngE9SkxwHBpPCqw.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/project/openai_api/files/img-EWwpOBlQ3ngE9SkxwHBpPCqw.png
--------------------------------------------------------------------------------
/project/openai_api/files/img-GyOanQxzFuiTrPrdIV72mM76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/project/openai_api/files/img-GyOanQxzFuiTrPrdIV72mM76.png
--------------------------------------------------------------------------------
/project/openai_api/files/img-UxONH8mxhhRd9ABKmYnJnQ2d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/project/openai_api/files/img-UxONH8mxhhRd9ABKmYnJnQ2d.png
--------------------------------------------------------------------------------
/project/openai_api/files/img-ZJkajHQVUwIEmrU4Ei2iBUCw.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/project/openai_api/files/img-ZJkajHQVUwIEmrU4Ei2iBUCw.png
--------------------------------------------------------------------------------
/project/openai_api/files/img-iSjbeihvmNnvuSvSfiiRxkKF.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/project/openai_api/files/img-iSjbeihvmNnvuSvSfiiRxkKF.png
--------------------------------------------------------------------------------
/project/openai_api/files/img_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/project/openai_api/files/img_1.png
--------------------------------------------------------------------------------
/project/openai_api/files/speech.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/project/openai_api/files/speech.mp3
--------------------------------------------------------------------------------
/project/openai_api/files/work_10818_20231031_jxj3wSJ_preview.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/project/openai_api/files/work_10818_20231031_jxj3wSJ_preview.jpg
--------------------------------------------------------------------------------
/project/openai_api/files/羊皮卷1.txt:
--------------------------------------------------------------------------------
1 | 第 一 卷
2 |
3 | 今天,我开始新的生活。
4 |
5 | 今天,我爬出满是失败创伤的老茧。
6 |
7 | 今天,我从新来到这个世上,我出生在葡萄园中,园内的葡萄任人享用。
8 |
9 | 今天我要从最高最密的藤上摘下智慧的果实,这葡萄藤是好几代前的智者种下的。
10 |
11 | 今天,我要品尝葡萄的美味,还要吞下每一粒成功的种子,让新生命在我心里萌芽。
12 |
13 | 我选择的道路充满机遇,也有辛酸与绝望。失败的同伴数不胜数,叠在一起,比金字塔还高。
14 |
15 | 然而,我不会像他们一样失败,因为我手中持有航海图,可以领我越过汹涌的大海,抵达梦中的彼岸。
16 |
17 | 失败不再是我奋斗的代价。它和痛苦都将从我的生命中消失。失败和我,就像水火一样,互不相容。我不再像过去一样接受它们。我要在智慧的指引下,走出失败的阴影,步入富足、健康、快乐的乐园,这些都超出了我以往的梦想。
18 |
19 | 我要是能长生不老,就可以学到一切,但我不能永生,所以,在有限的人生里,我必须学会忍耐的艺术,因为大自然的行为一向是从容不迫的。造物主创造树中之王橄榄树需要一百年的时间,而洋葱经过短短的九个星期就会枯老。我不留恋从前那种洋葱式的生活,我要成为万树之王——橄榄树,成为现实生活中最伟大的推销员。
--------------------------------------------------------------------------------
/project/openai_api/files/羊皮卷speech.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/project/openai_api/files/羊皮卷speech.mp3
--------------------------------------------------------------------------------
/project/openai_api/files/英文单人.MP4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/project/openai_api/files/英文单人.MP4
--------------------------------------------------------------------------------
/project/openai_api/files/英文对话.MP4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/project/openai_api/files/英文对话.MP4
--------------------------------------------------------------------------------
/project/python/example_chat_completion.md:
--------------------------------------------------------------------------------
1 | ## 1、example_chat_completion.py 使用说明
2 |
3 | 本程序实现了一个简单的命令行聊天机器人,允许用户与机器人进行交互并记录对话历史。start_chat()
4 | 函数用于开始对话,用户可以输入消息进行交流,直到输入 "q" 结束对话。chat_with_bot(message) 函数用于与聊天机器人进行对话,调用
5 | OpenAI 的 ChatCompletion API 生成机器人的回复。整个程序提供了基本的对话功能,可以根据用户的输入和机器人的回复形成对话历史,为交互提供了简单的聊天体验。
6 |
7 | ### `chat_with_bot(message)`函数说明
8 |
9 | * 该函数用于与聊天机器人进行对话。根据传入的消息 message(以字典形式表示),函数调用了 OpenAI 的
10 | ChatCompletion API 进行对话生成,并返回机器人的回复。
11 |
12 | * 参数:`message`(字典):表示聊天对话的消息列表。每条消息都由 `{"role": "角色", "content": "内容"}` 格式的字典表示。`"角色"` 表示消息的发送者,可以是用户、系统或助手等,"内容" 表示消息的内容。
13 |
14 | * 返回值:机器人的回复,以字典形式表示。字典包含两个键值对:`{"role": "角色", "content": "回复内容"}`。其中 `"角色"`
15 | 表示机器人的角色,`"回复内容"` 表示机器人的回复内容。
16 |
17 | #### 使用方法
18 |
19 | * 构造一个消息列表 `message`,其中包含对话的初始消息,可以是系统消息或用户消息。
20 |
21 | * 调用 `chat_with_bot(message)` 函数,并传入消息列表 `message`。
22 |
23 | * 函数将根据传入的消息列表 `message` 调用 OpenAI 的 ChatCompletion API,并获取机器人的回复。
24 |
25 | * 返回机器人的回复,以字典形式表示。
26 |
27 | 请注意,这是一个示例函数,实际使用时,需要根据 OpenAI ChatCompletion API 的具体接口和返回格式进行调整。同时,确保安全处理用户输入和返回的内容,避免潜在的安全问题。
28 |
29 | ### `start_chat()` 函数说明
30 |
31 | * 运行 `start_chat()` 函数后,您可以开始与聊天机器人进行对话。
32 |
33 | * 首次开始会话时,您需要定义一个角色并提供简单描述。输入完成后,该信息将被添加到对话消息列表中,并显示为系统消息。
34 |
35 | * 后续每次会话时,程序将加载之前的对话内容到 `message` 列表中,以便您可以查看之前的对话历史。
36 |
37 | * 输入任意消息以与机器人进行对话,当您输入 'q' 并回车时,对话将结束。
38 |
39 | * 在对话过程中,您的输入将显示为用户消息,机器人的回复将显示为机器人消息。
40 |
41 | 请注意,这是一个示例函数,chat_with_bot() 函数的实现未在代码中给出,您需要根据实际情况自行定义并实现该函数。同时,确保安全处理用户输入和返回的内容,避免潜在的安全问题。
42 |
43 | ### 使用样例输出
44 |
45 | 
46 | # 2.example_chat_competion_use_weather_function.py
47 | 本程序实现了一个简单的命令行天气助手机器人,允许用户与机器人进行交互并记录对话历史。start_chat()
48 | #### web url:https://www.apispace.com/
49 | #### 需要注册登陆该网站并获取apikey,截止:2023-07-28日,该网站每一类接口,新用户有200次免费使用权限
50 | #### 在config.ini中配置自己的apikey
51 |
52 | 
53 | 祝您享受与聊天机器人的交互!
54 |
--------------------------------------------------------------------------------
/project/python/example_chat_completion.py:
--------------------------------------------------------------------------------
1 | import os
2 | import openai
3 | import configparser
4 |
5 | conf = configparser.ConfigParser()
6 | current_directory = os.path.dirname(os.path.realpath('__file__'))
7 | config_file_path = os.path.join(current_directory, '..', '..', 'config.ini')
8 | print(config_file_path)
9 | conf.read(config_file_path)
10 | api_key = conf.get("Openai", "api_key") # 在config.ini中配置自己的APIkey
11 | openai.api_key = api_key
12 | os.environ["HTTP_PROXY"] = conf.get("Proxy", "HTTP_PROXY") # 配置自己的代理
13 | os.environ["HTTPS_PROXY"] = conf.get("Proxy", "HTTPS_PROXY")
14 | chat_model = "gpt-3.5-turbo"
15 | text_model = "gpt-3.5-turbo-instruct" # text-davinci-003 2024-01-04已经下线了
16 |
17 | # 请根据自己的需求调整以下参数
18 | model = 'gpt-3.5-turbo'
19 | max_tokens = 500
20 | temperature = 0.2
21 |
22 |
23 | def chat_with_bot(message):
24 | """
25 | :param message: eg: {"role": "system", "content": "you are a translation assistant"})
26 | :return: eg: {"role": "assistant", "content": "...."})
27 | """
28 | # ChatCompletion
29 | conversation_3 = openai.ChatCompletion.create(
30 | model=model,
31 | messages=message,
32 | # max_tokens=max_tokens,
33 | temperature=temperature,
34 | )
35 | answer = conversation_3['choices'][0]["message"]
36 | new_message_dict = {"role": answer.role, "content": answer.content}
37 | return new_message_dict
38 |
39 |
40 | def start_chat():
41 | """
42 | 第一次开始会话时:需要给一个role
43 | 后面每次会话时将前面的内容加载到message里(后面可以优化,如何控制那些内容需要加载进去)
44 | :return:
45 | """
46 | message = []
47 | start = 0
48 | while True:
49 | if not start:
50 | content = input(
51 | "首次开始会话,请定义角色以及简单描述:如:你是我的翻译助手,请帮我将下面的内容翻译成中文,输入q 并回车结束对话。\nprompt system: ")
52 | message.append({"role": "system", "content": content})
53 | userinput = input("user:")
54 | message.append({"role": "user", "content": userinput})
55 | else:
56 | content = input("user: ")
57 | message.append({"role": "user", "content": content})
58 | if content == 'q':
59 | break
60 | # print('message:', message) # 可以看到每次输入的message
61 | res = chat_with_bot(message)
62 | print(f"{res['role']}:{res['content']}")
63 | message.append(res)
64 | start += 1
65 |
66 |
67 | if __name__ == '__main__':
68 | start_chat()
69 |
70 | # 你是专业的著作翻译家,帮我翻译成中文,确保翻译后的句子流畅连贯,并与原文意思保持一致。内容:The quick brown fox jumps over the lazy dog. This pangram contains every letter of the English alphabet at least once. Pangrams are often used to test fonts, keyboards, and other text-related tools. In addition to English, there are pangrams in many other languages. Some pangrams are more difficult to construct due to the unique characteristics of the language.
71 |
--------------------------------------------------------------------------------
/project/python/天气助手.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/project/python/天气助手.png
--------------------------------------------------------------------------------
/project/python/聊天助手.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/project/python/聊天助手.png
--------------------------------------------------------------------------------
/requirments.txt:
--------------------------------------------------------------------------------
1 | accelerate==0.26.1
2 | aiofiles==23.2.1
3 | aiohttp==3.8.5
4 | aioprometheus==23.12.0
5 | aiosignal==1.3.1
6 | altair==5.1.1
7 | annotated-types==0.5.0
8 | anyio==3.7.1
9 | appnope==0.1.3
10 | argon2-cffi==23.1.0
11 | argon2-cffi-bindings==21.2.0
12 | arrow==1.2.3
13 | asttokens==2.4.0
14 | async-lru==2.0.4
15 | async-timeout==4.0.3
16 | attrs==23.1.0
17 | Babel==2.12.1
18 | backcall==0.2.0
19 | bcrypt==4.2.0
20 | beautifulsoup4==4.12.2
21 | bleach==6.0.0
22 | blinker==1.6.2
23 | certifi==2023.7.22
24 | cffi==1.15.1
25 | charset-normalizer==3.2.0
26 | click==8.1.7
27 | cloudpickle==3.0.0
28 | colorama==0.4.6
29 | comm==0.1.4
30 | contourpy==1.1.1
31 | cpm-kernels==1.0.11
32 | cryptography==41.0.4
33 | cycler==0.11.0
34 | dataclasses-json==0.6.0
35 | debugpy==1.8.0
36 | decorator==5.1.1
37 | defusedxml==0.7.1
38 | distro==1.9.0
39 | ecdsa==0.19.0
40 | exceptiongroup==1.1.3
41 | executing==1.2.0
42 | faiss-cpu==1.7.4
43 | fastapi==0.110.3
44 | fastjsonschema==2.18.0
45 | ffmpy==0.3.1
46 | filelock==3.12.4
47 | Flask==2.3.3
48 | fonttools==4.42.1
49 | fqdn==1.5.1
50 | frozenlist==1.4.0
51 | fsspec==2023.9.2
52 | google-search-results==2.4.2
53 | gradio==4.26.0
54 | gradio_client==0.15.1
55 | h11==0.14.0
56 | httpcore==0.18.0
57 | httpx==0.25.0
58 | huggingface-hub==0.24.6
59 | idna==3.4
60 | importlib-resources==6.1.0
61 | ipykernel==6.25.2
62 | ipython==8.15.0
63 | ipython-genutils==0.2.0
64 | ipywidgets==8.1.1
65 | isoduration==20.11.0
66 | itsdangerous==2.1.2
67 | jedi==0.19.0
68 | Jinja2==3.1.2
69 | jiter==0.5.0
70 | joblib==1.3.2
71 | json5==0.9.14
72 | jsonpatch==1.33
73 | jsonpointer==2.4
74 | jsonschema==4.19.1
75 | jsonschema-specifications==2023.7.1
76 | jupyter==1.0.0
77 | jupyter-console==6.6.3
78 | jupyter-events==0.9.0
79 | jupyter-lsp==2.2.0
80 | jupyter_client==8.3.1
81 | jupyter_core==5.3.1
82 | jupyter_server==2.7.3
83 | jupyter_server_terminals==0.4.4
84 | jupyterlab==4.0.6
85 | jupyterlab-pygments==0.2.2
86 | jupyterlab-widgets==3.0.9
87 | jupyterlab_server==2.25.0
88 | kiwisolver==1.4.5
89 | langchain==0.2.14
90 | langchain-community==0.2.12
91 | langchain-core==0.2.34
92 | langchain-experimental==0.0.11
93 | langchain-openai==0.1.22
94 | langchain-text-splitters==0.2.2
95 | langsmith==0.1.104
96 | latex2mathml==3.77.0
97 | loguru==0.7.2
98 | Markdown==3.5.2
99 | markdown-it-py==3.0.0
100 | MarkupSafe==2.1.3
101 | marshmallow==3.20.1
102 | matplotlib==3.8.0
103 | matplotlib-inline==0.1.6
104 | mdtex2html==1.3.0
105 | mdurl==0.1.2
106 | mistune==3.0.1
107 | modelscope==1.17.1
108 | mpmath==1.3.0
109 | multidict==6.0.4
110 | mypy-extensions==1.0.0
111 | nbclient==0.8.0
112 | nbconvert==7.8.0
113 | nbformat==5.9.2
114 | nest-asyncio==1.5.8
115 | networkx==3.2.1
116 | notebook==7.0.4
117 | notebook_shim==0.2.3
118 | numexpr==2.8.7
119 | numpy==1.26.0
120 | openai==1.42.0
121 | orjson==3.10.7
122 | overrides==7.4.0
123 | packaging==24.1
124 | pandas==2.1.1
125 | pandocfilters==1.5.0
126 | parso==0.8.3
127 | passlib==1.7.4
128 | pdfminer.six==20221105
129 | pdfplumber==0.10.2
130 | peft==0.12.0
131 | pexpect==4.8.0
132 | pickleshare==0.7.5
133 | Pillow==10.0.1
134 | platformdirs==3.10.0
135 | plotly==5.17.0
136 | prometheus-client==0.17.1
137 | prompt-toolkit==3.0.39
138 | protobuf==4.25.2
139 | psutil==5.9.5
140 | ptyprocess==0.7.0
141 | pure-eval==0.2.2
142 | pyasn1==0.6.0
143 | pycparser==2.21
144 | pydantic==2.4.0
145 | pydantic_core==2.10.0
146 | pydub==0.25.1
147 | Pygments==2.16.1
148 | pynvml==11.5.3
149 | pyparsing==3.1.1
150 | pypdfium2==4.20.0
151 | python-dateutil==2.8.2
152 | python-jose==3.3.0
153 | python-json-logger==2.0.7
154 | python-multipart==0.0.9
155 | pytz==2023.3.post1
156 | PyYAML==6.0.1
157 | pyzmq==25.1.1
158 | qtconsole==5.4.4
159 | QtPy==2.4.0
160 | quantile-python==1.1
161 | referencing==0.30.2
162 | regex==2023.8.8
163 | reportlab==4.0.5
164 | requests==2.31.0
165 | rfc3339-validator==0.1.4
166 | rfc3986-validator==0.1.1
167 | rich==13.7.1
168 | rpds-py==0.10.3
169 | rsa==4.9
170 | ruff==0.6.2
171 | safetensors==0.4.2
172 | scikit-learn==1.3.1
173 | scipy==1.11.2
174 | semantic-version==2.10.0
175 | Send2Trash==1.8.2
176 | sentencepiece==0.1.99
177 | shellingham==1.5.4
178 | simplejson==3.19.1
179 | six==1.16.0
180 | sniffio==1.3.0
181 | soupsieve==2.5
182 | SQLAlchemy==2.0.21
183 | sse-starlette==2.1.3
184 | stack-data==0.6.2
185 | starlette==0.37.2
186 | sympy==1.12
187 | tabulate==0.9.0
188 | tblib==3.0.0
189 | tenacity==8.2.3
190 | termcolor==2.3.0
191 | terminado==0.17.1
192 | threadpoolctl==3.2.0
193 | tiktoken==0.7.0
194 | timm==1.0.8
195 | tinycss2==1.2.1
196 | tokenizers==0.19.1
197 | tomli==2.0.1
198 | tomlkit==0.12.0
199 | toolz==0.12.0
200 | torch==2.4.0
201 | torchvision==0.19.0
202 | tornado==6.3.3
203 | tqdm==4.66.1
204 | traitlets==5.10.0
205 | transformers==4.44.2
206 | typer==0.11.1
207 | typing-inspect==0.9.0
208 | typing_extensions==4.12.2
209 | tzdata==2023.3
210 | uri-template==1.3.0
211 | urllib3==2.0.5
212 | uvicorn==0.23.2
213 | uvloop==0.20.0
214 | wcwidth==0.2.6
215 | webcolors==1.13
216 | webencodings==0.5.1
217 | websocket-client==1.6.3
218 | websockets==11.0.3
219 | Werkzeug==2.3.7
220 | widgetsnbextension==4.0.9
221 | xinference==0.14.2
222 | xoscar==0.3.3
223 | yarl==1.9.2
--------------------------------------------------------------------------------
/resource/AI-LangChain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/resource/AI-LangChain.png
--------------------------------------------------------------------------------
/resource/AI-LangChain.xmind:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/resource/AI-LangChain.xmind
--------------------------------------------------------------------------------
/resource/LangChain案例.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/resource/LangChain案例.png
--------------------------------------------------------------------------------
/resource/LangChain设计.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/resource/LangChain设计.png
--------------------------------------------------------------------------------
/resource/Langchain版Auto-GPT技术方案与架构设计.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/resource/Langchain版Auto-GPT技术方案与架构设计.png
--------------------------------------------------------------------------------
/resource/Sales-Consultant业务流程与价值分析.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/resource/Sales-Consultant业务流程与价值分析.png
--------------------------------------------------------------------------------
/resource/Sales-Consultant技术方案与架构设计.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/resource/Sales-Consultant技术方案与架构设计.png
--------------------------------------------------------------------------------
/resource/homework_openai_translator_v2.0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/resource/homework_openai_translator_v2.0.png
--------------------------------------------------------------------------------
/resource/open_ai_models.json:
--------------------------------------------------------------------------------
1 | {
2 | "model_total": 53,
3 | "model_list": [
4 | {
5 | "name": "gpt-3.5-turbo-0613",
6 | "created": "2023-06-13 00:30:34"
7 | },
8 | {
9 | "name": "gpt-3.5-turbo-16k-0613",
10 | "created": "2023-05-31 03:17:27"
11 | },
12 | {
13 | "name": "gpt-3.5-turbo-16k",
14 | "created": "2023-05-11 06:35:02"
15 | },
16 | {
17 | "name": "gpt-3.5-turbo-0301",
18 | "created": "2023-03-01 13:52:43"
19 | },
20 | {
21 | "name": "gpt-3.5-turbo",
22 | "created": "2023-03-01 02:56:42"
23 | },
24 | {
25 | "name": "whisper-1",
26 | "created": "2023-02-28 05:13:04"
27 | },
28 | {
29 | "name": "text-embedding-ada-002",
30 | "created": "2022-12-17 03:01:39"
31 | },
32 | {
33 | "name": "text-davinci-003",
34 | "created": "2022-11-28 09:40:35"
35 | },
36 | {
37 | "name": "ada-code-search-text",
38 | "created": "2022-04-29 03:01:50"
39 | },
40 | {
41 | "name": "babbage-search-document",
42 | "created": "2022-04-29 03:01:50"
43 | },
44 | {
45 | "name": "curie-similarity",
46 | "created": "2022-04-29 03:01:50"
47 | },
48 | {
49 | "name": "babbage-code-search-code",
50 | "created": "2022-04-29 03:01:49"
51 | },
52 | {
53 | "name": "babbage-code-search-text",
54 | "created": "2022-04-29 03:01:49"
55 | },
56 | {
57 | "name": "davinci-search-document",
58 | "created": "2022-04-29 03:01:49"
59 | },
60 | {
61 | "name": "curie-search-query",
62 | "created": "2022-04-29 03:01:49"
63 | },
64 | {
65 | "name": "text-search-curie-query-001",
66 | "created": "2022-04-29 03:01:49"
67 | },
68 | {
69 | "name": "text-search-babbage-doc-001",
70 | "created": "2022-04-29 03:01:49"
71 | },
72 | {
73 | "name": "text-search-curie-doc-001",
74 | "created": "2022-04-29 03:01:49"
75 | },
76 | {
77 | "name": "babbage-search-query",
78 | "created": "2022-04-29 03:01:49"
79 | },
80 | {
81 | "name": "text-search-babbage-query-001",
82 | "created": "2022-04-29 03:01:49"
83 | },
84 | {
85 | "name": "davinci-similarity",
86 | "created": "2022-04-29 03:01:49"
87 | },
88 | {
89 | "name": "curie-search-document",
90 | "created": "2022-04-29 03:01:48"
91 | },
92 | {
93 | "name": "code-search-babbage-text-001",
94 | "created": "2022-04-29 03:01:47"
95 | },
96 | {
97 | "name": "code-search-babbage-code-001",
98 | "created": "2022-04-29 03:01:47"
99 | },
100 | {
101 | "name": "ada-similarity",
102 | "created": "2022-04-29 03:01:47"
103 | },
104 | {
105 | "name": "code-search-ada-text-001",
106 | "created": "2022-04-29 03:01:47"
107 | },
108 | {
109 | "name": "text-search-ada-doc-001",
110 | "created": "2022-04-29 03:01:47"
111 | },
112 | {
113 | "name": "text-similarity-curie-001",
114 | "created": "2022-04-29 03:01:47"
115 | },
116 | {
117 | "name": "code-search-ada-code-001",
118 | "created": "2022-04-29 03:01:47"
119 | },
120 | {
121 | "name": "ada-search-document",
122 | "created": "2022-04-29 03:01:47"
123 | },
124 | {
125 | "name": "text-similarity-babbage-001",
126 | "created": "2022-04-29 03:01:45"
127 | },
128 | {
129 | "name": "babbage-similarity",
130 | "created": "2022-04-29 03:01:45"
131 | },
132 | {
133 | "name": "text-similarity-ada-001",
134 | "created": "2022-04-29 03:01:45"
135 | },
136 | {
137 | "name": "ada-code-search-code",
138 | "created": "2022-04-29 03:01:45"
139 | },
140 | {
141 | "name": "text-search-ada-query-001",
142 | "created": "2022-04-29 03:01:45"
143 | },
144 | {
145 | "name": "ada-search-query",
146 | "created": "2022-04-29 03:01:45"
147 | },
148 | {
149 | "name": "text-search-davinci-query-001",
150 | "created": "2022-04-29 03:01:45"
151 | },
152 | {
153 | "name": "davinci-search-query",
154 | "created": "2022-04-29 03:01:45"
155 | },
156 | {
157 | "name": "text-search-davinci-doc-001",
158 | "created": "2022-04-29 03:01:45"
159 | },
160 | {
161 | "name": "text-similarity-davinci-001",
162 | "created": "2022-04-29 03:01:45"
163 | },
164 | {
165 | "name": "code-davinci-edit-001",
166 | "created": "2022-04-14 04:08:04"
167 | },
168 | {
169 | "name": "text-davinci-002",
170 | "created": "2022-04-14 04:08:04"
171 | },
172 | {
173 | "name": "text-davinci-edit-001",
174 | "created": "2022-04-13 08:19:39"
175 | },
176 | {
177 | "name": "text-curie-001",
178 | "created": "2022-04-08 04:40:43"
179 | },
180 | {
181 | "name": "text-babbage-001",
182 | "created": "2022-04-08 04:40:43"
183 | },
184 | {
185 | "name": "text-davinci-001",
186 | "created": "2022-04-08 04:40:42"
187 | },
188 | {
189 | "name": "text-ada-001",
190 | "created": "2022-04-08 04:40:42"
191 | },
192 | {
193 | "name": "curie-instruct-beta",
194 | "created": "2022-04-08 04:40:42"
195 | },
196 | {
197 | "name": "davinci-instruct-beta",
198 | "created": "2022-04-08 04:40:42"
199 | },
200 | {
201 | "name": "davinci",
202 | "created": "2022-04-08 03:31:14"
203 | },
204 | {
205 | "name": "curie",
206 | "created": "2022-04-08 03:31:14"
207 | },
208 | {
209 | "name": "babbage",
210 | "created": "2022-04-08 03:07:29"
211 | },
212 | {
213 | "name": "ada",
214 | "created": "2022-04-08 02:51:31"
215 | }
216 | ]
217 | }
218 |
219 |
--------------------------------------------------------------------------------
/resource/prompt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/resource/prompt.png
--------------------------------------------------------------------------------
/resource/使用FAISS向量数据库存储销售问答话术.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/resource/使用FAISS向量数据库存储销售问答话术.png
--------------------------------------------------------------------------------
/resource/使用Gradio实现聊天机器人的图形化界面.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/resource/使用Gradio实现聊天机器人的图形化界面.png
--------------------------------------------------------------------------------
/resource/使用RetrievalQA检索销售话术数据_similarity.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/resource/使用RetrievalQA检索销售话术数据_similarity.png
--------------------------------------------------------------------------------
/resource/使用RetrievalQA检索销售话术数据_topk.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/resource/使用RetrievalQA检索销售话术数据_topk.png
--------------------------------------------------------------------------------
/resource/基于知识库问答的典型用例.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/resource/基于知识库问答的典型用例.png
--------------------------------------------------------------------------------
/resource/笔记1-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/resource/笔记1-2.png
--------------------------------------------------------------------------------
/resource/笔记2-3-4.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/resource/笔记2-3-4.1.png
--------------------------------------------------------------------------------
/resource/笔记2-3-4.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/resource/笔记2-3-4.2.png
--------------------------------------------------------------------------------
/resource/销售话术.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShengqinYang/AINote/b2882d3cf5f0ee00dad7d4bde955368c37327ae6/resource/销售话术.png
--------------------------------------------------------------------------------