Source code for quackamollie.model.llama_index_simple.model_llama_index_simple
# -*- coding: utf-8 -*-
__all__ = ["SimpleLlamaIndexQuackamollieModel"]
__author__ = "QuacktorAI"
__copyright__ = "Copyright 2024, Forge of Absurd Ducks"
__credits__ = ["QuacktorAI"]
from ast import literal_eval
from llama_index.core.base.llms.types import ChatMessage
from llama_index.core.chat_engine.simple import SimpleChatEngine
from llama_index.core.chat_engine.types import StreamingAgentChatResponse
from llama_index.llms.ollama import Ollama
from quackamollie.core.cli.settings import get_settings_from_context, QuackamollieSettings
from quackamollie.core.enum.model_family_icon import ModelFamilyIcon
from quackamollie.model.meta.llama_index.llama_index_meta_model import MetaLlamaIndexQuackamollieModel
from typing import AsyncIterable, List, Optional, Tuple
from quackamollie.model.llama_index_simple.prompt.llama_index_simple_prompt import llama_index_simple_context
[docs]
class SimpleLlamaIndexQuackamollieModel(MetaLlamaIndexQuackamollieModel):
""" Simple Llama-Index model with chat history, managed by `LlamaIndexQuackamollieModelManager` """
model_families: List[ModelFamilyIcon] = [ModelFamilyIcon.LLAMA_INDEX]
DEFAULT_OLLAMA_BASE_MODEL: str = "llama3"
def __init__(self, model_config: Optional[str] = None):
""" Initialize the model with model additional configuration retrieved from the database
:param model_config: Additional configuration given as a string through CLI or Telegram `App Settings`
and retrieved from the database
:type model_config: Optional[str]
"""
super().__init__(model_config=model_config)
# Get config for ollama base URL
quackamollie_settings: QuackamollieSettings = get_settings_from_context()
# Get Ollama model name
ollama_base_model: str = self.DEFAULT_OLLAMA_BASE_MODEL
if model_config:
model_config_dict = literal_eval(model_config)
if isinstance(model_config_dict, dict):
ollama_base_model = model_config_dict.get("ollama_base_model", self.DEFAULT_OLLAMA_BASE_MODEL)
# Initialize LLM model
self.llm = Ollama(base_url=quackamollie_settings.ollama_base_url, model=ollama_base_model,
request_timeout=3600.0)
self.prefix_messages = [ChatMessage(role="system", content=llama_index_simple_context)]
# Initialize the chat engine
self.chat_engine: SimpleChatEngine = SimpleChatEngine.from_defaults(llm=self.llm,
prefix_messages=self.prefix_messages)
[docs]
@classmethod
async def astream_answer(cls, content: str, chat_history: List[ChatMessage],
model_config: Optional[str] = None, **kwargs) -> AsyncIterable[Tuple[str, bool]]:
""" Asynchronous iterator to stream the answer from a Llama-Index model
:param content: The new message content
:type content: str
:param chat_history: A list of past messages formatted accordingly by model manager
:type chat_history: List
:param model_config: Additional configuration given as a string through CLI or Telegram `App Settings`
and retrieved from the database
:type model_config: Optional[str]
:param kwargs: Additional streaming arguments
:type kwargs: Dict
:return: An asynchronous iterator giving a tuple containing the new chunk and a boolean indicating
if the model is done or not
:rtype: AsyncIterable[Tuple[str, bool]]
"""
# Initialize model with optional additional config
model: SimpleLlamaIndexQuackamollieModel = cls(model_config=model_config)
# Get streaming response async generator
astream_response: StreamingAgentChatResponse = await model.chat_engine.astream_chat(content,
chat_history=chat_history)
# Async generator of tuples with the chunk and is_done field
async for response in astream_response.async_response_gen():
yield response, False
else:
yield "", True