euriai 1.0.1__py3-none-any.whl → 1.0.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
euriai/langchain.py CHANGED
@@ -221,6 +221,24 @@ class EuriaiChatModel(BaseChatModel):
221
221
 
222
222
  return formatted_messages
223
223
 
224
+ def _messages_to_prompt(self, messages: List[BaseMessage]) -> str:
225
+ """Convert LangChain messages to a single prompt string."""
226
+ prompt_parts = []
227
+
228
+ for message in messages:
229
+ if isinstance(message, SystemMessage):
230
+ prompt_parts.append(f"System: {message.content}")
231
+ elif isinstance(message, HumanMessage):
232
+ prompt_parts.append(f"Human: {message.content}")
233
+ elif isinstance(message, AIMessage):
234
+ prompt_parts.append(f"Assistant: {message.content}")
235
+ elif isinstance(message, (FunctionMessage, ToolMessage)):
236
+ prompt_parts.append(f"Function: {message.content}")
237
+ else:
238
+ prompt_parts.append(f"User: {message.content}")
239
+
240
+ return "\n\n".join(prompt_parts)
241
+
224
242
  def _create_chat_result(self, response: Dict[str, Any]) -> ChatResult:
225
243
  """Create ChatResult from API response."""
226
244
  if "choices" not in response or not response["choices"]:
@@ -273,12 +291,12 @@ class EuriaiChatModel(BaseChatModel):
273
291
  **kwargs: Any,
274
292
  ) -> ChatResult:
275
293
  """Generate chat response."""
276
- # Format messages
277
- formatted_messages = self._format_messages(messages)
294
+ # Convert messages to prompt format
295
+ prompt = self._messages_to_prompt(messages)
278
296
 
279
297
  # Prepare request
280
298
  request_params = {
281
- "messages": formatted_messages,
299
+ "prompt": prompt,
282
300
  "temperature": self.temperature,
283
301
  "max_tokens": self.max_tokens,
284
302
  }
@@ -313,12 +331,12 @@ class EuriaiChatModel(BaseChatModel):
313
331
  **kwargs: Any,
314
332
  ) -> Iterator[ChatGenerationChunk]:
315
333
  """Stream chat response."""
316
- # Format messages
317
- formatted_messages = self._format_messages(messages)
334
+ # Convert messages to prompt format
335
+ prompt = self._messages_to_prompt(messages)
318
336
 
319
337
  # Prepare request
320
338
  request_params = {
321
- "messages": formatted_messages,
339
+ "prompt": prompt,
322
340
  "temperature": self.temperature,
323
341
  "max_tokens": self.max_tokens,
324
342
  }
@@ -464,11 +482,9 @@ class EuriaiChatModel(BaseChatModel):
464
482
  self,
465
483
  schema: Union[Dict, Type[BaseModel]],
466
484
  **kwargs: Any
467
- ) -> "EuriaiChatModel":
485
+ ) -> "EuriaiStructuredChatModel":
468
486
  """Create a version that returns structured output."""
469
- # This would need to be implemented with proper schema validation
470
- # For now, return self with structured output enabled
471
- return self.__class__(
487
+ return EuriaiStructuredChatModel(
472
488
  api_key=self.api_key,
473
489
  model=self.model,
474
490
  temperature=self.temperature,
@@ -479,11 +495,136 @@ class EuriaiChatModel(BaseChatModel):
479
495
  streaming=self.streaming,
480
496
  supports_function_calling=self.supports_function_calling,
481
497
  supports_structured_output=True,
482
- _structured_output_schema=schema,
498
+ schema=schema,
483
499
  **kwargs
484
500
  )
485
501
 
486
502
 
503
+ class EuriaiStructuredChatModel(EuriaiChatModel):
504
+ """
505
+ EuriaiChatModel with structured output support.
506
+
507
+ This class extends EuriaiChatModel to parse responses into structured Pydantic models.
508
+ """
509
+
510
+ def __init__(self, schema: Union[Dict, Type[BaseModel]], **kwargs):
511
+ # Initialize the parent class first
512
+ super().__init__(**kwargs)
513
+
514
+ # Store schema in private attributes to avoid Pydantic conflicts
515
+ self._output_schema = schema
516
+ self._schema_name = getattr(schema, '__name__', 'OutputSchema')
517
+
518
+ @property
519
+ def schema(self):
520
+ """Get the output schema."""
521
+ return self._output_schema
522
+
523
+ @property
524
+ def schema_name(self):
525
+ """Get the schema name."""
526
+ return self._schema_name
527
+
528
+ def _get_json_schema(self) -> Dict[str, Any]:
529
+ """Generate JSON schema from the Pydantic model."""
530
+ if hasattr(self.schema, 'model_json_schema'):
531
+ # Pydantic v2
532
+ return self.schema.model_json_schema()
533
+ elif hasattr(self.schema, 'schema'):
534
+ # Pydantic v1
535
+ return self.schema.schema()
536
+ else:
537
+ # Dictionary schema
538
+ return self.schema
539
+
540
+ def _create_structured_prompt(self, original_prompt: str) -> str:
541
+ """Create a prompt that requests structured JSON output."""
542
+ json_schema = self._get_json_schema()
543
+
544
+ structured_prompt = f"""{original_prompt}
545
+
546
+ Please respond with a valid JSON object that matches this exact schema:
547
+ ```json
548
+ {json.dumps(json_schema, indent=2)}
549
+ ```
550
+
551
+ Your response must be valid JSON that can be parsed. Do not include any other text outside the JSON object."""
552
+
553
+ return structured_prompt
554
+
555
+ def _parse_structured_response(self, response_content: str) -> Any:
556
+ """Parse the response content into the structured format."""
557
+ try:
558
+ # Try to find JSON in the response
559
+ response_content = response_content.strip()
560
+
561
+ # Handle cases where the response might have extra text
562
+ if '```json' in response_content:
563
+ # Extract JSON from code block
564
+ start = response_content.find('```json') + 7
565
+ end = response_content.find('```', start)
566
+ if end == -1:
567
+ end = len(response_content)
568
+ json_str = response_content[start:end].strip()
569
+ elif response_content.startswith('{') and response_content.endswith('}'):
570
+ # Response is already JSON
571
+ json_str = response_content
572
+ else:
573
+ # Try to find JSON object in the response
574
+ import re
575
+ json_match = re.search(r'\{.*\}', response_content, re.DOTALL)
576
+ if json_match:
577
+ json_str = json_match.group(0)
578
+ else:
579
+ raise ValueError("No JSON object found in response")
580
+
581
+ # Parse JSON
582
+ parsed_data = json.loads(json_str)
583
+
584
+ # Convert to Pydantic model if schema is a BaseModel
585
+ if hasattr(self.schema, 'model_validate'):
586
+ # Pydantic v2
587
+ return self.schema.model_validate(parsed_data)
588
+ elif hasattr(self.schema, 'parse_obj'):
589
+ # Pydantic v1
590
+ return self.schema.parse_obj(parsed_data)
591
+ else:
592
+ # Dictionary schema - return parsed data
593
+ return parsed_data
594
+
595
+ except Exception as e:
596
+ # Fallback: return raw response if parsing fails
597
+ raise ValueError(f"Failed to parse structured output: {e}\nResponse: {response_content}")
598
+
599
+ def _messages_to_prompt(self, messages: List[BaseMessage]) -> str:
600
+ """Convert LangChain messages to a single prompt string with structured output instructions."""
601
+ # Get the original prompt
602
+ original_prompt = super()._messages_to_prompt(messages)
603
+
604
+ # Add structured output instructions
605
+ return self._create_structured_prompt(original_prompt)
606
+
607
+ def invoke(self, input, config=None, **kwargs):
608
+ """Invoke the model and return structured output."""
609
+ # Get the regular AI message response
610
+ response = super().invoke(input, config, **kwargs)
611
+
612
+ # Parse the response content into structured format
613
+ structured_result = self._parse_structured_response(response.content)
614
+
615
+ return structured_result
616
+
617
+ async def ainvoke(self, input, config=None, **kwargs):
618
+ """Async invoke the model and return structured output."""
619
+ # Get the regular AI message response
620
+ response = await super().ainvoke(input, config, **kwargs)
621
+
622
+ # Parse the response content into structured format
623
+ structured_result = self._parse_structured_response(response.content)
624
+
625
+ return structured_result
626
+
627
+
487
628
  class EuriaiEmbeddings(Embeddings):
488
629
  """
489
630
  Enhanced LangChain Embeddings implementation using Euri API.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: euriai
3
- Version: 1.0.1
3
+ Version: 1.0.3
4
4
  Summary: Python client for Euri API (euron.one) with CLI, LangChain, and LlamaIndex integration
5
5
  Author: Euri
6
6
  Author-email: tech@euron.one
@@ -6,13 +6,13 @@ euriai/crewai.py,sha256=eeDfZQC9LtEePSnaj94DA0Kcb8Ayq0Gn_eDSQwbcMBU,7543
6
6
  euriai/embedding.py,sha256=uP66Ph1k9Ou6J5RAkztJxlfyj0S0MESOvZ4ulhnVo-o,1270
7
7
  euriai/euri_chat.py,sha256=DEAiet1ReRwB4ljkPYaTl1Nb5uc20-JF-3PQjGQZXk4,3567
8
8
  euriai/euri_embed.py,sha256=VE-RLUb5bYnEFA_dxFkj2c3Jr_SYyJKPmFOzsDOR0Ys,2137
9
- euriai/langchain.py,sha256=IByxc9xBd8flDZU0gFrXs6Hs5_N3TaLKFL3rilKDAuc,29285
9
+ euriai/langchain.py,sha256=gVF9eh21RC1WtDn7SQoEREUDqOObm5IRx6BFZtB5xcc,34968
10
10
  euriai/langgraph.py,sha256=sw9e-PnfwAwmp_tUCnAGIUB78GyJsMkAzxOGvFUafiM,34128
11
11
  euriai/llamaindex.py,sha256=c-ujod2bjL6QIvfAyuIxm1SvSCS00URFElYybKQ5Ew0,26551
12
12
  euriai/n8n.py,sha256=hjkckqyW_hZNL78UkBCof1WvKCKCIjwdvZdAgx6NrB8,3764
13
13
  euriai/smolagents.py,sha256=xlixGx2IWzAPTpSJGsYIK2L-SHGY9Mw1-8GbwVsEYtU,28507
14
- euriai-1.0.1.dist-info/METADATA,sha256=BdezMUKkYwKb7S4zZUY14E2v8lUtH3u1dTB01M_3cNI,6881
15
- euriai-1.0.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
16
- euriai-1.0.1.dist-info/entry_points.txt,sha256=9OkET8KIGcsjQn8UlnpPKRT75s2KW34jq1__1SXtpMA,43
17
- euriai-1.0.1.dist-info/top_level.txt,sha256=TG1htJ8cuD62MXn-NJ7DVF21QHY16w6M_QgfF_Er_EQ,7
18
- euriai-1.0.1.dist-info/RECORD,,
14
+ euriai-1.0.3.dist-info/METADATA,sha256=VL-iLUQt3qiPi5EMJg2_-19Z7m4zO74RvDtJ3CgwVu0,6881
15
+ euriai-1.0.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
16
+ euriai-1.0.3.dist-info/entry_points.txt,sha256=9OkET8KIGcsjQn8UlnpPKRT75s2KW34jq1__1SXtpMA,43
17
+ euriai-1.0.3.dist-info/top_level.txt,sha256=TG1htJ8cuD62MXn-NJ7DVF21QHY16w6M_QgfF_Er_EQ,7
18
+ euriai-1.0.3.dist-info/RECORD,,
File without changes