lollms-client 0.33.0__py3-none-any.whl → 1.1.0__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.
Potentially problematic release.
This version of lollms-client might be problematic. Click here for more details.
- lollms_client/__init__.py +1 -1
- lollms_client/llm_bindings/azure_openai/__init__.py +6 -10
- lollms_client/llm_bindings/claude/__init__.py +4 -7
- lollms_client/llm_bindings/gemini/__init__.py +3 -7
- lollms_client/llm_bindings/grok/__init__.py +3 -7
- lollms_client/llm_bindings/groq/__init__.py +4 -6
- lollms_client/llm_bindings/hugging_face_inference_api/__init__.py +4 -6
- lollms_client/llm_bindings/litellm/__init__.py +15 -6
- lollms_client/llm_bindings/llamacpp/__init__.py +27 -9
- lollms_client/llm_bindings/lollms/__init__.py +24 -14
- lollms_client/llm_bindings/lollms_webui/__init__.py +6 -12
- lollms_client/llm_bindings/mistral/__init__.py +3 -5
- lollms_client/llm_bindings/ollama/__init__.py +6 -11
- lollms_client/llm_bindings/open_router/__init__.py +4 -6
- lollms_client/llm_bindings/openai/__init__.py +7 -14
- lollms_client/llm_bindings/openllm/__init__.py +12 -12
- lollms_client/llm_bindings/pythonllamacpp/__init__.py +1 -1
- lollms_client/llm_bindings/tensor_rt/__init__.py +8 -13
- lollms_client/llm_bindings/transformers/__init__.py +14 -6
- lollms_client/llm_bindings/vllm/__init__.py +16 -12
- lollms_client/lollms_core.py +303 -490
- lollms_client/lollms_discussion.py +431 -78
- lollms_client/lollms_llm_binding.py +192 -381
- lollms_client/lollms_mcp_binding.py +33 -2
- lollms_client/lollms_tti_binding.py +107 -2
- lollms_client/mcp_bindings/local_mcp/__init__.py +3 -2
- lollms_client/mcp_bindings/remote_mcp/__init__.py +6 -5
- lollms_client/mcp_bindings/standard_mcp/__init__.py +3 -5
- lollms_client/stt_bindings/lollms/__init__.py +6 -8
- lollms_client/stt_bindings/whisper/__init__.py +2 -4
- lollms_client/stt_bindings/whispercpp/__init__.py +15 -16
- lollms_client/tti_bindings/dalle/__init__.py +50 -29
- lollms_client/tti_bindings/diffusers/__init__.py +227 -439
- lollms_client/tti_bindings/gemini/__init__.py +320 -0
- lollms_client/tti_bindings/lollms/__init__.py +8 -9
- lollms_client-1.1.0.dist-info/METADATA +1214 -0
- lollms_client-1.1.0.dist-info/RECORD +69 -0
- {lollms_client-0.33.0.dist-info → lollms_client-1.1.0.dist-info}/top_level.txt +0 -2
- examples/article_summary/article_summary.py +0 -58
- examples/console_discussion/console_app.py +0 -266
- examples/console_discussion.py +0 -448
- examples/deep_analyze/deep_analyse.py +0 -30
- examples/deep_analyze/deep_analyze_multiple_files.py +0 -32
- examples/function_calling_with_local_custom_mcp.py +0 -250
- examples/generate_a_benchmark_for_safe_store.py +0 -89
- examples/generate_and_speak/generate_and_speak.py +0 -251
- examples/generate_game_sfx/generate_game_fx.py +0 -240
- examples/generate_text_with_multihop_rag_example.py +0 -210
- examples/gradio_chat_app.py +0 -228
- examples/gradio_lollms_chat.py +0 -259
- examples/internet_search_with_rag.py +0 -226
- examples/lollms_chat/calculator.py +0 -59
- examples/lollms_chat/derivative.py +0 -48
- examples/lollms_chat/test_openai_compatible_with_lollms_chat.py +0 -12
- examples/lollms_discussions_test.py +0 -155
- examples/mcp_examples/external_mcp.py +0 -267
- examples/mcp_examples/local_mcp.py +0 -171
- examples/mcp_examples/openai_mcp.py +0 -203
- examples/mcp_examples/run_remote_mcp_example_v2.py +0 -290
- examples/mcp_examples/run_standard_mcp_example.py +0 -204
- examples/simple_text_gen_test.py +0 -173
- examples/simple_text_gen_with_image_test.py +0 -178
- examples/test_local_models/local_chat.py +0 -9
- examples/text_2_audio.py +0 -77
- examples/text_2_image.py +0 -144
- examples/text_2_image_diffusers.py +0 -274
- examples/text_and_image_2_audio.py +0 -59
- examples/text_gen.py +0 -30
- examples/text_gen_system_prompt.py +0 -29
- lollms_client-0.33.0.dist-info/METADATA +0 -854
- lollms_client-0.33.0.dist-info/RECORD +0 -101
- test/test_lollms_discussion.py +0 -368
- {lollms_client-0.33.0.dist-info → lollms_client-1.1.0.dist-info}/WHEEL +0 -0
- {lollms_client-0.33.0.dist-info → lollms_client-1.1.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
# lollms_client/examples/game_sfx_generation/generate_game_sfx.py
|
|
2
|
-
from pathlib import Path
|
|
3
|
-
import time
|
|
4
|
-
import argparse # For command-line arguments
|
|
5
|
-
|
|
6
|
-
# Ensure pygame is installed for this example
|
|
7
|
-
try:
|
|
8
|
-
import pipmaster as pm
|
|
9
|
-
pm.ensure_packages(["pygame"])
|
|
10
|
-
import pygame
|
|
11
|
-
PYGAME_AVAILABLE = True
|
|
12
|
-
except ImportError:
|
|
13
|
-
print("Pygame not found or pipmaster failed. Please install it manually: pip install pygame")
|
|
14
|
-
PYGAME_AVAILABLE = False
|
|
15
|
-
except Exception as e:
|
|
16
|
-
print(f"Could not ensure pygame: {e}")
|
|
17
|
-
PYGAME_AVAILABLE = False
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
from lollms_client import LollmsClient # Removed LollmsDiscussion, LollmsMessage as not used
|
|
21
|
-
from ascii_colors import ASCIIColors, trace_exception
|
|
22
|
-
|
|
23
|
-
# --- Configuration ---
|
|
24
|
-
# Output directory for generated sound effects
|
|
25
|
-
SFX_OUTPUT_DIR = Path(__file__).parent / "sfx_output"
|
|
26
|
-
SFX_OUTPUT_DIR.mkdir(exist_ok=True)
|
|
27
|
-
|
|
28
|
-
# Sound effect descriptions. Note: 'duration' is more relevant for audiocraft.
|
|
29
|
-
# Bark's duration is more implicit based on prompt content.
|
|
30
|
-
SOUND_EFFECTS_TO_GENERATE = [
|
|
31
|
-
{
|
|
32
|
-
"filename": "sfx_crunch",
|
|
33
|
-
"prompt": "Sound effect of a single, sharp, dry crunch, like stepping on a crisp autumn leaf or a piece of dry wood breaking.",
|
|
34
|
-
"duration": 1, # audiocraft specific
|
|
35
|
-
"bark_params": {"fine_temperature": 0.4, "coarse_temperature": 0.6} # Example bark specific
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
"filename": "sfx_death_electronic",
|
|
39
|
-
"prompt": "Short, impactful electronic death sound effect for a video game character, like a quick digital zap or a brief power-down sound.",
|
|
40
|
-
"duration": 1.5,
|
|
41
|
-
"bark_params": {"voice_preset": None} # Try without preset for more raw SFX
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
"filename": "sfx_powerup_positive",
|
|
45
|
-
"prompt": "Bright, positive, short power-up collection sound effect, like a magical chime, a sparkling shimmer, or an uplifting notification. [SFX]",
|
|
46
|
-
"duration": 1.5
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
"filename": "sfx_laser_shot",
|
|
50
|
-
"prompt": "Sound effect of a futuristic laser gun firing a single shot, a quick 'pew' sound. [SFX: laser pew]",
|
|
51
|
-
"duration": 0.5
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
"filename": "sfx_coin_collect",
|
|
55
|
-
"prompt": "Classic video game coin collection sound effect, a short, metallic, cheerful 'ding' or 'jingle'. [SFX: coin]",
|
|
56
|
-
"duration": 0.7
|
|
57
|
-
}
|
|
58
|
-
]
|
|
59
|
-
|
|
60
|
-
def generate_sfx(lollms_client: LollmsClient, sfx_info: dict) -> Path | None:
|
|
61
|
-
"""Generates a single sound effect using the LollmsClient's TTM binding."""
|
|
62
|
-
filename_stem = sfx_info["filename"]
|
|
63
|
-
prompt = sfx_info["prompt"]
|
|
64
|
-
|
|
65
|
-
# Default output format
|
|
66
|
-
output_format = "wav" # WAV is generally best for SFX in pygame
|
|
67
|
-
output_path = SFX_OUTPUT_DIR / f"{filename_stem}_{lollms_client.ttm.binding_name}.{output_format}" # Add binding name to filename
|
|
68
|
-
|
|
69
|
-
ASCIIColors.cyan(f"\nGenerating SFX using '{lollms_client.ttm.binding_name}': '{filename_stem}'")
|
|
70
|
-
ASCIIColors.info(f"Prompt: '{prompt[:60]}...'")
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
if not lollms_client.ttm:
|
|
74
|
-
ASCIIColors.error("TTM (Text-to-Music/Sound) binding is not available in LollmsClient.")
|
|
75
|
-
return None
|
|
76
|
-
|
|
77
|
-
ttm_params = {"progress": True} # Common param for both
|
|
78
|
-
|
|
79
|
-
if lollms_client.ttm.binding_name == "audiocraft":
|
|
80
|
-
ttm_params["duration"] = sfx_info.get("duration", 1.0)
|
|
81
|
-
ttm_params["temperature"] = sfx_info.get("audiocraft_temperature", 1.0)
|
|
82
|
-
ttm_params["cfg_coef"] = sfx_info.get("audiocraft_cfg_coef", 3.0)
|
|
83
|
-
ASCIIColors.info(f"AudioCraft Params: duration={ttm_params['duration']}, temp={ttm_params['temperature']}, cfg={ttm_params['cfg_coef']}")
|
|
84
|
-
elif lollms_client.ttm.binding_name == "bark":
|
|
85
|
-
# Bark duration is implicit. Parameters are different.
|
|
86
|
-
bark_specific_params = sfx_info.get("bark_params", {})
|
|
87
|
-
ttm_params["voice_preset"] = bark_specific_params.get("voice_preset", None) # None might be good for SFX
|
|
88
|
-
ttm_params["fine_temperature"] = bark_specific_params.get("fine_temperature", 0.5)
|
|
89
|
-
ttm_params["coarse_temperature"] = bark_specific_params.get("coarse_temperature", 0.7)
|
|
90
|
-
ASCIIColors.info(f"Bark Params: preset={ttm_params['voice_preset']}, fine_temp={ttm_params['fine_temperature']}, coarse_temp={ttm_params['coarse_temperature']}")
|
|
91
|
-
else:
|
|
92
|
-
ASCIIColors.warning(f"Unknown TTM binding '{lollms_client.ttm.binding_name}'. Using generic parameters.")
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
try:
|
|
96
|
-
music_bytes = lollms_client.ttm.generate_music(prompt=prompt, **ttm_params)
|
|
97
|
-
|
|
98
|
-
if music_bytes:
|
|
99
|
-
with open(output_path, "wb") as f:
|
|
100
|
-
f.write(music_bytes)
|
|
101
|
-
ASCIIColors.green(f"SFX '{filename_stem}' ({lollms_client.ttm.binding_name}) saved to: {output_path}")
|
|
102
|
-
return output_path
|
|
103
|
-
else:
|
|
104
|
-
ASCIIColors.warning(f"SFX generation for '{filename_stem}' ({lollms_client.ttm.binding_name}) returned empty bytes.")
|
|
105
|
-
return None
|
|
106
|
-
except Exception as e:
|
|
107
|
-
ASCIIColors.error(f"Error generating SFX '{filename_stem}' ({lollms_client.ttm.binding_name}): {e}")
|
|
108
|
-
trace_exception(e)
|
|
109
|
-
return None
|
|
110
|
-
|
|
111
|
-
def main():
|
|
112
|
-
parser = argparse.ArgumentParser(description="Generate game sound effects using LOLLMS TTM bindings.")
|
|
113
|
-
parser.add_argument(
|
|
114
|
-
"--ttm_binding",
|
|
115
|
-
type=str,
|
|
116
|
-
choices=["audiocraft", "bark"],
|
|
117
|
-
default="bark", # Default to audiocraft
|
|
118
|
-
help="The TTM binding to use for generation."
|
|
119
|
-
)
|
|
120
|
-
parser.add_argument(
|
|
121
|
-
"--audiocraft_model",
|
|
122
|
-
type=str,
|
|
123
|
-
default="facebook/musicgen-small",
|
|
124
|
-
help="Hugging Face model ID for AudioCraft (e.g., facebook/musicgen-small, facebook/musicgen-melody)."
|
|
125
|
-
)
|
|
126
|
-
parser.add_argument(
|
|
127
|
-
"--bark_model",
|
|
128
|
-
type=str,
|
|
129
|
-
default="suno/bark-small",
|
|
130
|
-
help="Hugging Face model ID for Bark (e.g., suno/bark-small, suno/bark)."
|
|
131
|
-
)
|
|
132
|
-
parser.add_argument(
|
|
133
|
-
"--device",
|
|
134
|
-
type=str,
|
|
135
|
-
default=None, # Auto-detect
|
|
136
|
-
choices=["cpu", "cuda", "mps", None],
|
|
137
|
-
help="Device to run the TTM model on (cpu, cuda, mps, or auto-detect)."
|
|
138
|
-
)
|
|
139
|
-
args = parser.parse_args()
|
|
140
|
-
|
|
141
|
-
ASCIIColors.red(f"--- LOLLMS Game SFX Generation Example (Using: {args.ttm_binding}) ---")
|
|
142
|
-
|
|
143
|
-
ttm_binding_config = {"device": args.device} # Common device config
|
|
144
|
-
if args.ttm_binding == "audiocraft":
|
|
145
|
-
ttm_binding_config["model_name"] = args.audiocraft_model
|
|
146
|
-
ttm_binding_config["output_format"] = "wav" # Audiocraft binding defaults to wav for bytes
|
|
147
|
-
elif args.ttm_binding == "bark":
|
|
148
|
-
ttm_binding_config["model_name"] = args.bark_model
|
|
149
|
-
# Bark binding currently outputs WAV by default for bytes
|
|
150
|
-
else:
|
|
151
|
-
ASCIIColors.error(f"Unsupported TTM binding: {args.ttm_binding}")
|
|
152
|
-
return
|
|
153
|
-
|
|
154
|
-
try:
|
|
155
|
-
ASCIIColors.magenta(f"Initializing LollmsClient with {args.ttm_binding} for TTM...")
|
|
156
|
-
lollms_client = LollmsClient(
|
|
157
|
-
binding_name="lollms", # Can be a dummy if only using TTM
|
|
158
|
-
ttm_binding_name=args.ttm_binding,
|
|
159
|
-
ttm_binding_config=ttm_binding_config
|
|
160
|
-
)
|
|
161
|
-
ASCIIColors.green("LollmsClient initialized.")
|
|
162
|
-
except Exception as e:
|
|
163
|
-
ASCIIColors.error(f"Failed to initialize LollmsClient: {e}")
|
|
164
|
-
trace_exception(e)
|
|
165
|
-
return
|
|
166
|
-
|
|
167
|
-
if not lollms_client.ttm:
|
|
168
|
-
ASCIIColors.error(f"{args.ttm_binding.capitalize()} TTM binding could not be loaded. Exiting.")
|
|
169
|
-
return
|
|
170
|
-
|
|
171
|
-
generated_sfx_paths = {}
|
|
172
|
-
for sfx_info_item in SOUND_EFFECTS_TO_GENERATE:
|
|
173
|
-
sfx_path = generate_sfx(lollms_client, sfx_info_item)
|
|
174
|
-
if sfx_path:
|
|
175
|
-
generated_sfx_paths[sfx_info_item["filename"]] = {
|
|
176
|
-
"path": sfx_path,
|
|
177
|
-
"binding": args.ttm_binding # Store which binding generated it
|
|
178
|
-
}
|
|
179
|
-
time.sleep(0.5) # Small delay
|
|
180
|
-
|
|
181
|
-
ASCIIColors.red("\n--- SFX Generation Complete ---")
|
|
182
|
-
if not generated_sfx_paths:
|
|
183
|
-
ASCIIColors.warning("No sound effects were successfully generated.")
|
|
184
|
-
return
|
|
185
|
-
|
|
186
|
-
if not PYGAME_AVAILABLE:
|
|
187
|
-
ASCIIColors.warning("Pygame is not available. Skipping sound playback demo.")
|
|
188
|
-
ASCIIColors.info(f"Generated SFX can be found in: {SFX_OUTPUT_DIR.resolve()}")
|
|
189
|
-
return
|
|
190
|
-
|
|
191
|
-
ASCIIColors.magenta("\n--- Pygame SFX Playback Demo ---")
|
|
192
|
-
pygame.mixer.init()
|
|
193
|
-
game_sounds = {}
|
|
194
|
-
sfx_playback_order = [] # To map number keys to sounds
|
|
195
|
-
|
|
196
|
-
for filename_stem, sfx_data in generated_sfx_paths.items():
|
|
197
|
-
path = sfx_data["path"]
|
|
198
|
-
binding_used = sfx_data["binding"]
|
|
199
|
-
playback_name = f"{filename_stem} ({binding_used})"
|
|
200
|
-
try:
|
|
201
|
-
sound = pygame.mixer.Sound(str(path))
|
|
202
|
-
game_sounds[playback_name] = sound
|
|
203
|
-
sfx_playback_order.append(playback_name)
|
|
204
|
-
ASCIIColors.green(f"Loaded '{path.name}' into pygame as '{playback_name}'.")
|
|
205
|
-
except pygame.error as e:
|
|
206
|
-
ASCIIColors.warning(f"Could not load sound '{path.name}' into pygame: {e}")
|
|
207
|
-
|
|
208
|
-
if not game_sounds:
|
|
209
|
-
ASCIIColors.warning("No sounds loaded into pygame. Exiting demo.")
|
|
210
|
-
return
|
|
211
|
-
|
|
212
|
-
print("\nInstructions:")
|
|
213
|
-
for i, sfx_name_to_play in enumerate(sfx_playback_order):
|
|
214
|
-
print(f" Press key '{i+1}' to play: {sfx_name_to_play}")
|
|
215
|
-
print(" Press 'Q' to quit the demo.")
|
|
216
|
-
|
|
217
|
-
pygame.display.set_mode((400, 200))
|
|
218
|
-
pygame.display.set_caption(f"SFX Player ({args.ttm_binding.capitalize()})")
|
|
219
|
-
|
|
220
|
-
running = True
|
|
221
|
-
while running:
|
|
222
|
-
for event in pygame.event.get():
|
|
223
|
-
if event.type == pygame.QUIT: running = False
|
|
224
|
-
if event.type == pygame.KEYDOWN:
|
|
225
|
-
if event.key == pygame.K_q: running = False
|
|
226
|
-
for i in range(len(sfx_playback_order)):
|
|
227
|
-
if event.key == getattr(pygame, f"K_{i+1}", None): # Check if K_i+1 exists
|
|
228
|
-
sfx_name_to_play = sfx_playback_order[i]
|
|
229
|
-
if sfx_name_to_play in game_sounds:
|
|
230
|
-
ASCIIColors.cyan(f"Playing: {sfx_name_to_play}")
|
|
231
|
-
game_sounds[sfx_name_to_play].play()
|
|
232
|
-
break
|
|
233
|
-
pygame.time.Clock().tick(30)
|
|
234
|
-
|
|
235
|
-
pygame.quit()
|
|
236
|
-
ASCIIColors.red("--- Demo Finished ---")
|
|
237
|
-
ASCIIColors.info(f"Generated SFX are in: {SFX_OUTPUT_DIR.resolve()}")
|
|
238
|
-
|
|
239
|
-
if __name__ == "__main__":
|
|
240
|
-
main()
|
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
from lollms_client import LollmsClient, MSG_TYPE
|
|
2
|
-
from ascii_colors import ASCIIColors, trace_exception
|
|
3
|
-
from typing import List, Dict, Any, Optional, Callable
|
|
4
|
-
import json
|
|
5
|
-
from pathlib import Path
|
|
6
|
-
|
|
7
|
-
# --- Mock RAG Implementation ---
|
|
8
|
-
# In a real application, this would interact with your vector database (Pinecone, ChromaDB, FAISS, etc.)
|
|
9
|
-
# and use a real sentence transformer for vectorization.
|
|
10
|
-
|
|
11
|
-
MOCK_KNOWLEDGE_BASE = {
|
|
12
|
-
"python_basics.md": [
|
|
13
|
-
{"chunk_id": 1, "text": "Python is a high-level, interpreted programming language known for its readability and versatility. It was created by Guido van Rossum and first released in 1991."},
|
|
14
|
-
{"chunk_id": 2, "text": "Key features of Python include dynamic typing, automatic memory management (garbage collection), and a large standard library. It supports multiple programming paradigms, such as procedural, object-oriented, and functional programming."},
|
|
15
|
-
{"chunk_id": 3, "text": "Common applications of Python include web development (e.g., Django, Flask), data science (e.g., Pandas, NumPy, Scikit-learn), machine learning, artificial intelligence, automation, and scripting."},
|
|
16
|
-
],
|
|
17
|
-
"javascript_info.js": [
|
|
18
|
-
{"chunk_id": 1, "text": "JavaScript is a scripting language primarily used for front-end web development to create interactive effects within web browsers. It is also used in back-end development (Node.js), mobile app development, and game development."},
|
|
19
|
-
{"chunk_id": 2, "text": "JavaScript is dynamically typed, prototype-based, and multi-paradigm. Along with HTML and CSS, it is one of the core technologies of the World Wide Web."},
|
|
20
|
-
{"chunk_id": 3, "text": "Popular JavaScript frameworks and libraries include React, Angular, Vue.js for front-end, and Express.js for Node.js back-end applications."},
|
|
21
|
-
],
|
|
22
|
-
"ai_concepts.txt": [
|
|
23
|
-
{"chunk_id": 1, "text": "Artificial Intelligence (AI) refers to the simulation of human intelligence in machines that are programmed to think like humans and mimic their actions. The term may also be applied to any machine that exhibits traits associated with a human mind such as learning and problem-solving."},
|
|
24
|
-
{"chunk_id": 2, "text": "Machine Learning (ML) is a subset of AI that provides systems the ability to automatically learn and improve from experience without being explicitly programmed. Deep Learning (DL) is a further subset of ML based on artificial neural networks with representation learning."},
|
|
25
|
-
{"chunk_id": 3, "text": "Retrieval Augmented Generation (RAG) is an AI framework for improving the quality of LLM-generated responses by grounding the model on external sources of knowledge to supplement the LLM’s internal representation of information."},
|
|
26
|
-
]
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
def mock_rag_query_function(
|
|
30
|
-
query_text: str,
|
|
31
|
-
vectorizer_name: Optional[str] = None, # Ignored in mock
|
|
32
|
-
top_k: int = 3,
|
|
33
|
-
min_similarity_percent: float = 0.0 # Ignored in mock, simple keyword match
|
|
34
|
-
) -> List[Dict[str, Any]]:
|
|
35
|
-
"""
|
|
36
|
-
A mock RAG query function.
|
|
37
|
-
Performs a simple keyword search in the MOCK_KNOWLEDGE_BASE.
|
|
38
|
-
"""
|
|
39
|
-
ASCIIColors.magenta(f" [MOCK RAG] Querying with: '{query_text}', top_k={top_k}")
|
|
40
|
-
results = []
|
|
41
|
-
query_lower = query_text.lower()
|
|
42
|
-
|
|
43
|
-
all_chunks = []
|
|
44
|
-
for file_path, chunks_in_file in MOCK_KNOWLEDGE_BASE.items():
|
|
45
|
-
for chunk_data in chunks_in_file:
|
|
46
|
-
all_chunks.append({"file_path": file_path, **chunk_data})
|
|
47
|
-
|
|
48
|
-
# Simple keyword matching and scoring (very basic)
|
|
49
|
-
scored_chunks = []
|
|
50
|
-
for chunk_info in all_chunks:
|
|
51
|
-
score = 0
|
|
52
|
-
for keyword in query_lower.split():
|
|
53
|
-
if keyword in chunk_info["text"].lower() and len(keyword)>2: # Basic relevance
|
|
54
|
-
score += 1
|
|
55
|
-
if "python" in query_lower and "python" in chunk_info["file_path"].lower(): score+=5
|
|
56
|
-
if "javascript" in query_lower and "javascript" in chunk_info["file_path"].lower(): score+=5
|
|
57
|
-
if "ai" in query_lower and "ai" in chunk_info["file_path"].lower(): score+=3
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if score > 0 : # Only include if some keywords match
|
|
61
|
-
# Simulate similarity percentage (higher score = higher similarity)
|
|
62
|
-
similarity = min(100.0, score * 20.0 + 40.0) # Arbitrary scaling
|
|
63
|
-
if similarity >= min_similarity_percent:
|
|
64
|
-
scored_chunks.append({
|
|
65
|
-
"file_path": chunk_info["file_path"],
|
|
66
|
-
"chunk_text": chunk_info["text"],
|
|
67
|
-
"similarity_percent": similarity,
|
|
68
|
-
"_score_for_ranking": score # Internal score for sorting
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
# Sort by internal score (descending) and take top_k
|
|
72
|
-
scored_chunks.sort(key=lambda x: x["_score_for_ranking"], reverse=True)
|
|
73
|
-
results = [
|
|
74
|
-
{"file_path": c["file_path"], "chunk_text": c["chunk_text"], "similarity_percent": c["similarity_percent"]}
|
|
75
|
-
for c in scored_chunks[:top_k]
|
|
76
|
-
]
|
|
77
|
-
ASCIIColors.magenta(f" [MOCK RAG] Found {len(results)} relevant chunks.")
|
|
78
|
-
return results
|
|
79
|
-
|
|
80
|
-
# --- Streaming Callback for RAG and LLM ---
|
|
81
|
-
def rag_streaming_callback(
|
|
82
|
-
chunk: str,
|
|
83
|
-
msg_type: MSG_TYPE,
|
|
84
|
-
metadata: Optional[Dict] = None,
|
|
85
|
-
turn_history: Optional[List] = None # history of this specific RAG turn
|
|
86
|
-
) -> bool:
|
|
87
|
-
"""
|
|
88
|
-
Handles various stages of RAG and final LLM generation.
|
|
89
|
-
"""
|
|
90
|
-
metadata = metadata or {}
|
|
91
|
-
turn_history = turn_history or [] # Should be populated by LollmsClient
|
|
92
|
-
|
|
93
|
-
if msg_type == MSG_TYPE.MSG_TYPE_CHUNK: # Final answer chunks
|
|
94
|
-
ASCIIColors.success(chunk, end="", flush=True)
|
|
95
|
-
elif msg_type == MSG_TYPE.MSG_TYPE_STEP_START:
|
|
96
|
-
step_type = metadata.get("type", "step")
|
|
97
|
-
hop = metadata.get("hop", "")
|
|
98
|
-
info = metadata.get("query", chunk) if step_type == "rag_query_generation" or step_type == "rag_retrieval" else chunk
|
|
99
|
-
ASCIIColors.yellow(f"\n>> RAG Step Start (Hop {hop}): {step_type} - Info: {str(info)[:100]}...", flush=True)
|
|
100
|
-
elif msg_type == MSG_TYPE.MSG_TYPE_STEP_END:
|
|
101
|
-
step_type = metadata.get("type", "step")
|
|
102
|
-
hop = metadata.get("hop", "")
|
|
103
|
-
num_chunks = metadata.get("num_chunks", "")
|
|
104
|
-
query = metadata.get("query", "")
|
|
105
|
-
decision = metadata.get("decision", "")
|
|
106
|
-
|
|
107
|
-
info_str = ""
|
|
108
|
-
if step_type == "rag_query_generation" and query: info_str = f"Generated Query: {query}"
|
|
109
|
-
elif step_type == "rag_retrieval": info_str = f"Retrieved {num_chunks} chunks"
|
|
110
|
-
elif step_type == "rag_llm_decision": info_str = f"LLM Decision: {json.dumps(decision)}"
|
|
111
|
-
elif step_type == "final_answer_generation": info_str = "Final answer generation complete."
|
|
112
|
-
else: info_str = chunk
|
|
113
|
-
|
|
114
|
-
ASCIIColors.green(f"\n<< RAG Step End (Hop {hop}): {step_type} - {info_str}", flush=True)
|
|
115
|
-
elif msg_type == MSG_TYPE.MSG_TYPE_EXCEPTION:
|
|
116
|
-
ASCIIColors.error(f"\nError in RAG stream: {chunk}", flush=True)
|
|
117
|
-
|
|
118
|
-
# You can inspect turn_history here if needed:
|
|
119
|
-
# ASCIIColors.debug(f"Current RAG Turn History: {turn_history}")
|
|
120
|
-
return True
|
|
121
|
-
|
|
122
|
-
# --- Main Example ---
|
|
123
|
-
if __name__ == "__main__":
|
|
124
|
-
ASCIIColors.red("--- Multi-Hop RAG Example with LollmsClient ---")
|
|
125
|
-
|
|
126
|
-
# LLM Configuration (use a model good at instruction following and JSON)
|
|
127
|
-
# Ensure your Ollama server is running and has this model pulled.
|
|
128
|
-
LLM_BINDING_NAME = "ollama"
|
|
129
|
-
LLM_MODEL_NAME = "qwen3:4b" # or llama3, phi3 etc.
|
|
130
|
-
# LLM_MODEL_NAME = "qwen2:1.5b" # Smaller model for quicker tests, but might struggle with complex JSON
|
|
131
|
-
|
|
132
|
-
try:
|
|
133
|
-
lc = LollmsClient(
|
|
134
|
-
binding_name=LLM_BINDING_NAME,
|
|
135
|
-
model_name=LLM_MODEL_NAME,
|
|
136
|
-
temperature=0.1, # Default temp for final answer if not overridden
|
|
137
|
-
# Other LollmsClient params as needed
|
|
138
|
-
)
|
|
139
|
-
ASCIIColors.green(f"LollmsClient initialized with LLM: {LLM_BINDING_NAME}/{LLM_MODEL_NAME}")
|
|
140
|
-
|
|
141
|
-
# --- Test Case 1: Classic RAG (max_rag_hops = 0) ---
|
|
142
|
-
ASCIIColors.cyan("\n\n--- Test Case 1: Classic RAG (max_rag_hops = 0) ---")
|
|
143
|
-
classic_rag_prompt = "What are the key features of Python?"
|
|
144
|
-
ASCIIColors.blue(f"User Prompt: {classic_rag_prompt}")
|
|
145
|
-
|
|
146
|
-
classic_rag_result = lc.generate_text_with_rag(
|
|
147
|
-
prompt=classic_rag_prompt,
|
|
148
|
-
rag_query_function=mock_rag_query_function,
|
|
149
|
-
# rag_query_text=None, # Will use `prompt` for query
|
|
150
|
-
max_rag_hops=0,
|
|
151
|
-
rag_top_k=2, # Get 2 best chunks
|
|
152
|
-
rag_min_similarity_percent=50.0,
|
|
153
|
-
streaming_callback=rag_streaming_callback,
|
|
154
|
-
n_predict=1024 # Max tokens for final answer
|
|
155
|
-
)
|
|
156
|
-
print("\n--- End of Classic RAG ---")
|
|
157
|
-
ASCIIColors.magenta("\nClassic RAG Final Output:")
|
|
158
|
-
print(json.dumps(classic_rag_result, indent=2))
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
# --- Test Case 2: Multi-Hop RAG (max_rag_hops = 1) ---
|
|
162
|
-
ASCIIColors.cyan("\n\n--- Test Case 2: Multi-Hop RAG (max_rag_hops = 1) ---")
|
|
163
|
-
multihop_prompt_1 = "Compare Python and JavaScript for web development based on their common applications and core technologies."
|
|
164
|
-
ASCIIColors.blue(f"User Prompt: {multihop_prompt_1}")
|
|
165
|
-
|
|
166
|
-
multihop_rag_result_1 = lc.generate_text_with_rag(
|
|
167
|
-
prompt=multihop_prompt_1,
|
|
168
|
-
rag_query_function=mock_rag_query_function,
|
|
169
|
-
# rag_query_text="Python web development applications", # Optional: provide an initial query
|
|
170
|
-
max_rag_hops=1, # Allow one hop for LLM to refine search or decide
|
|
171
|
-
rag_top_k=2,
|
|
172
|
-
rag_min_similarity_percent=60.0,
|
|
173
|
-
streaming_callback=rag_streaming_callback,
|
|
174
|
-
n_predict=1024,
|
|
175
|
-
rag_hop_query_generation_temperature=0.1, # Focused query gen
|
|
176
|
-
)
|
|
177
|
-
print("\n--- End of Multi-Hop RAG (1 hop) ---")
|
|
178
|
-
ASCIIColors.magenta("\nMulti-Hop RAG (1 hop) Final Output:")
|
|
179
|
-
print(json.dumps(multihop_rag_result_1, indent=2))
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
# --- Test Case 3: Multi-Hop RAG (max_rag_hops = 2) - LLM might decide it has enough earlier ---
|
|
183
|
-
ASCIIColors.cyan("\n\n--- Test Case 3: Multi-Hop RAG (max_rag_hops = 2) ---")
|
|
184
|
-
multihop_prompt_2 = "Explain Retrieval Augmented Generation (RAG) and its relation to Machine Learning."
|
|
185
|
-
ASCIIColors.blue(f"User Prompt: {multihop_prompt_2}")
|
|
186
|
-
|
|
187
|
-
multihop_rag_result_2 = lc.generate_text_with_rag(
|
|
188
|
-
prompt=multihop_prompt_2,
|
|
189
|
-
rag_query_function=mock_rag_query_function,
|
|
190
|
-
max_rag_hops=2, # Allow up to two refinement hops
|
|
191
|
-
rag_top_k=1, # Get only the best chunk per hop to force more specific queries
|
|
192
|
-
rag_min_similarity_percent=50.0,
|
|
193
|
-
streaming_callback=rag_streaming_callback,
|
|
194
|
-
n_predict=300
|
|
195
|
-
)
|
|
196
|
-
print("\n--- End of Multi-Hop RAG (up to 2 hops) ---")
|
|
197
|
-
ASCIIColors.magenta("\nMulti-Hop RAG (up to 2 hops) Final Output:")
|
|
198
|
-
print(json.dumps(multihop_rag_result_2, indent=2))
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
except ValueError as ve:
|
|
202
|
-
ASCIIColors.error(f"Initialization or RAG parameter error: {ve}")
|
|
203
|
-
trace_exception(ve)
|
|
204
|
-
except ConnectionRefusedError:
|
|
205
|
-
ASCIIColors.error(f"Connection refused. Is the Ollama server ({LLM_BINDING_NAME}) running?")
|
|
206
|
-
except Exception as e:
|
|
207
|
-
ASCIIColors.error(f"An unexpected error occurred: {e}")
|
|
208
|
-
trace_exception(e)
|
|
209
|
-
|
|
210
|
-
ASCIIColors.red("\n--- Multi-Hop RAG Example Finished ---")
|