chat-console 0.1.96.dev1__py3-none-any.whl → 0.1.991.dev1__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.
- app/main.py +64 -15
- app/ui/chat_interface.py +16 -13
- app/utils.py +25 -5
- {chat_console-0.1.96.dev1.dist-info → chat_console-0.1.991.dev1.dist-info}/METADATA +1 -1
- {chat_console-0.1.96.dev1.dist-info → chat_console-0.1.991.dev1.dist-info}/RECORD +9 -9
- {chat_console-0.1.96.dev1.dist-info → chat_console-0.1.991.dev1.dist-info}/WHEEL +0 -0
- {chat_console-0.1.96.dev1.dist-info → chat_console-0.1.991.dev1.dist-info}/entry_points.txt +0 -0
- {chat_console-0.1.96.dev1.dist-info → chat_console-0.1.991.dev1.dist-info}/licenses/LICENSE +0 -0
- {chat_console-0.1.96.dev1.dist-info → chat_console-0.1.991.dev1.dist-info}/top_level.txt +0 -0
app/main.py
CHANGED
@@ -19,7 +19,8 @@ from openai import OpenAI
|
|
19
19
|
from app.models import Message, Conversation
|
20
20
|
from app.database import ChatDatabase
|
21
21
|
from app.config import CONFIG, OPENAI_API_KEY, ANTHROPIC_API_KEY, OLLAMA_BASE_URL
|
22
|
-
|
22
|
+
# Import InputWithFocus as well
|
23
|
+
from app.ui.chat_interface import MessageDisplay, InputWithFocus
|
23
24
|
from app.ui.model_selector import ModelSelector, StyleSelector
|
24
25
|
from app.ui.chat_list import ChatList
|
25
26
|
from app.api.base import BaseModelClient
|
@@ -114,10 +115,15 @@ class HistoryScreen(Screen):
|
|
114
115
|
class SimpleChatApp(App): # Keep SimpleChatApp class definition
|
115
116
|
"""Simplified Chat CLI application.""" # Keep SimpleChatApp docstring
|
116
117
|
|
117
|
-
TITLE = "Chat
|
118
|
+
TITLE = "Chat Console"
|
118
119
|
SUB_TITLE = "AI Chat Interface" # Keep SimpleChatApp SUB_TITLE
|
119
120
|
DARK = True # Keep SimpleChatApp DARK
|
120
121
|
|
122
|
+
# Ensure the log directory exists in a standard cache location
|
123
|
+
log_dir = os.path.expanduser("~/.cache/chat-cli")
|
124
|
+
os.makedirs(log_dir, exist_ok=True)
|
125
|
+
LOG_FILE = os.path.join(log_dir, "textual.log") # Use absolute path
|
126
|
+
|
121
127
|
CSS = """ # Keep SimpleChatApp CSS start
|
122
128
|
#main-content { # Keep SimpleChatApp CSS
|
123
129
|
width: 100%;
|
@@ -240,15 +246,17 @@ class SimpleChatApp(App): # Keep SimpleChatApp class definition
|
|
240
246
|
|
241
247
|
BINDINGS = [ # Keep SimpleChatApp BINDINGS, ensure Enter is not globally bound for settings
|
242
248
|
Binding("q", "quit", "Quit", show=True, key_display="q"),
|
249
|
+
# Removed priority=True - actions should only trigger when input is NOT focused
|
243
250
|
Binding("n", "action_new_conversation", "New Chat", show=True, key_display="n"),
|
244
|
-
Binding("c", "action_new_conversation", "New Chat", show=False, key_display="c"),
|
251
|
+
Binding("c", "action_new_conversation", "New Chat", show=False, key_display="c"), # Removed priority from alias
|
245
252
|
Binding("escape", "escape", "Cancel / Stop", show=True, key_display="esc"), # Escape might close settings panel too
|
246
253
|
Binding("ctrl+c", "quit", "Quit", show=False),
|
247
|
-
Binding("h", "view_history", "History", show=True, key_display="h"),
|
248
|
-
Binding("s", "settings", "Settings", show=True, key_display="s"),
|
254
|
+
Binding("h", "view_history", "History", show=True, key_display="h"), # Action method checks focus
|
255
|
+
Binding("s", "settings", "Settings", show=True, key_display="s"), # Action method checks focus
|
256
|
+
# Removed priority=True - action should only trigger when input is NOT focused
|
249
257
|
Binding("t", "action_update_title", "Update Title", show=True, key_display="t"),
|
250
258
|
] # Keep SimpleChatApp BINDINGS end
|
251
|
-
|
259
|
+
|
252
260
|
current_conversation = reactive(None) # Keep SimpleChatApp reactive var
|
253
261
|
is_generating = reactive(False) # Keep SimpleChatApp reactive var
|
254
262
|
|
@@ -259,7 +267,8 @@ class SimpleChatApp(App): # Keep SimpleChatApp class definition
|
|
259
267
|
self.selected_model = CONFIG["default_model"] # Keep SimpleChatApp __init__
|
260
268
|
self.selected_style = CONFIG["default_style"] # Keep SimpleChatApp __init__
|
261
269
|
self.initial_text = initial_text # Keep SimpleChatApp __init__
|
262
|
-
|
270
|
+
# Removed self.input_widget instance variable
|
271
|
+
|
263
272
|
def compose(self) -> ComposeResult: # Modify SimpleChatApp compose
|
264
273
|
"""Create the simplified application layout."""
|
265
274
|
yield Header()
|
@@ -278,7 +287,8 @@ class SimpleChatApp(App): # Keep SimpleChatApp class definition
|
|
278
287
|
|
279
288
|
# Input area
|
280
289
|
with Container(id="input-area"):
|
281
|
-
|
290
|
+
# Use the custom InputWithFocus widget
|
291
|
+
yield InputWithFocus(placeholder="Type your message here...", id="message-input")
|
282
292
|
# Removed Static widgets previously used for diagnosis
|
283
293
|
|
284
294
|
# --- Add Settings Panel (hidden initially) ---
|
@@ -335,10 +345,12 @@ class SimpleChatApp(App): # Keep SimpleChatApp class definition
|
|
335
345
|
await self.action_send_message() # Keep SimpleChatApp on_mount
|
336
346
|
else: # Keep SimpleChatApp on_mount
|
337
347
|
# Focus the input if no initial text # Keep SimpleChatApp on_mount
|
348
|
+
# Removed assignment to self.input_widget
|
338
349
|
self.query_one("#message-input").focus() # Keep SimpleChatApp on_mount
|
339
|
-
|
350
|
+
|
340
351
|
async def create_new_conversation(self) -> None: # Keep SimpleChatApp create_new_conversation
|
341
352
|
"""Create a new chat conversation.""" # Keep SimpleChatApp create_new_conversation docstring
|
353
|
+
log("Entering create_new_conversation") # Added log
|
342
354
|
# Create new conversation in database using selected model and style # Keep SimpleChatApp create_new_conversation
|
343
355
|
model = self.selected_model # Keep SimpleChatApp create_new_conversation
|
344
356
|
style = self.selected_style # Keep SimpleChatApp create_new_conversation
|
@@ -347,7 +359,9 @@ class SimpleChatApp(App): # Keep SimpleChatApp class definition
|
|
347
359
|
title = f"New conversation ({datetime.now().strftime('%Y-%m-%d %H:%M')})" # Keep SimpleChatApp create_new_conversation
|
348
360
|
|
349
361
|
# Create conversation in database using the correct method # Keep SimpleChatApp create_new_conversation
|
362
|
+
log(f"Creating conversation with title: {title}, model: {model}, style: {style}") # Added log
|
350
363
|
conversation_id = self.db.create_conversation(title, model, style) # Keep SimpleChatApp create_new_conversation
|
364
|
+
log(f"Database returned conversation_id: {conversation_id}") # Added log
|
351
365
|
|
352
366
|
# Get the full conversation data # Keep SimpleChatApp create_new_conversation
|
353
367
|
conversation_data = self.db.get_conversation(conversation_id) # Keep SimpleChatApp create_new_conversation
|
@@ -361,26 +375,42 @@ class SimpleChatApp(App): # Keep SimpleChatApp class definition
|
|
361
375
|
|
362
376
|
# Clear messages and update UI # Keep SimpleChatApp create_new_conversation
|
363
377
|
self.messages = [] # Keep SimpleChatApp create_new_conversation
|
378
|
+
log("Finished updating messages UI in create_new_conversation") # Added log
|
364
379
|
await self.update_messages_ui() # Keep SimpleChatApp create_new_conversation
|
365
|
-
|
380
|
+
|
366
381
|
async def action_new_conversation(self) -> None: # Keep SimpleChatApp action_new_conversation
|
367
382
|
"""Handle the new conversation action.""" # Keep SimpleChatApp action_new_conversation docstring
|
368
|
-
|
383
|
+
log("--- ENTERING action_new_conversation ---") # Add entry log
|
369
384
|
|
385
|
+
# Check if the currently focused widget is the input widget
|
386
|
+
currently_focused = self.focused
|
387
|
+
if currently_focused and currently_focused.id == "message-input":
|
388
|
+
log("action_new_conversation skipped: input has focus")
|
389
|
+
return
|
390
|
+
|
391
|
+
log("action_new_conversation EXECUTING") # Add execution log
|
392
|
+
await self.create_new_conversation() # Keep SimpleChatApp action_new_conversation
|
393
|
+
log("action_new_conversation finished") # Added log
|
394
|
+
|
370
395
|
def action_escape(self) -> None: # Modify SimpleChatApp action_escape
|
371
396
|
"""Handle escape key globally."""
|
397
|
+
log("action_escape triggered") # Added log
|
372
398
|
settings_panel = self.query_one("#settings-panel")
|
399
|
+
log(f"Settings panel visible: {settings_panel.has_class('visible')}") # Added log
|
373
400
|
if settings_panel.has_class("visible"):
|
401
|
+
log("Hiding settings panel") # Added log
|
374
402
|
# If settings panel is visible, hide it
|
375
403
|
settings_panel.remove_class("visible")
|
376
404
|
self.query_one("#message-input").focus() # Focus input after closing settings
|
377
405
|
elif self.is_generating:
|
406
|
+
log("Stopping generation") # Added log
|
378
407
|
# Otherwise, stop generation if running
|
379
408
|
self.is_generating = False # Keep SimpleChatApp action_escape
|
380
409
|
self.notify("Generation stopped", severity="warning") # Keep SimpleChatApp action_escape
|
381
410
|
loading = self.query_one("#loading-indicator") # Keep SimpleChatApp action_escape
|
382
411
|
loading.add_class("hidden") # Keep SimpleChatApp action_escape
|
383
|
-
|
412
|
+
else: # Optional: Add other escape behavior for the main screen if desired # Keep SimpleChatApp action_escape comment
|
413
|
+
log("Escape pressed, but settings not visible and not generating.") # Added log
|
384
414
|
# pass # Keep SimpleChatApp action_escape comment
|
385
415
|
|
386
416
|
# Removed action_confirm_or_send - Enter is handled by Input submission # Keep SimpleChatApp comment
|
@@ -490,6 +520,7 @@ class SimpleChatApp(App): # Keep SimpleChatApp class definition
|
|
490
520
|
return # Keep SimpleChatApp generate_response
|
491
521
|
|
492
522
|
self.is_generating = True # Keep SimpleChatApp generate_response
|
523
|
+
log(f"Setting is_generating to True") # Added log
|
493
524
|
loading = self.query_one("#loading-indicator") # Keep SimpleChatApp generate_response
|
494
525
|
loading.remove_class("hidden") # Keep SimpleChatApp generate_response
|
495
526
|
|
@@ -531,6 +562,7 @@ class SimpleChatApp(App): # Keep SimpleChatApp class definition
|
|
531
562
|
|
532
563
|
async def update_ui(content: str): # Keep SimpleChatApp generate_response
|
533
564
|
if not self.is_generating: # Keep SimpleChatApp generate_response
|
565
|
+
log("update_ui called but is_generating is False, returning.") # Added log
|
534
566
|
return # Keep SimpleChatApp generate_response
|
535
567
|
|
536
568
|
async with update_lock: # Keep SimpleChatApp generate_response
|
@@ -550,7 +582,7 @@ class SimpleChatApp(App): # Keep SimpleChatApp class definition
|
|
550
582
|
# Force another refresh to ensure content is visible # Keep SimpleChatApp generate_response
|
551
583
|
self.refresh(layout=True) # Keep SimpleChatApp generate_response
|
552
584
|
except Exception as e: # Keep SimpleChatApp generate_response
|
553
|
-
|
585
|
+
log.error(f"Error updating UI: {str(e)}") # Use log instead of logger
|
554
586
|
|
555
587
|
# Generate the response with timeout and cleanup # Keep SimpleChatApp generate_response
|
556
588
|
generation_task = None # Keep SimpleChatApp generate_response
|
@@ -558,6 +590,7 @@ class SimpleChatApp(App): # Keep SimpleChatApp class definition
|
|
558
590
|
# Create a task for the response generation # Keep SimpleChatApp generate_response
|
559
591
|
generation_task = asyncio.create_task( # Keep SimpleChatApp generate_response
|
560
592
|
generate_streaming_response( # Keep SimpleChatApp generate_response
|
593
|
+
self, # Pass the app instance
|
561
594
|
api_messages, # Keep SimpleChatApp generate_response
|
562
595
|
model, # Keep SimpleChatApp generate_response
|
563
596
|
style, # Keep SimpleChatApp generate_response
|
@@ -571,6 +604,7 @@ class SimpleChatApp(App): # Keep SimpleChatApp class definition
|
|
571
604
|
|
572
605
|
# Save to database only if we got a complete response # Keep SimpleChatApp generate_response
|
573
606
|
if self.is_generating and full_response: # Keep SimpleChatApp generate_response
|
607
|
+
log("Generation finished, saving full response to DB") # Added log
|
574
608
|
self.db.add_message( # Keep SimpleChatApp generate_response
|
575
609
|
self.current_conversation.id, # Keep SimpleChatApp generate_response
|
576
610
|
"assistant", # Keep SimpleChatApp generate_response
|
@@ -579,9 +613,11 @@ class SimpleChatApp(App): # Keep SimpleChatApp class definition
|
|
579
613
|
# Force a final refresh # Keep SimpleChatApp generate_response
|
580
614
|
self.refresh(layout=True) # Keep SimpleChatApp generate_response
|
581
615
|
await asyncio.sleep(0.1) # Wait for UI to update # Keep SimpleChatApp generate_response
|
616
|
+
elif not full_response:
|
617
|
+
log("Generation finished but full_response is empty/None") # Added log
|
582
618
|
|
583
619
|
except asyncio.TimeoutError: # Keep SimpleChatApp generate_response
|
584
|
-
|
620
|
+
log.error("Response generation timed out") # Use log instead of logger
|
585
621
|
error_msg = "Response generation timed out. The model may be busy or unresponsive. Please try again." # Keep SimpleChatApp generate_response
|
586
622
|
self.notify(error_msg, severity="error") # Keep SimpleChatApp generate_response
|
587
623
|
|
@@ -596,22 +632,25 @@ class SimpleChatApp(App): # Keep SimpleChatApp class definition
|
|
596
632
|
# Ensure task is properly cancelled and cleaned up # Keep SimpleChatApp generate_response
|
597
633
|
if generation_task: # Keep SimpleChatApp generate_response
|
598
634
|
if not generation_task.done(): # Keep SimpleChatApp generate_response
|
635
|
+
log("Cancelling generation task") # Added log
|
599
636
|
generation_task.cancel() # Keep SimpleChatApp generate_response
|
600
637
|
try: # Keep SimpleChatApp generate_response
|
601
638
|
await generation_task # Keep SimpleChatApp generate_response
|
602
639
|
except (asyncio.CancelledError, Exception) as e: # Keep SimpleChatApp generate_response
|
603
|
-
|
640
|
+
log.error(f"Error cleaning up generation task: {str(e)}") # Use log instead of logger
|
604
641
|
|
605
642
|
# Force a final UI refresh # Keep SimpleChatApp generate_response
|
606
643
|
self.refresh(layout=True) # Keep SimpleChatApp generate_response
|
607
644
|
|
608
645
|
except Exception as e: # Keep SimpleChatApp generate_response
|
646
|
+
log.error(f"Exception during generate_response: {str(e)}") # Added log
|
609
647
|
self.notify(f"Error generating response: {str(e)}", severity="error") # Keep SimpleChatApp generate_response
|
610
648
|
# Add error message # Keep SimpleChatApp generate_response
|
611
649
|
error_msg = f"Error generating response: {str(e)}" # Keep SimpleChatApp generate_response
|
612
650
|
self.messages.append(Message(role="assistant", content=error_msg)) # Keep SimpleChatApp generate_response
|
613
651
|
await self.update_messages_ui() # Keep SimpleChatApp generate_response
|
614
652
|
finally: # Keep SimpleChatApp generate_response
|
653
|
+
log(f"Setting is_generating to False in finally block") # Added log
|
615
654
|
self.is_generating = False # Keep SimpleChatApp generate_response
|
616
655
|
loading = self.query_one("#loading-indicator") # Keep SimpleChatApp generate_response
|
617
656
|
loading.add_class("hidden") # Keep SimpleChatApp generate_response
|
@@ -726,6 +765,16 @@ class SimpleChatApp(App): # Keep SimpleChatApp class definition
|
|
726
765
|
|
727
766
|
async def action_update_title(self) -> None:
|
728
767
|
"""Allow users to manually change the conversation title"""
|
768
|
+
log("--- ENTERING action_update_title ---") # Add entry log
|
769
|
+
|
770
|
+
# Check focus using self.focused instead of has_focus
|
771
|
+
currently_focused = self.focused
|
772
|
+
if currently_focused and currently_focused.id == "message-input":
|
773
|
+
log("action_update_title skipped: input has focus")
|
774
|
+
return
|
775
|
+
|
776
|
+
log("action_update_title EXECUTING") # Add execution log
|
777
|
+
|
729
778
|
if not self.current_conversation:
|
730
779
|
self.notify("No active conversation", severity="warning")
|
731
780
|
return
|
app/ui/chat_interface.py
CHANGED
@@ -129,20 +129,23 @@ class MessageDisplay(RichLog):
|
|
129
129
|
|
130
130
|
class InputWithFocus(Input):
|
131
131
|
"""Enhanced Input that better handles focus and maintains cursor position"""
|
132
|
-
|
132
|
+
# Reverted on_key to default Input behavior for 'n' and 't'
|
133
|
+
# Let the standard Input handle key presses when focused.
|
134
|
+
# We will rely on focus checks within the App's action methods.
|
135
|
+
|
136
|
+
# Keep custom handling only for Enter submission if needed,
|
137
|
+
# but standard Input might already do this. Let's simplify
|
138
|
+
# and remove the custom on_key entirely for now unless
|
133
139
|
def on_key(self, event) -> None:
|
134
|
-
|
135
|
-
#
|
136
|
-
if event.
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
# Normal input handling for other keys
|
145
|
-
super().on_key(event)
|
140
|
+
# Let global hotkeys 'n' and 't' pass through even when input has focus
|
141
|
+
# by simply *not* stopping the event here.
|
142
|
+
if event.key == "n" or event.key == "t":
|
143
|
+
# Do nothing, allow the event to bubble up to the app level bindings.
|
144
|
+
return # Explicitly return to prevent further processing in this method
|
145
|
+
|
146
|
+
# For all other keys, the event continues to be processed by the Input
|
147
|
+
# widget's internal handlers (like _on_key shown in the traceback)
|
148
|
+
# because we didn't stop it in this method.
|
146
149
|
|
147
150
|
class ChatInterface(Container):
|
148
151
|
"""Main chat interface container"""
|
app/utils.py
CHANGED
@@ -4,10 +4,14 @@ import time
|
|
4
4
|
import asyncio
|
5
5
|
import subprocess
|
6
6
|
import logging
|
7
|
-
from typing import Optional, Dict, Any, List
|
7
|
+
from typing import Optional, Dict, Any, List, TYPE_CHECKING
|
8
8
|
from datetime import datetime
|
9
9
|
from .config import CONFIG, save_config
|
10
10
|
|
11
|
+
# Import SimpleChatApp for type hinting only if TYPE_CHECKING is True
|
12
|
+
if TYPE_CHECKING:
|
13
|
+
from .main import SimpleChatApp
|
14
|
+
|
11
15
|
# Set up logging
|
12
16
|
logging.basicConfig(level=logging.INFO)
|
13
17
|
logger = logging.getLogger(__name__)
|
@@ -74,7 +78,8 @@ async def generate_conversation_title(message: str, model: str, client: Any) ->
|
|
74
78
|
logger.error(f"Failed to generate title after multiple retries. Last error: {last_error}")
|
75
79
|
return f"Conversation ({datetime.now().strftime('%Y-%m-%d %H:%M')})"
|
76
80
|
|
77
|
-
|
81
|
+
# Modified signature to accept app instance
|
82
|
+
async def generate_streaming_response(app: 'SimpleChatApp', messages: List[Dict], model: str, style: str, client: Any, callback: Any) -> str:
|
78
83
|
"""Generate a streaming response from the model"""
|
79
84
|
logger.info(f"Starting streaming response with model: {model}")
|
80
85
|
full_response = ""
|
@@ -84,6 +89,11 @@ async def generate_streaming_response(messages: List[Dict], model: str, style: s
|
|
84
89
|
|
85
90
|
try:
|
86
91
|
async for chunk in client.generate_stream(messages, model, style):
|
92
|
+
# Check if generation was cancelled by the app (e.g., via escape key)
|
93
|
+
if not app.is_generating:
|
94
|
+
logger.info("Generation cancelled by app flag.")
|
95
|
+
break # Exit the loop immediately
|
96
|
+
|
87
97
|
if chunk: # Only process non-empty chunks
|
88
98
|
buffer.append(chunk)
|
89
99
|
current_time = time.time()
|
@@ -92,6 +102,10 @@ async def generate_streaming_response(messages: List[Dict], model: str, style: s
|
|
92
102
|
if current_time - last_update >= update_interval or len(''.join(buffer)) > 100:
|
93
103
|
new_content = ''.join(buffer)
|
94
104
|
full_response += new_content
|
105
|
+
# Check again before calling callback, in case it was cancelled during chunk processing
|
106
|
+
if not app.is_generating:
|
107
|
+
logger.info("Generation cancelled before UI update.")
|
108
|
+
break
|
95
109
|
await callback(full_response)
|
96
110
|
buffer = []
|
97
111
|
last_update = current_time
|
@@ -99,16 +113,22 @@ async def generate_streaming_response(messages: List[Dict], model: str, style: s
|
|
99
113
|
# Small delay to let UI catch up
|
100
114
|
await asyncio.sleep(0.05)
|
101
115
|
|
102
|
-
# Send any remaining content
|
103
|
-
if buffer:
|
116
|
+
# Send any remaining content if generation wasn't cancelled
|
117
|
+
if buffer and app.is_generating:
|
104
118
|
new_content = ''.join(buffer)
|
105
119
|
full_response += new_content
|
106
120
|
await callback(full_response)
|
107
121
|
|
108
|
-
|
122
|
+
if app.is_generating:
|
123
|
+
logger.info("Streaming response completed normally.")
|
124
|
+
else:
|
125
|
+
logger.info("Streaming response loop exited due to cancellation.")
|
126
|
+
|
109
127
|
return full_response
|
110
128
|
except Exception as e:
|
111
129
|
logger.error(f"Error in streaming response: {str(e)}")
|
130
|
+
# Ensure the app knows generation stopped on error
|
131
|
+
app.is_generating = False
|
112
132
|
raise
|
113
133
|
|
114
134
|
def ensure_ollama_running() -> bool:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: chat-console
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.991.dev1
|
4
4
|
Summary: A command-line interface for chatting with LLMs, storing chats and (future) rag interactions
|
5
5
|
Home-page: https://github.com/wazacraftrfid/chat-console
|
6
6
|
Author: Johnathan Greenaway
|
@@ -1,23 +1,23 @@
|
|
1
1
|
app/__init__.py,sha256=OeqboIrx_Kjea0CY9Be8nLI-No1YWQfqbWIp-4lMOOI,131
|
2
2
|
app/config.py,sha256=sKNp6Za4ZfW-CZBOvEv0TncAS77AnKi86hTM51C4KQ4,5227
|
3
3
|
app/database.py,sha256=nt8CVuDpy6zw8mOYqDcfUmNw611t7Ln7pz22M0b6-MI,9967
|
4
|
-
app/main.py,sha256=
|
4
|
+
app/main.py,sha256=PepaAw5akZkWQDeq-BNRVhXWNqsztu9-Tgsz9LuIBTg,46275
|
5
5
|
app/models.py,sha256=4-y9Lytay2exWPFi0FDlVeRL3K2-I7E-jBqNzTfokqY,2644
|
6
|
-
app/utils.py,sha256=
|
6
|
+
app/utils.py,sha256=AgmLrmyikt1Y7KturNmZVK2eC6de-RfRadVbp3HmUAg,8434
|
7
7
|
app/api/__init__.py,sha256=A8UL84ldYlv8l7O-yKzraVFcfww86SgWfpl4p7R03-w,62
|
8
8
|
app/api/anthropic.py,sha256=x5PmBXEKe_ow2NWk8XdqSPR0hLOdCc_ypY5QAySeA78,4234
|
9
9
|
app/api/base.py,sha256=-6RSxSpqe-OMwkaq1wVWbu3pVkte-ZYy8rmdvt-Qh48,3953
|
10
10
|
app/api/ollama.py,sha256=zFZ3g2sYncvMgcvx92jTCLkigIaDvTuhILcLiCrwisc,11640
|
11
11
|
app/api/openai.py,sha256=1fYgFXXL6yj_7lQ893Yj28RYG4M8d6gt_q1gzhhjcig,3641
|
12
12
|
app/ui/__init__.py,sha256=RndfbQ1Tv47qdSiuQzvWP96lPS547SDaGE-BgOtiP_w,55
|
13
|
-
app/ui/chat_interface.py,sha256=
|
13
|
+
app/ui/chat_interface.py,sha256=VwmVvltxS9l18DI9U7kL43t8kSPPNsrkkrrUSoGu16Q,13623
|
14
14
|
app/ui/chat_list.py,sha256=WQTYVNSSXlx_gQal3YqILZZKL9UiTjmNMIDX2I9pAMM,11205
|
15
15
|
app/ui/model_selector.py,sha256=Aj1irAs9DQMn8wfcPsFZGxWmx0JTzHjSe7pVdDMwqTQ,13182
|
16
16
|
app/ui/search.py,sha256=b-m14kG3ovqW1-i0qDQ8KnAqFJbi5b1FLM9dOnbTyIs,9763
|
17
17
|
app/ui/styles.py,sha256=04AhPuLrOd2yenfRySFRestPeuTPeMLzhmMB67NdGvw,5615
|
18
|
-
chat_console-0.1.
|
19
|
-
chat_console-0.1.
|
20
|
-
chat_console-0.1.
|
21
|
-
chat_console-0.1.
|
22
|
-
chat_console-0.1.
|
23
|
-
chat_console-0.1.
|
18
|
+
chat_console-0.1.991.dev1.dist-info/licenses/LICENSE,sha256=srHZ3fvcAuZY1LHxE7P6XWju2njRCHyK6h_ftEbzxSE,1057
|
19
|
+
chat_console-0.1.991.dev1.dist-info/METADATA,sha256=1eRmKQXkPFNZT4f54lotKMLPMsmJP4gSLecZZN82VuY,2928
|
20
|
+
chat_console-0.1.991.dev1.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
21
|
+
chat_console-0.1.991.dev1.dist-info/entry_points.txt,sha256=kkVdEc22U9PAi2AeruoKklfkng_a_aHAP6VRVwrAD7c,67
|
22
|
+
chat_console-0.1.991.dev1.dist-info/top_level.txt,sha256=io9g7LCbfmTG1SFKgEOGXmCFB9uMP2H5lerm0HiHWQE,4
|
23
|
+
chat_console-0.1.991.dev1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|