Skip to content

Commit 0918264

Browse files
committed
feat: update readme and optimize diff logic
1 parent 3339d68 commit 0918264

File tree

3 files changed

+49
-77
lines changed

3 files changed

+49
-77
lines changed

README.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
# SwiftChat — A Cross-platform AI Chat App
1+
# SwiftChat — A Cross-platform AI Assistant
22

3-
> 🚀 Your Personal AI AssistantFast, Private, and Easy to use
3+
> 🚀 Your Personal AI WorkspaceChat, Create Apps, and More
44
55
[![GitHub Release](https://img.shields.io/github/v/release/aws-samples/swift-chat)](https://github.com/aws-samples/swift-chat/releases)
66
[![License](https://img.shields.io/badge/license-MIT--0-green)](LICENSE)
77

88
[中文](/README_CN.md)
99

10-
SwiftChat is a fast and responsive AI chat application developed with [React Native](https://reactnative.dev/) and
10+
SwiftChat is a fast and responsive AI assistant developed with [React Native](https://reactnative.dev/) and
1111
powered by [Amazon Bedrock](https://aws.amazon.com/bedrock/), with compatibility extending to other model providers such
1212
as Ollama, DeepSeek, OpenAI and OpenAI Compatible. With its minimalist design philosophy and robust privacy protection,
13-
it delivers real-time streaming conversations, AI image generation and voice conversation assistant capabilities
14-
across Android, iOS, and macOS platforms.
13+
it delivers real-time streaming conversations, AI image generation, instant web app creation and voice conversation
14+
capabilities across Android, iOS, and macOS platforms.
1515

1616
![](assets/promo.avif)
1717

@@ -32,7 +32,7 @@ across Android, iOS, and macOS platforms.
3232
<img src="assets/animations/share_and_import.avif" width=24%>
3333
</div>
3434

35-
**App Examples**: 2048 Game, Gomoku, News Reader and Tetris
35+
**App Examples**: 2048 Game, Gomoku, Tetris and News Reader
3636

3737
<div style="display: flex; flex-direction: 'row'; background-color: #888888;">
3838
<img src="assets/animations/app_2048.avif" width=24%>
@@ -245,6 +245,8 @@ can enable the **Use Proxy** option to forward your requests.
245245
## Key Features
246246

247247
- Real-time streaming chat with AI
248+
- Instant web app creation, editing and sharing
249+
- Web search for real-time information retrieval
248250
- Rich Markdown Support: Tables, Code Blocks, LaTeX, Mermaid Chart and More
249251
- AI image generation with progress
250252
- Multimodal support (images, videos & documents)

README_CN.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
# SwiftChat — 跨平台 AI 聊天应用
1+
# SwiftChat — 跨平台 AI 助手
22

3-
> 🚀 您的个人 AI 助手快速、私有、易于使用
3+
> 🚀 您的个人 AI 工作空间聊天、创建应用等
44
55
[![GitHub Release](https://img.shields.io/github/v/release/aws-samples/swift-chat)](https://github.com/aws-samples/swift-chat/releases)
66
[![License](https://img.shields.io/badge/license-MIT--0-green)](LICENSE)
77

88
[English](/README.md)
99

10-
SwiftChat 是一款快速响应的 AI 聊天应用,采用 [React Native](https://reactnative.dev/)
10+
SwiftChat 是一款快速响应的 AI 助手,采用 [React Native](https://reactnative.dev/)
1111
开发,并依托 [Amazon Bedrock](https://aws.amazon.com/bedrock/) 提供强大支持,同时兼容 Ollama、DeepSeek、OpenAI 和 OpenAI
1212
兼容的其他模型供应商。凭借其极简设计理念与坚实的隐私保护措施,该应用在 Android、iOS 和 macOS 平台上实现了实时流式对话、AI
13-
图像生成和语音对话助手功能
13+
图像生成、极速 Web 应用创建和语音对话功能
1414

1515
![](assets/promo.avif)
1616

@@ -31,7 +31,7 @@ SwiftChat 是一款快速响应的 AI 聊天应用,采用 [React Native](https
3131
<img src="assets/animations/share_and_import.avif" width=24%>
3232
</div>
3333

34-
**应用示例**:2048 游戏、五子棋、新闻阅读器和俄罗斯方块
34+
**应用示例**:2048 游戏、五子棋、俄罗斯方块和新闻阅读器
3535

3636
<div style="display: flex; flex-direction: 'row'; background-color: #888888;">
3737
<img src="assets/animations/app_2048.avif" width=24%>
@@ -234,7 +234,9 @@ SwiftChat 是一款快速响应的 AI 聊天应用,采用 [React Native](https
234234
## 主要功能
235235

236236
- 与 AI 进行实时流式聊天
237-
- 丰富的 Markdown 支持:表格、代码块、LaTeX, Mermaid图标等
237+
- 极速 Web 应用创建、编辑和分享
238+
- 网络搜索实时信息检索
239+
- 丰富的 Markdown 支持:表格、代码块、LaTeX、Mermaid 图表等
238240
- 带进度显示的 AI 图像生成
239241
- 多模态支持(图像、视频和文档)
240242
- 对话历史列表查看和管理

react-native/src/chat/util/ApplyDiff.ts

Lines changed: 33 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -287,36 +287,6 @@ function findAllMatches(
287287
return positions;
288288
}
289289

290-
/** Get the longest line from an array (most likely to be unique) */
291-
function getLongestLine(lines: string[]): string | null {
292-
if (lines.length === 0) {
293-
return null;
294-
}
295-
296-
let longest = lines[0];
297-
for (const line of lines) {
298-
if (line.trim().length > longest.trim().length) {
299-
longest = line;
300-
}
301-
}
302-
return longest.trim().length > 0 ? longest : null;
303-
}
304-
305-
/** Find line position in source */
306-
function findLinePosition(
307-
sourceLines: string[],
308-
line: string,
309-
startFrom: number = 0
310-
): number[] {
311-
const positions: number[] = [];
312-
const trimmedLine = line.trim();
313-
for (let i = startFrom; i < sourceLines.length; i++) {
314-
if (sourceLines[i].trim() === trimmedLine) {
315-
positions.push(i);
316-
}
317-
}
318-
return positions;
319-
}
320290

321291
/**
322292
* Find block position using three-layer fallback strategy
@@ -576,44 +546,28 @@ export function applyDiff(
576546
} else if (allPositions.length > 1) {
577547
// Multiple matches - try to disambiguate using middle context
578548
if (firstMiddleContext.length > 0) {
579-
const longestMiddleLine = getLongestLine(firstMiddleContext);
549+
// Sort candidates to prefer those after lastBlockEnd
550+
const sortedCandidates = [...allPositions].sort((a, b) => {
551+
const aAfter =
552+
a + effectiveContext.length >= lastBlockEnd ? 0 : 1;
553+
const bAfter =
554+
b + effectiveContext.length >= lastBlockEnd ? 0 : 1;
555+
return aAfter - bAfter || a - b;
556+
});
557+
558+
for (const candidatePos of sortedCandidates) {
559+
const changePos = candidatePos + effectiveContext.length;
560+
const searchAfter = changePos + removals.length;
580561

581-
if (longestMiddleLine) {
582-
// Find positions of the longest middle line
583-
const middleLinePositions = findLinePosition(
562+
// Check if middle context matches after this candidate
563+
const middlePositions = findAllMatches(
584564
sourceLines,
585-
longestMiddleLine,
586-
0
565+
firstMiddleContext,
566+
searchAfter
587567
);
588-
589-
// For each candidate position, check if middle line appears after it
590-
// Sort candidates to prefer those after lastBlockEnd
591-
const sortedCandidates = [...allPositions].sort((a, b) => {
592-
const aAfter =
593-
a + effectiveContext.length >= lastBlockEnd ? 0 : 1;
594-
const bAfter =
595-
b + effectiveContext.length >= lastBlockEnd ? 0 : 1;
596-
return aAfter - bAfter || a - b;
597-
});
598-
599-
for (const candidatePos of sortedCandidates) {
600-
const changePos = candidatePos + effectiveContext.length;
601-
const searchAfter = changePos + removals.length;
602-
603-
// Check if any middle line position is reasonably close after this candidate
604-
for (const middlePos of middleLinePositions) {
605-
if (
606-
middlePos >= searchAfter &&
607-
middlePos < searchAfter + 100
608-
) {
609-
// Found: this candidate has the middle context after it
610-
position = changePos;
611-
break;
612-
}
613-
}
614-
if (position !== -1) {
615-
break;
616-
}
568+
if (middlePositions.length > 0 && middlePositions[0] < searchAfter + 100) {
569+
position = changePos;
570+
break;
617571
}
618572
}
619573
}
@@ -641,6 +595,20 @@ export function applyDiff(
641595
position = findBlockPosition(sourceLines, block, lastBlockEnd);
642596
}
643597

598+
// Fallback: use firstMiddleContext to reverse-locate position
599+
// When context is wrong but middle context exists, find middle context position
600+
// and calculate insertion point by going back removals.length lines
601+
if (position === -1 && firstMiddleContext.length > 0) {
602+
const middlePositions = findAllMatches(
603+
sourceLines,
604+
firstMiddleContext,
605+
lastBlockEnd
606+
);
607+
if (middlePositions.length >= 1) {
608+
position = middlePositions[0] - removals.length;
609+
}
610+
}
611+
644612
if (position === -1) {
645613
const context = block.contextBefore.slice(0, 2).join('\n');
646614
const removal = block.removals.slice(0, 2).join('\n');

0 commit comments

Comments
 (0)