Skip to content

Commit

Permalink
News: added tags repository
Browse files Browse the repository at this point in the history
  • Loading branch information
YuJuncen committed Jul 26, 2023
1 parent 930402e commit 5b11e1f
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 29 deletions.
4 changes: 2 additions & 2 deletions lib/components/news.dart
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ class AIFetchingTask {
}

class NewsController extends GetxController {
HashMap<Uuid, AIFetchingTask> _pending_tasks = HashMap();
HashMap<String, AIFetchingTask> _pending_tasks = HashMap();

RxList<News> _$cached = <News>[].obs;
RxList<PromotedRecord> _$record = <PromotedRecord>[].obs;
Expand Down Expand Up @@ -202,7 +202,7 @@ class NewsController extends GetxController {

Future<PromotedRecord> recommendNews(List<News> news,
{UserProfile? profile}) async {
final id = Uuid();
final id = Uuid().v4();
_pending_tasks[id] = AIFetchingTask(source: news);
try {
final currentPromoted =
Expand Down
50 changes: 50 additions & 0 deletions lib/components/setting.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import 'dart:developer';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:moyubie/controller/chat_room.dart';
import 'package:moyubie/controller/settings.dart';
import 'package:get/get.dart';
import 'package:moyubie/repository/chat_room.dart';
import 'package:moyubie/repository/tags.dart';
import 'package:uuid/uuid.dart';

class SettingPage extends StatefulWidget {
const SettingPage({super.key});
Expand Down Expand Up @@ -361,6 +366,51 @@ class _SettingPageState extends State<SettingPage> {
child: const Text("Clear remote messages")),
],
),
// DEBUGGER
if (kDebugMode) ...[
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
const Text("Debugger"),
Tooltip(
message: "You can see me?",
child: IconButton(
iconSize: 10.0,
splashRadius: 10,
color: Theme.of(context).colorScheme.primary,
onPressed: () {},
icon: const Icon(Icons.question_mark),
),
),
],
),
divider,
sizedBoxSpace,
Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ElevatedButton(
onPressed: () {
final repo = Get.find<TagsRepository>();
repo
.addNewTags(List.generate(10, (index) => Uuid().v4()))
.then((value) => log("DONE?", name: "moyubie::tags"))
.catchError((err) => log("ERROR! [$err]", name: "moyubie::tags"));
},
child: const Text("Add some random tags for you!")),
ElevatedButton(
onPressed: () {
final repo = Get.find<TagsRepository>();
repo
.fetchMostPopularTags(5)
.then((value) => log("DONE? [$value]", name: "moyubie::tags"))
.catchError((err) => log("ERROR! [$err]", name: "moyubie::tags"));
},
child: const Text("Fetch tags of you!")),
],
)
]
],
);
}),
Expand Down
2 changes: 2 additions & 0 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'package:moyubie/controller/settings.dart';
import 'package:moyubie/components/setting.dart';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'package:moyubie/repository/tags.dart';
import 'package:sqflite_common_ffi_web/sqflite_ffi_web.dart';
import 'package:sqflite_common_ffi/sqflite_ffi.dart';
import 'package:moyubie/configs/translations.dart';
Expand Down Expand Up @@ -88,6 +89,7 @@ class MyApp extends StatelessWidget {
Get.put(MessageController());
Get.put(PromptController());
Get.put(ChatRoomController());
Get.put(TagsRepository.byConfig(settingsCtl));
Get.put(NewsController(settingsCtl.openAiKey, settingsCtl.gptModel));
final newsWinKey = GlobalKey();
return MaterialApp(
Expand Down
110 changes: 83 additions & 27 deletions lib/repository/tags.dart
Original file line number Diff line number Diff line change
@@ -1,39 +1,95 @@
import 'dart:developer';

import 'package:get/get.dart';
import 'package:get/get_rx/get_rx.dart';
import 'package:moyubie/controller/settings.dart';
import 'package:moyubie/utils/tidb.dart';
import 'package:mysql_client/mysql_client.dart';
import 'package:stream_transform/stream_transform.dart';

class _CachedConnection {
MySQLConnection? _last;

_CachedConnection(Stream<MySQLConnection> stream) {
stream.listen((event) {
if (_last != null && _last != event) {
log("Update connection. [old=$_last, new=$event]", name: "moyubie::_CachedConnection");
_last!.close();
}
_last = event;
},
onError: (err) =>
log("ERROR [$err]", name: "moyubie::_CachedConnection"),
onDone: () => log("APP CLOSED", name: "moyubie::_CachedConnection"),
cancelOnError: false);
}

import 'chat_room.dart';
MySQLConnection? get value => _last;
}

class TagsRepository {
static Future<MySQLConnection?> getRemoteDb(TiDBConnection conn,
{bool forceInit = false}) async {
bool shouldInit =
conn.connection == null || !conn.connection!.connected || forceInit;
if (conn.host.isEmpty ||
conn.port == 0 ||
conn.userName.isEmpty ||
conn.password.isEmpty) {
shouldInit = false;
}
factory TagsRepository.byConfig(SettingsController ctl,
{bool forceInit = false}) {
final stream = ctl.serverlessCmd.stream.switchMap((p0) {
final (host, port, user, password) = parseTiDBConnectionText(p0);
if (host.isEmpty || port == 0 || user.isEmpty) {
return Stream<MySQLConnection>.error(Exception("Invalid DB"));
}
return Stream.fromFuture(() async {
final conn = await MySQLConnection.createConnection(
host: host, port: port, userName: user, password: password);
await conn.connect();
await prepareTables(conn);
return conn;
}());
});
return TagsRepository(_CachedConnection(stream));
}

final _CachedConnection _conn;

if (shouldInit) {
// Make sure the old connection has been close
conn.connection?.close();
TagsRepository(this._conn);

var dbConn = await MySQLConnection.createConnection(
host: conn.host,
port: conn.port,
userName: conn.userName,
password: conn.password);
conn.connection = dbConn;
static const _tagName = "name";
static const _tagAddedAt = "added_at";
static const _table = "tags";
static const _db = "moyubie";

await dbConn.connect();
static Future<void> prepareTables(MySQLConnection conn) async {
await conn.execute("CREATE DATABASE IF NOT EXISTS $_db");
await conn.execute("CREATE TABLE IF NOT EXISTS `$_db`.$_table("
"$_tagName TEXT,"
"$_tagAddedAt DATETIME,"
"INDEX sand_of_time(added_at)"
");");
}

dbConn.onClose(() {
// I haven't check the client carefully.
// Is it enough to handle connection broken or someting bad?
conn.connection = null;
});
Future<void> addNewTags(List<String> tags) async {
final now = DateTime.now();
if (_conn.value == null) {
throw Exception("The connection isn't ready for now...");
}
final insert = await _conn.value!.prepare(
"INSERT INTO $_db.$_table($_tagName, $_tagAddedAt) VALUES (?, ?);");
await Future.wait(tags.map((e) => insert.execute([e, now])),
eagerError: true);
}

return conn.connection;
Future<List<String>> fetchMostPopularTags(int limit) async {
if (_conn.value == null) {
throw Exception("The connection isn't ready for now...");
}
final res = await _conn.value!.execute(
"SELECT t1.NAME AS $_tagName FROM "
"(SELECT COUNT($_tagName) AS CNT, $_tagName AS NAME FROM $_db.$_table GROUP BY $_tagName) AS t1"
" ORDER BY t1.CNT LIMIT :limit; ",
{"limit": limit});
final output = <String>[];
for (final rs in res) {
for (final row in rs.rows) {
output.add(row.colByName(_tagName) as String);
}
}
return output;
}
}
1 change: 1 addition & 0 deletions lib/utils/ai_recommend.dart
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ class NewsPromoter extends WithOpenAI {
],
// Make the output more predictable.
topP: 0.08,
presencePenalty: 1,
functionCall: FunctionCall.forFunction(_fn_recommend_news.name),
functions: [_fn_get_news, _fn_get_user_info, _fn_recommend_news]);
final args = res.choices[0].message.functionCall?.arguments;
Expand Down

0 comments on commit 5b11e1f

Please sign in to comment.