diff --git a/lib/base_exception.py b/lib/base_exception.py
new file mode 100644
index 0000000..534d08c
--- /dev/null
+++ b/lib/base_exception.py
@@ -0,0 +1,8 @@
+class PrestoBaseException(Exception):
+ def __init__(self, message: str, error_code: int = 500):
+ self.message = message
+ self.error_code = error_code
+ super().__init__(message)
+
+ def __str__(self):
+ return f"{self.error_code}: {self.message}"
\ No newline at end of file
diff --git a/lib/model/classycat.py b/lib/model/classycat.py
index 219016f..cceb17f 100644
--- a/lib/model/classycat.py
+++ b/lib/model/classycat.py
@@ -5,6 +5,7 @@
from lib.model.classycat_classify import Model as ClassifyModel
from lib.model.classycat_schema_create import Model as ClassyCatSchemaCreateModel
from lib.model.classycat_schema_lookup import Model as ClassyCatSchemaLookupModel
+from lib.base_exception import PrestoBaseException
class Model(Model):
@@ -21,5 +22,4 @@ def process(self, message: Message) -> Union[ClassyCatSchemaResponse, ClassyCatB
return ClassyCatSchemaCreateModel().process(message)
else:
logger.error(f"Unknown event type {event_type}")
- message.body.result.responseMessage = f"Unknown event type {event_type}"
- return message.body.result
\ No newline at end of file
+ raise PrestoBaseException(f"Unknown event type {event_type}", 422)
diff --git a/lib/model/classycat_classify.py b/lib/model/classycat_classify.py
index 9f69355..2f4b185 100644
--- a/lib/model/classycat_classify.py
+++ b/lib/model/classycat_classify.py
@@ -8,6 +8,7 @@
from lib.model.model import Model
from lib.schemas import Message, ClassyCatBatchClassificationResponse
from lib.s3 import load_file_from_s3, file_exists_in_s3, upload_file_to_s3
+from lib.base_exception import PrestoBaseException
class LLMClient:
@@ -65,7 +66,9 @@ def classify(self, task_prompt, items_count, max_tokens_per_item=200):
max_tokens=(max_tokens_per_item * items_count) + 15,
temperature=0.5
)
-# TODO: record metric here with model name and number of items submitted (https://meedan.atlassian.net/browse/CV2-4987)
+
+ # TODO: record metric here with model name and number of items submitted (https://meedan.atlassian.net/browse/CV2-4987)
+
return completion.choices[0].message.content
@@ -84,7 +87,7 @@ def get_llm_client(self, client_type, model_name):
elif client_type == 'openrouter':
return OpenRouterClient(model_name)
else:
- raise Exception(f"Unknown client type: {client_type}")
+ raise PrestoBaseException(f"Unknown LLM client type {client_type}", 500)
def format_input_for_classification_prompt(self, items):
return '\n'.join([f"{item}" for i, item in enumerate(items)])
@@ -119,13 +122,26 @@ def classify_and_store_results(self, schema_id, items):
if (classification_results is None or len(classification_results) == 0
or len(classification_results) != len(items)):
logger.info(f"Classification results: {classification_results}")
- raise Exception(f"Not all items were classified successfully: "
- f"input length {len(items)}, output length {len(classification_results)}")
- # TODO: validate response label against schema https://meedan.atlassian.net/browse/CV2-4801
+ raise PrestoBaseException(f"Not all items were classified successfully: input length {len(items)}, output length {len(classification_results)}", 502)
+
final_results = [{'id': items[i]['id'], 'text': items[i]['text'], 'labels': classification_results[i]}
for i in range(len(items))]
- results_file_id = str(uuid.uuid4())
- upload_file_to_s3(self.output_bucket, f"{schema_id}/{results_file_id}.json", json.dumps(final_results))
+
+ # filtering out the results that have out-of-schema labels
+ # our of schema labels will not be included in the final results,
+ # and items with no labels can be retried later by the user, indicated by an empty list for labels
+ permitted_labels = [topic['topic'] for topic in schema['topics']] + ['Other', 'Unsure']
+ for result in final_results:
+
+ # log the items that had at least one out-of-schema label
+ if not all([label in permitted_labels for label in result['labels']]):
+ logger.error(f"Item {result['id']} had out-of-schema labels: {result['labels']}, permitted labels: {permitted_labels}")
+
+ result['labels'] = [label for label in result['labels'] if label in permitted_labels]
+
+ if not all([len(result['labels']) == 0 for result in final_results]):
+ results_file_id = str(uuid.uuid4())
+ upload_file_to_s3(self.output_bucket, f"{schema_id}/{results_file_id}.json", json.dumps(final_results))
return final_results
@@ -199,12 +215,10 @@ def process(self, message: Message) -> ClassyCatBatchClassificationResponse:
result = message.body.result
if not self.schema_id_exists(schema_id):
- result.responseMessage = f"Schema id {schema_id} cannot be found"
- return result
+ raise PrestoBaseException(f"Schema id {schema_id} cannot be found", 404)
if len(items) > self.batch_size_limit:
- result.responseMessage = f"Number of items exceeds batch size limit of {self.batch_size_limit}"
- return result
+ raise PrestoBaseException(f"Number of items exceeds batch size limit of {self.batch_size_limit}", 422)
try:
result.classification_results = self.classify_and_store_results(schema_id, items)
@@ -212,5 +226,7 @@ def process(self, message: Message) -> ClassyCatBatchClassificationResponse:
return result
except Exception as e:
logger.exception(f"Error classifying items: {e}")
- result.responseMessage = f"Error classifying items: {e}"
- return result
+ if isinstance(e, PrestoBaseException):
+ raise e
+ else:
+ raise PrestoBaseException(f"Error classifying items: {e}", 500) from e
diff --git a/lib/model/classycat_schema_create.py b/lib/model/classycat_schema_create.py
index edbd9bb..b229c44 100644
--- a/lib/model/classycat_schema_create.py
+++ b/lib/model/classycat_schema_create.py
@@ -5,6 +5,7 @@
from lib.logger import logger
from lib.model.model import Model
from lib.schemas import Message, ClassyCatSchemaResponse
+from lib.base_exception import PrestoBaseException
class Model(Model):
@@ -192,15 +193,13 @@ def process(self, message: Message) -> ClassyCatSchemaResponse:
result = message.body.result
if self.schema_name_exists(schema_name):
- result.responseMessage = f"Schema name {schema_name} already exists"
- return result
+ raise PrestoBaseException(f"Schema name {schema_name} already exists", 422)
try:
self.verify_schema_parameters(schema_name, topics, examples, languages)
except Exception as e:
logger.exception(f"Error verifying schema parameters: {e}")
- result.responseMessage = f"Error verifying schema parameters. Stack trace: {e}"
- return result
+ raise PrestoBaseException(f"Error verifying schema parameters: {e}", 422) from e
try:
result.schema_id = self.create_schema(schema_name, topics, examples, languages)
@@ -208,8 +207,7 @@ def process(self, message: Message) -> ClassyCatSchemaResponse:
return result
except Exception as e:
logger.exception(f"Error creating schema: {e}")
- result.responseMessage = f"Error creating schema. Stack trace: {e}"
- return result
+ raise PrestoBaseException(f"Error creating schema: {e}", 500) from e
def verify_schema_parameters(self, schema_name, topics, examples, languages): #todo
diff --git a/lib/model/classycat_schema_lookup.py b/lib/model/classycat_schema_lookup.py
index f017800..af51b44 100644
--- a/lib/model/classycat_schema_lookup.py
+++ b/lib/model/classycat_schema_lookup.py
@@ -4,6 +4,7 @@
from lib.model.model import Model
from lib.s3 import load_file_from_s3, file_exists_in_s3
from lib.schemas import Message, ClassyCatSchemaResponse
+from lib.base_exception import PrestoBaseException
class Model(Model):
@@ -63,8 +64,7 @@ def process(self, message: Message) -> ClassyCatSchemaResponse:
result = message.body.result
if not self.schema_name_exists(schema_name):
- result.responseMessage = f"Schema name {schema_name} does not exist"
- return result
+ raise PrestoBaseException(f"Schema name {schema_name} does not exist", 404)
logger.debug(f"located schema_name record for '{schema_name}'")
@@ -74,5 +74,4 @@ def process(self, message: Message) -> ClassyCatSchemaResponse:
return result
except Exception as e:
logger.error(f"Error looking up schema name {schema_name}: {e}")
- result.responseMessage = f"Error looking up schema name {schema_name}: {e}"
- return result
\ No newline at end of file
+ raise PrestoBaseException(f"Error looking up schema name {schema_name}", 500) from e
\ No newline at end of file
diff --git a/lib/model/model.py b/lib/model/model.py
index 3e359e2..fc79271 100644
--- a/lib/model/model.py
+++ b/lib/model/model.py
@@ -10,9 +10,12 @@
from lib import schemas
from lib.cache import Cache
from lib.sentry import capture_custom_message
+from lib.base_exception import PrestoBaseException
+
class Model(ABC):
BATCH_SIZE = 1
+
def __init__(self):
self.model_name = os.environ.get("MODEL_NAME")
@@ -43,7 +46,7 @@ def get_tempfile(self) -> Any:
def process(self, messages: Union[List[schemas.Message], schemas.Message]) -> List[schemas.Message]:
return []
- def handle_fingerprinting_error(self, e):
+ def handle_fingerprinting_error(self, e: Exception, response_code: int = 500) -> schemas.ErrorResponse:
error_context = {"error": str(e)}
for attr in ["__cause__", "__context__", "args", "__traceback__"]:
if attr in dir(e):
@@ -51,10 +54,10 @@ def handle_fingerprinting_error(self, e):
error_context[attr] = '\n'.join(traceback.format_tb(getattr(e, attr)))
else:
error_context[attr] = str(getattr(e, attr))
- capture_custom_message("Error during fingerprinting for {self.model_name}", 'info', error_context)
- return schemas.ErrorResponse(error=str(e), error_details=error_context)
+ capture_custom_message(f"Error during fingerprinting for {self.model_name}", 'error', error_context)
+ return schemas.ErrorResponse(error=str(e), error_details=error_context, error_code=response_code)
- def get_response(self, message: schemas.Message) -> schemas.GenericItem:
+ def get_response(self, message: schemas.Message) -> schemas.GenericItem: # TODO note: the return type is wrong here
"""
Perform a lookup on the cache for a message, and if found, return that cached value.
"""
@@ -64,7 +67,10 @@ def get_response(self, message: schemas.Message) -> schemas.GenericItem:
result = self.process(message)
Cache.set_cached_result(message.body.content_hash, result)
except Exception as e:
- return self.handle_fingerprinting_error(e)
+ if isinstance(e, PrestoBaseException):
+ return self.handle_fingerprinting_error(e, e.error_code)
+ else:
+ return self.handle_fingerprinting_error(e)
return result
def respond(self, messages: Union[List[schemas.Message], schemas.Message]) -> List[schemas.Message]:
@@ -76,7 +82,7 @@ def respond(self, messages: Union[List[schemas.Message], schemas.Message]) -> Li
for message in messages:
message.body.result = self.get_response(message)
return messages
-
+
@classmethod
def create(cls):
"""
diff --git a/requirements.txt b/requirements.txt
index 5c04b61..aed95a1 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -13,7 +13,7 @@ fasttext==0.9.2
langcodes==3.3.0
requests==2.32.2
pytest==7.4.0
-sentry-sdk==1.30.0
+sentry-sdk==2.8.0
yake==0.4.8
opentelemetry-api==1.24.0
opentelemetry-exporter-otlp-proto-http==1.24.0
diff --git a/test/lib/model/test_classycat.py b/test/lib/model/test_classycat.py
index ff8cd1d..e85e708 100644
--- a/test/lib/model/test_classycat.py
+++ b/test/lib/model/test_classycat.py
@@ -3,6 +3,7 @@
from unittest.mock import MagicMock, patch
from lib.model.classycat import Model as ClassyCatModel
from lib import schemas
+from lib.base_exception import PrestoBaseException
import json
@@ -562,9 +563,11 @@ def test_classify_fail_wrong_response_format(self, file_exists_in_s3_mock, uploa
}
}
classify_message = schemas.parse_message(classify_input)
- result = self.classycat_model.process(classify_message)
- self.assertEqual(result.responseMessage, "Error classifying items: list index out of range")
+ with self.assertRaises(PrestoBaseException) as e:
+ self.classycat_model.process(classify_message)
+ self.assertIn("Error classifying items: list index out of range", e.message)
+ self.assertEqual(e.error_code, 500)
@patch('lib.model.classycat_classify.OpenRouterClient.classify')
@patch('lib.model.classycat_classify.load_file_from_s3')
@@ -700,9 +703,307 @@ def test_classify_fail_wrong_number_of_results(self, file_exists_in_s3_mock, upl
}
}
classify_message = schemas.parse_message(classify_input)
+
+ with self.assertRaises(PrestoBaseException) as e:
+ self.classycat_model.process(classify_message)
+ self.assertIn("Not all items were classified successfully: input length 1, output length 2", e.message)
+ self.assertEqual(e.error_code, 502)
+
+
+ @patch('lib.model.classycat_classify.OpenRouterClient.classify')
+ @patch('lib.model.classycat_classify.load_file_from_s3')
+ @patch('lib.model.classycat_classify.upload_file_to_s3')
+ @patch('lib.model.classycat_classify.file_exists_in_s3')
+ def test_classify_some_out_of_schema_labels(self, file_exists_in_s3_mock, upload_file_to_s3_mock,
+ load_file_from_s3_mock, openrouter_classify_mock):
+ file_exists_in_s3_mock.return_value = True
+ upload_file_to_s3_mock.return_value = None
+ load_file_from_s3_mock.return_value = json.dumps(
+ {
+ "schema_id": "123456",
+ "schema_name": "2024 Indian Election Test",
+ "prompt": "fake prompt hehe",
+ "topics": [
+ {
+ "topic": "Politics",
+ "description": "This topic includes political claims, attacks on leaders and parties, and general political commentary."
+ },
+ {
+ "topic": "Democracy & Election Integrity",
+ "description": "This topic covers the integrity of the election process, including voter fraud, election fraud, the security of voting machines, and election interference, and electoral bonds."
+ },
+ {
+ "topic": "Economy & Growth",
+ "description": "This topic covers claims around economic growth, economic policies, GDP , employment, taxation, issues among farmer and manufacturing industry, and economic inequality."
+ },
+ {
+ "topic": "Communalism",
+ "description": "This topic covers attack on religious minorities, statements on religious freedom and polarization."
+ },
+ {
+ "topic": "Education",
+ "description": "This topic covers education policy of governments, educational institutions created, and quality of education in India."
+ },
+ {
+ "topic": "Freedom of Expression",
+ "description": "This topic covers claims regarding freedom of expression and independence of media, and attacks on press freedom and journalists."
+ },
+ {
+ "topic": "Foreign Policy",
+ "description": "This topic covers India's relationship with neighbours and other countries, claims on effectiveness of foreign policy, international image and diplomacy."
+ },
+ {
+ "topic": "Safety of Women",
+ "description": "This topic covers the issue of safety of women and steps taken to prevent crimes against women. "
+ },
+ {
+ "topic": "Social Issues",
+ "description": "This topic covers topics on the citizenship ammendmend act and caste politics."
+ },
+ {
+ "topic": "Health & Pharma",
+ "description": "This topic covers health policies, claims on ayurveda, maternal and infant mortality, and the pharmaceutical industry."
+ },
+ {
+ "topic": "Terrorism & National Security",
+ "description": "This topics covers claims on UAPA, National security, Pakistan, and terrorism."
+ },
+ {
+ "topic": "Corruption",
+ "description": "This topic covers claims on corruptions and scams."
+ },
+ {
+ "topic": "History",
+ "description": "This topic covers claim on history of India and mythology."
+ },
+ {
+ "topic": "Science & Technology",
+ "description": "This topic covers claims on climate change, environment and science."
+ },
+ {
+ "topic": "Banking & Finance",
+ "description": "This topic covers claims around finance and banking."
+ }
+ ],
+ "examples": [
+ {
+ "text": "Congress Manifesto is horrible. Never seen such a dangerous manifesto in my life. It's like vision 2047 document of PFI\n\nCheck these points of manifesto\n\n1. Will bring back triple talak (Muslim personal law)\n2. Reservation to Muslim in govt n private jobs (Implement Sachchar committee report)\n3. Support Love Jihad (right to love)\n4. Support Burqa in school (right to dress)\n5. End majoritarianism (Hinduism)\n6. Ban bulldozer action\n7. Support Gaza (Hamas)\n8. Legalise Same Sex Marriage, gender fluidity, trans movement\n9. Increase Muslim judges in judiciary\n10. Communal violence bill (will stop mob lynching)\n11. Legalise beef (right to eat everything)\n12. Separate loan intrest for Muslims\n13. Allow treason (No sedition)\n\nAll those Hindu who are thinking to vote Indi Alliance, NOTA or independent. Read this and think.\n",
+ "labels": [
+ "Politics",
+ "Communalism"
+ ]
+ },
+ {
+ "text": "RSS ने अपने नागपुर मुख्यालय से 2024 लोकसभा चुनाव में कॉंग्रेस गठबंधन को समर्थन करने की घोषणा की कमाल की बात ये है कि इतनी महत्वपूर्ण खबर किसी भी news channel, और अखबार ने नहीं छापी RSS ने माना कि आज नरेंद्र मोदी भाजपा सरकार में देश का संविधान और लोकतंत्र खतरे में है इसलिए भाजपा को 2024 में रोकना अति आवश्यक है अगर देश की जनता धर्म के नशे में डूबी रही तो आने वाली नस्लें तुम्हें कभी माफ़ नहीं करेगी देश आज संकट में है और जो व्यक्ति इस समय कॉंग्रेस का साथ नहीं देगा वो भविष्य में खुद को कभी माफ़ नहीं कर पाएगा इस खबर को शेयर करके देश के एक जिम्मेदार नागरिक होने का फर्ज पूरा कीजिए",
+ "labels": [
+ "Politics",
+ "Democracy & Election Integrity"
+ ]
+ },
+ {
+ "text": "बेहद गंभीर मामला है। खबरों के मुताबिक, दवा बनाने वाली बहुत सी कंपनियां जिनकी दवाएं टेस्ट में फेल हुईं, इन कंपनियों ने इलेक्टोरल बॉन्ड से चंदा दिया। जैसे \uD83D\uDC47 1. गुजरात की कंपनी 'टोरेंट फार्मास्यूटिकल' की बनाई 3 दवाएं ड्रग टेस्ट में फेल हुईं। इस कंपनी ने BJP को 61 करोड़ का चंदा दिया। 2. सिप्ला लिमिटेड कंपनी की बनाई दवाओं के 7 बार ड्रग टेस्ट फ़ेल हुए। इस कंपनी ने BJP को 37 करोड़ का चंदा दिया। 3. सन फ़ार्मा कंपनी की बनाई गई दवाओं के 6 बार ड्रग टेस्ट फ़ेल हुए। सन फार्मा ने BJP को 31.5 करोड़ रुपए का चंदा दिया। 4. गुजरात की कंपनी इंटास फ़ार्मास्युटिकल्स की बनाई गई दवा का भी ड्रग टेस्ट फ़ेल हुआ। इंटास फ़ार्मा ने 20 करोड़ के इलेक्टोरल बॉन्ड ख़रीदे और सारा चंदा BJP को दिया। 5. ग्लेनमार्क फ़ार्मा कंपनी की दवाओं के 6 ड्रग टेस्ट फ़ेल हुए। ग्लेनमार्क फ़ार्मा 9.75 करोड़ रुपए के बॉन्ड ख़रीदे और सारा चंदा BJP को दिया।",
+ "labels": [
+ "Corruption",
+ "Health & Pharma",
+ "Politics"
+ ]
+ },
+ {
+ "text": "യുഎഇ അബുദാബിയിലെയും ദുബായിലെയും എല്ലാ അറബ് മന്ത്രിമാരും അറബ് ഷേക്'മാരും റമദാൻ മാസത്തിൽ ഇന്ന് അബുദാബി ഹിന്ദു ക്ഷേത്രത്തിലെത്തി പ്രസാദത്തോടെ ക്ഷേത്രത്തിൽ റമദാൻ വ്രതം പൂർത്തിയാക്കി. (ഇതൊരു വലിയ അത്ഭുതമാണ്.) ഈ വീഡിയോ കാണുക.\uD83D\uDEA9\uD83D\uDEA9\uD83D\uDEA9\n\n",
+ "labels": [
+ "Foreign Policy",
+ "Politics",
+ "Communalism"
+ ]
+ }
+ ],
+ "languages": [
+ "English",
+ "Hindi",
+ "Telugu",
+ "Malayalam"
+ ]
+ }
+ )
+ openrouter_classify_mock.return_value = ""
+ classify_input = {
+ "model_name": "classycat__Model",
+ "body": {
+ "id": 1200,
+ "parameters": {
+ "event_type": "classify",
+ "schema_id": "4a026b82-4a16-440d-aed7-bec07af12205",
+ "items": [
+ {
+ "id": "11",
+ "text": "modi and bjp want to rule india by dividing people against each other"
+ },
+ {
+ "id": "12",
+ "text": "modi and bjp are amazing politicians"
+ },
+ {
+ "id": "13",
+ "text": "modi is an amazing politician"
+ }
+ ]
+ },
+ "callback_url": "http://example.com?callback"
+ }
+ }
+ classify_message = schemas.parse_message(classify_input)
+ result = self.classycat_model.process(classify_message)
+
+ self.assertEqual("success", result.responseMessage)
+ self.assertEqual(3, len(result.classification_results))
+ self.assertListEqual(["Politics", "Communalism"], result.classification_results[0]['labels'])
+ self.assertListEqual([], result.classification_results[1]['labels'])
+ self.assertListEqual(["Politics"], result.classification_results[2]['labels'])
+
+ @patch('lib.model.classycat_classify.OpenRouterClient.classify')
+ @patch('lib.model.classycat_classify.load_file_from_s3')
+ @patch('lib.model.classycat_classify.upload_file_to_s3')
+ @patch('lib.model.classycat_classify.file_exists_in_s3')
+ def test_classify_all_out_of_schema_labels(self, file_exists_in_s3_mock, upload_file_to_s3_mock,
+ load_file_from_s3_mock, openrouter_classify_mock):
+ file_exists_in_s3_mock.return_value = True
+ upload_file_to_s3_mock.return_value = None
+ load_file_from_s3_mock.return_value = json.dumps(
+ {
+ "schema_id": "123456",
+ "schema_name": "2024 Indian Election Test",
+ "prompt": "fake prompt hehe",
+ "topics": [
+ {
+ "topic": "Politics",
+ "description": "This topic includes political claims, attacks on leaders and parties, and general political commentary."
+ },
+ {
+ "topic": "Democracy & Election Integrity",
+ "description": "This topic covers the integrity of the election process, including voter fraud, election fraud, the security of voting machines, and election interference, and electoral bonds."
+ },
+ {
+ "topic": "Economy & Growth",
+ "description": "This topic covers claims around economic growth, economic policies, GDP , employment, taxation, issues among farmer and manufacturing industry, and economic inequality."
+ },
+ {
+ "topic": "Communalism",
+ "description": "This topic covers attack on religious minorities, statements on religious freedom and polarization."
+ },
+ {
+ "topic": "Education",
+ "description": "This topic covers education policy of governments, educational institutions created, and quality of education in India."
+ },
+ {
+ "topic": "Freedom of Expression",
+ "description": "This topic covers claims regarding freedom of expression and independence of media, and attacks on press freedom and journalists."
+ },
+ {
+ "topic": "Foreign Policy",
+ "description": "This topic covers India's relationship with neighbours and other countries, claims on effectiveness of foreign policy, international image and diplomacy."
+ },
+ {
+ "topic": "Safety of Women",
+ "description": "This topic covers the issue of safety of women and steps taken to prevent crimes against women. "
+ },
+ {
+ "topic": "Social Issues",
+ "description": "This topic covers topics on the citizenship ammendmend act and caste politics."
+ },
+ {
+ "topic": "Health & Pharma",
+ "description": "This topic covers health policies, claims on ayurveda, maternal and infant mortality, and the pharmaceutical industry."
+ },
+ {
+ "topic": "Terrorism & National Security",
+ "description": "This topics covers claims on UAPA, National security, Pakistan, and terrorism."
+ },
+ {
+ "topic": "Corruption",
+ "description": "This topic covers claims on corruptions and scams."
+ },
+ {
+ "topic": "History",
+ "description": "This topic covers claim on history of India and mythology."
+ },
+ {
+ "topic": "Science & Technology",
+ "description": "This topic covers claims on climate change, environment and science."
+ },
+ {
+ "topic": "Banking & Finance",
+ "description": "This topic covers claims around finance and banking."
+ }
+ ],
+ "examples": [
+ {
+ "text": "Congress Manifesto is horrible. Never seen such a dangerous manifesto in my life. It's like vision 2047 document of PFI\n\nCheck these points of manifesto\n\n1. Will bring back triple talak (Muslim personal law)\n2. Reservation to Muslim in govt n private jobs (Implement Sachchar committee report)\n3. Support Love Jihad (right to love)\n4. Support Burqa in school (right to dress)\n5. End majoritarianism (Hinduism)\n6. Ban bulldozer action\n7. Support Gaza (Hamas)\n8. Legalise Same Sex Marriage, gender fluidity, trans movement\n9. Increase Muslim judges in judiciary\n10. Communal violence bill (will stop mob lynching)\n11. Legalise beef (right to eat everything)\n12. Separate loan intrest for Muslims\n13. Allow treason (No sedition)\n\nAll those Hindu who are thinking to vote Indi Alliance, NOTA or independent. Read this and think.\n",
+ "labels": [
+ "Politics",
+ "Communalism"
+ ]
+ },
+ {
+ "text": "RSS ने अपने नागपुर मुख्यालय से 2024 लोकसभा चुनाव में कॉंग्रेस गठबंधन को समर्थन करने की घोषणा की कमाल की बात ये है कि इतनी महत्वपूर्ण खबर किसी भी news channel, और अखबार ने नहीं छापी RSS ने माना कि आज नरेंद्र मोदी भाजपा सरकार में देश का संविधान और लोकतंत्र खतरे में है इसलिए भाजपा को 2024 में रोकना अति आवश्यक है अगर देश की जनता धर्म के नशे में डूबी रही तो आने वाली नस्लें तुम्हें कभी माफ़ नहीं करेगी देश आज संकट में है और जो व्यक्ति इस समय कॉंग्रेस का साथ नहीं देगा वो भविष्य में खुद को कभी माफ़ नहीं कर पाएगा इस खबर को शेयर करके देश के एक जिम्मेदार नागरिक होने का फर्ज पूरा कीजिए",
+ "labels": [
+ "Politics",
+ "Democracy & Election Integrity"
+ ]
+ },
+ {
+ "text": "बेहद गंभीर मामला है। खबरों के मुताबिक, दवा बनाने वाली बहुत सी कंपनियां जिनकी दवाएं टेस्ट में फेल हुईं, इन कंपनियों ने इलेक्टोरल बॉन्ड से चंदा दिया। जैसे \uD83D\uDC47 1. गुजरात की कंपनी 'टोरेंट फार्मास्यूटिकल' की बनाई 3 दवाएं ड्रग टेस्ट में फेल हुईं। इस कंपनी ने BJP को 61 करोड़ का चंदा दिया। 2. सिप्ला लिमिटेड कंपनी की बनाई दवाओं के 7 बार ड्रग टेस्ट फ़ेल हुए। इस कंपनी ने BJP को 37 करोड़ का चंदा दिया। 3. सन फ़ार्मा कंपनी की बनाई गई दवाओं के 6 बार ड्रग टेस्ट फ़ेल हुए। सन फार्मा ने BJP को 31.5 करोड़ रुपए का चंदा दिया। 4. गुजरात की कंपनी इंटास फ़ार्मास्युटिकल्स की बनाई गई दवा का भी ड्रग टेस्ट फ़ेल हुआ। इंटास फ़ार्मा ने 20 करोड़ के इलेक्टोरल बॉन्ड ख़रीदे और सारा चंदा BJP को दिया। 5. ग्लेनमार्क फ़ार्मा कंपनी की दवाओं के 6 ड्रग टेस्ट फ़ेल हुए। ग्लेनमार्क फ़ार्मा 9.75 करोड़ रुपए के बॉन्ड ख़रीदे और सारा चंदा BJP को दिया।",
+ "labels": [
+ "Corruption",
+ "Health & Pharma",
+ "Politics"
+ ]
+ },
+ {
+ "text": "യുഎഇ അബുദാബിയിലെയും ദുബായിലെയും എല്ലാ അറബ് മന്ത്രിമാരും അറബ് ഷേക്'മാരും റമദാൻ മാസത്തിൽ ഇന്ന് അബുദാബി ഹിന്ദു ക്ഷേത്രത്തിലെത്തി പ്രസാദത്തോടെ ക്ഷേത്രത്തിൽ റമദാൻ വ്രതം പൂർത്തിയാക്കി. (ഇതൊരു വലിയ അത്ഭുതമാണ്.) ഈ വീഡിയോ കാണുക.\uD83D\uDEA9\uD83D\uDEA9\uD83D\uDEA9\n\n",
+ "labels": [
+ "Foreign Policy",
+ "Politics",
+ "Communalism"
+ ]
+ }
+ ],
+ "languages": [
+ "English",
+ "Hindi",
+ "Telugu",
+ "Malayalam"
+ ]
+ }
+ )
+ openrouter_classify_mock.return_value = ""
+ classify_input = {
+ "model_name": "classycat__Model",
+ "body": {
+ "id": 1200,
+ "parameters": {
+ "event_type": "classify",
+ "schema_id": "4a026b82-4a16-440d-aed7-bec07af12205",
+ "items": [
+ {
+ "id": "11",
+ "text": "modi and bjp want to rule india by dividing people against each other"
+ },
+ {
+ "id": "12",
+ "text": "modi and bjp are amazing politicians"
+ }
+ ]
+ },
+ "callback_url": "http://example.com?callback"
+ }
+ }
+ classify_message = schemas.parse_message(classify_input)
result = self.classycat_model.process(classify_message)
- self.assertEqual(result.responseMessage, "Error classifying items: Not all items were classified successfully: input length 1, output length 2")
+ self.assertEqual("success", result.responseMessage)
+ self.assertEqual(2, len(result.classification_results))
+ self.assertListEqual([], result.classification_results[0]['labels'])
+ self.assertListEqual([], result.classification_results[1]['labels'])
if __name__ == '__main__':
unittest.main()