Ma77Ball commented on code in PR #6659:
URL: https://github.com/apache/texera/pull/6659#discussion_r3627119481


##########
common/workflow-operator/src/test/scala/org/apache/texera/amber/operator/huggingFace/codegen/ImageTaskCodegenSpec.scala:
##########
@@ -0,0 +1,224 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.texera.amber.operator.huggingFace.codegen
+
+import org.apache.texera.amber.pybuilder.PyStringTypes.EncodableString
+import org.scalatest.flatspec.AnyFlatSpec
+import org.scalatest.matchers.should.Matchers
+
+class ImageTaskCodegenSpec extends AnyFlatSpec with Matchers {
+
+  private def makeCtx(
+      hfApiToken: EncodableString = "token",
+      modelId: EncodableString = "Salesforce/blip-vqa-base",
+      promptColumn: EncodableString = "prompt",
+      resultColumn: EncodableString = "hf_response",
+      task: EncodableString = "image-classification",
+      systemPrompt: EncodableString = "You are a helpful assistant.",
+      safeMaxTokens: Int = 256,
+      safeTemp: Double = 0.7,
+      imageInput: EncodableString = "pic.png",
+      inputImageColumn: EncodableString = "image",
+      candidateLabels: EncodableString = "cat,dog"
+  ): CodegenContext =
+    CodegenContext(
+      hfApiToken = hfApiToken,
+      modelId = modelId,
+      promptColumn = promptColumn,
+      resultColumn = resultColumn,
+      task = task,
+      systemPrompt = systemPrompt,
+      safeMaxTokens = safeMaxTokens,
+      safeTemp = safeTemp,
+      imageInput = imageInput,
+      inputImageColumn = inputImageColumn,
+      candidateLabels = candidateLabels
+    )
+
+  "ImageTaskCodegen.task" should "be the canonical image-classification 
string" in {
+    ImageTaskCodegen.task shouldBe "image-classification"
+  }
+
+  "ImageTaskCodegen.tasks" should "cover exactly the nine image task families" 
in {
+    ImageTaskCodegen.tasks shouldBe Set(
+      "image-classification",
+      "object-detection",
+      "image-segmentation",
+      "image-to-text",
+      "visual-question-answering",
+      "document-question-answering",
+      "zero-shot-image-classification",
+      "image-text-to-text",
+      "image-to-image"
+    )
+  }
+
+  it should "include its primary task among the handled tasks" in {
+    ImageTaskCodegen.tasks should contain(ImageTaskCodegen.task)
+  }
+
+  "ImageTaskCodegen.payloadPython" should "send raw image bytes as the binary 
body for image-only tasks" in {
+    val out = ImageTaskCodegen.payloadPython(makeCtx())
+    out should include("if task in image_only_tasks:")
+    out should include("payload = current_image_bytes")
+    out should include("use_raw_binary_body = True")
+    out should include("raw_binary_headers = image_headers")
+  }
+
+  it should "bundle a base64 image and question for the visual/document QA 
tasks" in {
+    val out = ImageTaskCodegen.payloadPython(makeCtx())
+    out should include(
+      """elif task in ("visual-question-answering", 
"document-question-answering"):"""
+    )
+    out should include("self._image_input_as_base64(current_image_bytes)")
+    out should include(""""question": prompt_value""")
+  }
+
+  it should "build an OpenAI chat payload with the model id and token cap for 
image-text-to-text" in {
+    val out = ImageTaskCodegen.payloadPython(makeCtx())
+    out should include("""elif task == "image-text-to-text":""")
+    out should include("self.MODEL_ID")
+    out should include("self.MAX_NEW_TOKENS")
+    out should include("image_url")
+    out should include("messages")
+  }
+
+  it should "guard zero-shot-image-classification with a minimum of two 
candidate labels" in {
+    val out = ImageTaskCodegen.payloadPython(makeCtx())
+    out should include("""elif task == "zero-shot-image-classification":""")
+    out should include("self.CANDIDATE_LABELS")
+    out should include("candidate_labels")
+    out should include("if len(labels) < 2:")
+    out should include("raise ValueError(")
+  }
+
+  it should "route image-to-image through the raw binary body path" in {
+    val out = ImageTaskCodegen.payloadPython(makeCtx())
+    out should include("""elif task == "image-to-image":""")
+  }
+
+  it should "fall back to shipping the raw prompt as inputs" in {
+    val out = ImageTaskCodegen.payloadPython(makeCtx())
+    out should include("else:")
+    out should include("""payload = {"inputs": prompt_value}""")
+  }
+
+  "ImageTaskCodegen.parsePython" should "branch across the response-bearing 
image tasks" in {
+    val out = ImageTaskCodegen.parsePython(makeCtx())
+    out should include("""if task == "image-to-text":""")
+    out should include(
+      """elif task in ("visual-question-answering", 
"document-question-answering"):"""
+    )
+    out should include("""elif task == "image-text-to-text":""")
+    out should include("""elif task == "image-to-image":""")
+  }
+
+  it should "extract chat and generated-text shapes for the text-producing 
image tasks" in {
+    val out = ImageTaskCodegen.parsePython(makeCtx())
+    out should include("""body["choices"][0]["message"]["content"]""")
+    out should include("""body.get("answer"""")
+    out should include("generated_text")
+  }

Review Comment:
   Verified this compiles: line 143 is just the closing brace, and the 
triple-quoted strings above it are correctly terminated (the trailing `"]` is 
inside the string, not an extra quote).
   



##########
common/workflow-operator/src/test/scala/org/apache/texera/amber/operator/huggingFace/codegen/ImageTaskCodegenSpec.scala:
##########
@@ -0,0 +1,224 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.texera.amber.operator.huggingFace.codegen
+
+import org.apache.texera.amber.pybuilder.PyStringTypes.EncodableString
+import org.scalatest.flatspec.AnyFlatSpec
+import org.scalatest.matchers.should.Matchers
+
+class ImageTaskCodegenSpec extends AnyFlatSpec with Matchers {
+
+  private def makeCtx(
+      hfApiToken: EncodableString = "token",
+      modelId: EncodableString = "Salesforce/blip-vqa-base",
+      promptColumn: EncodableString = "prompt",
+      resultColumn: EncodableString = "hf_response",
+      task: EncodableString = "image-classification",
+      systemPrompt: EncodableString = "You are a helpful assistant.",
+      safeMaxTokens: Int = 256,
+      safeTemp: Double = 0.7,
+      imageInput: EncodableString = "pic.png",
+      inputImageColumn: EncodableString = "image",
+      candidateLabels: EncodableString = "cat,dog"
+  ): CodegenContext =
+    CodegenContext(
+      hfApiToken = hfApiToken,
+      modelId = modelId,
+      promptColumn = promptColumn,
+      resultColumn = resultColumn,
+      task = task,
+      systemPrompt = systemPrompt,
+      safeMaxTokens = safeMaxTokens,
+      safeTemp = safeTemp,
+      imageInput = imageInput,
+      inputImageColumn = inputImageColumn,
+      candidateLabels = candidateLabels
+    )
+
+  "ImageTaskCodegen.task" should "be the canonical image-classification 
string" in {
+    ImageTaskCodegen.task shouldBe "image-classification"
+  }
+
+  "ImageTaskCodegen.tasks" should "cover exactly the nine image task families" 
in {
+    ImageTaskCodegen.tasks shouldBe Set(
+      "image-classification",
+      "object-detection",
+      "image-segmentation",
+      "image-to-text",
+      "visual-question-answering",
+      "document-question-answering",
+      "zero-shot-image-classification",
+      "image-text-to-text",
+      "image-to-image"
+    )
+  }
+
+  it should "include its primary task among the handled tasks" in {
+    ImageTaskCodegen.tasks should contain(ImageTaskCodegen.task)
+  }
+
+  "ImageTaskCodegen.payloadPython" should "send raw image bytes as the binary 
body for image-only tasks" in {
+    val out = ImageTaskCodegen.payloadPython(makeCtx())
+    out should include("if task in image_only_tasks:")
+    out should include("payload = current_image_bytes")
+    out should include("use_raw_binary_body = True")
+    out should include("raw_binary_headers = image_headers")
+  }
+
+  it should "bundle a base64 image and question for the visual/document QA 
tasks" in {
+    val out = ImageTaskCodegen.payloadPython(makeCtx())
+    out should include(
+      """elif task in ("visual-question-answering", 
"document-question-answering"):"""
+    )
+    out should include("self._image_input_as_base64(current_image_bytes)")
+    out should include(""""question": prompt_value""")
+  }
+
+  it should "build an OpenAI chat payload with the model id and token cap for 
image-text-to-text" in {
+    val out = ImageTaskCodegen.payloadPython(makeCtx())
+    out should include("""elif task == "image-text-to-text":""")
+    out should include("self.MODEL_ID")
+    out should include("self.MAX_NEW_TOKENS")
+    out should include("image_url")
+    out should include("messages")
+  }
+
+  it should "guard zero-shot-image-classification with a minimum of two 
candidate labels" in {
+    val out = ImageTaskCodegen.payloadPython(makeCtx())
+    out should include("""elif task == "zero-shot-image-classification":""")
+    out should include("self.CANDIDATE_LABELS")
+    out should include("candidate_labels")
+    out should include("if len(labels) < 2:")
+    out should include("raise ValueError(")
+  }
+
+  it should "route image-to-image through the raw binary body path" in {
+    val out = ImageTaskCodegen.payloadPython(makeCtx())
+    out should include("""elif task == "image-to-image":""")
+  }

Review Comment:
   The assertion pins the full contiguous block starting at `elif task == 
"image-to-image":`, so a regression in that branch would fail it. The identical 
lines in the earlier branch sit under a different header, so they cannot make 
this pass.
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to