AiBot güncellemeleri

This commit is contained in:
Sedat Öztürk 2026-03-21 19:59:22 +03:00
parent 52e52bb03c
commit 4807d9de32
7 changed files with 226 additions and 721 deletions

View file

@ -6,5 +6,6 @@ namespace Sozsoft.Platform.AiBots;
public class AiBotDto : FullAuditedEntityDto<Guid> public class AiBotDto : FullAuditedEntityDto<Guid>
{ {
public string Name { get; set; } public string Name { get; set; }
public string ApiUrl { get; set; }
} }

View file

@ -1,9 +1,9 @@
{ {
"AiBots": [ "AiBots": [
{ {
"Name": "Chat Bot", "Name": "Chat",
"Description": "A general purpose chat bot that can answer questions and have conversations.", "Description": "Sözsoft Chat Bot",
"ApiUrl": "https://api.openai.com/v1/chat/completions", "ApiUrl": "https://ai.sozsoft.com/webhook/chat",
"IsActive": true "IsActive": true
} }
], ],

View file

@ -1200,7 +1200,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
SelectCommandType = SelectCommandTypeEnum.Table, SelectCommandType = SelectCommandTypeEnum.Table,
SelectCommand = TableNameResolver.GetFullTableName(nameof(TableNameEnum.AiBot)), SelectCommand = TableNameResolver.GetFullTableName(nameof(TableNameEnum.AiBot)),
KeyFieldName = "Id", KeyFieldName = "Id",
KeyFieldDbSourceType = DbType.Int32, KeyFieldDbSourceType = DbType.Guid,
SortMode = GridOptions.SortModeSingle, SortMode = GridOptions.SortModeSingle,
FilterRowJson = DefaultFilterRowJson, FilterRowJson = DefaultFilterRowJson,
HeaderFilterJson = DefaultHeaderFilterJson, HeaderFilterJson = DefaultHeaderFilterJson,

194
configs/ai/Chat.json Normal file
View file

@ -0,0 +1,194 @@
{
"name": "Chat",
"nodes": [
{
"parameters": {
"multipleMethods": true,
"httpMethod": [
"POST"
],
"path": "chat",
"responseMode": "lastNode",
"responseData": "allEntries",
"options": {}
},
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
-704,
224
],
"id": "5624c28a-5e8f-4fd9-88ac-bc9a630a9cc0",
"name": "Webhook",
"webhookId": "562dfd4f-4e0b-4292-9986-2fbd3b8ecdc9",
"alwaysOutputData": true,
"executeOnce": false,
"retryOnFail": false
},
{
"parameters": {
"promptType": "define",
"text": "={{ $('Webhook').item.json.body.question }}",
"options": {
"systemMessage": "Kullanıcı: {{ $json.body.question }}\n\nDoğrudan yanıt ver. Açıklayıcı, öğretici ve samimi ol."
}
},
"type": "@n8n/n8n-nodes-langchain.agent",
"typeVersion": 1.8,
"position": [
-48,
224
],
"id": "f5a4eb80-6e3f-47a3-9e42-069fb6992a8b",
"name": "AI Chat",
"alwaysOutputData": false,
"onError": "continueErrorOutput"
},
{
"parameters": {
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.memoryManager",
"typeVersion": 1.1,
"position": [
-448,
224
],
"id": "f008f540-216b-42f3-815c-b17658b4c7ad",
"name": "Chat Memory Manager",
"alwaysOutputData": false,
"disabled": true
},
{
"parameters": {
"sessionIdType": "customKey",
"sessionKey": "={{ $('Webhook').item.json.body.sessionId }}",
"contextWindowLength": 100
},
"type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
"typeVersion": 1.3,
"position": [
-304,
480
],
"id": "80c637b6-06e1-41b1-a946-84065a9e327a",
"name": "Simple Memory"
},
{
"parameters": {
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"typeVersion": 1,
"position": [
-48,
480
],
"id": "08879cec-78df-4bd7-a8aa-f0ec6fc5e0ae",
"name": "Google Gemini Chat Model",
"credentials": {
"googlePalmApi": {
"id": "2y8O0r5mQKG5cdcc",
"name": "Google Gemini(PaLM) Api account"
}
}
},
{
"parameters": {
"jsCode": "const cleanText = (text) =>\n text\n .replace(/\\\\/g, \"\\\\\\\\\") // ters slash\n .replace(/\"/g, '\\\\\"'); // çift tırnak\n\nreturn [\n {\n json: {\n type: \"chat\",\n question: $('Webhook').first().json.body.question,\n sql: null,\n answer: cleanText($input.first().json.output),\n chart: null,\n error: $input.first().json.error || null\n }\n }\n];\n\n"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
560,
224
],
"id": "7f66cfbf-d19e-421b-92c3-d9a1909c1434",
"name": "Chat Code",
"alwaysOutputData": true
}
],
"pinData": {},
"connections": {
"Webhook": {
"main": [
[
{
"node": "Chat Memory Manager",
"type": "main",
"index": 0
}
],
[]
]
},
"AI Chat": {
"main": [
[
{
"node": "Chat Code",
"type": "main",
"index": 0
}
],
[
{
"node": "Chat Code",
"type": "main",
"index": 0
}
]
]
},
"Chat Memory Manager": {
"main": [
[
{
"node": "AI Chat",
"type": "main",
"index": 0
}
]
]
},
"Simple Memory": {
"ai_memory": [
[
{
"node": "AI Chat",
"type": "ai_memory",
"index": 0
},
{
"node": "Chat Memory Manager",
"type": "ai_memory",
"index": 0
}
]
]
},
"Google Gemini Chat Model": {
"ai_languageModel": [
[
{
"node": "AI Chat",
"type": "ai_languageModel",
"index": 0
}
]
]
}
},
"active": true,
"settings": {
"executionOrder": "v1",
"availableInMCP": false
},
"versionId": "84010ee3-81a9-48c8-9b48-a0661355d85c",
"meta": {
"templateCredsSetupCompleted": true,
"instanceId": "1d288821beaaeeada5e8dce6f282c802098a0c83ef6ddb35a174b09a9d43850e"
},
"id": "R1V2XtEQCknLJvSkwUW6s",
"tags": []
}

File diff suppressed because one or more lines are too long

View file

@ -2,4 +2,5 @@ import { FullAuditedEntityDto } from '../abp'
export interface AiDto extends FullAuditedEntityDto<string> { export interface AiDto extends FullAuditedEntityDto<string> {
name: string name: string
apiUrl?: string
} }

View file

@ -39,14 +39,13 @@ const Assistant = () => {
const [messages, setMessages] = useState<Message[]>([]) const [messages, setMessages] = useState<Message[]>([])
const [input, setInput] = useState('') const [input, setInput] = useState('')
const [loading, setLoading] = useState(false) const [loading, setLoading] = useState(false)
const [bot, setBot] = useState<{ key: string; name: string }[]>([]) const [bot, setBot] = useState<AiDto[]>([])
const [selectedBot, setSelectedBot] = useState<string | null>(null) const [selectedBot, setSelectedBot] = useState<string | null>(null)
const { id, avatar } = useStoreState((state) => state.auth.user) const { id, avatar } = useStoreState((state) => state.auth.user)
const inputRef = useRef<HTMLTextAreaElement | null>(null) const inputRef = useRef<HTMLTextAreaElement | null>(null)
const bottomRef = useRef<HTMLDivElement | null>(null) const bottomRef = useRef<HTMLDivElement | null>(null)
const { VITE_AI_URL } = import.meta.env
const { translate } = useLocalization() const { translate } = useLocalization()
const aiPosts = useStoreState((state) => state.base.messages.aiPosts) const aiPosts = useStoreState((state) => state.base.messages.aiPosts)
@ -66,14 +65,16 @@ const Assistant = () => {
maxResultCount: 1000, maxResultCount: 1000,
sorting: 'name', sorting: 'name',
}) })
const items =
result?.data?.items?.map((bot: AiDto) => ({
key: bot.id!,
name: bot.name,
})) ?? []
setBot(items) if (!result?.data?.items) {
if (items.length > 0) setSelectedBot(items[0].key) console.warn('Bot listesi boş veya hatalı formatta:', result)
setBot([])
return
}
setBot(result?.data?.items)
const firstBotId = result?.data?.items?.find((item) => item.id)?.id ?? null
setSelectedBot(firstBotId)
} catch (error) { } catch (error) {
console.error('Bot listesi alınırken hata oluştu:', error) console.error('Bot listesi alınırken hata oluştu:', error)
} }
@ -110,7 +111,14 @@ const Assistant = () => {
setMessages((prev) => [...prev, { role: 'user', content: userMessage }]) setMessages((prev) => [...prev, { role: 'user', content: userMessage }])
try { try {
const response = await fetch(VITE_AI_URL + selectedBot, { const selectedBotItem = bot.find((item) => item.id === selectedBot)
const targetUrl = (selectedBotItem?.apiUrl || '').trim()
if (!targetUrl) {
throw new Error('AI bot URL bulunamadı.')
}
const response = await fetch(targetUrl, {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ body: JSON.stringify({
@ -340,15 +348,16 @@ const Assistant = () => {
<Dropdown <Dropdown
placement="top-start" placement="top-start"
title={ title={
bot.find((item) => item.key === selectedBot)?.name || bot.find((item) => item.id === selectedBot)?.name || translate('::AI.SelectModel')
translate('::AI.SelectModel')
} }
> >
{bot.map((item) => ( {bot
<Dropdown.Item key={item.key} eventKey={item.key} onSelect={onBotItemClick}> .filter((item) => !!item.id)
{item.name} .map((item) => (
</Dropdown.Item> <Dropdown.Item key={item.id!} eventKey={item.id!} onSelect={onBotItemClick}>
))} {item.name}
</Dropdown.Item>
))}
</Dropdown> </Dropdown>
</div> </div>