Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ env:

jobs:
build:
name: ${{ matrix.os }}
strategy:
matrix:
os: [macos-latest, windows-latest]
fail-fast: false
name: ${{ matrix.os }}
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v6
Expand Down
67 changes: 35 additions & 32 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -1,32 +1,35 @@
name: Lint

on:
push:
branches: ['main']
pull_request:

env:
REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}

jobs:
lint:
runs-on: ubuntu-latest
steps:
# refer: https://v2.tauri.app/start/prerequisites/#linux
- run: |
sudo apt update
sudo apt install libwebkit2gtk-4.1-dev \
build-essential \
curl \
wget \
file \
libxdo-dev \
libssl-dev \
libayatana-appindicator3-dev \
librsvg2-dev
- uses: actions/checkout@v6
- uses: Swatinem/rust-cache@v2
- uses: reviewdog/action-setup@v1
- run: cargo check -q --message-format=short | reviewdog -f cargo-check -reporter=github-check
- run: cargo clippy -q --message-format=short | reviewdog -f clippy -reporter=github-check
- uses: bnjbvr/cargo-machete@main
name: Lint
Comment thread
fffonion marked this conversation as resolved.

on:
push:
branches: ['main']
pull_request:

env:
CARGO_TERM_COLOR: always

jobs:
lint:
name: Lint
env:
REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
runs-on: ubuntu-latest
steps:
# refer: https://v2.tauri.app/start/prerequisites/#linux
- run: |
sudo apt update
sudo apt install libwebkit2gtk-4.1-dev \
build-essential \
curl \
wget \
file \
libxdo-dev \
libssl-dev \
libayatana-appindicator3-dev \
librsvg2-dev
- uses: actions/checkout@v6
- uses: Swatinem/rust-cache@v2
- uses: reviewdog/action-setup@v1
- run: cargo check -q --message-format=short | reviewdog -f cargo-check -reporter=github-check
- run: cargo clippy -q --message-format=short | reviewdog -f clippy -reporter=github-check
- uses: bnjbvr/cargo-machete@main
32 changes: 32 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Test

on:
push:
branches: ['main']
pull_request:

env:
CARGO_TERM_COLOR: always

jobs:
test:
name: Integration tests
runs-on: ubuntu-latest
steps:
# refer: https://v2.tauri.app/start/prerequisites/#linux
- run: |
sudo apt update
sudo apt install libwebkit2gtk-4.1-dev \
build-essential \
curl \
wget \
file \
libxdo-dev \
libssl-dev \
libayatana-appindicator3-dev \
librsvg2-dev \
fonts-noto-cjk
- uses: actions/checkout@v6
- uses: Swatinem/rust-cache@v2
- run: cargo test --no-run
- run: cargo test --workspace --tests
23 changes: 16 additions & 7 deletions koharu-ml/src/lama/fft/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,16 +104,21 @@ pub fn irfft2(storage: &CpuStorage, layout: &Layout, width: usize) -> Result<(Cp
let base = x * 2;
*c = Complex32::new(row[base], row[base + 1]);
}
for x in 1..w_half {
let mirror = width - x;
dst_row[mirror] = dst_row[x].conj();
}
}

for row in buffer.chunks_exact_mut(width) {
ifft_w.process(row);
// Reconstruct the full complex spectrum using the conjugate symmetry
// property of real-valued signals: F(-ky, -kx) = conj(F(ky, kx)).
for ky in 0..height {
let mirror_ky = if ky == 0 { 0 } else { height - ky };
let row_start = ky * width;
let mirror_row_start = mirror_ky * width;
for kx in 1..w_half {
let mirror_kx = width - kx;
Comment thread
mayocream marked this conversation as resolved.
buffer[row_start + mirror_kx] = buffer[mirror_row_start + kx].conj();
}
}

// Apply the inverse transform in the reverse order of the forward pass:
// first undo the height transform, then undo the width transform.
for x in 0..width {
for (dst, src) in col_buffer
.iter_mut()
Expand All @@ -132,6 +137,10 @@ pub fn irfft2(storage: &CpuStorage, layout: &Layout, width: usize) -> Result<(Cp
}
}

for row in buffer.chunks_exact_mut(width) {
ifft_w.process(row);
}

let out_plane = &mut dst[bc * plane_out_stride..(bc + 1) * plane_out_stride];
for (out, val) in out_plane.iter_mut().zip(buffer.iter()) {
*out = val.re;
Expand Down
5 changes: 2 additions & 3 deletions koharu-ml/tests/comic_text_detector.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
use std::path::Path;

use koharu_ml::{comic_text_detector::ComicTextDetector, device};
use koharu_ml::comic_text_detector::ComicTextDetector;

#[tokio::test]
async fn comic_text_detector() -> anyhow::Result<()> {
let device = device(true)?;
let model = ComicTextDetector::load(device).await?;
let model = ComicTextDetector::load(false).await?;

let img = image::open(Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/1.jpg"))?;
let (boxes, mask) = model.inference(&img)?;
Expand Down
Binary file added koharu-ml/tests/fixtures/dialog.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added koharu-ml/tests/fixtures/image.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added koharu-ml/tests/fixtures/mask.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
36 changes: 36 additions & 0 deletions koharu-ml/tests/inpaint.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use std::path::Path;

use koharu_ml::lama::Lama;
use image::GenericImageView;

#[tokio::test]
async fn lama_inpainting_updates_masked_region() -> anyhow::Result<()> {
let fixtures = Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures");

let lama = Lama::load(false).await?;
let base = image::open(fixtures.join("image.jpg"))?;
let mask = image::open(fixtures.join("mask.png"))?;

let output = lama.inference(&base, &mask)?;

assert_eq!(output.dimensions(), base.dimensions());

let mask = mask.to_luma8();
let base = base.to_rgb8();
let output = output.to_rgb8();

let mut changed = false;
for ((mask_px, base_px), out_px) in mask
.pixels()
.zip(base.pixels())
.zip(output.pixels())
{
if mask_px.0[0] > 0 && base_px.0 != out_px.0 {
changed = true;
break;
}
}

assert!(changed, "inpainting should change at least one masked pixel");
Ok(())
}
29 changes: 29 additions & 0 deletions koharu-ml/tests/llm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use koharu_ml::llm::{GenerateOptions, Llm, ModelId};
use strum::IntoEnumIterator;

#[tokio::test]
async fn llm_generates_text_for_all_models() -> anyhow::Result<()> {
let prompt = "こんにちは、テストです。";

for model in ModelId::iter() {
let mut llm = Llm::load(model, false).await?;
let opts = GenerateOptions {
max_tokens: 32,
temperature: 0.0,
top_k: None,
top_p: None,
seed: 1,
split_prompt: false,
repeat_penalty: 1.0,
repeat_last_n: 64,
};

let generated = llm.generate(prompt, &opts)?;
assert!(
!generated.trim().is_empty(),
"model {model:?} should return some text"
);
}

Ok(())
}
20 changes: 20 additions & 0 deletions koharu-ml/tests/ocr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use std::path::Path;

use koharu_ml::manga_ocr::MangaOcr;

#[tokio::test]
async fn manga_ocr_reads_dialog_image() -> anyhow::Result<()> {
let fixtures = Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures");
let image = image::open(fixtures.join("dialog.jpg"))?;

let ocr = MangaOcr::load(false).await?;
let results = ocr.inference(&[image])?;

assert_eq!(results.len(), 1);
assert!(
!results[0].trim().is_empty(),
"OCR result should contain text"
);

Ok(())
}
Loading