2023/08/31
はじめに
本コードの動作確認は2023/05時点までしか行っていません。
当時動作していたコードをそのまま公開いたします。
現在のAPIでの動作確認はしていないこと、ご了承ください。
以前、OpenAIのChat Completionsを叩くアプリを作っていた。 しかし、いつしか熱が冷めて開発が止まっていたので、眠らせておくくらいならと思い、コードを公開する。
また、一つの記事にまとめたかったが、ボリュームが大きくなりすぎてしまったので、記事をいくつかに分割した。
目次
- 0 概要
- 1 カスタムエラー
- 2 型定義
- 3 リクエストユーティリティ
- 4 モジュール本体
実装対象
ここでは、モジュールのために利用するエラーを定義しておく。モジュールそのもので吐き出すエラー以外に、外部クレートによるエラーの変換も統合しておく。
src/
└── chatter
├── error.rs # <-
├── headers.rs
├── json.rs
├── message.rs
├── mod.rs
├── request_builder.rs
├── role.rs
└── stream_data.rs
コード
error.rs
use reqwest::header::InvalidHeaderValue;
use std::{fmt, io};
use thiserror::Error;
pub type ChatterResult<T> = Result<T, ChatterError>;
#[derive(Debug)]
pub(super) struct UnitError;
impl fmt::Display for UnitError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "UnitError")
}
}
impl std::error::Error for UnitError {}
#[derive(Debug, Error)]
pub enum ChatterError {
#[error("I/O error occurred: {0}")]
IoError(#[from] io::Error),
#[error("error occurred: {0}")]
InvalidHeaderValue(#[from] InvalidHeaderValue),
#[error("error occurred: {0}")]
ReqwestError(#[from] reqwest::Error),
#[error("Error occurred on from_str::<StreamData>()")]
StreamParsingError,
#[error("Error occurred on to_stream_data()")]
StreamDataConvertingError,
#[error("Error occurred on send()")]
DuplicatedSendingError,
#[error("undefined error")]
UnknownError,
}
impl From<ChatterError> for io::Error {
fn from(value: ChatterError) -> Self {
match value {
ChatterError::IoError(e) => e,
_ => io::Error::new(io::ErrorKind::Other, format!("{value}")),
}
}
}
解説
error.rs
受け取れるようにするクレートのエラー型などをuse
use reqwest::header::InvalidHeaderValue;
use std::{fmt, io};
use thiserror::Error;
カスタムエラー返すResultを簡潔に利用できるように型エイリアスを定義
pub type ChatterResult<T> = Result<T, ChatterError>;
当時のコードに含まれていたが、おそらくここは不要。意図としては、「空のエラー(=とりあえず投げるエラー)」を目的とする型で開発段階で利用していた。
#[derive(Debug)]
pub(super) struct UnitError;
impl fmt::Display for UnitError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "UnitError")
}
}
impl std::error::Error for UnitError {}
本題であるカスタムエラーの定義。
io::Error
, InvalidHeaderValue
, reqwest::Error
空の変換を定義しつつ、モジュール内コードで発生するエラーを定義しておく。
UnknownError
は、今回公開するコード内では使っていないが、開発段階で利用していた。
#[derive(Debug, Error)]
pub enum ChatterError {
#[error("I/O error occurred: {0}")]
IoError(#[from] io::Error),
#[error("error occurred: {0}")]
InvalidHeaderValue(#[from] InvalidHeaderValue),
#[error("error occurred: {0}")]
ReqwestError(#[from] reqwest::Error),
#[error("Error occurred on from_str::<StreamData>()")]
StreamParsingError,
#[error("Error occurred on to_stream_data()")]
StreamDataConvertingError,
#[error("Error occurred on send()")]
DuplicatedSendingError,
#[error("undefined error")]
UnknownError,
}
io::Error
への変換を実装しておくことで、io::Result
で?
を使えるようにする。
impl From<ChatterError> for io::Error {
fn from(value: ChatterError) -> Self {
match value {
ChatterError::IoError(e) => e,
_ => io::Error::new(io::ErrorKind::Other, format!("{value}")),
}
}
}