写在前面

  • 解析 Json?
  • 自己动手吗?
  • 不用!

Extract JSONL text.

2024年7月8日
https://chatgpt.com/share/7b1772f6-e298-4caa-90e9-f4c3c70438d1


Extract JSONL text.

🧑‍🦰User

1
我有一个文件,其中每一行都是一个 JSON 对象(类似于 jsonl 格式)。每个 JSON 对象都有一个名为 "text" 的字段,以及一些我不关心的其他内容。能否编写一个 python 函数,提取每行的 "text" 字段?

🤖 Assistant

当然!以下是一个 python 函数,它读取一个 JSONL 文件,并从每行中提取 “text” 字段的值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import json

def extract_text_from_jsonl(file_path):
extracted_texts = []

with open(file_path, 'r') as file:
for line in file:
json_object = json.loads(line)
if "text" in json_object:
extracted_texts.append(json_object["text"])

return extracted_texts

# Example usage:
file_path = 'your_file.jsonl'
texts = extract_text_from_jsonl(file_path)
print(texts)

'your_file.jsonl' 替换为 JSONL 文件的路径。该函数将返回一个包含每行 “text” 字段值的字符串列表。

🧑‍🦰User

1
能否用 Rust 实现这个功能?

🤖 Assistant

当然!以下是用 Rust 实现的函数,它读取 JSONL 文件,并提取每行中的 “text” 字段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
use std::fs::File;
use std::io::{BufRead, BufReader};
use serde_json::Value;
use std::path::Path;
use std::error::Error;

fn extract_text_from_jsonl(file_path: &amp;Path) -> Result<Vec<String>, Box<dyn Error>> {
let file = File::open(file_path)?;
let reader = BufReader::new(file);
let mut extracted_texts = Vec::new();

for line in reader.lines() {
let line = line?;
let json_object: Value = serde_json::from_str(&amp;line)?;

if let Some(text) = json_object.get("text") {
if let Some(text) = text.as_str() {
extracted_texts.push(text.to_string());
}
}
}

Ok(extracted_texts)
}

// Example usage:
fn main() {
let file_path = Path::new("your_file.jsonl");
match extract_text_from_jsonl(&amp;file_path) {
Ok(texts) => println!("{:?}", texts),
Err(e) => println!("Error: {}", e),
}
}

在您的 Cargo.toml 文件中添加以下依赖:

1
2
3
[dependencies]
Serde = { version = "1.0", features = ["derive"] }
Serde_json = "1.0"

"your_file.jsonl" 替换为 JSONL 文件路径。函数将返回 Result<Vec<String>, Box<dyn Error>>,如果成功,它将返回一个包含每行 “text” 字段值的字符串列表。

🧑‍🦰User

1
出现了 "unresolved import `serde_json`" 错误怎么办?

🤖 Assistant

抱歉,可能是没有添加必要的依赖项。请确保在 Cargo.toml 文件中添加了 serdeserde_json 依赖:

1
2
3
[dependencies]
Serde = { version = "1.0", features = ["derive"] }
Serde_json = "1.0"

Cargo.toml 中添加依赖项后,运行 cargo build 下载并编译这些依赖项。然后,Rust 代码应该能正确编译,不会出现未解析的导入错误。如果还有问题,请告诉我!

🧑‍🦰User

1
需要在 Rust 代码中添加 crate 吗?

🤖 Assistant

对不起,之前的解释有些混乱。现在 Rust 的 2018 版已经不再需要手动添加 extern crate 语句。只要在 Cargo.toml 中添加了必要的依赖项,之前的代码应该可以正常工作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
extern crate serde;
extern crate serde_json;

use std::fs::File;
use std::io::{BufRead, BufReader};
use serde_json::Value;
use std::path::Path;
use std::error::Error;

fn extract_text_from_jsonl(file_path: &amp;Path) -> Result<Vec<String>, Box<dyn Error>> {
let file = File::open(file_path)?;
let reader = BufReader::new(file);
let mut extracted_texts = Vec::new();

for line in reader.lines() {
let line = line?;
let json_object: Value = serde_json::from_str(&amp;line)?;

if let Some(text) = json_object.get("text") {
if let Some(text) = text.as_str() {
extracted_texts.push(text.to_string());
}
}
}

Ok(extracted_texts)
}

// Example usage:
fn main() {
let file_path = Path::new("your_file.jsonl");
match extract_text_from_jsonl(&amp;file_path) {
Ok(texts) => println!("{:?}", texts),
Err(e) => println!("Error: {}", e),
}
}

不过,从 Rust 2018 版开始,大多数情况下不再需要使用 extern crate 语句。只要在 Cargo.toml 文件中添加了所需的依赖项,之前的代码在没有 extern crate 语句的情况下也能正常运行。

如果您使用的是较早的 Rust 版本,可能仍然需要在代码中包含 extern crate 语句,如更新后的代码所示。要检查您使用的是哪个版本,可以查看 Cargo.toml 文件中的 edition 字段:

1
2
3
4
[package]
Name = "your_project"
Version = "0.1.0"
Edition = "2018"

如果您使用的是 2018 版或更新的 Rust,可以去掉 extern crate 语句,代码依然能正常运行。

🧑‍🦰User

1
能否使用 `tokenizers` 库对每一行进行 Byte-Pair 编码?不用重新训练模型,直接使用磁盘上的现有模型。

🤖 Assistant

当然!要使用 tokenizers 库进行 Byte-Pair 编码,您可以加载磁盘上的预训练模型,然后对每一行的文本进行编码。以下是更新后的 Rust 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
extern crate tokenizers;
extern crate serde;
extern crate serde_json;

use std::fs::File;
use std::io::{BufRead, BufReader};
use serde_json::Value;
use std::path::Path;
use std::error::Error;
use tokenizers::tokenizer::Tokenizer;

fn extract_and_encode_text_from_jsonl(
file_path: &amp;Path,
tokenizer_path: &amp;Path,
) -> Result<Vec<Vec<u32>>, Box<dyn Error>> {
let file = File::open(file_path)?;
let reader = BufReader::new(file);
let mut extracted_texts = Vec::new();

let tokenizer = Tokenizer::from_file(tokenizer_path.to_str().unwrap())?;

for line in reader.lines() {
let line = line?;
let json_object: Value = serde_json::from_str(&amp;line)?;

if let Some(text) = json_object.get("text") {
if let Some(text) = text.as_str() {
let encoding = tokenizer.encode(text, true)?;
extracted_texts.push(encoding.get_ids().to_vec());
}
}
}

Ok(extracted_texts)
}

// Example usage:
fn main() {
let file_path = Path::new("your_file.jsonl");
let tokenizer_path = Path::new("path/to/your/tokenizer.json");

match extract_and_encode_text_from_jsonl(&amp;file_path, &amp;tokenizer_path) {
Ok(encoded_texts) => println!("{:?}", encoded_texts),
Err(e) => println!("Error: {}", e),
}
}

在您的 Cargo.toml 文件中添加以下依赖:

1
2
3
4
[dependencies]
Serde = { version = "1.0", features = ["derive"] }
Serde_json = "1.0"
Tokenizers = "0.11"

"your_file.jsonl" 替换为 JSONL 文件路径,将 "path/to/your/tokenizer.json" 替换为预训练 tokenizer 的路径。

函数 extract_and_encode_text_from_jsonl 需要两个路径作为输入:一个是 JSONL 文件路径,另一个是预训练的 tokenizer 文件路径。它将返回 Result<Vec<Vec<u32>>, Box<dyn Error>>。如果成功,返回的将是一个向量,其中每个内部向量都是经过 Byte-Pair 编码的文本。

🧑‍🦰User

1
这行代码 `let tokenizer = Tokenizer::from_file(tokenizer_path.to_str().unwrap())?;` 显示 "doesn't have a size known at compile-time" 错误。

🤖 Assistant

对不起,之前代码有些问题。Tokenizers 库需要 String 类型的文件路径,而不是 Path。以下是修正后的 Rust 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
extern crate tokenizers;
extern crate serde;
extern crate serde_json;

use std::fs::File;
use std::io::{BufRead, BufReader};
use serde_json::Value;
use std::path::Path;
use std::error::Error;
use tokenizers::tokenizer::Tokenizer;

fn extract_and_encode_text_from_jsonl(
file_path: &amp;Path,
tokenizer_path: &amp;Path,
) -> Result<Vec<Vec<u32>>, Box<dyn Error>> {
let file = File::open(file_path)?;
let reader = BufReader::new(file);
let mut extracted_texts = Vec::new();

let tokenizer = Tokenizer::from_file(tokenizer_path.to_str().unwrap().to_string())?;

for line in reader.lines() {
let line = line?;
let json_object: Value = serde_json::from_str(&amp;line)?;

if let Some(text) = json_object.get("text") {
if let Some(text) = text.as_str() {
let encoding = tokenizer.encode(text, true)?;
extracted_texts.push(encoding.get_ids().to_vec());
}
}
}

Ok(extracted_texts)
}

// Example usage:
fn main() {
let file_path = Path::new("your_file.jsonl");
let tokenizer_path = Path::new("path/to/your/tokenizer.json");

match extract_and_encode_text_from_jsonl(&amp;file_path, &amp;tokenizer_path) {
Ok(encoded_texts) => println!("{:?}", encoded_texts),
Err(e) => println!("Error: {}", e),
}
}

let tokenizer = Tokenizer::from_file(tokenizer_path.to_str().unwrap())?; 替换为 let tokenizer = Tokenizer::from_file(tokenizer_path.to_str().unwrap().to_string())?;,这样就修复了错误。

现在代码应该能够正确编译并正常工作。