fix(csv file generation bug):

This commit is contained in:
Alexander Myasoedov committed 2025-02-17 20:21:47 +02:00
1 parent 653e9a7234
commit 4ffca42e48
6 files changed
+52 -20

No files matched your search

+2
View File
@@ -35,6 +35,7 @@ class ScanResult(BaseModel):
prompt: str = "" prompt: str = ""
model: str = "" model: str = ""
refused: bool = False refused: bool = False
latency: float = 0.0
@classmethod @classmethod
def status_msg(cls, msg: str) -> str: def status_msg(cls, msg: str) -> str:
@@ -48,6 +49,7 @@ class ScanResult(BaseModel):
prompt="", prompt="",
model="", model="",
refused=False, refused=False,
latency=0,
).model_dump_json() ).model_dump_json()
+22 -5
View File
@@ -1,7 +1,7 @@
import asyncio import asyncio
import random import random
from collections.abc import AsyncGenerator from collections.abc import AsyncGenerator
import time
import httpx import httpx
import pandas as pd import pandas as pd
from loguru import logger from loguru import logger
@@ -44,7 +44,7 @@ def multi_modality_spec(llm_spec):
async def process_prompt( async def process_prompt(
request_factory, prompt, tokens, module_name, refusals, errors request_factory, prompt, tokens, module_name, refusals, errors, outputs
) -> tuple[int, bool]: ) -> tuple[int, bool]:
""" """
Process a single prompt and update the token count and failure status. Process a single prompt and update the token count and failure status.
@@ -63,10 +63,12 @@ async def process_prompt(
response_text = response.text response_text = response.text
tokens += len(response_text.split()) tokens += len(response_text.split())
if refusal_heuristic(response.json()): refused = refusal_heuristic(response.json())
if refused:
refusals.append((module_name, prompt, response.status_code, response_text)) refusals.append((module_name, prompt, response.status_code, response_text))
return tokens, True
return tokens, False outputs.append((module_name, prompt, response_text, refused))
return tokens, refused
except httpx.RequestError as exc: except httpx.RequestError as exc:
logger.error(f"Request error: {exc}") logger.error(f"Request error: {exc}")
@@ -98,6 +100,7 @@ async def perform_single_shot_scan(
errors = [] errors = []
refusals = [] refusals = []
outputs = []
total_prompts = sum(len(m.prompts) for m in prompt_modules if not m.lazy) total_prompts = sum(len(m.prompts) for m in prompt_modules if not m.lazy)
processed_prompts = 0 processed_prompts = 0
@@ -131,6 +134,7 @@ async def perform_single_shot_scan(
100 * processed_prompts / total_prompts if total_prompts else 0 100 * processed_prompts / total_prompts if total_prompts else 0
) )
total_tokens -= tokens total_tokens -= tokens
start = time.time()
tokens, failed = await process_prompt( tokens, failed = await process_prompt(
request_factory, request_factory,
prompt, prompt,
@@ -138,7 +142,9 @@ async def perform_single_shot_scan(
module.dataset_name, module.dataset_name,
refusals, refusals,
errors, errors,
outputs,
) )
end = time.time()
total_tokens += tokens total_tokens += tokens
# logger.debug(f"Trying prompt: {prompt}, {failed=}") # logger.debug(f"Trying prompt: {prompt}, {failed=}")
if failed: if failed:
@@ -147,6 +153,13 @@ async def perform_single_shot_scan(
failure_rates.append(failure_rate) failure_rates.append(failure_rate)
cost = calculate_cost(tokens) cost = calculate_cost(tokens)
# TODO: improve this cond
last_output = outputs[-1] if outputs else None
if last_output and last_output[1] == prompt:
response_text = last_output[2]
else:
response_text = ""
yield ScanResult( yield ScanResult(
module=module.dataset_name, module=module.dataset_name,
tokens=round(tokens / 1000, 1), tokens=round(tokens / 1000, 1),
@@ -154,6 +167,8 @@ async def perform_single_shot_scan(
progress=round(progress, 2), progress=round(progress, 2),
failureRate=round(failure_rate * 100, 2), failureRate=round(failure_rate * 100, 2),
prompt=prompt[:MAX_PROMPT_LENGTH], prompt=prompt[:MAX_PROMPT_LENGTH],
latency=end - start,
model=response_text,
).model_dump_json() ).model_dump_json()
if optimize and len(failure_rates) >= 5: if optimize and len(failure_rates) >= 5:
@@ -219,6 +234,7 @@ async def perform_many_shot_scan(
errors = [] errors = []
refusals = [] refusals = []
outputs = []
total_prompts = sum(len(m.prompts) for m in prompt_modules if not m.lazy) total_prompts = sum(len(m.prompts) for m in prompt_modules if not m.lazy)
processed_prompts = 0 processed_prompts = 0
@@ -270,6 +286,7 @@ async def perform_many_shot_scan(
module.dataset_name, module.dataset_name,
refusals, refusals,
errors, errors,
outputs,
) )
if failed: if failed:
module_failures += 1 module_failures += 1
@@ -209,6 +209,7 @@ class TestProcessPrompt(unittest.IsolatedAsyncioTestCase):
module_name="module_a", module_name="module_a",
refusals=[], refusals=[],
errors=[], errors=[],
outputs=[],
) )
self.assertEqual(tokens, 3) # Tokens from "Valid response text" self.assertEqual(tokens, 3) # Tokens from "Valid response text"
@@ -226,6 +227,7 @@ class TestProcessPrompt(unittest.IsolatedAsyncioTestCase):
) )
refusals = [] refusals = []
outputs = []
tokens, refusal = await process_prompt( tokens, refusal = await process_prompt(
request_factory=mock_request_factory, request_factory=mock_request_factory,
prompt="test prompt", prompt="test prompt",
@@ -233,6 +235,7 @@ class TestProcessPrompt(unittest.IsolatedAsyncioTestCase):
module_name="module_a", module_name="module_a",
refusals=refusals, refusals=refusals,
errors=[], errors=[],
outputs=outputs,
) )
self.assertEqual(tokens, 3) # Tokens from "Response indicating refusal" self.assertEqual(tokens, 3) # Tokens from "Response indicating refusal"
@@ -257,6 +260,7 @@ class TestProcessPrompt(unittest.IsolatedAsyncioTestCase):
module_name="module_a", module_name="module_a",
refusals=refusals, refusals=refusals,
errors=[], errors=[],
outputs=[],
) )
async def test_request_error(self): async def test_request_error(self):
@@ -273,6 +277,7 @@ class TestProcessPrompt(unittest.IsolatedAsyncioTestCase):
module_name="module_a", module_name="module_a",
refusals=[], refusals=[],
errors=errors, errors=errors,
outputs=[],
) )
self.assertEqual(tokens, 0) self.assertEqual(tokens, 0)
+7 -7
View File
@@ -1,13 +1,13 @@
let URL = window.location.href; let SELF_URL = window.location.href;
if (URL.endsWith('/')) { if (SELF_URL.endsWith('/')) {
URL = URL.slice(0, -1); SELF_URL = SELF_URL.slice(0, -1);
} }
URL = URL.replace('/#', ''); SELF_URL = SELF_URL.replace('/#', '');
// Vue application // Vue application
let LLM_SPECS = [ let LLM_SPECS = [
`POST ${URL}/v1/self-probe `POST ${SELF_URL}/v1/self-probe
Authorization: Bearer XXXXX Authorization: Bearer XXXXX
Content-Type: application/json Content-Type: application/json
@@ -79,7 +79,7 @@ Content-Type: application/json
] ]
} }
`, `,
`POST ${URL}/v1/self-probe-image `POST ${SELF_URL}/v1/self-probe-image
Authorization: Bearer XXXXX Authorization: Bearer XXXXX
Content-Type: application/json Content-Type: application/json
@@ -101,7 +101,7 @@ Content-Type: application/json
} }
] ]
`, `,
`POST ${URL}/v1/self-probe-file `POST ${SELF_URL}/v1/self-probe-file
Authorization: Bearer $GROQ_API_KEY Authorization: Bearer $GROQ_API_KEY
Content-Type: multipart/form-data Content-Type: multipart/form-data
+4 -1
View File
@@ -95,7 +95,6 @@
<h2 class="text-2xl font-bold">LLM API Spec</h2> <h2 class="text-2xl font-bold">LLM API Spec</h2>
<span :class="statusDotClass" <span :class="statusDotClass"
class="w-3 h-3 rounded-full mr-2"></span> class="w-3 h-3 rounded-full mr-2"></span>
<span v-if="latency" class="text-sm text-gray-400 ml-2">Latency: {{latency}}s</span>
<svg :class="{'rotate-180': showLLMSpec}" <svg :class="{'rotate-180': showLLMSpec}"
class="w-6 h-6 transition-transform duration-200" class="w-6 h-6 transition-transform duration-200"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
@@ -140,6 +139,8 @@
<strong class="font-bold">></strong> <strong class="font-bold">></strong>
<span class="block sm:inline">{{okMsg}}</span> <span class="block sm:inline">{{okMsg}}</span>
</div> </div>
<span v-if="latency" class="text-sm text-gray-400 ml-2">Latency: {{latency}}s</span>
<!-- Action Buttons --> <!-- Action Buttons -->
<section class="flex justify-center space-x-4 mt-10"> <section class="flex justify-center space-x-4 mt-10">
@@ -419,6 +420,8 @@
<strong class="font-bold">></strong> <strong class="font-bold">></strong>
<span class="block sm:inline">{{okMsg}}</span> <span class="block sm:inline">{{okMsg}}</span>
</div> </div>
<span v-if="latency" class="text-sm text-gray-400 ml-2">Latency: {{latency}}s</span>
<!-- Action Buttons --> <!-- Action Buttons -->
<section class="flex justify-center space-x-4"> <section class="flex justify-center space-x-4">
+12 -7
View File
@@ -193,7 +193,8 @@ var app = new Vue({
let payload = { let payload = {
spec: this.modelSpec, spec: this.modelSpec,
}; };
const response = await fetch(`${URL}/verify`, { let startTime = performance.now(); // Capture start time
const response = await fetch(`${SELF_URL}/verify`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@@ -202,7 +203,10 @@ var app = new Vue({
}); });
console.log(response); console.log(response);
let r = await response.json(); let r = await response.json();
this.latency = r.elapsed; let endTime = performance.now(); // Capture end time
let latency = endTime - startTime; // Calculate latency in milliseconds
latency = latency.toFixed(3) / 1000; // Round to 2 decimal places
this.latency = latency;
if (!response.ok) { if (!response.ok) {
this.updateStatusDot(false); this.updateStatusDot(false);
this.errorMsg = 'Integration verification failed:' + JSON.stringify(r); this.errorMsg = 'Integration verification failed:' + JSON.stringify(r);
@@ -218,7 +222,7 @@ var app = new Vue({
this.saveStateToLocalStorage(); this.saveStateToLocalStorage();
}, },
loadConfigs: async function () { loadConfigs: async function () {
const response = await fetch(`${URL}/v1/data-config`, { const response = await fetch(`${SELF_URL}/v1/data-config`, {
method: 'GET', method: 'GET',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@@ -290,6 +294,7 @@ var app = new Vue({
this.okMsg = `${event.module}`; this.okMsg = `${event.module}`;
return return
} }
this.latency = event.latency.toFixed(3);
console.log('New event'); console.log('New event');
// { "module": "Module 49", "tokens": 480, "cost": 4.800000000000001, "progress": 9.8 } // { "module": "Module 49", "tokens": 480, "cost": 4.800000000000001, "progress": 9.8 }
let progress = event.progress; let progress = event.progress;
@@ -325,14 +330,14 @@ var app = new Vue({
let payload = { let payload = {
table: this.mainTable, table: this.mainTable,
}; };
const response = await fetch(`${URL}/plot.jpeg`, { const response = await fetch(`${SELF_URL}/plot.jpeg`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
body: JSON.stringify(payload), body: JSON.stringify(payload),
}); });
// Convert image response to a data URL for the <img> src // Convert image response to a data SELF_URL for the <img> src
const blob = await response.blob(); const blob = await response.blob();
const reader = new FileReader(); const reader = new FileReader();
reader.readAsDataURL(blob); reader.readAsDataURL(blob);
@@ -375,7 +380,7 @@ var app = new Vue({
}, },
stopScan: async function () { stopScan: async function () {
this.scanRunning = false; this.scanRunning = false;
const response = await fetch(`${URL}/stop`, { const response = await fetch(`${SELF_URL}/stop`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@@ -391,7 +396,7 @@ var app = new Vue({
optimize: this.optimize, optimize: this.optimize,
enableMultiStepAttack: this.enableMultiStepAttack, enableMultiStepAttack: this.enableMultiStepAttack,
}; };
const response = await fetch(`${URL}/scan`, { const response = await fetch(`${SELF_URL}/scan`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',