Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions admin/src/views/LoginView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ async function handleSubmit() {

<!-- Telegram Support -->
<a
href="https://t.me/shaerware_digital_bot"
href="https://t.me/ai_sekretar24bot"
target="_blank"
rel="noopener noreferrer"
title="Техподдержка 24/7 в Telegram"
Expand Down Expand Up @@ -815,7 +815,7 @@ async function handleSubmit() {
</p>
<div class="flex flex-wrap gap-3">
<a
href="https://t.me/shaerware_digital_bot"
href="https://t.me/ai_sekretar24bot"
target="_blank"
rel="noopener noreferrer"
class="inline-flex items-center gap-2 rounded-lg bg-zinc-800 px-4 py-2 text-sm font-medium text-white ring-1 ring-zinc-700 hover:bg-zinc-700 hover:ring-orange-600/50 transition-all"
Expand Down
6 changes: 6 additions & 0 deletions db/repositories/chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ async def update_session(
knowledge_collection_ids: Optional[list[int]] = None,
context_files: Optional[list] = None,
web_search_enabled: Optional[bool] = None,
source: Optional[str] = None,
source_id: Optional[str] = None,
) -> Optional[dict]:
"""Update session title, system prompt, pinned status, RAG config, or context files."""
result = await self.session.execute(
Expand Down Expand Up @@ -216,6 +218,10 @@ async def update_session(
)
if web_search_enabled is not None:
session.web_search_enabled = web_search_enabled
if source is not None:
session.source = source
if source_id is not None:
session.source_id = source_id if source_id else None
session.updated = datetime.utcnow()

await self.session.flush()
Expand Down
105 changes: 105 additions & 0 deletions mobile/src/api/admin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,119 @@ export interface LlmOption {
type: "vllm" | "cloud";
}

export interface ShareableUser {
id: number;
username: string;
display_name: string;
role: string;
}

export interface ChatShare {
id: number;
session_id: string;
user_id: number;
permission: "read" | "write";
shared_by: number;
shared_at: string;
username: string;
display_name: string;
is_default_mobile: boolean;
}

export interface MobileInstance {
id: string;
name: string;
description: string;
enabled: boolean;
llm_backend: string;
llm_persona: string;
system_prompt: string | null;
rag_mode: string;
knowledge_collection_ids: number[] | null;
share_count: number;
}

export interface MobileShare {
id: number;
resource_id: string;
user_id: number;
permission: "view" | "edit";
username: string;
display_name: string;
}

export const adminApi = {
// LLM providers
getProviders: () =>
api.get<{ providers: CloudProvider[] }>(
"/admin/llm/providers?enabled_only=true",
),

// RAG collections
getCollections: () =>
api.get<{ collections: KnowledgeCollection[] }>(
"/admin/wiki-rag/collections",
),

// Shareable users
getShareableUsers: () =>
api.get<{ users: ShareableUser[] }>(
"/admin/chat/shareable-users",
),

// Chat shares
getSessionShares: (sessionId: string) =>
api.get<{ shares: ChatShare[] }>(
`/admin/chat/sessions/${sessionId}/shares`,
),

shareSession: (sessionId: string, userId: number, permission: "read" | "write" = "read") =>
api.post<{ share: ChatShare }>(
`/admin/chat/sessions/${sessionId}/shares`,
{ user_id: userId, permission },
),

removeSessionShare: (sessionId: string, userId: number) =>
api.delete<{ status: string }>(
`/admin/chat/sessions/${sessionId}/shares/${userId}`,
),

// Default mobile session
getDefaultMobileUsers: (sessionId: string) =>
api.get<{ users: ShareableUser[] }>(
`/admin/chat/sessions/${sessionId}/default-mobile-users`,
),

setDefaultMobile: (sessionId: string, userIds: number[]) =>
api.put<{ shares: ChatShare[] }>(
`/admin/chat/sessions/${sessionId}/default-mobile`,
{ user_ids: userIds },
),

removeDefaultMobile: (sessionId: string, userId: number) =>
api.delete<{ status: string }>(
`/admin/chat/sessions/${sessionId}/default-mobile/${userId}`,
),

// Mobile instances
getMobileInstances: () =>
api.get<{ instances: MobileInstance[] }>(
"/admin/mobile/instances",
),

getMobileInstanceShares: (instanceId: string) =>
api.get<{ shares: MobileShare[] }>(
`/admin/mobile/instances/${instanceId}/shares`,
),

assignMobileInstance: (instanceId: string, userId: number, permission: "view" | "edit" = "edit") =>
api.post<{ share: MobileShare }>(
`/admin/mobile/instances/${instanceId}/shares`,
{ user_id: userId, permission },
),

removeMobileInstanceShare: (instanceId: string, userId: number) =>
api.delete<{ status: string }>(
`/admin/mobile/instances/${instanceId}/shares/${userId}`,
),
};
3 changes: 3 additions & 0 deletions mobile/src/api/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export interface ChatSession {
messages: ChatMessage[];
system_prompt?: string;
source?: string | null;
source_id?: string | null;
context_files?: ContextFile[];
web_search_enabled?: boolean;
created: string;
Expand Down Expand Up @@ -100,6 +101,8 @@ export const chatApi = {
system_prompt?: string;
context_files?: ContextFile[];
web_search_enabled?: boolean;
source?: string;
source_id?: string;
},
) =>
api.put<{ session: ChatSession }>(
Expand Down
164 changes: 80 additions & 84 deletions mobile/src/components/MessageBubble.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,11 @@ const props = defineProps<{
message: ChatMessage;
isStreaming?: boolean;
isSpeaking?: boolean;
isAdmin?: boolean;
}>();

const emit = defineEmits<{
speak: [text: string, id: string];
stopSpeak: [];
copy: [text: string];
edit: [messageId: string, content: string];
saveToContext: [messageId: string, content: string];
summarizeBranch: [messageId: string];
Expand Down Expand Up @@ -153,50 +151,49 @@ function cancelEdit() {
</svg>
</button>

<!-- Additional actions -->
<!-- Edit -->
<button
class="p-1.5 rounded text-stone-500 hover:text-stone-300 transition-colors"
title="Редактировать"
@click="startEdit"
>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" /><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" />
</svg>
</button>
<!-- Edit -->
<button
class="p-1.5 rounded text-stone-500 hover:text-stone-300 transition-colors"
title="Редактировать"
@click="startEdit"
>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" /><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" />
</svg>
</button>

<!-- Save to context -->
<button
class="p-1.5 rounded text-stone-500 hover:text-stone-300 transition-colors"
title="В контекст"
@click="$emit('saveToContext', message.id, message.content)"
>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="m21.44 11.05-9.19 9.19a6 6 0 0 1-8.49-8.49l8.57-8.57A4 4 0 1 1 18 8.84l-8.59 8.57a2 2 0 0 1-2.83-2.83l8.49-8.48" />
</svg>
</button>
<!-- Save to context -->
<button
class="p-1.5 rounded text-stone-500 hover:text-stone-300 transition-colors"
title="В контекст"
@click="$emit('saveToContext', message.id, message.content)"
>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="m21.44 11.05-9.19 9.19a6 6 0 0 1-8.49-8.49l8.57-8.57A4 4 0 1 1 18 8.84l-8.59 8.57a2 2 0 0 1-2.83-2.83l8.49-8.48" />
</svg>
</button>

<!-- Summarize branch -->
<button
class="p-1.5 rounded text-stone-500 hover:text-stone-300 transition-colors"
title="Суммаризация ветки"
@click="$emit('summarizeBranch', message.id)"
>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" /><polyline points="14 2 14 8 20 8" /><line x1="16" y1="13" x2="8" y2="13" /><line x1="16" y1="17" x2="8" y2="17" /><polyline points="10 9 9 9 8 9" />
</svg>
</button>
<!-- Summarize branch -->
<button
class="p-1.5 rounded text-stone-500 hover:text-stone-300 transition-colors"
title="Суммаризация ветки"
@click="$emit('summarizeBranch', message.id)"
>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" /><polyline points="14 2 14 8 20 8" /><line x1="16" y1="13" x2="8" y2="13" /><line x1="16" y1="17" x2="8" y2="17" /><polyline points="10 9 9 9 8 9" />
</svg>
</button>

<!-- Delete branch from here -->
<button
class="p-1.5 rounded text-stone-500 hover:text-red-400 transition-colors"
title="Удалить ветку"
@click="$emit('deleteBranch', message.id)"
>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="3 6 5 6 21 6" /><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" />
</svg>
</button>
<!-- Delete branch from here -->
<button
class="p-1.5 rounded text-stone-500 hover:text-red-400 transition-colors"
title="Удалить ветку"
@click="$emit('deleteBranch', message.id)"
>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="3 6 5 6 21 6" /><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" />
</svg>
</button>
</div>

<!-- Action buttons for user messages -->
Expand Down Expand Up @@ -233,50 +230,49 @@ function cancelEdit() {
</svg>
</button>

<!-- Additional actions -->
<!-- Edit -->
<button
class="p-1.5 rounded text-amber-300/50 hover:text-amber-200 transition-colors"
title="Редактировать"
@click="startEdit"
>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" /><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" />
</svg>
</button>
<!-- Edit -->
<button
class="p-1.5 rounded text-amber-300/50 hover:text-amber-200 transition-colors"
title="Редактировать"
@click="startEdit"
>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" /><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" />
</svg>
</button>

<!-- Regenerate response -->
<button
class="p-1.5 rounded text-amber-300/50 hover:text-amber-200 transition-colors"
title="Перегенерировать"
@click="$emit('regenerate', message.id)"
>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="23 4 23 10 17 10" /><path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10" />
</svg>
</button>
<!-- Regenerate response -->
<button
class="p-1.5 rounded text-amber-300/50 hover:text-amber-200 transition-colors"
title="Перегенерировать"
@click="$emit('regenerate', message.id)"
>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="23 4 23 10 17 10" /><path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10" />
</svg>
</button>

<!-- Summarize branch -->
<button
class="p-1.5 rounded text-amber-300/50 hover:text-amber-200 transition-colors"
title="Суммаризация ветки"
@click="$emit('summarizeBranch', message.id)"
>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" /><polyline points="14 2 14 8 20 8" /><line x1="16" y1="13" x2="8" y2="13" /><line x1="16" y1="17" x2="8" y2="17" /><polyline points="10 9 9 9 8 9" />
</svg>
</button>
<!-- Summarize branch -->
<button
class="p-1.5 rounded text-amber-300/50 hover:text-amber-200 transition-colors"
title="Суммаризация ветки"
@click="$emit('summarizeBranch', message.id)"
>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" /><polyline points="14 2 14 8 20 8" /><line x1="16" y1="13" x2="8" y2="13" /><line x1="16" y1="17" x2="8" y2="17" /><polyline points="10 9 9 9 8 9" />
</svg>
</button>

<!-- Delete branch from here -->
<button
class="p-1.5 rounded text-amber-300/50 hover:text-red-400 transition-colors"
title="Удалить ветку"
@click="$emit('deleteBranch', message.id)"
>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="3 6 5 6 21 6" /><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" />
</svg>
</button>
<!-- Delete branch from here -->
<button
class="p-1.5 rounded text-amber-300/50 hover:text-red-400 transition-colors"
title="Удалить ветку"
@click="$emit('deleteBranch', message.id)"
>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="3 6 5 6 21 6" /><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" />
</svg>
</button>
</div>
</template>
</div>
Expand Down
Loading
Loading