<commit_before>import * as React from "react";
import { FarmbotColorPicker } from "../farmbot_picker";
import { BlurableInput } from "../../ui/index";
import { ImageFlipper } from "../image_flipper";
import { HSV } from "../interfaces";
import { WeedDetectorSlider } from "./slider";
import { TaggedImage } from "../../resources/tagged_resources";
import { t } from "i18next";
import * as _ from "lodash";

const RANGES = {
  H: { LOWEST: 0, HIGHEST: 179 },
  S: { LOWEST: 0, HIGHEST: 255 },
  V: { LOWEST: 0, HIGHEST: 255 },
  BLUR: { LOWEST: 0, HIGHEST: 100 },
  MORPH: { LOWEST: 0, HIGHEST: 100 },
  ITERATION: { LOWEST: 0, HIGHEST: 100 },
};

/** Number values that the <ImageWorkspace/> panel deals with. */
export interface NumericValues {
  iteration: number;
  morph: number;
  blur: number;
  H_LO: number;
  H_HI: number;
  S_LO: number;
  S_HI: number;
  V_LO: number;
  V_HI: number;
}

type NumericKeyName = keyof NumericValues;

interface Props extends NumericValues {
  onFlip(uuid: string | undefined): void;
  onProcessPhoto(image_id: number): void;
  currentImage: TaggedImage | undefined;
  images: TaggedImage[];
  onChange(key: NumericKeyName, value: number): void;
}

/** Mapping of HSV values to FBOS Env variables. */
let CHANGE_MAP: Record<HSV, [NumericKeyName, NumericKeyName]> = {
  H: ["H_LO", "H_HI"],
  S: ["S_LO", "S_HI"],
  V: ["V_LO", "V_HI"]
};

export class ImageWorkspace extends React.Component<Props, {}> {
  /** Generates a function to handle changes to blur/morph/iteration. */
  numericChange = (key: NumericKeyName) =>
    (e: React.SyntheticEvent<HTMLInputElement>) => {
      this.props.onChange(key, parseInt(e.currentTarget.value, 10) || 0);
    };

  maybeProcessPhoto = () => {
    let img = this.props.currentImage || this.props.images[0];
    if (img && img.body.id) {
      this.props.onProcessPhoto(img.body.id);
    }
  };

  /** This will trigger onChange callback twice. Once for (H|S|L)_HI and again
   * for (H|S|L)_LO */
  onHslChange = (key: keyof typeof CHANGE_MAP) =>
    (values: [number, number]) => {
      let keys = CHANGE_MAP[key];
      [0, 1].map(i => this.props.onChange(keys[i], values[i]));
    };

  render() {
    let { H_LO, H_HI, S_LO, S_HI, V_LO, V_HI } = this.props;

    return <div className="widget-content">
      <div className="row">
        <div className="col-md-6 col-sm-12">
          <h4>
            <i>{t("Color Range")}</i>
          </h4>
          <label htmlFor="hue">{t("HUE")}</label>
          <WeedDetectorSlider
            onRelease={this.onHslChange("H")}
            lowest={RANGES.H.LOWEST}
            highest={RANGES.H.HIGHEST}
            lowValue={H_LO}
            highValue={H_HI} />
          <label htmlFor="saturation">{t("SATURATION")}</label>
          <WeedDetectorSlider
            onRelease={this.onHslChange("S")}
            lowest={RANGES.S.LOWEST}
            highest={RANGES.S.HIGHEST}
            lowValue={S_LO}
            highValue={S_HI} />
          <label htmlFor="value">{t("VALUE")}</label>
          <WeedDetectorSlider
            onRelease={this.onHslChange("V")}
            lowest={RANGES.V.LOWEST}
            highest={RANGES.V.HIGHEST}
            lowValue={V_LO}
            highValue={V_HI} />
        </div>
        <div className="col-md-6 col-sm-12">
          <FarmbotColorPicker
            h={[H_LO, H_HI]}
            s={[S_LO, S_HI]}
            v={[V_LO, V_HI]} />
        </div>
      </div>
      <div className="row">
        <div className="col-md-12 col-sm-12">
          <h4>
            <i>{t("Processing Parameters")}</i>
          </h4>
        </div>

        <div className="col-md-4 col-sm-4">
          <label>{t("BLUR")}</label>
          <BlurableInput type="number"
            min={RANGES.BLUR.LOWEST}
            max={RANGES.BLUR.HIGHEST}
            onCommit={this.numericChange("blur")}
            value={"" + this.props.blur} />
        </div>

        <div className="col-md-4 col-sm-4">
          <label>{t("MORPH")}</label>
          <BlurableInput type="number"
            min={RANGES.MORPH.LOWEST}
            max={RANGES.MORPH.HIGHEST}
            onCommit={this.numericChange("morph")}
            value={"" + this.props.morph} />
        </div>
        <div className="col-md-4 col-sm-4">
          <label>{t("ITERATION")}</label>
          <BlurableInput type="number"
            min={RANGES.ITERATION.LOWEST}
            max={RANGES.ITERATION.HIGHEST}
            onCommit={this.numericChange("iteration")}
            value={"" + this.props.iteration} />
        </div>
      </div>
      <button
        className="green fb-button"
        title="Scan this image for Weeds"
        onClick={this.maybeProcessPhoto}
        hidden={!this.props.images.length} >
        {t("Scan for Weeds")}
      </button>
      <ImageFlipper
        onFlip={this.props.onFlip}
        images={this.props.images}
        currentImage={this.props.currentImage} />
    </div>;
  }
}<commit_msg>weed detector styles<commit_after>import * as React from "react";
import { FarmbotColorPicker } from "../farmbot_picker";
import { BlurableInput, Row, Col } from "../../ui/index";
import { ImageFlipper } from "../image_flipper";
import { HSV } from "../interfaces";
import { WeedDetectorSlider } from "./slider";
import { TaggedImage } from "../../resources/tagged_resources";
import { t } from "i18next";
import * as _ from "lodash";

const RANGES = {
  H: { LOWEST: 0, HIGHEST: 179 },
  S: { LOWEST: 0, HIGHEST: 255 },
  V: { LOWEST: 0, HIGHEST: 255 },
  BLUR: { LOWEST: 0, HIGHEST: 100 },
  MORPH: { LOWEST: 0, HIGHEST: 100 },
  ITERATION: { LOWEST: 0, HIGHEST: 100 },
};

/** Number values that the <ImageWorkspace/> panel deals with. */
export interface NumericValues {
  iteration: number;
  morph: number;
  blur: number;
  H_LO: number;
  H_HI: number;
  S_LO: number;
  S_HI: number;
  V_LO: number;
  V_HI: number;
}

type NumericKeyName = keyof NumericValues;

interface Props extends NumericValues {
  onFlip(uuid: string | undefined): void;
  onProcessPhoto(image_id: number): void;
  currentImage: TaggedImage | undefined;
  images: TaggedImage[];
  onChange(key: NumericKeyName, value: number): void;
}

/** Mapping of HSV values to FBOS Env variables. */
let CHANGE_MAP: Record<HSV, [NumericKeyName, NumericKeyName]> = {
  H: ["H_LO", "H_HI"],
  S: ["S_LO", "S_HI"],
  V: ["V_LO", "V_HI"]
};

export class ImageWorkspace extends React.Component<Props, {}> {
  /** Generates a function to handle changes to blur/morph/iteration. */
  numericChange = (key: NumericKeyName) =>
    (e: React.SyntheticEvent<HTMLInputElement>) => {
      this.props.onChange(key, parseInt(e.currentTarget.value, 10) || 0);
    };

  maybeProcessPhoto = () => {
    let img = this.props.currentImage || this.props.images[0];
    if (img && img.body.id) {
      this.props.onProcessPhoto(img.body.id);
    }
  };

  /** This will trigger onChange callback twice. Once for (H|S|L)_HI and again
   * for (H|S|L)_LO */
  onHslChange = (key: keyof typeof CHANGE_MAP) =>
    (values: [number, number]) => {
      let keys = CHANGE_MAP[key];
      [0, 1].map(i => this.props.onChange(keys[i], values[i]));
    };

  render() {
    let { H_LO, H_HI, S_LO, S_HI, V_LO, V_HI } = this.props;

    return (
      <div className="widget-content">
        <Row>
          <Col xs={12} md={6}>
            <h4>
              <i>{t("Color Range")}</i>
            </h4>
            <label htmlFor="hue">{t("HUE")}</label>
            <WeedDetectorSlider
              onRelease={this.onHslChange("H")}
              lowest={RANGES.H.LOWEST}
              highest={RANGES.H.HIGHEST}
              lowValue={H_LO}
              highValue={H_HI} />
            <label htmlFor="saturation">{t("SATURATION")}</label>
            <WeedDetectorSlider
              onRelease={this.onHslChange("S")}
              lowest={RANGES.S.LOWEST}
              highest={RANGES.S.HIGHEST}
              lowValue={S_LO}
              highValue={S_HI} />
            <label htmlFor="value">{t("VALUE")}</label>
            <WeedDetectorSlider
              onRelease={this.onHslChange("V")}
              lowest={RANGES.V.LOWEST}
              highest={RANGES.V.HIGHEST}
              lowValue={V_LO}
              highValue={V_HI} />
          </Col>
          <Col xs={12} md={6}>
            <FarmbotColorPicker
              h={[H_LO, H_HI]}
              s={[S_LO, S_HI]}
              v={[V_LO, V_HI]} />
          </Col>
        </Row>
        <Row>
          <Col xs={12}>
            <h4>
              <i>{t("Processing Parameters")}</i>
            </h4>
          </Col>

          <Col xs={4}>
            <label>{t("BLUR")}</label>
            <BlurableInput type="number"
              min={RANGES.BLUR.LOWEST}
              max={RANGES.BLUR.HIGHEST}
              onCommit={this.numericChange("blur")}
              value={"" + this.props.blur} />
          </Col>

          <Col xs={4}>
            <label>{t("MORPH")}</label>
            <BlurableInput type="number"
              min={RANGES.MORPH.LOWEST}
              max={RANGES.MORPH.HIGHEST}
              onCommit={this.numericChange("morph")}
              value={"" + this.props.morph} />
          </Col>
          <Col xs={4}>
            <label>{t("ITERATION")}</label>
            <BlurableInput type="number"
              min={RANGES.ITERATION.LOWEST}
              max={RANGES.ITERATION.HIGHEST}
              onCommit={this.numericChange("iteration")}
              value={"" + this.props.iteration} />
          </Col>
        </Row>
        <Row>
          <Col xs={12}>
            <button
              className="green fb-button"
              title="Scan this image for Weeds"
              onClick={this.maybeProcessPhoto}
              hidden={!this.props.images.length} >
              {t("Scan for Weeds")}
            </button>
          </Col>
        </Row>
        <ImageFlipper
          onFlip={this.props.onFlip}
          images={this.props.images}
          currentImage={this.props.currentImage} />
      </div>
    );
  }
}
{'fraction_non_alphanumeric': 0.16149253731343283, 'fraction_numerical': 0.010049751243781095, 'mean_word_length': 2.1726641414141414, 'pattern_counts': {'":': 0, '<': 111, '<?xml version=': 0, '>': 123, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2880472', 'n_tokens_mistral': 3524, 'n_tokens_neox': 3430, 'n_words': 659}